binfile.c revision 2
2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 2N/A * write binary audit records directly to a file. 2N/A * auditd_plugin_open(), auditd_plugin() and auditd_plugin_close() 2N/A * implement a replacable library for use by auditd; they are a 2N/A * project private interface and may change without notice. 2N/A/* gettext() obfuscation routine for lint */ 2N/A /* per-directory status */ 2N/A#
define AVAIL_MIN 50 /* If there are less that this number */ 2N/A /* of blocks avail, the filesystem is */ 2N/A /* presumed full. */ 2N/A/* minimum reasonable size in bytes to roll over an audit file */ 2N/A * The directory list is a circular linked list. It is pointed into by 2N/A * activeDir. Each element contains the pointer to the next 2N/A * element, the directory pathname, a flag for how much space there is 2N/A * in the directory's filesystem, and a file handle. Since a new 2N/A * directory list can be created from auditd_plugin_open() while the 2N/A * current list is in use, activeDir is protected by log_mutex. 2N/A int dl_fd;
/* file handle, -1 unless open */ 2N/A * Defines for dl_flags 2N/A /* flag from audit_plugin_open to audit_plugin_close */ 2N/A * These are used to implement a maximum size for the auditing 2N/A * file. binfile_maxsize is set via the 'p_fsize' parameter to the 2N/A * audit_binfile plugin. 2N/A /* avoid excess audit_warnage */ 2N/A * Free up the old directory list if any 2N/A * add to a linked list of directories available for writing 2N/A while ((*
bs ==
' ') || (*
bs ==
'\t'))
/* trim blanks */ 2N/A while (
be >
bs) {
/* trim trailing blanks */ 2N/A * create a linked list of directories available for writing 2N/A * if a list already exists, the two are compared and the new one is 2N/A * used only if it is different than the old. 2N/A * returns -2 for new or changed list, 0 for unchanged list and -1 for 2N/A * error. (Positive returns are for AUDITD_<error code> values) 2N/A "(audit_binfile)\n"));
2N/A * there was a problem getting the directory 2N/A * list or remote host info from the audit_binfile 2N/A * configuration even though auditd thought there was 2N/A * at least 1 good entry 2N/A "problem getting directory / libpath list " 2N/A "from audit_binfile configuration.\n"));
2N/A /* print out directory list */ 2N/A /* See if the list has changed (rc = 0 if no change, else 1) */ 2N/A "binfile: new dirname = %s\n" 2N/A "binfile: old dirname = %s\n",
2N/A "binfile: old dir count = %d\n" 2N/A "binfile: new dir count = %d\n",
2N/A "loadauditlist: close / open audit.log(4)\n"));
2N/A /* Get the minfree value. */ 2N/A rc = -
2;
/* data change */ 2N/A * getauditdate - get the current time (GMT) and put it in the form 2N/A * NOTE: if we want to use gmtime, we have to be aware that the 2N/A * structure only keeps the year as an offset from TM_YEAR_BASE. 2N/A * I have used TM_YEAR_BASE in this code so that if they change 2N/A * this base from 1900 to 2000, it will hopefully mean that this 2N/A * code does not have to change. TM_YEAR_BASE is defined in 2N/A * write_file_token - put the file token into the audit log 2N/A * close_log - close the file if open. Also put the name of the 2N/A * new log file in the trailer, and rename the old file 2N/A * to oldname. The caller must hold log_mutext while calling 2N/A * close_log since any change to activeDir is a complete redo 2N/A * of all it points to. 2N/A * oldname - the new name for the file to be closed 2N/A * newname - the name of the new log file (for the trailer) 2N/A * If oldname is blank, we were called by auditd_plugin_close() 2N/A * instead of by open_log, so we need to update our name. 2N/A * Write the trailer record and rename and close the file. 2N/A * If any of the write, rename, or close fail, ignore it 2N/A * since there is not much else we can do and the next open() 2N/A * will trigger the necessary full directory logic. 2N/A * newname is "" if binfile is being closed down. 2N/A * open_log - open a new file in the current directory. If a 2N/A * file is already open, close it. 2N/A * return 1 if ok, 0 if all directories are full. 2N/A * lastOpenDir - used to get the oldfile name (and change it), 2N/A * to close the oldfile. 2N/A * The caller must hold log_mutex while calling open_log. 2N/A char *
name;
/* pointer into oldname */ 2N/A /* previous directory with open log file */ 2N/A /* Get a filename which does not already exist */ 2N/A "%s/%s.not_terminated.%s",
2N/A "open_log says duplicate for %s " 2N/A "open_log says about %s: %s\n",
2N/A "open_log says full for %s: %s\n",
2N/A * When we get here, we have opened our new log file. 2N/A * Now we need to update the name of the old file to 2N/A * store in this file's header. lastOpenDir may point 2N/A * to current_dir if the list is only one entry long and 2N/A * there is only one list. 2N/A /* write token failed */ 2N/A "(%s, %s [fd: %d])\n",
2N/A * New file opened, so reset file size statistic (used 2N/A * to ensure audit log does not grow above size limit 2N/A * spacecheck - determine whether the given directory's filesystem 2N/A * has the at least the space requested. Also set the space 2N/A * value in the directory list structure. If the caller 2N/A * passes other than PLENTY_SPACE or SOFT_SPACE, the caller should 2N/A * ignore the return value. Otherwise, 0 = less than the 2N/A * requested space is available, 1 = at least the requested space 2N/A * log_mutex must be held by the caller 2N/A * -1 is returned if stat fails 2N/A * IGNORE_SIZE is one page (Sol 9 / 10 timeframe) and is the default 2N/A * buffer size written for Sol 9 and earlier. To keep the same accuracy 2N/A * for the soft limit check as before, spacecheck checks for space 2N/A * remaining IGNORE_SIZE bytes. This reduces the number of statvfs() 2N/A * calls and related math. 2N/A * minfree - the soft limit, i.e., the % of filesystem to reserve 2N/A * Parses p_fsize and checks the value for minimal size higher than FSIZE_MIN. 2N/A * Defaults to 0 (unchanged value) if the value is invalid or missing. 2N/A "p_fsize parameter has invalid format (%s)",
2N/A }
else {
/* maxsize string not provided */ 2N/A * auditd_plugin() writes a buffer to the currently open file. The 2N/A * global "openNewFile" is used to force a new log file for cases such 2N/A * as the initial open, when minfree is reached, the p_fsize value is 2N/A * exceeded or the current file system fills up, and "audit -s" with 2N/A * changed parameters. For "audit -n" a new log file is opened 2N/A * immediately in auditd_plugin_open(). 2N/A * This function manages one or more audit directories as follows: 2N/A * If the current open file is in a directory that has not 2N/A * reached the soft limit, write the input data and return. 2N/A * Scan the list of directories for one which has not reached 2N/A * the soft limit; if one is found, write and return. Such 2N/A * a writable directory is in "PLENTY_SPACE" state. 2N/A * Scan the list of directories for one which has not reached 2N/A * the hard limit; if one is found, write and return. This 2N/A * directory in in "SOFT_SPACE" state. 2N/A * Oh, and if a write fails, handle it like a hard space limit. 2N/A * audit_warn (via __audit_dowarn()) is used to alert an operator 2N/A * at various levels of fullness. 2N/A "binfile: buffer sequence=%llu but prev=%llu=n",
2N/A * lock is for activeDir, referenced by open_log() and close_log() 2N/A * If this would take us over the maximum size, open a new 2N/A * file, unless maxsize is 0, in which case growth of the 2N/A * audit log is unrestricted. 2N/A "binfile: maxsize exceeded, opening new audit file.\n"));
2N/A * consider "space ok" return and error return the same; 2N/A * a -1 means spacecheck couldn't check for space. 2N/A "binfile: returned from spacecheck\n"));
2N/A * The last copy of last_file_written_to is 2N/A * never free'd, so there will be one open 2N/A * memory reference on exit. It's debug only. 2N/A "binfile: now writing to %s\n",
2N/A "binfile: finished some debug stuff\n"));
2N/A "binfile: write_count=%llu, sequence=%llu," 2N/A "binfile: write failed, sequence=%llu, " 2N/A "binfile: statrc=%d, fullness_state=%d\n",
2N/A }
else {
/* full circle twice */ 2N/A "all partitions full\n"));
2N/A * It may be called multiple times as auditd handles SIGHUP and SIGUSR1 2N/A * corresponding to the audit(1M) flags -s and -n 2N/A * kvlist is NULL only if auditd caught a SIGUSR1 (audit -n), so after the first 2N/A * time open is called; the reason is -s if kvlist != NULL and -n otherwise. 2N/A case 0:
/* initial open */ 2N/A case 2:
/* audit -s */ 2N/A /* handle p_fsize parameter */ 2N/A }
else {
/* status is 0 or -2 (no change or changed) */ 2N/A "binfile: loadauditlist returned %d\n",
status));
2N/A case 1:
/* audit -n */ 2N/A "when already closed.");