4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * write binary audit records directly to a file.
30 #define DPRINT(x) { (void) fprintf x; }
36 * auditd_plugin_open(), auditd_plugin() and auditd_plugin_close()
37 * implement a replacable library for use by auditd; they are a
38 * project private interface and may change without notice.
43 #include <bsm/audit.h>
44 #include <bsm/audit_record.h>
45 #include <bsm/libbsm.h>
56 #include <sys/param.h>
57 #include <sys/types.h>
64 #include <security/auditd.h>
65 #include <audit_plugin.h>
67 #define AUDIT_DATE_SZ 14
68 #define AUDIT_FNAME_SZ 2 * AUDIT_DATE_SZ + 2 + MAXHOSTNAMELEN
70 /* per-directory status */
71 #define SOFT_SPACE 0 /* minfree or less space available */
72 #define PLENTY_SPACE 1 /* more than minfree available */
73 #define SPACE_FULL 2 /* out of space */
75 #define AVAIL_MIN 50 /* If there are less that this number */
76 /* of blocks avail, the filesystem is */
79 #define ALLHARD_DELAY 20 /* Call audit_warn(allhard) every 20 seconds */
81 /* minimum reasonable size in bytes to roll over an audit file */
82 #define FSIZE_MIN 512000
85 * The directory list is a circular linked list. It is pointed into by
86 * activeDir. Each element contains the pointer to the next
87 * element, the directory pathname, a flag for how much space there is
88 * in the directory's filesystem, and a file handle. Since a new
89 * directory list can be created from auditd_plugin_open() while the
90 * current list is in use, activeDir is protected by log_mutex.
92 typedef struct dirlist_s dirlist_t
;
98 char *dl_filename
; /* file name (not path) if open */
99 int dl_fd
; /* file handle, -1 unless open */
102 * Defines for dl_flags
104 #define SOFT_WARNED 0x0001 /* already did soft warning for this dir */
105 #define HARD_WARNED 0x0002 /* already did hard warning for this dir */
108 static FILE *dbfp
; /* debug file */
111 static pthread_mutex_t log_mutex
;
112 static int binfile_is_open
= 0;
114 static int minfree
= -1;
115 static int minfreeblocks
; /* minfree in blocks */
117 static dirlist_t
*lastOpenDir
= NULL
; /* last activeDir */
118 static dirlist_t
*activeDir
= NULL
; /* to be current directory */
119 static dirlist_t
*startdir
; /* first dir in the ring */
120 static int activeCount
= 0; /* number of dirs in the ring */
122 static int openNewFile
= 0; /* need to open a new file */
123 static int hung_count
= 0; /* count of audit_warn hard */
125 /* flag from audit_plugin_open to audit_plugin_close */
126 static int am_open
= 0;
127 /* preferred dir state */
128 static int fullness_state
= PLENTY_SPACE
;
131 * These are used to implement a maximum size for the auditing
132 * file. binfile_maxsize is set via the 'p_fsize' parameter to the
133 * audit_binfile plugin.
135 static uint_t binfile_cursize
= 0;
136 static uint_t binfile_maxsize
= 0;
138 static int open_log(dirlist_t
*);
141 freedirlist(dirlist_t
*head
)
145 * Free up the old directory list if any
151 free(n1
->dl_dirname
);
152 free(n1
->dl_filename
);
155 } while (n1
!= head
);
160 dupdirnode(dirlist_t
*node_orig
)
164 if ((node_new
= calloc(1, sizeof (dirlist_t
))) == NULL
) {
168 if (node_orig
->dl_dirname
!= NULL
&&
169 (node_new
->dl_dirname
= strdup(node_orig
->dl_dirname
)) == NULL
||
170 node_orig
->dl_filename
!= NULL
&&
171 (node_new
->dl_filename
= strdup(node_orig
->dl_filename
)) == NULL
) {
172 freedirlist(node_new
);
176 node_new
->dl_next
= node_new
;
177 node_new
->dl_space
= node_orig
->dl_space
;
178 node_new
->dl_flags
= node_orig
->dl_flags
;
179 node_new
->dl_fd
= node_orig
->dl_fd
;
185 * add to a linked list of directories available for writing
189 growauditlist(dirlist_t
**listhead
, char *dirlist
,
190 dirlist_t
*endnode
, int *count
)
198 DPRINT((dbfp
, "binfile: dirlist=%s\n", dirlist
));
200 if (*listhead
== NULL
)
203 node_p
= &(endnode
->dl_next
);
206 while ((dirname
= strtok_r(dirlist
, ",", &remainder
)) != NULL
) {
209 DPRINT((dbfp
, "binfile: p_dir = %s\n", dirname
));
212 node
= malloc(sizeof (dirlist_t
));
214 return (AUDITD_NO_MEMORY
);
217 node
->dl_filename
= NULL
;
219 node
->dl_space
= PLENTY_SPACE
;
221 node
->dl_dirname
= malloc((unsigned)strlen(dirname
) + 1);
222 if (node
->dl_dirname
== NULL
)
223 return (AUDITD_NO_MEMORY
);
226 while ((*bs
== ' ') || (*bs
== '\t')) /* trim blanks */
228 be
= bs
+ strlen(bs
) - 1;
229 while (be
> bs
) { /* trim trailing blanks */
230 if ((*bs
!= ' ') && (*bs
!= '\t'))
235 (void) strlcpy(node
->dl_dirname
, bs
, AUDIT_FNAME_SZ
);
237 if (*listhead
!= NULL
)
238 node
->dl_next
= *listhead
;
240 node
->dl_next
= node
;
242 node_p
= &(node
->dl_next
);
249 * create a linked list of directories available for writing
251 * if a list already exists, the two are compared and the new one is
252 * used only if it is different than the old.
254 * returns -2 for new or changed list, 0 for unchanged list and -1 for
255 * error. (Positive returns are for AUDITD_<error code> values)
259 loadauditlist(char *dirstr
, char *minfreestr
)
262 dirlist_t
*listhead
= NULL
;
266 int temp_minfree
= 0;
268 static dirlist_t
*activeList
= NULL
; /* directory list */
270 DPRINT((dbfp
, "binfile: Loading audit list from audit service "
271 "(audit_binfile)\n"));
273 if (dirstr
== NULL
|| minfreestr
== NULL
) {
274 DPRINT((dbfp
, "binfile: internal error"));
277 if ((rc
= growauditlist(&listhead
, dirstr
, NULL
, &node_count
)) != 0) {
280 if (node_count
== 0) {
282 * there was a problem getting the directory
283 * list or remote host info from the audit_binfile
284 * configuration even though auditd thought there was
285 * at least 1 good entry
287 DPRINT((dbfp
, "binfile: "
288 "problem getting directory / libpath list "
289 "from audit_binfile configuration.\n"));
294 /* print out directory list */
295 if (listhead
!= NULL
) {
296 (void) fprintf(dbfp
, "Directory list:\n\t%s\n",
297 listhead
->dl_dirname
);
298 thisdir
= listhead
->dl_next
;
300 while (thisdir
!= listhead
) {
301 (void) fprintf(dbfp
, "\t%s\n", thisdir
->dl_dirname
);
302 thisdir
= thisdir
->dl_next
;
309 /* See if the list has changed (rc = 0 if no change, else 1) */
311 if (node_count
== activeCount
) {
315 if (strcmp(n1
->dl_dirname
, n2
->dl_dirname
) != 0) {
317 "binfile: new dirname = %s\n"
318 "binfile: old dirname = %s\n",
326 } while ((n1
!= listhead
) && (n2
!= activeList
));
328 DPRINT((dbfp
, "binfile: dir counts differs\n"
329 "binfile: old dir count = %d\n"
330 "binfile: new dir count = %d\n",
331 activeCount
, node_count
));
335 (void) pthread_mutex_lock(&log_mutex
);
336 DPRINT((dbfp
, "loadauditlist: close / open audit.log(4)\n"));
337 if (open_log(listhead
) == 0) {
338 openNewFile
= 1; /* try again later */
342 freedirlist(activeList
); /* old list */
343 activeList
= listhead
; /* new list */
344 activeDir
= startdir
= thisdir
;
345 activeCount
= node_count
;
346 (void) pthread_mutex_unlock(&log_mutex
);
348 freedirlist(listhead
);
351 /* Get the minfree value. */
352 temp_minfree
= atoi(minfreestr
);
354 if ((temp_minfree
< 0) || (temp_minfree
> 100))
357 if (minfree
!= temp_minfree
) {
358 DPRINT((dbfp
, "minfree: old = %d, new = %d\n",
359 minfree
, temp_minfree
));
360 rc
= -2; /* data change */
361 minfree
= temp_minfree
;
368 * getauditdate - get the current time (GMT) and put it in the form
372 getauditdate(char *date
)
378 (void) gettimeofday(&tp
, &tzp
);
379 tm
= *gmtime(&tp
.tv_sec
);
381 * NOTE: if we want to use gmtime, we have to be aware that the
382 * structure only keeps the year as an offset from TM_YEAR_BASE.
383 * I have used TM_YEAR_BASE in this code so that if they change
384 * this base from 1900 to 2000, it will hopefully mean that this
385 * code does not have to change. TM_YEAR_BASE is defined in
388 (void) sprintf(date
, "%.4d%.2d%.2d%.2d%.2d%.2d",
389 tm
.tm_year
+ TM_YEAR_BASE
, tm
.tm_mon
+ 1, tm
.tm_mday
,
390 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
);
396 * write_file_token - put the file token into the audit log
399 write_file_token(int fd
, char *name
)
401 adr_t adr
; /* xdr ptr */
402 struct timeval tv
; /* time now */
403 char for_adr
[AUDIT_FNAME_SZ
+ AUDIT_FNAME_SZ
]; /* plenty of room */
407 (void) gettimeofday(&tv
, NULL
);
408 i
= strlen(name
) + 1;
409 adr_start(&adr
, for_adr
);
411 token_id
= AUT_OTHER_FILE64
;
412 adr_char(&adr
, &token_id
, 1);
413 adr_int64(&adr
, (int64_t *)& tv
, 2);
415 token_id
= AUT_OTHER_FILE32
;
416 adr_char(&adr
, &token_id
, 1);
417 adr_int32(&adr
, (int32_t *)& tv
, 2);
420 adr_short(&adr
, &i
, 1);
421 adr_char(&adr
, name
, i
);
423 if (write(fd
, for_adr
, adr_count(&adr
)) < 0) {
424 DPRINT((dbfp
, "binfile: Bad write\n"));
431 * close_log - close the file if open. Also put the name of the
432 * new log file in the trailer, and rename the old file
433 * to oldname. The caller must hold log_mutext while calling
434 * close_log since any change to activeDir is a complete redo
435 * of all it points to.
437 * oldname - the new name for the file to be closed
438 * newname - the name of the new log file (for the trailer)
441 close_log(dirlist_t
**lastOpenDir_ptr
, char *oname
, char *newname
)
443 char auditdate
[AUDIT_DATE_SZ
+1];
445 char oldname
[AUDIT_FNAME_SZ
+1];
446 dirlist_t
*currentdir
= *lastOpenDir_ptr
;
448 if ((currentdir
== NULL
) || (currentdir
->dl_fd
== -1))
451 * If oldname is blank, we were called by auditd_plugin_close()
452 * instead of by open_log, so we need to update our name.
454 (void) strlcpy(oldname
, oname
, AUDIT_FNAME_SZ
);
456 if (strcmp(oldname
, "") == 0) {
457 getauditdate(auditdate
);
459 assert(currentdir
->dl_filename
!= NULL
);
461 (void) strlcpy(oldname
, currentdir
->dl_filename
,
464 name
= strrchr(oldname
, '/') + 1;
465 (void) memcpy(name
+ AUDIT_DATE_SZ
+ 1, auditdate
,
469 * Write the trailer record and rename and close the file.
470 * If any of the write, rename, or close fail, ignore it
471 * since there is not much else we can do and the next open()
472 * will trigger the necessary full directory logic.
474 * newname is "" if binfile is being closed down.
476 (void) write_file_token(currentdir
->dl_fd
, newname
);
477 if (currentdir
->dl_fd
>= 0) {
478 (void) fsync(currentdir
->dl_fd
);
479 (void) close(currentdir
->dl_fd
);
481 currentdir
->dl_fd
= -1;
482 (void) rename(currentdir
->dl_filename
, oldname
);
484 DPRINT((dbfp
, "binfile: Log closed %s\n", oldname
));
486 freedirlist(currentdir
);
487 *lastOpenDir_ptr
= NULL
;
492 * open_log - open a new file in the current directory. If a
493 * file is already open, close it.
495 * return 1 if ok, 0 if all directories are full.
497 * lastOpenDir - used to get the oldfile name (and change it),
498 * to close the oldfile.
500 * The caller must hold log_mutex while calling open_log.
504 open_log(dirlist_t
*current_dir
)
506 char auditdate
[AUDIT_DATE_SZ
+ 1];
507 char oldname
[AUDIT_FNAME_SZ
+ 1] = "";
508 char newname
[AUDIT_FNAME_SZ
+ 1];
509 char *name
; /* pointer into oldname */
514 static char host
[MAXHOSTNAMELEN
+ 1] = "";
515 /* previous directory with open log file */
518 (void) gethostname(host
, MAXHOSTNAMELEN
);
520 /* Get a filename which does not already exist */
522 getauditdate(auditdate
);
523 (void) snprintf(newname
, AUDIT_FNAME_SZ
,
524 "%s/%s.not_terminated.%s",
525 current_dir
->dl_dirname
, auditdate
, host
);
526 newfd
= open(newname
,
527 O_RDWR
| O_APPEND
| O_CREAT
| O_EXCL
, 0640);
532 "open_log says duplicate for %s "
533 "(will try another)\n", newname
));
539 (void) asprintf(&msg
,
540 gettext("No such p_dir: %s\n"),
541 current_dir
->dl_dirname
);
543 "open_log says about %s: %s\n",
544 newname
, strerror(errno
)));
545 __audit_syslog("audit_binfile.so",
546 LOG_CONS
| LOG_NDELAY
,
547 LOG_DAEMON
, LOG_ERR
, msg
);
549 current_dir
= current_dir
->dl_next
;
555 "open_log says full for %s: %s\n",
556 newname
, strerror(errno
)));
557 current_dir
->dl_space
= SPACE_FULL
;
558 current_dir
= current_dir
->dl_next
;
566 * When we get here, we have opened our new log file.
567 * Now we need to update the name of the old file to
568 * store in this file's header. lastOpenDir may point
569 * to current_dir if the list is only one entry long and
570 * there is only one list.
572 if ((lastOpenDir
!= NULL
) && (lastOpenDir
->dl_filename
!= NULL
)) {
573 (void) strlcpy(oldname
, lastOpenDir
->dl_filename
,
575 name
= (char *)strrchr(oldname
, '/') + 1;
577 (void) memcpy(name
+ AUDIT_DATE_SZ
+ 1, auditdate
,
580 close_log(&lastOpenDir
, oldname
, newname
);
582 error
= write_file_token(newfd
, oldname
);
584 /* write token failed */
587 current_dir
->dl_space
= SPACE_FULL
;
588 current_dir
->dl_fd
= -1;
589 free(current_dir
->dl_filename
);
590 current_dir
->dl_filename
= NULL
;
591 current_dir
= current_dir
->dl_next
;
594 if (current_dir
->dl_filename
!= NULL
) {
595 free(current_dir
->dl_filename
);
597 current_dir
->dl_filename
= strdup(newname
);
598 current_dir
->dl_fd
= newfd
;
600 if (lastOpenDir
== NULL
) {
601 freedirlist(lastOpenDir
);
602 if ((lastOpenDir
= dupdirnode(current_dir
)) == NULL
) {
603 __audit_syslog("audit_binfile.so",
604 LOG_CONS
| LOG_NDELAY
,
605 LOG_DAEMON
, LOG_ERR
, gettext("no memory"));
608 DPRINT((dbfp
, "open_log created new lastOpenDir "
609 "(%s, %s [fd: %d])\n",
610 lastOpenDir
->dl_dirname
== NULL
? "" :
611 lastOpenDir
->dl_dirname
,
612 lastOpenDir
->dl_filename
== NULL
? "" :
613 lastOpenDir
->dl_filename
, lastOpenDir
->dl_fd
));
617 * New file opened, so reset file size statistic (used
618 * to ensure audit log does not grow above size limit
623 (void) __logpost(newname
);
625 DPRINT((dbfp
, "binfile: Log opened: %s\n", newname
));
630 #define IGNORE_SIZE 8192
632 * spacecheck - determine whether the given directory's filesystem
633 * has the at least the space requested. Also set the space
634 * value in the directory list structure. If the caller
635 * passes other than PLENTY_SPACE or SOFT_SPACE, the caller should
636 * ignore the return value. Otherwise, 0 = less than the
637 * requested space is available, 1 = at least the requested space
640 * log_mutex must be held by the caller
642 * -1 is returned if stat fails
644 * IGNORE_SIZE is one page (Sol 9 / 10 timeframe) and is the default
645 * buffer size written for Sol 9 and earlier. To keep the same accuracy
646 * for the soft limit check as before, spacecheck checks for space
647 * remaining IGNORE_SIZE bytes. This reduces the number of statvfs()
648 * calls and related math.
651 * minfree - the soft limit, i.e., the % of filesystem to reserve
654 spacecheck(dirlist_t
*thisdir
, int test_limit
, size_t next_buf_size
)
657 static int ignore_size
= 0;
659 ignore_size
+= next_buf_size
;
661 if ((test_limit
== PLENTY_SPACE
) && (ignore_size
< IGNORE_SIZE
))
664 assert(thisdir
!= NULL
);
666 if (statvfs(thisdir
->dl_dirname
, &sb
) < 0) {
667 thisdir
->dl_space
= SPACE_FULL
;
668 minfreeblocks
= AVAIL_MIN
;
671 minfreeblocks
= ((minfree
* sb
.f_blocks
) / 100) + AVAIL_MIN
;
673 if (sb
.f_bavail
< AVAIL_MIN
)
674 thisdir
->dl_space
= SPACE_FULL
;
675 else if (sb
.f_bavail
> minfreeblocks
) {
676 thisdir
->dl_space
= fullness_state
= PLENTY_SPACE
;
679 thisdir
->dl_space
= SOFT_SPACE
;
681 if (thisdir
->dl_space
== PLENTY_SPACE
)
684 return (thisdir
->dl_space
== test_limit
);
688 * Parses p_fsize value and contains it within the range FSIZE_MIN and
689 * INT_MAX so using uints won't cause an undetected overflow of
690 * INT_MAX. Defaults to 0 if the value is invalid or is missing.
693 save_maxsize(char *maxsize
)
696 * strtol() returns a long which could be larger than int so
697 * store here for sanity checking first
699 long proposed_maxsize
;
701 if (maxsize
!= NULL
) {
703 * There is no explicit error return from strtol() so
704 * we may need to depend on the value of errno.
707 proposed_maxsize
= strtol(maxsize
, (char **)NULL
, 10);
710 * If sizeof(long) is greater than sizeof(int) on this
711 * platform, proposed_maxsize might be greater than
712 * INT_MAX without it being reported as ERANGE.
714 if ((errno
== ERANGE
) ||
715 ((proposed_maxsize
!= 0) &&
716 (proposed_maxsize
< FSIZE_MIN
)) ||
717 (proposed_maxsize
> INT_MAX
)) {
719 DPRINT((dbfp
, "binfile: p_fsize parameter out of "
720 "range: %s\n", maxsize
));
722 * Inform administrator of the error via
725 __audit_syslog("audit_binfile.so",
726 LOG_CONS
| LOG_NDELAY
,
728 gettext("p_fsize parameter out of range\n"));
730 binfile_maxsize
= proposed_maxsize
;
732 } else { /* p_fsize string was not present */
736 DPRINT((dbfp
, "binfile: set maxsize to %d\n", binfile_maxsize
));
740 * auditd_plugin() writes a buffer to the currently open file. The
741 * global "openNewFile" is used to force a new log file for cases such
742 * as the initial open, when minfree is reached, the p_fsize value is
743 * exceeded or the current file system fills up, and "audit -s" with
744 * changed parameters. For "audit -n" a new log file is opened
745 * immediately in auditd_plugin_open().
747 * This function manages one or more audit directories as follows:
749 * If the current open file is in a directory that has not
750 * reached the soft limit, write the input data and return.
752 * Scan the list of directories for one which has not reached
753 * the soft limit; if one is found, write and return. Such
754 * a writable directory is in "PLENTY_SPACE" state.
756 * Scan the list of directories for one which has not reached
757 * the hard limit; if one is found, write and return. This
758 * directory in in "SOFT_SPACE" state.
760 * Oh, and if a write fails, handle it like a hard space limit.
762 * audit_warn (via __audit_dowarn()) is used to alert an operator
763 * at various levels of fullness.
767 auditd_plugin(const char *input
, size_t in_len
, uint64_t sequence
, char **error
)
769 auditd_rc_t rc
= AUDITD_FAIL
;
772 /* avoid excess audit_warnage */
773 static int allsoftfull_warning
= 0;
774 static int allhard_pause
= 0;
775 static struct timeval next_allhard
;
779 static char *last_file_written_to
= NULL
;
780 static uint64_t last_sequence
= 0;
781 static uint64_t write_count
= 0;
783 if ((last_sequence
> 0) && (sequence
!= last_sequence
+ 1))
785 "binfile: buffer sequence=%llu but prev=%llu=n",
786 sequence
, last_sequence
);
787 last_sequence
= sequence
;
789 (void) fprintf(dbfp
, "binfile: input seq=%llu, len=%d\n",
794 * lock is for activeDir, referenced by open_log() and close_log()
796 (void) pthread_mutex_lock(&log_mutex
);
799 * If this would take us over the maximum size, open a new
800 * file, unless maxsize is 0, in which case growth of the
801 * audit log is unrestricted.
803 if ((binfile_maxsize
!= 0) &&
804 ((binfile_cursize
+ in_len
) > binfile_maxsize
)) {
805 DPRINT((dbfp
, "binfile: maxsize exceeded, opening new audit "
810 while (rc
== AUDITD_FAIL
) {
813 open_status
= open_log(activeDir
);
814 if (open_status
== 1) /* ok */
818 * consider "space ok" return and error return the same;
819 * a -1 means spacecheck couldn't check for space.
822 if ((open_status
== 1) &&
823 (spacecheck(activeDir
, fullness_state
, in_len
) != 0)) {
825 if ((open_status
== 1) &&
826 (statrc
= spacecheck(activeDir
, fullness_state
,
828 DPRINT((dbfp
, "binfile: returned from spacecheck\n"));
830 * The last copy of last_file_written_to is
831 * never free'd, so there will be one open
832 * memory reference on exit. It's debug only.
834 if ((last_file_written_to
!= NULL
) &&
835 (strcmp(last_file_written_to
,
836 activeDir
->dl_filename
) != 0)) {
837 DPRINT((dbfp
, "binfile: now writing to %s\n",
838 activeDir
->dl_filename
));
839 free(last_file_written_to
);
841 DPRINT((dbfp
, "binfile: finished some debug stuff\n"));
842 last_file_written_to
=
843 strdup(activeDir
->dl_filename
);
845 out_len
= write(activeDir
->dl_fd
, input
, in_len
);
846 DPRINT((dbfp
, "binfile: finished the write\n"));
848 binfile_cursize
+= out_len
;
850 if (out_len
== in_len
) {
852 "binfile: write_count=%llu, sequence=%llu,"
854 ++write_count
, sequence
, out_len
));
855 allsoftfull_warning
= 0;
856 activeDir
->dl_flags
= 0;
860 } else if (!(activeDir
->dl_flags
& HARD_WARNED
)) {
862 "binfile: write failed, sequence=%llu, "
863 "l=%u\n", sequence
, out_len
));
864 DPRINT((dbfp
, "hard warning sent.\n"));
865 __audit_dowarn("hard", activeDir
->dl_dirname
,
868 activeDir
->dl_flags
|= HARD_WARNED
;
871 DPRINT((dbfp
, "binfile: statrc=%d, fullness_state=%d\n",
872 statrc
, fullness_state
));
873 if (!(activeDir
->dl_flags
& SOFT_WARNED
) &&
874 (activeDir
->dl_space
== SOFT_SPACE
)) {
875 DPRINT((dbfp
, "soft warning sent\n"));
876 __audit_dowarn("soft",
877 activeDir
->dl_dirname
, 0);
878 activeDir
->dl_flags
|= SOFT_WARNED
;
880 if (!(activeDir
->dl_flags
& HARD_WARNED
) &&
881 (activeDir
->dl_space
== SPACE_FULL
)) {
882 DPRINT((dbfp
, "hard warning sent.\n"));
883 __audit_dowarn("hard",
884 activeDir
->dl_dirname
, 0);
885 activeDir
->dl_flags
|= HARD_WARNED
;
888 DPRINT((dbfp
, "binfile: activeDir=%s, next=%s\n",
889 activeDir
->dl_dirname
, activeDir
->dl_next
->dl_dirname
));
891 activeDir
= activeDir
->dl_next
;
894 if (activeDir
== startdir
) { /* full circle */
895 if (fullness_state
== PLENTY_SPACE
) { /* once */
896 fullness_state
= SOFT_SPACE
;
897 if (allsoftfull_warning
== 0) {
898 allsoftfull_warning
++;
899 __audit_dowarn("allsoft", "", 0);
901 } else { /* full circle twice */
902 if ((hung_count
> 0) && !allhard_pause
) {
904 (void) gettimeofday(&next_allhard
,
906 next_allhard
.tv_sec
+= ALLHARD_DELAY
;
910 (void) gettimeofday(&now
, NULL
);
911 if (now
.tv_sec
>= next_allhard
.tv_sec
) {
913 __audit_dowarn("allhard", "",
917 __audit_dowarn("allhard", "",
920 minfreeblocks
= AVAIL_MIN
;
922 *error
= strdup(gettext(
923 "all partitions full\n"));
924 (void) __logpost("");
928 (void) pthread_mutex_unlock(&log_mutex
);
935 * It may be called multiple times as auditd handles SIGHUP and SIGUSR1
936 * corresponding to the audit(1M) flags -s and -n
938 * kvlist is NULL only if auditd caught a SIGUSR1 (audit -n), so after the first
939 * time open is called; the reason is -s if kvlist != NULL and -n otherwise.
943 auditd_plugin_open(const kva_t
*kvlist
, char **ret_list
, char **error
)
955 kv
= (kva_t
*)kvlist
;
959 reason
= 1; /* audit -n */
961 reason
= 2; /* audit -s */
963 reason
= 0; /* initial open */
965 dbfp
= __auditd_debug_file_open();
968 DPRINT((dbfp
, "binfile: am_open=%d, reason=%d\n", am_open
, reason
));
972 if (kvlist
== NULL
) {
977 dirlist
= kva_match(kv
, "p_dir");
978 minfree
= kva_match(kv
, "p_minfree");
979 maxsize
= kva_match(kv
, "p_fsize");
982 case 0: /* initial open */
983 if (!binfile_is_open
)
984 (void) pthread_mutex_init(&log_mutex
, NULL
);
988 case 2: /* audit -s */
989 /* handle p_fsize parameter */
990 save_maxsize(maxsize
);
992 fullness_state
= PLENTY_SPACE
;
993 status
= loadauditlist(dirlist
, minfree
);
996 (void) __logpost("");
997 *error
= strdup(gettext("no directories configured"));
998 return (AUDITD_RETRY
);
999 } else if (status
== AUDITD_NO_MEMORY
) {
1000 (void) __logpost("");
1001 *error
= strdup(gettext("no memory"));
1003 } else { /* status is 0 or -2 (no change or changed) */
1005 DPRINT((dbfp
, "binfile: loadauditlist returned %d\n",
1009 case 1: /* audit -n */
1010 (void) pthread_mutex_lock(&log_mutex
);
1011 if (open_log(activeDir
) == 1) /* ok */
1013 (void) pthread_mutex_unlock(&log_mutex
);
1017 rc
= AUDITD_SUCCESS
;
1024 auditd_plugin_close(char **error
)
1028 (void) pthread_mutex_lock(&log_mutex
);
1029 close_log(&lastOpenDir
, "", "");
1030 freedirlist(activeDir
);
1032 (void) pthread_mutex_unlock(&log_mutex
);
1034 DPRINT((dbfp
, "binfile: closed\n"));
1036 (void) __logpost("");
1038 if (binfile_is_open
) {
1039 (void) pthread_mutex_destroy(&log_mutex
);
1040 binfile_is_open
= 0;
1043 (void) fprintf(dbfp
,
1044 "auditd_plugin_close() called when already closed.");
1048 return (AUDITD_SUCCESS
);