]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/openbsm/libauditd/auditd_lib.c
Merge OpenBSM alpha 4 from OpenBSM vendor branch to head, both
[FreeBSD/FreeBSD.git] / contrib / openbsm / libauditd / auditd_lib.c
1 /*-
2  * Copyright (c) 2008 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#1 $
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 <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
80 struct dir_ent {
81         char                    *dirname;
82         uint8_t                  softlim;
83         uint8_t                  hardlim;
84         TAILQ_ENTRY(dir_ent)     dirs;
85 };
86
87 static TAILQ_HEAD(, dir_ent)    dir_q;
88 static int minval = -1;
89
90 static 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) */
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  */
121 const char *
122 auditd_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  */
136 static void
137 free_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  */
155 static char *
156 affixdir(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
168         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  */
177 static void
178 insert_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  */
204 int
205 auditd_set_host(void)
206 {
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
214         if (getachost(hoststr, MAXHOSTNAMELEN) != 0) {
215
216                 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         }
232         error = getaddrinfo(hoststr, 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  */
269 int
270 auditd_set_minfree(void)
271 {
272         au_qctrl_t qctrl;
273
274         if (getacmin(&minval) != 0)
275                 return (ADE_PARSE);
276         
277         if (auditon(A_GETQCTRL, &qctrl, sizeof(qctrl)) != 0)
278                 return (ADE_AUDITON);
279
280         if (qctrl.aq_minfree != minval) {
281                 qctrl.aq_minfree = minval;
282                 if (auditon(A_SETQCTRL, &qctrl, sizeof(qctrl)) != 0)
283                         return (ADE_AUDITON);
284         }
285
286         return (0);
287 }
288
289 /*
290  * 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:
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  */
300 int
301 auditd_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
312         if (minval == -1 && (err = auditd_set_minfree()) != 0)
313                 return (err);
314
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 */
332                 soft = (sfs.f_bfree < (sfs.f_blocks / (100 / minval))) ? 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
366 void
367 auditd_close_dirs(void)
368 {
369         free_dir_q();
370         minval = -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  */
380 int
381 auditd_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  */
428 int
429 auditd_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  */
453 int
454 auditd_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  */
479 int
480 auditd_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  */
503 static int
504 open_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  */
534 int
535 auditd_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. */
552         while ((dirent = TAILQ_FIRST(&dir_q))) {
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  */
609 int
610 auditd_prevent_audit(void)
611 {
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 }
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  */
639 int
640 auditd_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  */
693 int
694 auditd_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) {
716                                 strlcpy(ptr, CRASH_RECOVERY, TIMESTAMP_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  */
749 int
750 audit_quick_start(void)
751 {
752         int err;
753         char *newfile;
754         time_t tt;
755         char TS[TIMESTAMP_LEN];
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);
776         if (err != ADE_NOERR && err != ADE_ACTL)
777                 return (-1);
778
779         /*
780          * Add the current symlink and recover from crash, if needed. 
781          */
782         if (auditd_new_curlink(newfile) != 0)
783                 return(-1);
784
785         /*
786          * At this point auditing has started so generate audit start-up record.
787          */
788         if (auditd_gen_record(AUE_audit_startup, NULL) != 0)
789                 return (-1);
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
801         return (0);
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  */
810 int
811 audit_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_DISABLED)
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) {
858                 strlcpy(ptr, TS, TIMESTAMP_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 }