Deleted Added
full compact
auditd_lib.c (187214) auditd_lib.c (189279)
1/*-
1/*-
2 * Copyright (c) 2008 Apple Inc.
2 * Copyright (c) 2008-2009 Apple 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 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 *
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 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/libauditd/auditd_lib.c#2 $
29 * $P4: //depot/projects/trustedbsd/openbsm/libauditd/auditd_lib.c#7 $
30 */
31
32#include <sys/param.h>
33
34#include <config/config.h>
35
36#include <sys/dirent.h>
37#include <sys/mount.h>
38#include <sys/socket.h>
39#ifdef HAVE_FULL_QUEUE_H
40#include <sys/queue.h>
41#else /* !HAVE_FULL_QUEUE_H */
42#include <compat/queue.h>
43#endif /* !HAVE_FULL_QUEUE_H */
44
45#include <sys/stat.h>
46#include <sys/time.h>
47
48#include <netinet/in.h>
49
50#include <bsm/audit.h>
51#include <bsm/audit_uevents.h>
52#include <bsm/auditd_lib.h>
53#include <bsm/libbsm.h>
54
30 */
31
32#include <sys/param.h>
33
34#include <config/config.h>
35
36#include <sys/dirent.h>
37#include <sys/mount.h>
38#include <sys/socket.h>
39#ifdef HAVE_FULL_QUEUE_H
40#include <sys/queue.h>
41#else /* !HAVE_FULL_QUEUE_H */
42#include <compat/queue.h>
43#endif /* !HAVE_FULL_QUEUE_H */
44
45#include <sys/stat.h>
46#include <sys/time.h>
47
48#include <netinet/in.h>
49
50#include <bsm/audit.h>
51#include <bsm/audit_uevents.h>
52#include <bsm/auditd_lib.h>
53#include <bsm/libbsm.h>
54
55#include <dirent.h>
55#include <err.h>
56#include <errno.h>
57#include <fcntl.h>
58#include <stdio.h>
59#include <string.h>
60#include <stdlib.h>
61#include <time.h>
62#include <unistd.h>
63#include <netdb.h>
64
65#ifdef __APPLE__
66#include <notify.h>
67#ifndef __BSM_INTERNAL_NOTIFY_KEY
68#define __BSM_INTERNAL_NOTIFY_KEY "com.apple.audit.change"
69#endif /* __BSM_INTERNAL_NOTIFY_KEY */
70#endif /* __APPLE__ */
71
72/*
73 * XXX This is temporary until this is moved to <bsm/audit.h> and shared with
74 * the kernel.
75 */
76#ifndef AUDIT_HARD_LIMIT_FREE_BLOCKS
77#define AUDIT_HARD_LIMIT_FREE_BLOCKS 4
78#endif
79
56#include <err.h>
57#include <errno.h>
58#include <fcntl.h>
59#include <stdio.h>
60#include <string.h>
61#include <stdlib.h>
62#include <time.h>
63#include <unistd.h>
64#include <netdb.h>
65
66#ifdef __APPLE__
67#include <notify.h>
68#ifndef __BSM_INTERNAL_NOTIFY_KEY
69#define __BSM_INTERNAL_NOTIFY_KEY "com.apple.audit.change"
70#endif /* __BSM_INTERNAL_NOTIFY_KEY */
71#endif /* __APPLE__ */
72
73/*
74 * XXX This is temporary until this is moved to <bsm/audit.h> and shared with
75 * the kernel.
76 */
77#ifndef AUDIT_HARD_LIMIT_FREE_BLOCKS
78#define AUDIT_HARD_LIMIT_FREE_BLOCKS 4
79#endif
80
81/*
82 * Number of seconds to January 1, 2000
83 */
84#define JAN_01_2000 946598400
85
80struct dir_ent {
81 char *dirname;
82 uint8_t softlim;
83 uint8_t hardlim;
84 TAILQ_ENTRY(dir_ent) dirs;
85};
86
87static TAILQ_HEAD(, dir_ent) dir_q;
86struct dir_ent {
87 char *dirname;
88 uint8_t softlim;
89 uint8_t hardlim;
90 TAILQ_ENTRY(dir_ent) dirs;
91};
92
93static TAILQ_HEAD(, dir_ent) dir_q;
88static int minval = -1;
89
94
95struct audit_trail {
96 time_t at_time;
97 char *at_path;
98 off_t at_size;
99
100 TAILQ_ENTRY(audit_trail) at_trls;
101};
102
103static int auditd_minval = -1;
104
105static char auditd_host[MAXHOSTNAMELEN];
106static int auditd_hostlen = -1;
107
90static char *auditd_errmsg[] = {
91 "no error", /* ADE_NOERR ( 0) */
92 "could not parse audit_control(5) file", /* ADE_PARSE ( 1) */
93 "auditon(2) failed", /* ADE_AUDITON ( 2) */
94 "malloc(3) failed", /* ADE_NOMEM ( 3) */
95 "all audit log directories over soft limit", /* ADE_SOFTLIM ( 4) */
96 "all audit log directories over hard limit", /* ADE_HARDLIM ( 5) */
97 "could not create file name string", /* ADE_STRERR ( 6) */
98 "could not open audit record", /* ADE_AU_OPEN ( 7) */
99 "could not close audit record", /* ADE_AU_CLOSE ( 8) */
100 "could not set active audit session state", /* ADE_SETAUDIT ( 9) */
101 "auditctl(2) failed (trail still swapped)", /* ADE_ACTL (10) */
102 "auditctl(2) failed (trail not swapped)", /* ADE_ACTLERR (11) */
103 "could not swap audit trail file", /* ADE_SWAPERR (12) */
104 "could not rename crash recovery file", /* ADE_RENAME (13) */
105 "could not read 'current' link file", /* ADE_READLINK (14) */
106 "could not create 'current' link file", /* ADE_SYMLINK (15) */
107 "invalid argument", /* ADE_INVAL (16) */
108 "could not resolve hostname to address", /* ADE_GETADDR (17) */
109 "address family not supported", /* ADE_ADDRFAM (18) */
108static char *auditd_errmsg[] = {
109 "no error", /* ADE_NOERR ( 0) */
110 "could not parse audit_control(5) file", /* ADE_PARSE ( 1) */
111 "auditon(2) failed", /* ADE_AUDITON ( 2) */
112 "malloc(3) failed", /* ADE_NOMEM ( 3) */
113 "all audit log directories over soft limit", /* ADE_SOFTLIM ( 4) */
114 "all audit log directories over hard limit", /* ADE_HARDLIM ( 5) */
115 "could not create file name string", /* ADE_STRERR ( 6) */
116 "could not open audit record", /* ADE_AU_OPEN ( 7) */
117 "could not close audit record", /* ADE_AU_CLOSE ( 8) */
118 "could not set active audit session state", /* ADE_SETAUDIT ( 9) */
119 "auditctl(2) failed (trail still swapped)", /* ADE_ACTL (10) */
120 "auditctl(2) failed (trail not swapped)", /* ADE_ACTLERR (11) */
121 "could not swap audit trail file", /* ADE_SWAPERR (12) */
122 "could not rename crash recovery file", /* ADE_RENAME (13) */
123 "could not read 'current' link file", /* ADE_READLINK (14) */
124 "could not create 'current' link file", /* ADE_SYMLINK (15) */
125 "invalid argument", /* ADE_INVAL (16) */
126 "could not resolve hostname to address", /* ADE_GETADDR (17) */
127 "address family not supported", /* ADE_ADDRFAM (18) */
128 "error expiring audit trail files", /* ADE_EXPIRE (19) */
110};
111
112#define MAXERRCODE (sizeof(auditd_errmsg) / sizeof(auditd_errmsg[0]))
113
114#define NA_EVENT_STR_SIZE 25
115#define POL_STR_SIZE 128
116
117
118/*
119 * Look up and return the error string for the given audit error code.
120 */
121const char *
122auditd_strerror(int errcode)
123{
124 int idx = -errcode;
125
126 if (idx < 0 || idx > (int)MAXERRCODE)
127 return ("Invalid auditd error code");
128
129 return (auditd_errmsg[idx]);
130}
131
132
133/*
134 * Free our local list of directory names and init list
135 */
136static void
137free_dir_q(void)
138{
139 struct dir_ent *d1, *d2;
140
141 d1 = TAILQ_FIRST(&dir_q);
142 while (d1 != NULL) {
143 d2 = TAILQ_NEXT(d1, dirs);
144 free(d1->dirname);
145 free(d1);
146 d1 = d2;
147 }
148 TAILQ_INIT(&dir_q);
149}
150
151/*
152 * Concat the directory name to the given file name.
153 * XXX We should affix the hostname also
154 */
155static char *
156affixdir(char *name, struct dir_ent *dirent)
157{
158 char *fn = NULL;
159
160 /*
161 * Sanity check on file name.
162 */
163 if (strlen(name) != (FILENAME_LEN - 1)) {
164 errno = EINVAL;
165 return (NULL);
166 }
167
129};
130
131#define MAXERRCODE (sizeof(auditd_errmsg) / sizeof(auditd_errmsg[0]))
132
133#define NA_EVENT_STR_SIZE 25
134#define POL_STR_SIZE 128
135
136
137/*
138 * Look up and return the error string for the given audit error code.
139 */
140const char *
141auditd_strerror(int errcode)
142{
143 int idx = -errcode;
144
145 if (idx < 0 || idx > (int)MAXERRCODE)
146 return ("Invalid auditd error code");
147
148 return (auditd_errmsg[idx]);
149}
150
151
152/*
153 * Free our local list of directory names and init list
154 */
155static void
156free_dir_q(void)
157{
158 struct dir_ent *d1, *d2;
159
160 d1 = TAILQ_FIRST(&dir_q);
161 while (d1 != NULL) {
162 d2 = TAILQ_NEXT(d1, dirs);
163 free(d1->dirname);
164 free(d1);
165 d1 = d2;
166 }
167 TAILQ_INIT(&dir_q);
168}
169
170/*
171 * Concat the directory name to the given file name.
172 * XXX We should affix the hostname also
173 */
174static char *
175affixdir(char *name, struct dir_ent *dirent)
176{
177 char *fn = NULL;
178
179 /*
180 * Sanity check on file name.
181 */
182 if (strlen(name) != (FILENAME_LEN - 1)) {
183 errno = EINVAL;
184 return (NULL);
185 }
186
168 asprintf(&fn, "%s/%s", dirent->dirname, name);
187 /*
188 * If the host is set then also add the hostname to the filename.
189 */
190 if (auditd_hostlen != -1)
191 asprintf(&fn, "%s/%s.%s", dirent->dirname, name, auditd_host);
192 else
193 asprintf(&fn, "%s/%s", dirent->dirname, name);
169 return (fn);
170}
171
172/*
173 * Insert the directory entry in the list by the way they are ordered in
174 * audit_control(5). Move the entries that are over the soft and hard limits
175 * toward the tail.
176 */
177static void
178insert_orderly(struct dir_ent *denew)
179{
180 struct dir_ent *dep;
181
182 TAILQ_FOREACH(dep, &dir_q, dirs) {
183 if (dep->softlim == 1 && denew->softlim == 0) {
184 TAILQ_INSERT_BEFORE(dep, denew, dirs);
185 return;
186 }
187 if (dep->hardlim == 1 && denew->hardlim == 0) {
188 TAILQ_INSERT_BEFORE(dep, denew, dirs);
189 return;
190 }
191 }
192 TAILQ_INSERT_TAIL(&dir_q, denew, dirs);
193}
194
195/*
196 * Get the host from audit_control(5) and set it in the audit kernel
197 * information. Return:
198 * ADE_NOERR on success.
199 * ADE_PARSE error parsing audit_control(5).
200 * ADE_AUDITON error getting/setting auditon(2) value.
201 * ADE_GETADDR error getting address info for host.
202 * ADE_ADDRFAM un-supported address family.
203 */
204int
205auditd_set_host(void)
206{
194 return (fn);
195}
196
197/*
198 * Insert the directory entry in the list by the way they are ordered in
199 * audit_control(5). Move the entries that are over the soft and hard limits
200 * toward the tail.
201 */
202static void
203insert_orderly(struct dir_ent *denew)
204{
205 struct dir_ent *dep;
206
207 TAILQ_FOREACH(dep, &dir_q, dirs) {
208 if (dep->softlim == 1 && denew->softlim == 0) {
209 TAILQ_INSERT_BEFORE(dep, denew, dirs);
210 return;
211 }
212 if (dep->hardlim == 1 && denew->hardlim == 0) {
213 TAILQ_INSERT_BEFORE(dep, denew, dirs);
214 return;
215 }
216 }
217 TAILQ_INSERT_TAIL(&dir_q, denew, dirs);
218}
219
220/*
221 * Get the host from audit_control(5) and set it in the audit kernel
222 * information. Return:
223 * ADE_NOERR on success.
224 * ADE_PARSE error parsing audit_control(5).
225 * ADE_AUDITON error getting/setting auditon(2) value.
226 * ADE_GETADDR error getting address info for host.
227 * ADE_ADDRFAM un-supported address family.
228 */
229int
230auditd_set_host(void)
231{
207 char hoststr[MAXHOSTNAMELEN];
208 struct sockaddr_in6 *sin6;
209 struct sockaddr_in *sin;
210 struct addrinfo *res;
211 struct auditinfo_addr aia;
212 int error, ret = ADE_NOERR;
213
232 struct sockaddr_in6 *sin6;
233 struct sockaddr_in *sin;
234 struct addrinfo *res;
235 struct auditinfo_addr aia;
236 int error, ret = ADE_NOERR;
237
214 if (getachost(hoststr, MAXHOSTNAMELEN) != 0) {
215
216 ret = ADE_PARSE;
238 if (getachost(auditd_host, sizeof(auditd_host)) != 0) {
239 ret = ADE_PARSE;
217
218 /*
219 * To maintain reverse compatability with older audit_control
220 * files, simply drop a warning if the host parameter has not
221 * been set. However, we will explicitly disable the
222 * generation of extended audit header by passing in a zeroed
223 * termid structure.
224 */
225 bzero(&aia, sizeof(aia));
226 aia.ai_termid.at_type = AU_IPv4;
227 error = auditon(A_SETKAUDIT, &aia, sizeof(aia));
228 if (error < 0 && errno != ENOSYS)
229 ret = ADE_AUDITON;
230 return (ret);
231 }
240
241 /*
242 * To maintain reverse compatability with older audit_control
243 * files, simply drop a warning if the host parameter has not
244 * been set. However, we will explicitly disable the
245 * generation of extended audit header by passing in a zeroed
246 * termid structure.
247 */
248 bzero(&aia, sizeof(aia));
249 aia.ai_termid.at_type = AU_IPv4;
250 error = auditon(A_SETKAUDIT, &aia, sizeof(aia));
251 if (error < 0 && errno != ENOSYS)
252 ret = ADE_AUDITON;
253 return (ret);
254 }
232 error = getaddrinfo(hoststr, NULL, NULL, &res);
255 auditd_hostlen = strlen(auditd_host);
256 error = getaddrinfo(auditd_host, NULL, NULL, &res);
233 if (error)
234 return (ADE_GETADDR);
235 switch (res->ai_family) {
236 case PF_INET6:
237 sin6 = (struct sockaddr_in6 *) res->ai_addr;
238 bcopy(&sin6->sin6_addr.s6_addr,
239 &aia.ai_termid.at_addr[0], sizeof(struct in6_addr));
240 aia.ai_termid.at_type = AU_IPv6;
241 break;
242
243 case PF_INET:
244 sin = (struct sockaddr_in *) res->ai_addr;
245 bcopy(&sin->sin_addr.s_addr,
246 &aia.ai_termid.at_addr[0], sizeof(struct in_addr));
247 aia.ai_termid.at_type = AU_IPv4;
248 break;
249
250 default:
251 /* Un-supported address family in host parameter. */
252 errno = EAFNOSUPPORT;
253 return (ADE_ADDRFAM);
254 }
255
256 if (auditon(A_SETKAUDIT, &aia, sizeof(aia)) < 0)
257 ret = ADE_AUDITON;
258
259 return (ret);
260}
261
262/*
263 * Get the min percentage of free blocks from audit_control(5) and that
264 * value in the kernel. Return:
265 * ADE_NOERR on success,
266 * ADE_PARSE error parsing audit_control(5),
267 * ADE_AUDITON error getting/setting auditon(2) value.
268 */
269int
270auditd_set_minfree(void)
271{
272 au_qctrl_t qctrl;
273
257 if (error)
258 return (ADE_GETADDR);
259 switch (res->ai_family) {
260 case PF_INET6:
261 sin6 = (struct sockaddr_in6 *) res->ai_addr;
262 bcopy(&sin6->sin6_addr.s6_addr,
263 &aia.ai_termid.at_addr[0], sizeof(struct in6_addr));
264 aia.ai_termid.at_type = AU_IPv6;
265 break;
266
267 case PF_INET:
268 sin = (struct sockaddr_in *) res->ai_addr;
269 bcopy(&sin->sin_addr.s_addr,
270 &aia.ai_termid.at_addr[0], sizeof(struct in_addr));
271 aia.ai_termid.at_type = AU_IPv4;
272 break;
273
274 default:
275 /* Un-supported address family in host parameter. */
276 errno = EAFNOSUPPORT;
277 return (ADE_ADDRFAM);
278 }
279
280 if (auditon(A_SETKAUDIT, &aia, sizeof(aia)) < 0)
281 ret = ADE_AUDITON;
282
283 return (ret);
284}
285
286/*
287 * Get the min percentage of free blocks from audit_control(5) and that
288 * value in the kernel. Return:
289 * ADE_NOERR on success,
290 * ADE_PARSE error parsing audit_control(5),
291 * ADE_AUDITON error getting/setting auditon(2) value.
292 */
293int
294auditd_set_minfree(void)
295{
296 au_qctrl_t qctrl;
297
274 if (getacmin(&minval) != 0)
298 if (getacmin(&auditd_minval) != 0)
275 return (ADE_PARSE);
276
277 if (auditon(A_GETQCTRL, &qctrl, sizeof(qctrl)) != 0)
278 return (ADE_AUDITON);
279
299 return (ADE_PARSE);
300
301 if (auditon(A_GETQCTRL, &qctrl, sizeof(qctrl)) != 0)
302 return (ADE_AUDITON);
303
280 if (qctrl.aq_minfree != minval) {
281 qctrl.aq_minfree = minval;
304 if (qctrl.aq_minfree != auditd_minval) {
305 qctrl.aq_minfree = auditd_minval;
282 if (auditon(A_SETQCTRL, &qctrl, sizeof(qctrl)) != 0)
283 return (ADE_AUDITON);
284 }
285
286 return (0);
287}
288
289/*
306 if (auditon(A_SETQCTRL, &qctrl, sizeof(qctrl)) != 0)
307 return (ADE_AUDITON);
308 }
309
310 return (0);
311}
312
313/*
314 * Convert a trailname into a timestamp (seconds). Return 0 if the conversion
315 * was successful.
316 */
317static int
318trailname_to_tstamp(char *fn, time_t *tstamp)
319{
320 struct tm tm;
321 char ts[TIMESTAMP_LEN];
322 char *p;
323
324 *tstamp = 0;
325
326 /*
327 * Get the ending time stamp.
328 */
329 if ((p = strchr(fn, '.')) == NULL)
330 return (1);
331 strlcpy(ts, ++p, TIMESTAMP_LEN);
332 if (strlen(ts) != POSTFIX_LEN)
333 return (1);
334
335 bzero(&tm, sizeof(tm));
336
337 /* seconds (0-60) */
338 p = ts + POSTFIX_LEN - 2;
339 tm.tm_sec = atol(p);
340 if (tm.tm_sec < 0 || tm.tm_sec > 60)
341 return (1);
342
343 /* minutes (0-59) */
344 *p = '\0'; p -= 2;
345 tm.tm_min = atol(p);
346 if (tm.tm_min < 0 || tm.tm_min > 59)
347 return (1);
348
349 /* hours (0 - 23) */
350 *p = '\0'; p -= 2;
351 tm.tm_hour = atol(p);
352 if (tm.tm_hour < 0 || tm.tm_hour > 23)
353 return (1);
354
355 /* day of month (1-31) */
356 *p = '\0'; p -= 2;
357 tm.tm_mday = atol(p);
358 if (tm.tm_mday < 1 || tm.tm_mday > 31)
359 return (1);
360
361 /* month (0 - 11) */
362 *p = '\0'; p -= 2;
363 tm.tm_mon = atol(p) - 1;
364 if (tm.tm_mon < 0 || tm.tm_mon > 11)
365 return (1);
366
367 /* year (year - 1900) */
368 *p = '\0'; p -= 4;
369 tm.tm_year = atol(p) - 1900;
370 if (tm.tm_year < 0)
371 return (1);
372
373 *tstamp = timegm(&tm);
374
375 return (0);
376}
377
378/*
379 * Remove audit trails files according to the expiration conditions. Returns:
380 * ADE_NOERR on success or there is nothing to do.
381 * ADE_PARSE if error parsing audit_control(5).
382 * ADE_NOMEM if could not allocate memory.
383 * ADE_EXPIRE if there was an unespected error.
384 */
385int
386auditd_expire_trails(int (*warn_expired)(char *))
387{
388 int andflg, ret = ADE_NOERR;
389 size_t expire_size, total_size = 0L;
390 time_t expire_age, oldest_time, current_time = time(NULL);
391 struct dir_ent *traildir;
392 struct audit_trail *at;
393 char *afnp, *pn;
394 TAILQ_HEAD(au_trls_head, audit_trail) head =
395 TAILQ_HEAD_INITIALIZER(head);
396 struct stat stbuf;
397 char activefn[MAXPATHLEN];
398
399 /*
400 * Read the expiration conditions. If no conditions then return no
401 * error.
402 */
403 if (getacexpire(&andflg, &expire_age, &expire_size) < 0)
404 return (ADE_PARSE);
405 if (!expire_age && !expire_size)
406 return (ADE_NOERR);
407
408 /*
409 * Read the 'current' trail file name. Trim off directory path.
410 */
411 activefn[0] = '\0';
412 readlink(AUDIT_CURRENT_LINK, activefn, MAXPATHLEN - 1);
413 if ((afnp = strrchr(activefn, '/')) != NULL)
414 afnp++;
415
416
417 /*
418 * Build tail queue of the trail files.
419 */
420 TAILQ_FOREACH(traildir, &dir_q, dirs) {
421 DIR *dirp;
422 struct dirent *dp;
423
424 dirp = opendir(traildir->dirname);
425 while ((dp = readdir(dirp)) != NULL) {
426 time_t tstamp = 0;
427 struct audit_trail *new;
428
429 /*
430 * Quickly filter non-trail files.
431 */
432 if (dp->d_namlen != (FILENAME_LEN - 1) ||
433#ifdef DT_REG
434 dp->d_type != DT_REG ||
435#endif
436 dp->d_name[POSTFIX_LEN] != '.')
437 continue;
438
439 if (asprintf(&pn, "%s/%s", traildir->dirname,
440 dp->d_name) < 0) {
441 ret = ADE_NOMEM;
442 break;
443 }
444
445 if (stat(pn, &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) {
446 free(pn);
447 continue;
448 }
449
450 total_size += stbuf.st_size;
451
452 /*
453 * If this is the 'current' audit trail then
454 * don't add it to the tail queue.
455 */
456 if (NULL != afnp &&
457 strncmp(dp->d_name, afnp, FILENAME_LEN) == 0) {
458 free(pn);
459 continue;
460 }
461
462 /*
463 * Get the ending time stamp encoded in the trail
464 * name. If we can't read it or if it is older
465 * than Jan 1, 2000 then use the mtime.
466 */
467 if (trailname_to_tstamp(dp->d_name, &tstamp) != 0 ||
468 tstamp < JAN_01_2000)
469 tstamp = stbuf.st_mtime;
470
471 /*
472 * If the time stamp is older than Jan 1, 2000 then
473 * update the mtime of the trail file to the current
474 * time. This is so we don't prematurely remove a trail
475 * file that was created while the system clock reset
476 * to the * "beginning of time" but later the system
477 * clock is set to the correct current time.
478 */
479 if (current_time >= JAN_01_2000 &&
480 tstamp < JAN_01_2000) {
481 struct timeval tv[2];
482
483 tstamp = stbuf.st_mtime = current_time;
484 TIMESPEC_TO_TIMEVAL(&tv[0],
485 &stbuf.st_atimespec);
486 TIMESPEC_TO_TIMEVAL(&tv[1],
487 &stbuf.st_mtimespec);
488 utimes(pn, tv);
489 }
490
491 /*
492 * Allocate and populate the new entry.
493 */
494 new = malloc(sizeof(*new));
495 if (NULL == new) {
496 free(pn);
497 ret = ADE_NOMEM;
498 break;
499 }
500 new->at_time = tstamp;
501 new->at_size = stbuf.st_size;
502 new->at_path = pn;
503
504 /*
505 * Check to see if we have a new head. Otherwise,
506 * walk the tailq from the tail first and do a simple
507 * insertion sort.
508 */
509 if (TAILQ_EMPTY(&head) ||
510 (new->at_time <= TAILQ_FIRST(&head)->at_time)) {
511 TAILQ_INSERT_HEAD(&head, new, at_trls);
512 continue;
513 }
514
515 TAILQ_FOREACH_REVERSE(at, &head, au_trls_head, at_trls)
516 if (new->at_time >= at->at_time) {
517 TAILQ_INSERT_AFTER(&head, at, new,
518 at_trls);
519 break;
520 }
521
522 }
523 }
524
525 oldest_time = current_time - expire_age;
526
527 /*
528 * Expire trail files, oldest (mtime) first, if the given
529 * conditions are met.
530 */
531 at = TAILQ_FIRST(&head);
532 while (NULL != at) {
533 struct audit_trail *at_next = TAILQ_NEXT(at, at_trls);
534
535 if (andflg) {
536 if ((expire_size && total_size > expire_size) &&
537 (expire_age && at->at_time < oldest_time)) {
538 if (warn_expired)
539 (*warn_expired)(at->at_path);
540 if (unlink(at->at_path) < 0)
541 ret = ADE_EXPIRE;
542 total_size -= at->at_size;
543 }
544 } else {
545 if ((expire_size && total_size > expire_size) ||
546 (expire_age && at->at_time < oldest_time)) {
547 if (warn_expired)
548 (*warn_expired)(at->at_path);
549 if (unlink(at->at_path) < 0)
550 ret = ADE_EXPIRE;
551 total_size -= at->at_size;
552 }
553 }
554
555 free(at->at_path);
556 free(at);
557 at = at_next;
558 }
559
560 return (ret);
561}
562
563/*
290 * Parses the "dir" entry in audit_control(5) into an ordered list. Also, will
564 * Parses the "dir" entry in audit_control(5) into an ordered list. Also, will
291 * set the minfree value if not already set. Arguments include function
292 * pointers to audit_warn functions for soft and hard limits. Returns:
565 * set the minfree and host values if not already set. Arguments include
566 * function pointers to audit_warn functions for soft and hard limits. Returns:
293 * ADE_NOERR on success,
294 * ADE_PARSE error parsing audit_control(5),
295 * ADE_AUDITON error getting/setting auditon(2) value,
296 * ADE_NOMEM error allocating memory,
297 * ADE_SOFTLIM if all the directories are over the soft limit,
298 * ADE_HARDLIM if all the directories are over the hard limit,
299 */
300int
301auditd_read_dirs(int (*warn_soft)(char *), int (*warn_hard)(char *))
302{
303 char cur_dir[MAXNAMLEN];
304 struct dir_ent *dirent;
305 struct statfs sfs;
306 int err;
307 char soft, hard;
308 int tcnt = 0;
309 int scnt = 0;
310 int hcnt = 0;
311
567 * ADE_NOERR on success,
568 * ADE_PARSE error parsing audit_control(5),
569 * ADE_AUDITON error getting/setting auditon(2) value,
570 * ADE_NOMEM error allocating memory,
571 * ADE_SOFTLIM if all the directories are over the soft limit,
572 * ADE_HARDLIM if all the directories are over the hard limit,
573 */
574int
575auditd_read_dirs(int (*warn_soft)(char *), int (*warn_hard)(char *))
576{
577 char cur_dir[MAXNAMLEN];
578 struct dir_ent *dirent;
579 struct statfs sfs;
580 int err;
581 char soft, hard;
582 int tcnt = 0;
583 int scnt = 0;
584 int hcnt = 0;
585
312 if (minval == -1 && (err = auditd_set_minfree()) != 0)
586 if (auditd_minval == -1 && (err = auditd_set_minfree()) != 0)
313 return (err);
314
587 return (err);
588
589 if (auditd_hostlen == -1)
590 auditd_set_host();
591
315 /*
316 * Init directory q. Force a re-read of the file the next time.
317 */
318 free_dir_q();
319 endac();
320
321 /*
322 * Read the list of directories into an ordered linked list
323 * admin's preference, then those over soft limit and, finally,
324 * those over the hard limit.
325 *
326 * XXX We should use the reentrant interfaces once they are
327 * available.
328 */
329 while (getacdir(cur_dir, MAXNAMLEN) >= 0) {
330 if (statfs(cur_dir, &sfs) < 0)
331 continue; /* XXX should warn */
592 /*
593 * Init directory q. Force a re-read of the file the next time.
594 */
595 free_dir_q();
596 endac();
597
598 /*
599 * Read the list of directories into an ordered linked list
600 * admin's preference, then those over soft limit and, finally,
601 * those over the hard limit.
602 *
603 * XXX We should use the reentrant interfaces once they are
604 * available.
605 */
606 while (getacdir(cur_dir, MAXNAMLEN) >= 0) {
607 if (statfs(cur_dir, &sfs) < 0)
608 continue; /* XXX should warn */
332 soft = (sfs.f_bfree < (sfs.f_blocks / (100 / minval))) ? 1 : 0;
609 soft = (sfs.f_bfree < (sfs.f_blocks / (100 / auditd_minval))) ?
610 1 : 0;
333 hard = (sfs.f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) ? 1 : 0;
334 if (soft) {
335 if (warn_soft)
336 (*warn_soft)(cur_dir);
337 scnt++;
338 }
339 if (hard) {
340 if (warn_hard)
341 (*warn_hard)(cur_dir);
342 hcnt++;
343 }
344 dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent));
345 if (dirent == NULL)
346 return (ADE_NOMEM);
347 dirent->softlim = soft;
348 dirent->hardlim = hard;
349 dirent->dirname = (char *) malloc(MAXNAMLEN);
350 if (dirent->dirname == NULL) {
351 free(dirent);
352 return (ADE_NOMEM);
353 }
354 strlcpy(dirent->dirname, cur_dir, MAXNAMLEN);
355 insert_orderly(dirent);
356 tcnt++;
357 }
358
359 if (hcnt == tcnt)
360 return (ADE_HARDLIM);
361 if (scnt == tcnt)
362 return (ADE_SOFTLIM);
363 return (0);
364}
365
366void
367auditd_close_dirs(void)
368{
369 free_dir_q();
611 hard = (sfs.f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) ? 1 : 0;
612 if (soft) {
613 if (warn_soft)
614 (*warn_soft)(cur_dir);
615 scnt++;
616 }
617 if (hard) {
618 if (warn_hard)
619 (*warn_hard)(cur_dir);
620 hcnt++;
621 }
622 dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent));
623 if (dirent == NULL)
624 return (ADE_NOMEM);
625 dirent->softlim = soft;
626 dirent->hardlim = hard;
627 dirent->dirname = (char *) malloc(MAXNAMLEN);
628 if (dirent->dirname == NULL) {
629 free(dirent);
630 return (ADE_NOMEM);
631 }
632 strlcpy(dirent->dirname, cur_dir, MAXNAMLEN);
633 insert_orderly(dirent);
634 tcnt++;
635 }
636
637 if (hcnt == tcnt)
638 return (ADE_HARDLIM);
639 if (scnt == tcnt)
640 return (ADE_SOFTLIM);
641 return (0);
642}
643
644void
645auditd_close_dirs(void)
646{
647 free_dir_q();
370 minval = -1;
648 auditd_minval = -1;
649 auditd_hostlen = -1;
371}
372
373
374/*
375 * Process the audit event file, obtaining a class mapping for each event, and
376 * set that mapping into the kernel. Return:
377 * n number of event mappings that were successfully processed,
378 * ADE_NOMEM if there was an error allocating memory.
379 */
380int
381auditd_set_evcmap(void)
382{
383 au_event_ent_t ev, *evp;
384 au_evclass_map_t evc_map;
385 int ctr = 0;
386
387
388 /*
389 * XXX There's a risk here that the BSM library will return NULL
390 * for an event when it can't properly map it to a class. In that
391 * case, we will not process any events beyond the one that failed,
392 * but should. We need a way to get a count of the events.
393 */
394 ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX);
395 ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX);
396 if ((ev.ae_name == NULL) || (ev.ae_desc == NULL)) {
397 if (ev.ae_name != NULL)
398 free(ev.ae_name);
399 return (ADE_NOMEM);
400 }
401
402 /*
403 * XXXRW: Currently we have no way to remove mappings from the kernel
404 * when they are removed from the file-based mappings.
405 */
406 evp = &ev;
407 setauevent();
408 while ((evp = getauevent_r(evp)) != NULL) {
409 evc_map.ec_number = evp->ae_number;
410 evc_map.ec_class = evp->ae_class;
411 if (auditon(A_SETCLASS, &evc_map, sizeof(au_evclass_map_t))
412 == 0)
413 ctr++;
414 }
415 endauevent();
416 free(ev.ae_name);
417 free(ev.ae_desc);
418
419 return (ctr);
420}
421
422/*
423 * Get the non-attributable event string and set the kernel mask. Return:
424 * ADE_NOERR on success,
425 * ADE_PARSE error parsing audit_control(5),
426 * ADE_AUDITON error setting the mask using auditon(2).
427 */
428int
429auditd_set_namask(void)
430{
431 au_mask_t aumask;
432 char naeventstr[NA_EVENT_STR_SIZE];
433
434 if ((getacna(naeventstr, NA_EVENT_STR_SIZE) != 0) ||
435 (getauditflagsbin(naeventstr, &aumask) != 0))
436 return (ADE_PARSE);
437
438 if (auditon(A_SETKMASK, &aumask, sizeof(au_mask_t)))
439 return (ADE_AUDITON);
440
441 return (ADE_NOERR);
442}
443
444/*
445 * Set the audit control policy if a policy is configured in audit_control(5),
446 * implement the policy. However, if one isn't defined or if there is an error
447 * parsing the control file, set AUDIT_CNT to avoid leaving the system in a
448 * fragile state. Return:
449 * ADE_NOERR on success,
450 * ADE_PARSE error parsing audit_control(5),
451 * ADE_AUDITON error setting policy using auditon(2).
452 */
453int
454auditd_set_policy(void)
455{
456 long policy;
457 char polstr[POL_STR_SIZE];
458
459 if ((getacpol(polstr, POL_STR_SIZE) != 0) ||
460 (au_strtopol(polstr, &policy) != 0)) {
461 policy = AUDIT_CNT;
462 if (auditon(A_SETPOLICY, &policy, sizeof(policy)))
463 return (ADE_AUDITON);
464 return (ADE_PARSE);
465 }
466
467 if (auditon(A_SETPOLICY, &policy, sizeof(policy)))
468 return (ADE_AUDITON);
469
470 return (ADE_NOERR);
471}
472
473/*
474 * Set trail rotation size. Return:
475 * ADE_NOERR on success,
476 * ADE_PARSE error parsing audit_control(5),
477 * ADE_AUDITON error setting file size using auditon(2).
478 */
479int
480auditd_set_fsize(void)
481{
482 size_t filesz;
483 au_fstat_t au_fstat;
484
485 /*
486 * Set trail rotation size.
487 */
488 if (getacfilesz(&filesz) != 0)
489 return (ADE_PARSE);
490
491 bzero(&au_fstat, sizeof(au_fstat));
492 au_fstat.af_filesz = filesz;
493 if (auditon(A_SETFSIZE, &au_fstat, sizeof(au_fstat)) < 0)
494 return (ADE_AUDITON);
495
496 return (ADE_NOERR);
497}
498
499/*
500 * Create the new audit file with appropriate permissions and ownership. Try
501 * to clean up if something goes wrong.
502 */
503static int
504open_trail(char *fname, gid_t gid)
505{
506 int error, fd;
507
508 fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP);
509 if (fd < 0)
510 return (-1);
511 if (fchown(fd, -1, gid) < 0) {
512 error = errno;
513 close(fd);
514 (void)unlink(fname);
515 errno = error;
516 return (-1);
517 }
518 return (fd);
519}
520
521/*
522 * Create the new audit trail file, swap with existing audit file. Arguments
523 * include timestamp for the filename, a pointer to a string for returning the
524 * new file name, GID for trail file, and audit_warn function pointer for
525 * 'getacdir()' errors. Returns:
526 * ADE_NOERR on success,
527 * ADE_STRERR if the file name string could not be created,
528 * ADE_SWAPERR if the audit trail file could not be swapped,
529 * ADE_ACTL if the auditctl(2) call failed but file swap still
530 * successful.
531 * ADE_ACTLERR if the auditctl(2) call failed and file swap failed.
532 * ADE_SYMLINK if symlink(2) failed updating the current link.
533 */
534int
535auditd_swap_trail(char *TS, char **newfile, gid_t gid,
536 int (*warn_getacdir)(char *))
537{
538 char timestr[FILENAME_LEN];
539 char *fn;
540 struct dir_ent *dirent;
541 int fd;
542 int error;
543 int saverrno = 0;
544
545 if (strlen(TS) != (TIMESTAMP_LEN - 1) ||
546 snprintf(timestr, FILENAME_LEN, "%s.%s", TS, NOT_TERMINATED) < 0) {
547 errno = EINVAL;
548 return (ADE_STRERR);
549 }
550
551 /* Try until we succeed. */
650}
651
652
653/*
654 * Process the audit event file, obtaining a class mapping for each event, and
655 * set that mapping into the kernel. Return:
656 * n number of event mappings that were successfully processed,
657 * ADE_NOMEM if there was an error allocating memory.
658 */
659int
660auditd_set_evcmap(void)
661{
662 au_event_ent_t ev, *evp;
663 au_evclass_map_t evc_map;
664 int ctr = 0;
665
666
667 /*
668 * XXX There's a risk here that the BSM library will return NULL
669 * for an event when it can't properly map it to a class. In that
670 * case, we will not process any events beyond the one that failed,
671 * but should. We need a way to get a count of the events.
672 */
673 ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX);
674 ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX);
675 if ((ev.ae_name == NULL) || (ev.ae_desc == NULL)) {
676 if (ev.ae_name != NULL)
677 free(ev.ae_name);
678 return (ADE_NOMEM);
679 }
680
681 /*
682 * XXXRW: Currently we have no way to remove mappings from the kernel
683 * when they are removed from the file-based mappings.
684 */
685 evp = &ev;
686 setauevent();
687 while ((evp = getauevent_r(evp)) != NULL) {
688 evc_map.ec_number = evp->ae_number;
689 evc_map.ec_class = evp->ae_class;
690 if (auditon(A_SETCLASS, &evc_map, sizeof(au_evclass_map_t))
691 == 0)
692 ctr++;
693 }
694 endauevent();
695 free(ev.ae_name);
696 free(ev.ae_desc);
697
698 return (ctr);
699}
700
701/*
702 * Get the non-attributable event string and set the kernel mask. Return:
703 * ADE_NOERR on success,
704 * ADE_PARSE error parsing audit_control(5),
705 * ADE_AUDITON error setting the mask using auditon(2).
706 */
707int
708auditd_set_namask(void)
709{
710 au_mask_t aumask;
711 char naeventstr[NA_EVENT_STR_SIZE];
712
713 if ((getacna(naeventstr, NA_EVENT_STR_SIZE) != 0) ||
714 (getauditflagsbin(naeventstr, &aumask) != 0))
715 return (ADE_PARSE);
716
717 if (auditon(A_SETKMASK, &aumask, sizeof(au_mask_t)))
718 return (ADE_AUDITON);
719
720 return (ADE_NOERR);
721}
722
723/*
724 * Set the audit control policy if a policy is configured in audit_control(5),
725 * implement the policy. However, if one isn't defined or if there is an error
726 * parsing the control file, set AUDIT_CNT to avoid leaving the system in a
727 * fragile state. Return:
728 * ADE_NOERR on success,
729 * ADE_PARSE error parsing audit_control(5),
730 * ADE_AUDITON error setting policy using auditon(2).
731 */
732int
733auditd_set_policy(void)
734{
735 long policy;
736 char polstr[POL_STR_SIZE];
737
738 if ((getacpol(polstr, POL_STR_SIZE) != 0) ||
739 (au_strtopol(polstr, &policy) != 0)) {
740 policy = AUDIT_CNT;
741 if (auditon(A_SETPOLICY, &policy, sizeof(policy)))
742 return (ADE_AUDITON);
743 return (ADE_PARSE);
744 }
745
746 if (auditon(A_SETPOLICY, &policy, sizeof(policy)))
747 return (ADE_AUDITON);
748
749 return (ADE_NOERR);
750}
751
752/*
753 * Set trail rotation size. Return:
754 * ADE_NOERR on success,
755 * ADE_PARSE error parsing audit_control(5),
756 * ADE_AUDITON error setting file size using auditon(2).
757 */
758int
759auditd_set_fsize(void)
760{
761 size_t filesz;
762 au_fstat_t au_fstat;
763
764 /*
765 * Set trail rotation size.
766 */
767 if (getacfilesz(&filesz) != 0)
768 return (ADE_PARSE);
769
770 bzero(&au_fstat, sizeof(au_fstat));
771 au_fstat.af_filesz = filesz;
772 if (auditon(A_SETFSIZE, &au_fstat, sizeof(au_fstat)) < 0)
773 return (ADE_AUDITON);
774
775 return (ADE_NOERR);
776}
777
778/*
779 * Create the new audit file with appropriate permissions and ownership. Try
780 * to clean up if something goes wrong.
781 */
782static int
783open_trail(char *fname, gid_t gid)
784{
785 int error, fd;
786
787 fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP);
788 if (fd < 0)
789 return (-1);
790 if (fchown(fd, -1, gid) < 0) {
791 error = errno;
792 close(fd);
793 (void)unlink(fname);
794 errno = error;
795 return (-1);
796 }
797 return (fd);
798}
799
800/*
801 * Create the new audit trail file, swap with existing audit file. Arguments
802 * include timestamp for the filename, a pointer to a string for returning the
803 * new file name, GID for trail file, and audit_warn function pointer for
804 * 'getacdir()' errors. Returns:
805 * ADE_NOERR on success,
806 * ADE_STRERR if the file name string could not be created,
807 * ADE_SWAPERR if the audit trail file could not be swapped,
808 * ADE_ACTL if the auditctl(2) call failed but file swap still
809 * successful.
810 * ADE_ACTLERR if the auditctl(2) call failed and file swap failed.
811 * ADE_SYMLINK if symlink(2) failed updating the current link.
812 */
813int
814auditd_swap_trail(char *TS, char **newfile, gid_t gid,
815 int (*warn_getacdir)(char *))
816{
817 char timestr[FILENAME_LEN];
818 char *fn;
819 struct dir_ent *dirent;
820 int fd;
821 int error;
822 int saverrno = 0;
823
824 if (strlen(TS) != (TIMESTAMP_LEN - 1) ||
825 snprintf(timestr, FILENAME_LEN, "%s.%s", TS, NOT_TERMINATED) < 0) {
826 errno = EINVAL;
827 return (ADE_STRERR);
828 }
829
830 /* Try until we succeed. */
552 while ((dirent = TAILQ_FIRST(&dir_q))) {
831 TAILQ_FOREACH(dirent, &dir_q, dirs) {
553 if (dirent->hardlim)
554 continue;
555 if ((fn = affixdir(timestr, dirent)) == NULL)
556 return (ADE_STRERR);
557
558 /*
559 * Create and open the file; then close and pass to the
560 * kernel if all went well.
561 */
562 fd = open_trail(fn, gid);
563 if (fd >= 0) {
564 error = auditctl(fn);
565 if (error) {
566 /*
567 * auditctl failed setting log file.
568 * Try again.
569 */
570 saverrno = errno;
571 close(fd);
572 } else {
573 /* Success. */
574 *newfile = fn;
575 close(fd);
576 if (error)
577 return (error);
578 if (saverrno) {
579 /*
580 * auditctl() failed but still
581 * successful. Return errno and "soft"
582 * error.
583 */
584 errno = saverrno;
585 return (ADE_ACTL);
586 }
587 return (ADE_NOERR);
588 }
589 }
590
591 /*
592 * Tell the administrator about lack of permissions for dir.
593 */
594 if (warn_getacdir != NULL)
595 (*warn_getacdir)(dirent->dirname);
596 }
597 if (saverrno) {
598 errno = saverrno;
599 return (ADE_ACTLERR);
600 } else
601 return (ADE_SWAPERR);
602}
603
604/*
605 * Mask calling process from being audited. Returns:
606 * ADE_NOERR on success,
607 * ADE_SETAUDIT if setaudit(2) fails.
608 */
832 if (dirent->hardlim)
833 continue;
834 if ((fn = affixdir(timestr, dirent)) == NULL)
835 return (ADE_STRERR);
836
837 /*
838 * Create and open the file; then close and pass to the
839 * kernel if all went well.
840 */
841 fd = open_trail(fn, gid);
842 if (fd >= 0) {
843 error = auditctl(fn);
844 if (error) {
845 /*
846 * auditctl failed setting log file.
847 * Try again.
848 */
849 saverrno = errno;
850 close(fd);
851 } else {
852 /* Success. */
853 *newfile = fn;
854 close(fd);
855 if (error)
856 return (error);
857 if (saverrno) {
858 /*
859 * auditctl() failed but still
860 * successful. Return errno and "soft"
861 * error.
862 */
863 errno = saverrno;
864 return (ADE_ACTL);
865 }
866 return (ADE_NOERR);
867 }
868 }
869
870 /*
871 * Tell the administrator about lack of permissions for dir.
872 */
873 if (warn_getacdir != NULL)
874 (*warn_getacdir)(dirent->dirname);
875 }
876 if (saverrno) {
877 errno = saverrno;
878 return (ADE_ACTLERR);
879 } else
880 return (ADE_SWAPERR);
881}
882
883/*
884 * Mask calling process from being audited. Returns:
885 * ADE_NOERR on success,
886 * ADE_SETAUDIT if setaudit(2) fails.
887 */
888#ifdef __APPLE__
609int
610auditd_prevent_audit(void)
611{
889int
890auditd_prevent_audit(void)
891{
892 auditinfo_addr_t aia;
893
894 /*
895 * To prevent event feedback cycles and avoid audit becoming stalled if
896 * auditing is suspended we mask this processes events from being
897 * audited. We allow the uid, tid, and mask fields to be implicitly
898 * set to zero, but do set the audit session ID to the PID.
899 *
900 * XXXRW: Is there more to it than this?
901 */
902 bzero(&aia, sizeof(aia));
903 aia.ai_asid = AU_ASSIGN_ASID;
904 aia.ai_termid.at_type = AU_IPv4;
905 if (setaudit_addr(&aia, sizeof(aia)) != 0)
906 return (ADE_SETAUDIT);
907 return (ADE_NOERR);
908}
909#else
910int
911auditd_prevent_audit(void)
912{
612 auditinfo_t ai;
613
614 /*
615 * To prevent event feedback cycles and avoid audit becoming stalled if
616 * auditing is suspended we mask this processes events from being
617 * audited. We allow the uid, tid, and mask fields to be implicitly
618 * set to zero, but do set the audit session ID to the PID.
619 *
620 * XXXRW: Is there more to it than this?
621 */
622 bzero(&ai, sizeof(ai));
623 ai.ai_asid = getpid();
624 if (setaudit(&ai) != 0)
625 return (ADE_SETAUDIT);
626 return (ADE_NOERR);
627}
913 auditinfo_t ai;
914
915 /*
916 * To prevent event feedback cycles and avoid audit becoming stalled if
917 * auditing is suspended we mask this processes events from being
918 * audited. We allow the uid, tid, and mask fields to be implicitly
919 * set to zero, but do set the audit session ID to the PID.
920 *
921 * XXXRW: Is there more to it than this?
922 */
923 bzero(&ai, sizeof(ai));
924 ai.ai_asid = getpid();
925 if (setaudit(&ai) != 0)
926 return (ADE_SETAUDIT);
927 return (ADE_NOERR);
928}
929#endif /* __APPLE__ */
628
629/*
630 * Generate and submit audit record for audit startup or shutdown. The event
631 * argument can be AUE_audit_recovery, AUE_audit_startup or
632 * AUE_audit_shutdown. The path argument will add a path token, if not NULL.
633 * Returns:
634 * AUE_NOERR on success,
635 * ADE_NOMEM if memory allocation fails,
636 * ADE_AU_OPEN if au_open(3) fails,
637 * ADE_AU_CLOSE if au_close(3) fails.
638 */
639int
640auditd_gen_record(int event, char *path)
641{
642 int aufd;
643 uid_t uid;
644 pid_t pid;
645 char *autext = NULL;
646 token_t *tok;
647 struct auditinfo_addr aia;
648
649 if (event == AUE_audit_startup)
650 asprintf(&autext, "%s::Audit startup", getprogname());
651 else if (event == AUE_audit_shutdown)
652 asprintf(&autext, "%s::Audit shutdown", getprogname());
653 else if (event == AUE_audit_recovery)
654 asprintf(&autext, "%s::Audit recovery", getprogname());
655 else
656 return (ADE_INVAL);
657 if (autext == NULL)
658 return (ADE_NOMEM);
659
660 if ((aufd = au_open()) == -1) {
661 free(autext);
662 return (ADE_AU_OPEN);
663 }
664 bzero(&aia, sizeof(aia));
665 uid = getuid(); pid = getpid();
666 if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, getgid(),
667 pid, pid, &aia.ai_termid)) != NULL)
668 au_write(aufd, tok);
669 if ((tok = au_to_text(autext)) != NULL)
670 au_write(aufd, tok);
671 free(autext);
672 if (path != NULL && (tok = au_to_path(path)) != NULL)
673 au_write(aufd, tok);
674 if ((tok = au_to_return32(0, 0)) != NULL)
675 au_write(aufd, tok);
676 if (au_close(aufd, 1, event) == -1)
677 return (ADE_AU_CLOSE);
678
679 return (ADE_NOERR);
680}
681
682/*
683 * Check for a 'current' symlink and do crash recovery, if needed. Create a new
684 * 'current' symlink. The argument 'curfile' is the file the 'current' symlink
685 * should point to. Returns:
686 * ADE_NOERR on success,
687 * ADE_AU_OPEN if au_open(3) fails,
688 * ADE_AU_CLOSE if au_close(3) fails.
689 * ADE_RENAME if error renaming audit trail file,
690 * ADE_READLINK if error reading the 'current' link,
691 * ADE_SYMLINK if error creating 'current' link.
692 */
693int
694auditd_new_curlink(char *curfile)
695{
696 int len, err;
697 char *ptr;
698 char *path = NULL;
699 struct stat sb;
700 char recoveredname[MAXPATHLEN];
701 char newname[MAXPATHLEN];
702
703 /*
704 * Check to see if audit was shutdown properly. If not, clean up,
705 * recover previous audit trail file, and generate audit record.
706 */
707 len = readlink(AUDIT_CURRENT_LINK, recoveredname, MAXPATHLEN - 1);
708 if (len > 0) {
709 /* 'current' exist but is it pointing at a valid file? */
710 recoveredname[len++] = '\0';
711 if (stat(recoveredname, &sb) == 0) {
712 /* Yes, rename it to a crash recovery file. */
713 strlcpy(newname, recoveredname, MAXPATHLEN);
714
715 if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) {
930
931/*
932 * Generate and submit audit record for audit startup or shutdown. The event
933 * argument can be AUE_audit_recovery, AUE_audit_startup or
934 * AUE_audit_shutdown. The path argument will add a path token, if not NULL.
935 * Returns:
936 * AUE_NOERR on success,
937 * ADE_NOMEM if memory allocation fails,
938 * ADE_AU_OPEN if au_open(3) fails,
939 * ADE_AU_CLOSE if au_close(3) fails.
940 */
941int
942auditd_gen_record(int event, char *path)
943{
944 int aufd;
945 uid_t uid;
946 pid_t pid;
947 char *autext = NULL;
948 token_t *tok;
949 struct auditinfo_addr aia;
950
951 if (event == AUE_audit_startup)
952 asprintf(&autext, "%s::Audit startup", getprogname());
953 else if (event == AUE_audit_shutdown)
954 asprintf(&autext, "%s::Audit shutdown", getprogname());
955 else if (event == AUE_audit_recovery)
956 asprintf(&autext, "%s::Audit recovery", getprogname());
957 else
958 return (ADE_INVAL);
959 if (autext == NULL)
960 return (ADE_NOMEM);
961
962 if ((aufd = au_open()) == -1) {
963 free(autext);
964 return (ADE_AU_OPEN);
965 }
966 bzero(&aia, sizeof(aia));
967 uid = getuid(); pid = getpid();
968 if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, getgid(),
969 pid, pid, &aia.ai_termid)) != NULL)
970 au_write(aufd, tok);
971 if ((tok = au_to_text(autext)) != NULL)
972 au_write(aufd, tok);
973 free(autext);
974 if (path != NULL && (tok = au_to_path(path)) != NULL)
975 au_write(aufd, tok);
976 if ((tok = au_to_return32(0, 0)) != NULL)
977 au_write(aufd, tok);
978 if (au_close(aufd, 1, event) == -1)
979 return (ADE_AU_CLOSE);
980
981 return (ADE_NOERR);
982}
983
984/*
985 * Check for a 'current' symlink and do crash recovery, if needed. Create a new
986 * 'current' symlink. The argument 'curfile' is the file the 'current' symlink
987 * should point to. Returns:
988 * ADE_NOERR on success,
989 * ADE_AU_OPEN if au_open(3) fails,
990 * ADE_AU_CLOSE if au_close(3) fails.
991 * ADE_RENAME if error renaming audit trail file,
992 * ADE_READLINK if error reading the 'current' link,
993 * ADE_SYMLINK if error creating 'current' link.
994 */
995int
996auditd_new_curlink(char *curfile)
997{
998 int len, err;
999 char *ptr;
1000 char *path = NULL;
1001 struct stat sb;
1002 char recoveredname[MAXPATHLEN];
1003 char newname[MAXPATHLEN];
1004
1005 /*
1006 * Check to see if audit was shutdown properly. If not, clean up,
1007 * recover previous audit trail file, and generate audit record.
1008 */
1009 len = readlink(AUDIT_CURRENT_LINK, recoveredname, MAXPATHLEN - 1);
1010 if (len > 0) {
1011 /* 'current' exist but is it pointing at a valid file? */
1012 recoveredname[len++] = '\0';
1013 if (stat(recoveredname, &sb) == 0) {
1014 /* Yes, rename it to a crash recovery file. */
1015 strlcpy(newname, recoveredname, MAXPATHLEN);
1016
1017 if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) {
716 strlcpy(ptr, CRASH_RECOVERY, TIMESTAMP_LEN);
1018 memcpy(ptr, CRASH_RECOVERY, POSTFIX_LEN);
717 if (rename(recoveredname, newname) != 0)
718 return (ADE_RENAME);
719 } else
720 return (ADE_STRERR);
721
722 path = newname;
723 }
724
725 /* 'current' symlink is (now) invalid so remove it. */
726 (void) unlink(AUDIT_CURRENT_LINK);
727
728 /* Note the crash recovery in current audit trail */
729 err = auditd_gen_record(AUE_audit_recovery, path);
730 if (err)
731 return (err);
732 }
733
734 if (len < 0 && errno != ENOENT)
735 return (ADE_READLINK);
736
737 if (symlink(curfile, AUDIT_CURRENT_LINK) != 0)
738 return (ADE_SYMLINK);
739
740 return (0);
741}
742
743/*
744 * Do just what we need to quickly start auditing. Assume no system logging or
745 * notify. Return:
746 * 0 on success,
747 * -1 on failure.
748 */
749int
750audit_quick_start(void)
751{
752 int err;
1019 if (rename(recoveredname, newname) != 0)
1020 return (ADE_RENAME);
1021 } else
1022 return (ADE_STRERR);
1023
1024 path = newname;
1025 }
1026
1027 /* 'current' symlink is (now) invalid so remove it. */
1028 (void) unlink(AUDIT_CURRENT_LINK);
1029
1030 /* Note the crash recovery in current audit trail */
1031 err = auditd_gen_record(AUE_audit_recovery, path);
1032 if (err)
1033 return (err);
1034 }
1035
1036 if (len < 0 && errno != ENOENT)
1037 return (ADE_READLINK);
1038
1039 if (symlink(curfile, AUDIT_CURRENT_LINK) != 0)
1040 return (ADE_SYMLINK);
1041
1042 return (0);
1043}
1044
1045/*
1046 * Do just what we need to quickly start auditing. Assume no system logging or
1047 * notify. Return:
1048 * 0 on success,
1049 * -1 on failure.
1050 */
1051int
1052audit_quick_start(void)
1053{
1054 int err;
753 char *newfile;
1055 char *newfile = NULL;
754 time_t tt;
755 char TS[TIMESTAMP_LEN];
1056 time_t tt;
1057 char TS[TIMESTAMP_LEN];
1058 int ret = 0;
756
757 /*
758 * Mask auditing of this process.
759 */
760 if (auditd_prevent_audit() != 0)
761 return (-1);
762
763 /*
764 * Read audit_control and get log directories.
765 */
766 err = auditd_read_dirs(NULL, NULL);
767 if (err != ADE_NOERR && err != ADE_SOFTLIM)
768 return (-1);
769
770 /*
771 * Create a new audit trail log.
772 */
773 if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0)
774 return (-1);
775 err = auditd_swap_trail(TS, &newfile, getgid(), NULL);
1059
1060 /*
1061 * Mask auditing of this process.
1062 */
1063 if (auditd_prevent_audit() != 0)
1064 return (-1);
1065
1066 /*
1067 * Read audit_control and get log directories.
1068 */
1069 err = auditd_read_dirs(NULL, NULL);
1070 if (err != ADE_NOERR && err != ADE_SOFTLIM)
1071 return (-1);
1072
1073 /*
1074 * Create a new audit trail log.
1075 */
1076 if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0)
1077 return (-1);
1078 err = auditd_swap_trail(TS, &newfile, getgid(), NULL);
776 if (err != ADE_NOERR && err != ADE_ACTL)
777 return (-1);
1079 if (err != ADE_NOERR && err != ADE_ACTL) {
1080 ret = -1;
1081 goto out;
1082 }
778
779 /*
780 * Add the current symlink and recover from crash, if needed.
781 */
1083
1084 /*
1085 * Add the current symlink and recover from crash, if needed.
1086 */
782 if (auditd_new_curlink(newfile) != 0)
783 return(-1);
1087 if (auditd_new_curlink(newfile) != 0) {
1088 ret = -1;
1089 goto out;
1090 }
784
785 /*
786 * At this point auditing has started so generate audit start-up record.
787 */
1091
1092 /*
1093 * At this point auditing has started so generate audit start-up record.
1094 */
788 if (auditd_gen_record(AUE_audit_startup, NULL) != 0)
789 return (-1);
1095 if (auditd_gen_record(AUE_audit_startup, NULL) != 0) {
1096 ret = -1;
1097 goto out;
1098 }
790
791 /*
792 * Configure the audit controls.
793 */
794 (void) auditd_set_evcmap();
795 (void) auditd_set_namask();
796 (void) auditd_set_policy();
797 (void) auditd_set_fsize();
798 (void) auditd_set_minfree();
799 (void) auditd_set_host();
800
1099
1100 /*
1101 * Configure the audit controls.
1102 */
1103 (void) auditd_set_evcmap();
1104 (void) auditd_set_namask();
1105 (void) auditd_set_policy();
1106 (void) auditd_set_fsize();
1107 (void) auditd_set_minfree();
1108 (void) auditd_set_host();
1109
801 return (0);
1110out:
1111 if (newfile != NULL)
1112 free(newfile);
1113
1114 return (ret);
802}
803
804/*
805 * Shut down auditing quickly. Assumes that is only called on system shutdown.
806 * Returns:
807 * 0 on success,
808 * -1 on failure.
809 */
810int
811audit_quick_stop(void)
812{
813 int len;
814 long cond;
815 char *ptr;
816 time_t tt;
817 char oldname[MAXPATHLEN];
818 char newname[MAXPATHLEN];
819 char TS[TIMESTAMP_LEN];
820
821 /*
822 * Auditing already disabled?
823 */
824 if (auditon(A_GETCOND, &cond, sizeof(cond)) < 0)
825 return (-1);
826 if (cond == AUC_NOAUDIT)
827 return (0);
828
829 /*
830 * Generate audit shutdown record.
831 */
832 (void) auditd_gen_record(AUE_audit_shutdown, NULL);
833
834 /*
835 * Shutdown auditing in the kernel.
836 */
837 cond = AUC_DISABLED;
838 if (auditon(A_SETCOND, &cond, sizeof(cond)) != 0)
839 return (-1);
840#ifdef __BSM_INTERNAL_NOTIFY_KEY
841 notify_post(__BSM_INTERNAL_NOTIFY_KEY);
842#endif
843
844 /*
845 * Rename last audit trail and remove 'current' link.
846 */
847 len = readlink(AUDIT_CURRENT_LINK, oldname, MAXPATHLEN - 1);
848 if (len < 0)
849 return (-1);
850 oldname[len++] = '\0';
851
852 if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0)
853 return (-1);
854
855 strlcpy(newname, oldname, len);
856
857 if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) {
1115}
1116
1117/*
1118 * Shut down auditing quickly. Assumes that is only called on system shutdown.
1119 * Returns:
1120 * 0 on success,
1121 * -1 on failure.
1122 */
1123int
1124audit_quick_stop(void)
1125{
1126 int len;
1127 long cond;
1128 char *ptr;
1129 time_t tt;
1130 char oldname[MAXPATHLEN];
1131 char newname[MAXPATHLEN];
1132 char TS[TIMESTAMP_LEN];
1133
1134 /*
1135 * Auditing already disabled?
1136 */
1137 if (auditon(A_GETCOND, &cond, sizeof(cond)) < 0)
1138 return (-1);
1139 if (cond == AUC_NOAUDIT)
1140 return (0);
1141
1142 /*
1143 * Generate audit shutdown record.
1144 */
1145 (void) auditd_gen_record(AUE_audit_shutdown, NULL);
1146
1147 /*
1148 * Shutdown auditing in the kernel.
1149 */
1150 cond = AUC_DISABLED;
1151 if (auditon(A_SETCOND, &cond, sizeof(cond)) != 0)
1152 return (-1);
1153#ifdef __BSM_INTERNAL_NOTIFY_KEY
1154 notify_post(__BSM_INTERNAL_NOTIFY_KEY);
1155#endif
1156
1157 /*
1158 * Rename last audit trail and remove 'current' link.
1159 */
1160 len = readlink(AUDIT_CURRENT_LINK, oldname, MAXPATHLEN - 1);
1161 if (len < 0)
1162 return (-1);
1163 oldname[len++] = '\0';
1164
1165 if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0)
1166 return (-1);
1167
1168 strlcpy(newname, oldname, len);
1169
1170 if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) {
858 strlcpy(ptr, TS, TIMESTAMP_LEN);
1171 memcpy(ptr, TS, POSTFIX_LEN);
859 if (rename(oldname, newname) != 0)
860 return (-1);
861 } else
862 return (-1);
863
864 (void) unlink(AUDIT_CURRENT_LINK);
865
866 return (0);
867}
1172 if (rename(oldname, newname) != 0)
1173 return (-1);
1174 } else
1175 return (-1);
1176
1177 (void) unlink(AUDIT_CURRENT_LINK);
1178
1179 return (0);
1180}