]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/openbsm/libauditd/auditd_lib.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / openbsm / libauditd / auditd_lib.c
1 /*-
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  *
29  * $P4: //depot/projects/trustedbsd/openbsm/libauditd/auditd_lib.c#11 $
30  */
31
32 #include <sys/param.h>
33
34 #include <config/config.h>
35
36 #include <sys/dirent.h>
37 #ifdef HAVE_FULL_QUEUE_H
38 #include <sys/queue.h>
39 #else /* !HAVE_FULL_QUEUE_H */
40 #include <compat/queue.h>
41 #endif /* !HAVE_FULL_QUEUE_H */
42 #include <sys/mount.h>
43 #include <sys/socket.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>
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
86 struct dir_ent {
87         char                    *dirname;
88         uint8_t                  softlim;
89         uint8_t                  hardlim;
90         TAILQ_ENTRY(dir_ent)     dirs;
91 };
92
93 static TAILQ_HEAD(, dir_ent)    dir_q;
94
95 struct 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
103 static int auditd_minval = -1;
104
105 static char auditd_host[MAXHOSTNAMELEN];
106 static int auditd_hostlen = -1;
107
108 static 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) */
129 };
130
131 #define MAXERRCODE (sizeof(auditd_errmsg) / sizeof(auditd_errmsg[0]))
132
133 #define NA_EVENT_STR_SIZE       128
134 #define POL_STR_SIZE            128
135
136
137 /*
138  * Look up and return the error string for the given audit error code.
139  */
140 const char *
141 auditd_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  */
155 static void
156 free_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  */
174 static char *
175 affixdir(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
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);
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  */
202 static void
203 insert_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  */
229 int
230 auditd_set_host(void)
231 {
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
238         if (getachost(auditd_host, sizeof(auditd_host)) != 0) {
239                 ret = ADE_PARSE;        
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 = audit_set_kaudit(&aia, sizeof(aia));
251                 if (error < 0 && errno != ENOSYS)
252                         ret = ADE_AUDITON;
253                 return (ret);
254         }
255         auditd_hostlen = strlen(auditd_host);
256         error = getaddrinfo(auditd_host, NULL, NULL, &res);
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 (audit_set_kaudit(&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  */
293 int
294 auditd_set_minfree(void)
295 {
296         au_qctrl_t qctrl;
297
298         if (getacmin(&auditd_minval) != 0)
299                 return (ADE_PARSE);
300         
301         if (audit_get_qctrl(&qctrl, sizeof(qctrl)) != 0)
302                 return (ADE_AUDITON);
303
304         if (qctrl.aq_minfree != auditd_minval) {
305                 qctrl.aq_minfree = auditd_minval;
306                 if (audit_set_qctrl(&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  */
317 static int
318 trailname_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  */
385 int
386 auditd_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 /*
564  * Parses the "dir" entry in audit_control(5) into an ordered list.  Also, will
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:
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  */
574 int
575 auditd_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
586         if (auditd_minval == -1 && (err = auditd_set_minfree()) != 0)
587                 return (err);
588
589         if (auditd_hostlen == -1)
590                 auditd_set_host();
591
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 */
609                 soft = (sfs.f_bfree < (sfs.f_blocks / (100 / auditd_minval))) ?
610                     1 : 0;
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
644 void
645 auditd_close_dirs(void)
646 {
647         free_dir_q();
648         auditd_minval = -1;
649         auditd_hostlen = -1;
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  */
659 int
660 auditd_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 (audit_set_class(&evc_map, sizeof(evc_map)) == 0)
691                         ctr++;
692         }
693         endauevent();
694         free(ev.ae_name);
695         free(ev.ae_desc);
696
697         return (ctr);
698 }
699
700 /*
701  * Get the non-attributable event string and set the kernel mask.  Return:
702  *      ADE_NOERR       on success,
703  *      ADE_PARSE       error parsing audit_control(5),
704  *      ADE_AUDITON     error setting the mask using auditon(2).
705  */
706 int
707 auditd_set_namask(void)
708 {
709         au_mask_t aumask;
710         char naeventstr[NA_EVENT_STR_SIZE];
711                          
712         if ((getacna(naeventstr, NA_EVENT_STR_SIZE) != 0) || 
713             (getauditflagsbin(naeventstr, &aumask) != 0)) 
714                 return (ADE_PARSE);
715
716         if (audit_set_kmask(&aumask, sizeof(aumask)) != 0)
717                 return (ADE_AUDITON);
718
719         return (ADE_NOERR);
720 }
721
722 /*
723  * Set the audit control policy if a policy is configured in audit_control(5),
724  * implement the policy. However, if one isn't defined or if there is an error
725  * parsing the control file, set AUDIT_CNT to avoid leaving the system in a
726  * fragile state.  Return:
727  *      ADE_NOERR       on success,
728  *      ADE_PARSE       error parsing audit_control(5),
729  *      ADE_AUDITON     error setting policy using auditon(2).
730  */
731 int
732 auditd_set_policy(void)
733 {
734         int policy;
735         char polstr[POL_STR_SIZE];
736
737         if ((getacpol(polstr, POL_STR_SIZE) != 0) || 
738             (au_strtopol(polstr, &policy) != 0)) {
739                 policy = AUDIT_CNT;
740                 if (audit_set_policy(&policy) != 0)
741                         return (ADE_AUDITON);
742                 return (ADE_PARSE);
743         }
744
745         if (audit_set_policy(&policy) != 0)
746                 return (ADE_AUDITON);
747
748         return (ADE_NOERR);
749 }
750
751 /* 
752  * Set trail rotation size.  Return:
753  *      ADE_NOERR       on success,
754  *      ADE_PARSE       error parsing audit_control(5),
755  *      ADE_AUDITON     error setting file size using auditon(2).
756  */
757 int
758 auditd_set_fsize(void)
759 {
760         size_t filesz;
761         au_fstat_t au_fstat;
762
763         /*
764          * Set trail rotation size.
765          */
766         if (getacfilesz(&filesz) != 0)
767                 return (ADE_PARSE);
768
769         bzero(&au_fstat, sizeof(au_fstat));
770         au_fstat.af_filesz = filesz;
771         if (audit_set_fsize(&au_fstat, sizeof(au_fstat)) != 0)
772                 return (ADE_AUDITON);
773
774         return (ADE_NOERR);
775 }
776
777 /*
778  * Create the new audit file with appropriate permissions and ownership.  Try
779  * to clean up if something goes wrong.
780  */
781 static int
782 open_trail(char *fname, gid_t gid)
783 {
784         int error, fd;
785         
786         fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP);
787         if (fd < 0)
788                 return (-1);
789         if (fchown(fd, -1, gid) < 0) {
790                 error = errno;
791                 close(fd);
792                 (void)unlink(fname);
793                 errno = error;
794                 return (-1);
795         }
796         return (fd);
797 }
798
799 /*
800  * Create the new audit trail file, swap with existing audit file.  Arguments
801  * include timestamp for the filename, a pointer to a string for returning the
802  * new file name, GID for trail file, and audit_warn function pointer for 
803  * 'getacdir()' errors.  Returns:
804  *      ADE_NOERR       on success,
805  *      ADE_STRERR      if the file name string could not be created,
806  *      ADE_SWAPERR     if the audit trail file could not be swapped,
807  *      ADE_ACTL        if the auditctl(2) call failed but file swap still
808  *                      successful.
809  *      ADE_ACTLERR     if the auditctl(2) call failed and file swap failed.
810  *      ADE_SYMLINK     if symlink(2) failed updating the current link.
811  */
812 int
813 auditd_swap_trail(char *TS, char **newfile, gid_t gid, 
814     int (*warn_getacdir)(char *))
815 {
816         char timestr[FILENAME_LEN];
817         char *fn;
818         struct dir_ent *dirent;
819         int fd;
820         int error;
821         int saverrno = 0;
822                 
823         if (strlen(TS) !=  (TIMESTAMP_LEN - 1) ||
824             snprintf(timestr, FILENAME_LEN, "%s.%s", TS, NOT_TERMINATED) < 0) {
825                 errno = EINVAL;
826                 return (ADE_STRERR);
827         }
828                 
829         /* Try until we succeed. */
830         TAILQ_FOREACH(dirent, &dir_q, dirs) {
831                 if (dirent->hardlim) 
832                         continue;
833                 if ((fn = affixdir(timestr, dirent)) == NULL)
834                         return (ADE_STRERR);
835
836                 /*
837                  * Create and open the file; then close and pass to the
838                  * kernel if all went well.
839                  */
840                 fd = open_trail(fn, gid);
841                 if (fd >= 0) {
842                         error = auditctl(fn);
843                         if (error) {
844                                 /* 
845                                  * auditctl failed setting log file.  
846                                  * Try again.
847                                  */
848                                 saverrno = errno;
849                                 close(fd);
850                         } else {
851                                 /* Success. */
852                                 *newfile = fn;
853                                 close(fd);
854                                 if (error)
855                                         return (error);
856                                 if (saverrno) {
857                                         /*
858                                          * auditctl() failed but still
859                                          * successful. Return errno and "soft" 
860                                          * error.
861                                          */
862                                         errno = saverrno;
863                                         return (ADE_ACTL);
864                                 }
865                                 return (ADE_NOERR);
866                         }
867                 }
868
869                 /*
870                  * Tell the administrator about lack of permissions for dir.
871                  */
872                 if (warn_getacdir != NULL)
873                         (*warn_getacdir)(dirent->dirname);
874         }
875         if (saverrno) {
876                 errno = saverrno;
877                 return (ADE_ACTLERR);
878         } else
879                 return (ADE_SWAPERR);
880 }
881
882 /*
883  * Mask calling process from being audited. Returns:
884  *      ADE_NOERR       on success,
885  *      ADE_SETAUDIT    if setaudit(2) fails.
886  */
887 #ifdef __APPLE__
888 int
889 auditd_prevent_audit(void)
890 {
891         auditinfo_addr_t aia;
892
893         /* 
894          * To prevent event feedback cycles and avoid audit becoming stalled if
895          * auditing is suspended we mask this processes events from being
896          * audited.  We allow the uid, tid, and mask fields to be implicitly
897          * set to zero, but do set the audit session ID to the PID. 
898          *
899          * XXXRW: Is there more to it than this?
900          */
901         bzero(&aia, sizeof(aia));
902         aia.ai_asid = AU_ASSIGN_ASID;
903         aia.ai_termid.at_type = AU_IPv4;
904         if (setaudit_addr(&aia, sizeof(aia)) != 0)
905                 return (ADE_SETAUDIT); 
906         return (ADE_NOERR);
907 }
908 #else
909 int
910 auditd_prevent_audit(void)
911 {
912         auditinfo_t ai;
913
914         /* 
915          * To prevent event feedback cycles and avoid audit becoming stalled if
916          * auditing is suspended we mask this processes events from being
917          * audited.  We allow the uid, tid, and mask fields to be implicitly
918          * set to zero, but do set the audit session ID to the PID. 
919          *
920          * XXXRW: Is there more to it than this?
921          */
922         bzero(&ai, sizeof(ai));
923         ai.ai_asid = getpid();
924         if (setaudit(&ai) != 0)
925                 return (ADE_SETAUDIT); 
926         return (ADE_NOERR);
927 }
928 #endif /* __APPLE__ */
929
930 /*
931  * Generate and submit audit record for audit startup or shutdown.  The event
932  * argument can be AUE_audit_recovery, AUE_audit_startup or
933  * AUE_audit_shutdown. The path argument will add a path token, if not NULL.
934  * Returns:
935  *      AUE_NOERR       on success,
936  *      ADE_NOMEM       if memory allocation fails,
937  *      ADE_AU_OPEN     if au_open(3) fails,
938  *      ADE_AU_CLOSE    if au_close(3) fails.
939  */
940 int
941 auditd_gen_record(int event, char *path)
942 {
943         int aufd;
944         uid_t uid;
945         pid_t pid;
946         char *autext = NULL;
947         token_t *tok;
948         struct auditinfo_addr aia;
949
950         if (event == AUE_audit_startup)
951                 asprintf(&autext, "%s::Audit startup", getprogname());
952         else if (event == AUE_audit_shutdown)
953                 asprintf(&autext, "%s::Audit shutdown", getprogname());
954         else if (event == AUE_audit_recovery)
955                 asprintf(&autext, "%s::Audit recovery", getprogname());
956         else 
957                 return (ADE_INVAL);
958         if (autext == NULL)
959                 return (ADE_NOMEM);
960
961         if ((aufd = au_open()) == -1) {
962                 free(autext);
963                 return (ADE_AU_OPEN);
964         }
965         bzero(&aia, sizeof(aia));
966         uid = getuid(); pid = getpid();
967         if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, getgid(),
968              pid, pid, &aia.ai_termid)) != NULL)
969                 au_write(aufd, tok);
970         if ((tok = au_to_text(autext)) != NULL)
971                 au_write(aufd, tok);
972         free(autext);
973         if (path != NULL && (tok = au_to_path(path)) != NULL)
974                 au_write(aufd, tok);
975         if ((tok = au_to_return32(0, 0)) != NULL)
976                 au_write(aufd, tok);
977         if (au_close(aufd, 1, event) == -1)
978                 return (ADE_AU_CLOSE);
979
980         return (ADE_NOERR);
981 }
982
983 /*
984  * Check for a 'current' symlink and do crash recovery, if needed. Create a new
985  * 'current' symlink. The argument 'curfile' is the file the 'current' symlink
986  * should point to.  Returns:
987  *      ADE_NOERR       on success,
988  *      ADE_AU_OPEN     if au_open(3) fails,
989  *      ADE_AU_CLOSE    if au_close(3) fails.
990  *      ADE_RENAME      if error renaming audit trail file,
991  *      ADE_READLINK    if error reading the 'current' link,
992  *      ADE_SYMLINK     if error creating 'current' link.
993  */
994 int
995 auditd_new_curlink(char *curfile)
996 {
997         int len, err;
998         char *ptr;
999         char *path = NULL;
1000         struct stat sb;
1001         char recoveredname[MAXPATHLEN];
1002         char newname[MAXPATHLEN];
1003
1004         /*
1005          * Check to see if audit was shutdown properly.  If not, clean up,
1006          * recover previous audit trail file, and generate audit record.
1007          */
1008         len = readlink(AUDIT_CURRENT_LINK, recoveredname, MAXPATHLEN - 1);
1009         if (len > 0) {
1010                 /* 'current' exist but is it pointing at a valid file?  */
1011                 recoveredname[len++] = '\0';
1012                 if (stat(recoveredname, &sb) == 0) { 
1013                         /* Yes, rename it to a crash recovery file. */
1014                         strlcpy(newname, recoveredname, MAXPATHLEN);
1015
1016                         if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) {
1017                                 memcpy(ptr, CRASH_RECOVERY, POSTFIX_LEN);
1018                                 if (rename(recoveredname, newname) != 0)
1019                                         return (ADE_RENAME);
1020                         } else
1021                                 return (ADE_STRERR);
1022
1023                         path = newname;
1024                 }
1025
1026                 /* 'current' symlink is (now) invalid so remove it. */
1027                 (void) unlink(AUDIT_CURRENT_LINK);
1028
1029                 /* Note the crash recovery in current audit trail */
1030                 err = auditd_gen_record(AUE_audit_recovery, path);
1031                 if (err)
1032                         return (err);
1033         }
1034
1035         if (len < 0 && errno != ENOENT)
1036                 return (ADE_READLINK);
1037
1038         if (symlink(curfile, AUDIT_CURRENT_LINK) != 0)
1039                 return (ADE_SYMLINK);
1040
1041         return (0);
1042 }
1043
1044 /*
1045  * Do just what we need to quickly start auditing.  Assume no system logging or
1046  * notify.  Return:
1047  *   0   on success,
1048  *  -1   on failure.
1049  */
1050 int
1051 audit_quick_start(void)
1052 {
1053         int err;
1054         char *newfile = NULL;
1055         time_t tt;
1056         char TS[TIMESTAMP_LEN];
1057         int ret = 0;
1058
1059         /* 
1060          * Mask auditing of this process.
1061          */
1062         if (auditd_prevent_audit() != 0)
1063                 return (-1);
1064
1065         /*
1066          * Read audit_control and get log directories.
1067          */
1068         err = auditd_read_dirs(NULL, NULL);
1069         if (err != ADE_NOERR && err != ADE_SOFTLIM)
1070                 return (-1);
1071
1072         /*
1073          *  Create a new audit trail log.
1074          */
1075         if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0)
1076                 return (-1);
1077         err = auditd_swap_trail(TS, &newfile, getgid(), NULL);
1078         if (err != ADE_NOERR && err != ADE_ACTL) {
1079                 ret = -1;
1080                 goto out;
1081         }
1082
1083         /*
1084          * Add the current symlink and recover from crash, if needed. 
1085          */
1086         if (auditd_new_curlink(newfile) != 0) {
1087                 ret = -1;
1088                 goto out;
1089         }
1090
1091         /*
1092          * At this point auditing has started so generate audit start-up record.
1093          */
1094         if (auditd_gen_record(AUE_audit_startup, NULL) != 0) {
1095                 ret = -1;
1096                 goto out;
1097         }
1098
1099         /*
1100          *  Configure the audit controls.
1101          */
1102         (void) auditd_set_evcmap();
1103         (void) auditd_set_namask();
1104         (void) auditd_set_policy();
1105         (void) auditd_set_fsize();
1106         (void) auditd_set_minfree();
1107         (void) auditd_set_host();
1108
1109 out:
1110         if (newfile != NULL)
1111                 free(newfile);
1112
1113         return (ret);
1114 }
1115
1116 /*
1117  * Shut down auditing quickly.  Assumes that is only called on system shutdown.
1118  * Returns:
1119  *       0      on success,
1120  *      -1      on failure.
1121  */
1122 int
1123 audit_quick_stop(void)
1124 {
1125         int len;
1126         int cond;
1127         char *ptr;
1128         time_t tt;
1129         char oldname[MAXPATHLEN];
1130         char newname[MAXPATHLEN];
1131         char TS[TIMESTAMP_LEN];
1132
1133         /*
1134          * Auditing already disabled?
1135          */
1136         if (audit_get_cond(&cond) != 0)
1137                 return (-1);
1138         if (cond == AUC_NOAUDIT)
1139                 return (0);
1140
1141         /*
1142          *  Generate audit shutdown record.
1143          */
1144         (void) auditd_gen_record(AUE_audit_shutdown, NULL);
1145
1146         /*
1147          * Shutdown auditing in the kernel.
1148          */
1149         cond = AUC_DISABLED;
1150         if (audit_set_cond(&cond) != 0)
1151                 return (-1);
1152 #ifdef  __BSM_INTERNAL_NOTIFY_KEY
1153         notify_post(__BSM_INTERNAL_NOTIFY_KEY);
1154 #endif
1155
1156         /*
1157          * Rename last audit trail and remove 'current' link.
1158          */
1159         len = readlink(AUDIT_CURRENT_LINK, oldname, MAXPATHLEN - 1);
1160         if (len < 0)
1161                 return (-1);
1162         oldname[len++] = '\0';
1163
1164         if (getTSstr(tt, TS, TIMESTAMP_LEN) != 0)
1165                 return (-1);
1166
1167         strlcpy(newname, oldname, len);
1168
1169         if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) {
1170                 memcpy(ptr, TS, POSTFIX_LEN);
1171                 if (rename(oldname, newname) != 0)
1172                         return (-1);
1173         } else
1174                 return (-1);
1175         
1176         (void) unlink(AUDIT_CURRENT_LINK);
1177
1178         return (0);
1179 }