10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55007Spaulson * Common Development and Distribution License (the "License"). 65007Spaulson * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 2211700Sgww@eng.sun.com * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate * 250Sstevel@tonic-gate * write binary audit records directly to a file. 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate #define DEBUG 0 290Sstevel@tonic-gate 300Sstevel@tonic-gate #if DEBUG 310Sstevel@tonic-gate #define DPRINT(x) {fprintf x; } 320Sstevel@tonic-gate #else 330Sstevel@tonic-gate #define DPRINT(x) 340Sstevel@tonic-gate #endif 350Sstevel@tonic-gate 360Sstevel@tonic-gate /* 370Sstevel@tonic-gate * auditd_plugin_open(), auditd_plugin() and auditd_plugin_close() 380Sstevel@tonic-gate * implement a replacable library for use by auditd; they are a 390Sstevel@tonic-gate * project private interface and may change without notice. 400Sstevel@tonic-gate * 410Sstevel@tonic-gate */ 420Sstevel@tonic-gate 430Sstevel@tonic-gate #include <assert.h> 440Sstevel@tonic-gate #include <bsm/audit.h> 450Sstevel@tonic-gate #include <bsm/audit_record.h> 460Sstevel@tonic-gate #include <bsm/libbsm.h> 470Sstevel@tonic-gate #include <errno.h> 480Sstevel@tonic-gate #include <fcntl.h> 490Sstevel@tonic-gate #include <libintl.h> 500Sstevel@tonic-gate #include <netdb.h> 510Sstevel@tonic-gate #include <pthread.h> 520Sstevel@tonic-gate #include <secdb.h> 530Sstevel@tonic-gate #include <signal.h> 540Sstevel@tonic-gate #include <stdio.h> 550Sstevel@tonic-gate #include <stdlib.h> 560Sstevel@tonic-gate #include <string.h> 570Sstevel@tonic-gate #include <sys/param.h> 580Sstevel@tonic-gate #include <sys/types.h> 590Sstevel@tonic-gate #include <time.h> 600Sstevel@tonic-gate #include <tzfile.h> 610Sstevel@tonic-gate #include <unistd.h> 620Sstevel@tonic-gate #include <sys/vfs.h> 636697Spr131582 #include <limits.h> 646697Spr131582 #include <syslog.h> 650Sstevel@tonic-gate #include <security/auditd.h> 660Sstevel@tonic-gate #include <audit_plugin.h> 670Sstevel@tonic-gate 680Sstevel@tonic-gate #define AUDIT_DATE_SZ 14 690Sstevel@tonic-gate #define AUDIT_FNAME_SZ 2 * AUDIT_DATE_SZ + 2 + MAXHOSTNAMELEN 700Sstevel@tonic-gate 710Sstevel@tonic-gate /* per-directory status */ 720Sstevel@tonic-gate #define SOFT_SPACE 0 /* minfree or less space available */ 730Sstevel@tonic-gate #define PLENTY_SPACE 1 /* more than minfree available */ 740Sstevel@tonic-gate #define SPACE_FULL 2 /* out of space */ 750Sstevel@tonic-gate 760Sstevel@tonic-gate #define AVAIL_MIN 50 /* If there are less that this number */ 770Sstevel@tonic-gate /* of blocks avail, the filesystem is */ 780Sstevel@tonic-gate /* presumed full. */ 790Sstevel@tonic-gate 805007Spaulson #define ALLHARD_DELAY 20 /* Call audit_warn(allhard) every 20 seconds */ 815007Spaulson 826697Spr131582 /* minimum reasonable size in bytes to roll over an audit file */ 836697Spr131582 #define FSIZE_MIN 512000 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * The directory list is a circular linked list. It is pointed into by 870Sstevel@tonic-gate * activeDir. Each element contains the pointer to the next 880Sstevel@tonic-gate * element, the directory pathname, a flag for how much space there is 890Sstevel@tonic-gate * in the directory's filesystem, and a file handle. Since a new 900Sstevel@tonic-gate * directory list can be created from auditd_plugin_open() while the 910Sstevel@tonic-gate * current list is in use, activeDir is protected by log_mutex. 920Sstevel@tonic-gate */ 930Sstevel@tonic-gate typedef struct dirlist_s dirlist_t; 940Sstevel@tonic-gate struct dirlist_s { 950Sstevel@tonic-gate dirlist_t *dl_next; 960Sstevel@tonic-gate int dl_space; 970Sstevel@tonic-gate int dl_flags; 980Sstevel@tonic-gate char *dl_dirname; 990Sstevel@tonic-gate char *dl_filename; /* file name (not path) if open */ 1000Sstevel@tonic-gate int dl_fd; /* file handle, -1 unless open */ 1010Sstevel@tonic-gate }; 1020Sstevel@tonic-gate /* 1030Sstevel@tonic-gate * Defines for dl_flags 1040Sstevel@tonic-gate */ 1050Sstevel@tonic-gate #define SOFT_WARNED 0x0001 /* already did soft warning for this dir */ 1060Sstevel@tonic-gate #define HARD_WARNED 0x0002 /* already did hard warning for this dir */ 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate #if DEBUG 1090Sstevel@tonic-gate static FILE *dbfp; /* debug file */ 1100Sstevel@tonic-gate #endif 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate static pthread_mutex_t log_mutex; 1130Sstevel@tonic-gate static int binfile_is_open = 0; 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate static int minfree = -1; 1160Sstevel@tonic-gate static int minfreeblocks; /* minfree in blocks */ 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate static dirlist_t *activeDir = NULL; /* current directory */ 1195007Spaulson static dirlist_t *startdir; /* first dir in the ring */ 1200Sstevel@tonic-gate static int activeCount = 0; /* number of dirs in the ring */ 1210Sstevel@tonic-gate 1225007Spaulson static int openNewFile = 0; /* need to open a new file */ 1230Sstevel@tonic-gate static int hung_count = 0; /* count of audit_warn hard */ 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate /* flag from audit_plugin_open to audit_plugin_close */ 1260Sstevel@tonic-gate static int am_open = 0; 1270Sstevel@tonic-gate /* preferred dir state */ 1280Sstevel@tonic-gate static int fullness_state = PLENTY_SPACE; 1290Sstevel@tonic-gate 1306697Spr131582 /* 1316697Spr131582 * These are used to implement a maximum size for the auditing 1326697Spr131582 * file. binfile_maxsize is set via the 'p_fsize' parameter to the 1336697Spr131582 * audit_binfile plugin. 1346697Spr131582 */ 1356697Spr131582 static uint_t binfile_cursize = 0; 1366697Spr131582 static uint_t binfile_maxsize = 0; 1376697Spr131582 1380Sstevel@tonic-gate static int open_log(dirlist_t *); 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate static void 1410Sstevel@tonic-gate freedirlist(dirlist_t *head) 1420Sstevel@tonic-gate { 1430Sstevel@tonic-gate dirlist_t *n1, *n2; 1440Sstevel@tonic-gate /* 1450Sstevel@tonic-gate * Free up the old directory list if any 1460Sstevel@tonic-gate */ 1470Sstevel@tonic-gate if (head != NULL) { 1480Sstevel@tonic-gate n1 = head; 1490Sstevel@tonic-gate do { 1500Sstevel@tonic-gate n2 = n1->dl_next; 1510Sstevel@tonic-gate free(n1->dl_dirname); 1520Sstevel@tonic-gate free(n1->dl_filename); 1530Sstevel@tonic-gate free(n1); 1540Sstevel@tonic-gate n1 = n2; 1550Sstevel@tonic-gate } while (n1 != head); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate /* 1610Sstevel@tonic-gate * add to a linked list of directories available for writing 1620Sstevel@tonic-gate * 1630Sstevel@tonic-gate */ 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate static int 1660Sstevel@tonic-gate growauditlist(dirlist_t **listhead, char *dirlist, 1670Sstevel@tonic-gate dirlist_t *endnode, int *count) 1680Sstevel@tonic-gate { 1690Sstevel@tonic-gate dirlist_t *node; 1700Sstevel@tonic-gate char *bs, *be; 1710Sstevel@tonic-gate dirlist_t **node_p; 1720Sstevel@tonic-gate char *dirname; 1730Sstevel@tonic-gate char *remainder; 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate DPRINT((dbfp, "binfile: dirlist=%s\n", dirlist)); 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate if (*listhead == NULL) 1780Sstevel@tonic-gate node_p = listhead; 1790Sstevel@tonic-gate else 1800Sstevel@tonic-gate node_p = &(endnode->dl_next); 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate node = NULL; 1830Sstevel@tonic-gate while ((dirname = strtok_r(dirlist, ",", &remainder)) != NULL) { 1840Sstevel@tonic-gate dirlist = NULL; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate DPRINT((dbfp, "binfile: p_dir = %s\n", dirname)); 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate (*count)++; 1890Sstevel@tonic-gate node = malloc(sizeof (dirlist_t)); 1900Sstevel@tonic-gate if (node == NULL) 1910Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate node->dl_flags = 0; 1940Sstevel@tonic-gate node->dl_filename = NULL; 1950Sstevel@tonic-gate node->dl_fd = -1; 1960Sstevel@tonic-gate node->dl_space = PLENTY_SPACE; 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate node->dl_dirname = malloc((unsigned)strlen(dirname) + 1); 1990Sstevel@tonic-gate if (node->dl_dirname == NULL) 2000Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate bs = dirname; 2030Sstevel@tonic-gate while ((*bs == ' ') || (*bs == '\t')) /* trim blanks */ 2040Sstevel@tonic-gate bs++; 2050Sstevel@tonic-gate be = bs + strlen(bs) - 1; 2060Sstevel@tonic-gate while (be > bs) { /* trim trailing blanks */ 2070Sstevel@tonic-gate if ((*bs != ' ') && (*bs != '\t')) 2080Sstevel@tonic-gate break; 2090Sstevel@tonic-gate be--; 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate *(be + 1) = '\0'; 2120Sstevel@tonic-gate (void) strlcpy(node->dl_dirname, bs, AUDIT_FNAME_SZ); 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate if (*listhead != NULL) 2150Sstevel@tonic-gate node->dl_next = *listhead; 2160Sstevel@tonic-gate else 2170Sstevel@tonic-gate node->dl_next = node; 2180Sstevel@tonic-gate *node_p = node; 2190Sstevel@tonic-gate node_p = &(node->dl_next); 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate return (0); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate /* 2260Sstevel@tonic-gate * create a linked list of directories available for writing 2270Sstevel@tonic-gate * 2280Sstevel@tonic-gate * if a list already exists, the two are compared and the new one is 2290Sstevel@tonic-gate * used only if it is different than the old. 2300Sstevel@tonic-gate * 2310Sstevel@tonic-gate * returns -2 for new or changed list, 0 for unchanged list and -1 for 2320Sstevel@tonic-gate * error. (Positive returns are for AUDITD_<error code> values) 2330Sstevel@tonic-gate * 2340Sstevel@tonic-gate */ 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate static int 2370Sstevel@tonic-gate loadauditlist(char *dirstr, char *minfreestr) 2380Sstevel@tonic-gate { 2390Sstevel@tonic-gate char buf[MAXPATHLEN]; 2400Sstevel@tonic-gate char *bs, *be; 2410Sstevel@tonic-gate dirlist_t *node, *n1, *n2; 2420Sstevel@tonic-gate dirlist_t **node_p; 2430Sstevel@tonic-gate dirlist_t *listhead = NULL; 2440Sstevel@tonic-gate dirlist_t *thisdir; 2450Sstevel@tonic-gate int acresult; 2460Sstevel@tonic-gate int node_count = 0; 2470Sstevel@tonic-gate int rc; 2480Sstevel@tonic-gate int temp_minfree; 2490Sstevel@tonic-gate au_acinfo_t *ach; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate static dirlist_t *activeList = NULL; /* directory list */ 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate DPRINT((dbfp, "binfile: Loading audit list from auditcontrol\n")); 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate /* 2560Sstevel@tonic-gate * Build new directory list 2570Sstevel@tonic-gate */ 2580Sstevel@tonic-gate /* part 1 -- using pre Sol 10 audit_control directives */ 2590Sstevel@tonic-gate node_p = &listhead; 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate ach = _openac(NULL); 2620Sstevel@tonic-gate if (ach == NULL) 2630Sstevel@tonic-gate return (-1); 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate /* at least one directory is needed */ 2660Sstevel@tonic-gate while ((acresult = _getacdir(ach, buf, sizeof (buf))) == 0 || 2675007Spaulson acresult == 2 || acresult == -3) { 2680Sstevel@tonic-gate /* 2690Sstevel@tonic-gate * loop if the result is 0 (success), 2 (a warning 27011700Sgww@eng.sun.com * that the audit_control file has been rewound), 2710Sstevel@tonic-gate * or -3 (a directory entry was found, but it 2720Sstevel@tonic-gate * was badly formatted. 2730Sstevel@tonic-gate */ 2740Sstevel@tonic-gate if (acresult == 0) { 2750Sstevel@tonic-gate /* 2760Sstevel@tonic-gate * A directory entry was found. 2770Sstevel@tonic-gate */ 2780Sstevel@tonic-gate node_count++; 2790Sstevel@tonic-gate node = malloc(sizeof (dirlist_t)); 2800Sstevel@tonic-gate if (node == NULL) 2810Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate node->dl_flags = 0; 2840Sstevel@tonic-gate node->dl_fd = -1; 2850Sstevel@tonic-gate node->dl_space = PLENTY_SPACE; 2860Sstevel@tonic-gate node->dl_filename = NULL; 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate node->dl_dirname = malloc((unsigned)strlen(buf) + 1); 2890Sstevel@tonic-gate if (node->dl_dirname == NULL) 2900Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate bs = buf; 2930Sstevel@tonic-gate while ((*bs == ' ') || (*bs == '\t')) 2940Sstevel@tonic-gate bs++; 2950Sstevel@tonic-gate be = bs + strlen(bs) - 1; 2960Sstevel@tonic-gate while (be > bs) { /* trim trailing blanks */ 2970Sstevel@tonic-gate if ((*bs != ' ') && (*bs != '\t')) 2980Sstevel@tonic-gate break; 2990Sstevel@tonic-gate be--; 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate *(be + 1) = '\0'; 3020Sstevel@tonic-gate (void) strlcpy(node->dl_dirname, bs, AUDIT_FNAME_SZ); 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate if (listhead != NULL) 3050Sstevel@tonic-gate node->dl_next = listhead; 3060Sstevel@tonic-gate else 3070Sstevel@tonic-gate node->dl_next = node; 3080Sstevel@tonic-gate *node_p = node; 3090Sstevel@tonic-gate node_p = &(node->dl_next); 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate } /* end of getacdir while */ 3120Sstevel@tonic-gate /* 3130Sstevel@tonic-gate * part 2 -- use directories and minfree from the (new as of Sol 10) 3140Sstevel@tonic-gate * plugin directive 3150Sstevel@tonic-gate */ 3160Sstevel@tonic-gate if (dirstr != NULL) { 3170Sstevel@tonic-gate if (node_count == 0) { 3180Sstevel@tonic-gate listhead = NULL; 3190Sstevel@tonic-gate node = NULL; 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate rc = growauditlist(&listhead, dirstr, node, &node_count); 3220Sstevel@tonic-gate if (rc) 3230Sstevel@tonic-gate return (rc); 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate if (node_count == 0) { 3260Sstevel@tonic-gate /* 3270Sstevel@tonic-gate * there was a problem getting the directory 3280Sstevel@tonic-gate * list or remote host info from the audit_control file 3290Sstevel@tonic-gate * even though auditd thought there was at least 1 good 3300Sstevel@tonic-gate * entry 3310Sstevel@tonic-gate */ 3320Sstevel@tonic-gate DPRINT((dbfp, "binfile: " 3330Sstevel@tonic-gate "problem getting directory / libpath list " 3340Sstevel@tonic-gate "from audit_control.\n")); 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate _endac(ach); 3370Sstevel@tonic-gate return (-1); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate #if DEBUG 3400Sstevel@tonic-gate /* print out directory list */ 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate if (listhead != NULL) { 3430Sstevel@tonic-gate fprintf(dbfp, "Directory list:\n\t%s\n", listhead->dl_dirname); 3440Sstevel@tonic-gate thisdir = listhead->dl_next; 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate while (thisdir != listhead) { 3470Sstevel@tonic-gate fprintf(dbfp, "\t%s\n", thisdir->dl_dirname); 3480Sstevel@tonic-gate thisdir = thisdir->dl_next; 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate #endif /* DEBUG */ 3520Sstevel@tonic-gate thisdir = listhead; 3530Sstevel@tonic-gate /* 3540Sstevel@tonic-gate * See if the list has changed. 3550Sstevel@tonic-gate * If there was a change rc = 0 if no change, else 1 3560Sstevel@tonic-gate */ 3570Sstevel@tonic-gate rc = 0; /* no change */ 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate if (node_count == activeCount) { 3600Sstevel@tonic-gate n1 = listhead; 3610Sstevel@tonic-gate n2 = activeList; 3620Sstevel@tonic-gate do { 3630Sstevel@tonic-gate if (strcmp(n1->dl_dirname, n2->dl_dirname) != 0) { 3640Sstevel@tonic-gate DPRINT((dbfp, 3650Sstevel@tonic-gate "binfile: new dirname = %s\n" 3660Sstevel@tonic-gate "binfile: old dirname = %s\n", 3670Sstevel@tonic-gate n1->dl_dirname, 3680Sstevel@tonic-gate n2->dl_dirname)); 3690Sstevel@tonic-gate rc = -2; 3700Sstevel@tonic-gate break; 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate n1 = n1->dl_next; 3730Sstevel@tonic-gate n2 = n2->dl_next; 3740Sstevel@tonic-gate } while ((n1 != listhead) && (n2 != activeList)); 3750Sstevel@tonic-gate } else { 3760Sstevel@tonic-gate DPRINT((dbfp, "binfile: old dir count = %d\n" 3770Sstevel@tonic-gate "binfile: new dir count = %d\n", 3780Sstevel@tonic-gate activeCount, node_count)); 3790Sstevel@tonic-gate rc = -2; 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate if (rc == -2) { 3820Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 3830Sstevel@tonic-gate DPRINT((dbfp, "loadauditlist: close / open log\n")); 3845007Spaulson if (open_log(listhead) == 0) { 3850Sstevel@tonic-gate openNewFile = 1; /* try again later */ 3865007Spaulson } else { 3875007Spaulson openNewFile = 0; 3885007Spaulson } 3890Sstevel@tonic-gate freedirlist(activeList); /* old list */ 3900Sstevel@tonic-gate activeList = listhead; /* new list */ 3915007Spaulson activeDir = startdir = thisdir; 3920Sstevel@tonic-gate activeCount = node_count; 3930Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 3940Sstevel@tonic-gate } else 3950Sstevel@tonic-gate freedirlist(listhead); 3960Sstevel@tonic-gate /* 3970Sstevel@tonic-gate * Get the minfree value. If minfree comes in via the attribute 3980Sstevel@tonic-gate * list, ignore the possibility it may also be listed on a separate 3990Sstevel@tonic-gate * audit_control line. 4000Sstevel@tonic-gate */ 4010Sstevel@tonic-gate if (minfreestr != NULL) 4020Sstevel@tonic-gate temp_minfree = atoi(minfreestr); 4030Sstevel@tonic-gate else if (!(_getacmin(ach, &temp_minfree) == 0)) 4040Sstevel@tonic-gate temp_minfree = 0; 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate if ((temp_minfree < 0) || (temp_minfree > 100)) 4070Sstevel@tonic-gate temp_minfree = 0; 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate if (minfree != temp_minfree) { 4100Sstevel@tonic-gate DPRINT((dbfp, "minfree: old = %d, new = %d\n", 4110Sstevel@tonic-gate minfree, temp_minfree)); 4120Sstevel@tonic-gate rc = -2; /* data change */ 4130Sstevel@tonic-gate minfree = temp_minfree; 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate _endac(ach); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate return (rc); 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /* 4220Sstevel@tonic-gate * getauditdate - get the current time (GMT) and put it in the form 4230Sstevel@tonic-gate * yyyymmddHHMMSS . 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate static void 4260Sstevel@tonic-gate getauditdate(char *date) 4270Sstevel@tonic-gate { 4280Sstevel@tonic-gate struct timeval tp; 4290Sstevel@tonic-gate struct timezone tzp; 4300Sstevel@tonic-gate struct tm tm; 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate (void) gettimeofday(&tp, &tzp); 4330Sstevel@tonic-gate tm = *gmtime(&tp.tv_sec); 4340Sstevel@tonic-gate /* 4350Sstevel@tonic-gate * NOTE: if we want to use gmtime, we have to be aware that the 4360Sstevel@tonic-gate * structure only keeps the year as an offset from TM_YEAR_BASE. 4370Sstevel@tonic-gate * I have used TM_YEAR_BASE in this code so that if they change 4380Sstevel@tonic-gate * this base from 1900 to 2000, it will hopefully mean that this 4390Sstevel@tonic-gate * code does not have to change. TM_YEAR_BASE is defined in 4400Sstevel@tonic-gate * tzfile.h . 4410Sstevel@tonic-gate */ 4420Sstevel@tonic-gate (void) sprintf(date, "%.4d%.2d%.2d%.2d%.2d%.2d", 4435007Spaulson tm.tm_year + TM_YEAR_BASE, tm.tm_mon + 1, tm.tm_mday, 4445007Spaulson tm.tm_hour, tm.tm_min, tm.tm_sec); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate /* 4500Sstevel@tonic-gate * write_file_token - put the file token into the audit log 4510Sstevel@tonic-gate */ 4520Sstevel@tonic-gate static int 4530Sstevel@tonic-gate write_file_token(int fd, char *name) 4540Sstevel@tonic-gate { 4550Sstevel@tonic-gate adr_t adr; /* xdr ptr */ 4560Sstevel@tonic-gate struct timeval tv; /* time now */ 4570Sstevel@tonic-gate char for_adr[AUDIT_FNAME_SZ + AUDIT_FNAME_SZ]; /* plenty of room */ 4580Sstevel@tonic-gate char token_id; 4590Sstevel@tonic-gate short i; 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate (void) gettimeofday(&tv, (struct timezone *)0); 4620Sstevel@tonic-gate i = strlen(name) + 1; 4630Sstevel@tonic-gate adr_start(&adr, for_adr); 4640Sstevel@tonic-gate #ifdef _LP64 4650Sstevel@tonic-gate token_id = AUT_OTHER_FILE64; 4660Sstevel@tonic-gate adr_char(&adr, &token_id, 1); 4670Sstevel@tonic-gate adr_int64(&adr, (int64_t *)& tv, 2); 4680Sstevel@tonic-gate #else 4690Sstevel@tonic-gate token_id = AUT_OTHER_FILE32; 4700Sstevel@tonic-gate adr_char(&adr, &token_id, 1); 4710Sstevel@tonic-gate adr_int32(&adr, (int32_t *)& tv, 2); 4720Sstevel@tonic-gate #endif 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate adr_short(&adr, &i, 1); 4750Sstevel@tonic-gate adr_char(&adr, name, i); 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate if (write(fd, for_adr, adr_count(&adr)) < 0) { 4780Sstevel@tonic-gate DPRINT((dbfp, "binfile: Bad write\n")); 4790Sstevel@tonic-gate return (errno); 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate return (0); 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate /* 4850Sstevel@tonic-gate * close_log - close the file if open. Also put the name of the 4860Sstevel@tonic-gate * new log file in the trailer, and rename the old file 4870Sstevel@tonic-gate * to oldname. The caller must hold log_mutext while calling 4880Sstevel@tonic-gate * close_log since any change to activeDir is a complete redo 4890Sstevel@tonic-gate * of all it points to. 4900Sstevel@tonic-gate * arguments - 4910Sstevel@tonic-gate * oldname - the new name for the file to be closed 4920Sstevel@tonic-gate * newname - the name of the new log file (for the trailer) 4930Sstevel@tonic-gate */ 4940Sstevel@tonic-gate static void 4950Sstevel@tonic-gate close_log(dirlist_t *currentdir, char *oname, char *newname) 4960Sstevel@tonic-gate { 4970Sstevel@tonic-gate char auditdate[AUDIT_DATE_SZ+1]; 4980Sstevel@tonic-gate char *name; 4990Sstevel@tonic-gate char oldname[AUDIT_FNAME_SZ+1]; 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate if ((currentdir == NULL) || (currentdir->dl_fd == -1)) 5020Sstevel@tonic-gate return; 5030Sstevel@tonic-gate /* 5040Sstevel@tonic-gate * If oldname is blank, we were called by auditd_plugin_close() 5050Sstevel@tonic-gate * instead of by open_log, so we need to update our name. 5060Sstevel@tonic-gate */ 5070Sstevel@tonic-gate (void) strlcpy(oldname, oname, AUDIT_FNAME_SZ); 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate if (strcmp(oldname, "") == 0) { 5100Sstevel@tonic-gate getauditdate(auditdate); 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate assert(currentdir->dl_filename != NULL); 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate (void) strlcpy(oldname, currentdir->dl_filename, 5150Sstevel@tonic-gate AUDIT_FNAME_SZ); 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate name = strrchr(oldname, '/') + 1; 5180Sstevel@tonic-gate (void) memcpy(name + AUDIT_DATE_SZ + 1, auditdate, 5190Sstevel@tonic-gate AUDIT_DATE_SZ); 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate /* 5220Sstevel@tonic-gate * Write the trailer record and rename and close the file. 5230Sstevel@tonic-gate * If any of the write, rename, or close fail, ignore it 5240Sstevel@tonic-gate * since there is not much else we can do and the next open() 5250Sstevel@tonic-gate * will trigger the necessary full directory logic. 5260Sstevel@tonic-gate * 5270Sstevel@tonic-gate * newname is "" if binfile is being closed down. 5280Sstevel@tonic-gate */ 5290Sstevel@tonic-gate (void) write_file_token(currentdir->dl_fd, newname); 5305319Stz204579 if (currentdir->dl_fd >= 0) { 5315319Stz204579 (void) fsync(currentdir->dl_fd); 5320Sstevel@tonic-gate (void) close(currentdir->dl_fd); 5335319Stz204579 } 5340Sstevel@tonic-gate currentdir->dl_fd = -1; 5350Sstevel@tonic-gate (void) rename(currentdir->dl_filename, oldname); 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate DPRINT((dbfp, "binfile: Log closed %s\n", oldname)); 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate free(currentdir->dl_filename); 5400Sstevel@tonic-gate currentdir->dl_filename = NULL; 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate /* 5450Sstevel@tonic-gate * open_log - open a new file in the current directory. If a 5460Sstevel@tonic-gate * file is already open, close it. 5470Sstevel@tonic-gate * 5480Sstevel@tonic-gate * return 1 if ok, 0 if all directories are full. 5490Sstevel@tonic-gate * 5500Sstevel@tonic-gate * lastOpenDir - used to get the oldfile name (and change it), 5510Sstevel@tonic-gate * to close the oldfile. 5520Sstevel@tonic-gate * 5530Sstevel@tonic-gate * The caller must hold log_mutex while calling open_log. 5540Sstevel@tonic-gate * 5550Sstevel@tonic-gate */ 5560Sstevel@tonic-gate static int 5570Sstevel@tonic-gate open_log(dirlist_t *current_dir) 5580Sstevel@tonic-gate { 5590Sstevel@tonic-gate char auditdate[AUDIT_DATE_SZ + 1]; 5600Sstevel@tonic-gate char oldname[AUDIT_FNAME_SZ + 1] = ""; 5610Sstevel@tonic-gate char newname[AUDIT_FNAME_SZ + 1]; 5620Sstevel@tonic-gate char *name; /* pointer into oldname */ 5630Sstevel@tonic-gate int opened; 5640Sstevel@tonic-gate int error = 0; 5650Sstevel@tonic-gate int newfd = 0; 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate static char host[MAXHOSTNAMELEN + 1] = ""; 5680Sstevel@tonic-gate /* previous directory with open log file */ 5690Sstevel@tonic-gate static dirlist_t *lastOpenDir = NULL; 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate if (host[0] == '\0') 5720Sstevel@tonic-gate (void) gethostname(host, MAXHOSTNAMELEN); 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate /* Get a filename which does not already exist */ 5750Sstevel@tonic-gate opened = 0; 5760Sstevel@tonic-gate while (!opened) { 5770Sstevel@tonic-gate getauditdate(auditdate); 5780Sstevel@tonic-gate (void) snprintf(newname, AUDIT_FNAME_SZ, 5790Sstevel@tonic-gate "%s/%s.not_terminated.%s", 5800Sstevel@tonic-gate current_dir->dl_dirname, auditdate, host); 5810Sstevel@tonic-gate newfd = open(newname, 582832Sme23304 O_RDWR | O_APPEND | O_CREAT | O_EXCL, 0640); 5830Sstevel@tonic-gate if (newfd < 0) { 5840Sstevel@tonic-gate switch (errno) { 5850Sstevel@tonic-gate case EEXIST: 5860Sstevel@tonic-gate DPRINT((dbfp, 5870Sstevel@tonic-gate "open_log says duplicate for %s " 5880Sstevel@tonic-gate "(will try another)\n", newname)); 5890Sstevel@tonic-gate (void) sleep(1); 5900Sstevel@tonic-gate break; 5910Sstevel@tonic-gate default: 5920Sstevel@tonic-gate /* open failed */ 5930Sstevel@tonic-gate DPRINT((dbfp, 5940Sstevel@tonic-gate "open_log says full for %s: %s\n", 5950Sstevel@tonic-gate newname, strerror(errno))); 5960Sstevel@tonic-gate current_dir->dl_space = SPACE_FULL; 5970Sstevel@tonic-gate current_dir = current_dir->dl_next; 5980Sstevel@tonic-gate return (0); 5990Sstevel@tonic-gate } /* switch */ 6000Sstevel@tonic-gate } else 6010Sstevel@tonic-gate opened = 1; 6020Sstevel@tonic-gate } /* while */ 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate /* 6050Sstevel@tonic-gate * When we get here, we have opened our new log file. 6060Sstevel@tonic-gate * Now we need to update the name of the old file to 6070Sstevel@tonic-gate * store in this file's header. lastOpenDir may point 6080Sstevel@tonic-gate * to current_dir if the list is only one entry long and 6090Sstevel@tonic-gate * there is only one list. 6100Sstevel@tonic-gate */ 6110Sstevel@tonic-gate if ((lastOpenDir != NULL) && (lastOpenDir->dl_filename != NULL)) { 6120Sstevel@tonic-gate (void) strlcpy(oldname, lastOpenDir->dl_filename, 6130Sstevel@tonic-gate AUDIT_FNAME_SZ); 6140Sstevel@tonic-gate name = (char *)strrchr(oldname, '/') + 1; 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate (void) memcpy(name + AUDIT_DATE_SZ + 1, auditdate, 6175007Spaulson AUDIT_DATE_SZ); 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate close_log(lastOpenDir, oldname, newname); 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate error = write_file_token(newfd, oldname); 6220Sstevel@tonic-gate if (error) { 6230Sstevel@tonic-gate /* write token failed */ 6240Sstevel@tonic-gate (void) close(newfd); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate current_dir->dl_space = SPACE_FULL; 6270Sstevel@tonic-gate current_dir->dl_fd = -1; 6280Sstevel@tonic-gate free(current_dir->dl_filename); 6290Sstevel@tonic-gate current_dir->dl_filename = NULL; 6300Sstevel@tonic-gate current_dir = current_dir->dl_next; 6310Sstevel@tonic-gate return (0); 6320Sstevel@tonic-gate } else { 6330Sstevel@tonic-gate lastOpenDir = current_dir; 6340Sstevel@tonic-gate current_dir->dl_fd = newfd; 6350Sstevel@tonic-gate current_dir->dl_filename = strdup(newname); 6360Sstevel@tonic-gate 6376697Spr131582 /* 6386697Spr131582 * New file opened, so reset file size statistic (used 6396697Spr131582 * to ensure audit log does not grow above size limit 6406697Spr131582 * set by p_fsize). 6416697Spr131582 */ 6426697Spr131582 binfile_cursize = 0; 6436697Spr131582 64411411SSurya.Prakki@Sun.COM (void) __logpost(newname); 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate DPRINT((dbfp, "binfile: Log opened: %s\n", newname)); 6470Sstevel@tonic-gate return (1); 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate #define IGNORE_SIZE 8192 6520Sstevel@tonic-gate /* 6530Sstevel@tonic-gate * spacecheck - determine whether the given directory's filesystem 6540Sstevel@tonic-gate * has the at least the space requested. Also set the space 6550Sstevel@tonic-gate * value in the directory list structure. If the caller 6560Sstevel@tonic-gate * passes other than PLENTY_SPACE or SOFT_SPACE, the caller should 6570Sstevel@tonic-gate * ignore the return value. Otherwise, 0 = less than the 6580Sstevel@tonic-gate * requested space is available, 1 = at least the requested space 6590Sstevel@tonic-gate * is available. 6600Sstevel@tonic-gate * 6610Sstevel@tonic-gate * log_mutex must be held by the caller 6620Sstevel@tonic-gate * 6630Sstevel@tonic-gate * -1 is returned if stat fails 6640Sstevel@tonic-gate * 6650Sstevel@tonic-gate * IGNORE_SIZE is one page (Sol 9 / 10 timeframe) and is the default 6660Sstevel@tonic-gate * buffer size written for Sol 9 and earlier. To keep the same accuracy 6670Sstevel@tonic-gate * for the soft limit check as before, spacecheck checks for space 6680Sstevel@tonic-gate * remaining IGNORE_SIZE bytes. This reduces the number of statvfs() 6690Sstevel@tonic-gate * calls and related math. 6700Sstevel@tonic-gate * 6710Sstevel@tonic-gate * globals - 6720Sstevel@tonic-gate * minfree - the soft limit, i.e., the % of filesystem to reserve 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate static int 6750Sstevel@tonic-gate spacecheck(dirlist_t *thisdir, int test_limit, size_t next_buf_size) 6760Sstevel@tonic-gate { 6770Sstevel@tonic-gate struct statvfs sb; 6780Sstevel@tonic-gate static int ignore_size = 0; 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate ignore_size += next_buf_size; 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate if ((test_limit == PLENTY_SPACE) && (ignore_size < IGNORE_SIZE)) 6830Sstevel@tonic-gate return (1); 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate assert(thisdir != NULL); 6860Sstevel@tonic-gate 6875007Spaulson if (statvfs(thisdir->dl_dirname, &sb) < 0) { 6880Sstevel@tonic-gate thisdir->dl_space = SPACE_FULL; 6890Sstevel@tonic-gate minfreeblocks = AVAIL_MIN; 6900Sstevel@tonic-gate return (-1); 6910Sstevel@tonic-gate } else { 6920Sstevel@tonic-gate minfreeblocks = ((minfree * sb.f_blocks) / 100) + AVAIL_MIN; 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate if (sb.f_bavail < AVAIL_MIN) 6950Sstevel@tonic-gate thisdir->dl_space = SPACE_FULL; 6965007Spaulson else if (sb.f_bavail > minfreeblocks) { 6975007Spaulson thisdir->dl_space = fullness_state = PLENTY_SPACE; 6985007Spaulson ignore_size = 0; 6995007Spaulson } else 7000Sstevel@tonic-gate thisdir->dl_space = SOFT_SPACE; 7010Sstevel@tonic-gate } 7020Sstevel@tonic-gate if (thisdir->dl_space == PLENTY_SPACE) 7030Sstevel@tonic-gate return (1); 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate return (thisdir->dl_space == test_limit); 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate /* 7096697Spr131582 * Parses p_fsize value and contains it within the range FSIZE_MIN and 7106697Spr131582 * INT_MAX so using uints won't cause an undetected overflow of 7116697Spr131582 * INT_MAX. Defaults to 0 if the value is invalid or is missing. 7126697Spr131582 */ 7136697Spr131582 static void 7146697Spr131582 save_maxsize(char *maxsize) { 7156697Spr131582 /* 7166697Spr131582 * strtol() returns a long which could be larger than int so 7176697Spr131582 * store here for sanity checking first 7186697Spr131582 */ 7196697Spr131582 long proposed_maxsize; 7206697Spr131582 7216697Spr131582 if (maxsize != NULL) { 7226697Spr131582 /* 7236697Spr131582 * There is no explicit error return from strtol() so 7246697Spr131582 * we may need to depend on the value of errno. 7256697Spr131582 */ 7266697Spr131582 errno = 0; 7276697Spr131582 proposed_maxsize = strtol(maxsize, (char **)NULL, 10); 7286697Spr131582 7296697Spr131582 /* 7306697Spr131582 * If sizeof(long) is greater than sizeof(int) on this 7316697Spr131582 * platform, proposed_maxsize might be greater than 7326697Spr131582 * INT_MAX without it being reported as ERANGE. 7336697Spr131582 */ 7346697Spr131582 if ((errno == ERANGE) || 7356697Spr131582 ((proposed_maxsize != 0) && 7366697Spr131582 (proposed_maxsize < FSIZE_MIN)) || 7376697Spr131582 (proposed_maxsize > INT_MAX)) { 7386697Spr131582 binfile_maxsize = 0; 7396697Spr131582 DPRINT((dbfp, "binfile: p_fsize parameter out of " 7406697Spr131582 "range: %s\n", maxsize)); 7416697Spr131582 /* 7426697Spr131582 * Inform administrator of the error via 7436697Spr131582 * syslog 7446697Spr131582 */ 7456697Spr131582 __audit_syslog("audit_binfile.so", 7466697Spr131582 LOG_CONS | LOG_NDELAY, 7476697Spr131582 LOG_DAEMON, LOG_ERR, 7486697Spr131582 gettext("p_fsize parameter out of range\n")); 7496697Spr131582 } else { 7506697Spr131582 binfile_maxsize = proposed_maxsize; 7516697Spr131582 } 7526697Spr131582 } else { /* p_fsize string was not present */ 7536697Spr131582 binfile_maxsize = 0; 7546697Spr131582 } 7556697Spr131582 7566697Spr131582 DPRINT((dbfp, "binfile: set maxsize to %d\n", binfile_maxsize)); 7576697Spr131582 } 7586697Spr131582 7596697Spr131582 /* 7605007Spaulson * auditd_plugin() writes a buffer to the currently open file. The 7616697Spr131582 * global "openNewFile" is used to force a new log file for cases such 7626697Spr131582 * as the initial open, when minfree is reached, the p_fsize value is 7636697Spr131582 * exceeded or the current file system fills up, and "audit -s" with 7646697Spr131582 * changed parameters. For "audit -n" a new log file is opened 7656697Spr131582 * immediately in auditd_plugin_open(). 7660Sstevel@tonic-gate * 7670Sstevel@tonic-gate * This function manages one or more audit directories as follows: 7680Sstevel@tonic-gate * 7690Sstevel@tonic-gate * If the current open file is in a directory that has not 7700Sstevel@tonic-gate * reached the soft limit, write the input data and return. 7710Sstevel@tonic-gate * 7720Sstevel@tonic-gate * Scan the list of directories for one which has not reached 7730Sstevel@tonic-gate * the soft limit; if one is found, write and return. Such 7740Sstevel@tonic-gate * a writable directory is in "PLENTY_SPACE" state. 7750Sstevel@tonic-gate * 7760Sstevel@tonic-gate * Scan the list of directories for one which has not reached 7770Sstevel@tonic-gate * the hard limit; if one is found, write and return. This 7780Sstevel@tonic-gate * directory in in "SOFT_SPACE" state. 7790Sstevel@tonic-gate * 7800Sstevel@tonic-gate * Oh, and if a write fails, handle it like a hard space limit. 7810Sstevel@tonic-gate * 7820Sstevel@tonic-gate * audit_warn (via __audit_dowarn()) is used to alert an operator 7830Sstevel@tonic-gate * at various levels of fullness. 7840Sstevel@tonic-gate */ 7850Sstevel@tonic-gate /* ARGSUSED */ 7860Sstevel@tonic-gate auditd_rc_t 787*11704SJan.Friedel@Sun.COM auditd_plugin(const char *input, size_t in_len, uint64_t sequence, char **error) 7880Sstevel@tonic-gate { 7890Sstevel@tonic-gate auditd_rc_t rc = AUDITD_FAIL; 7900Sstevel@tonic-gate int open_status; 7910Sstevel@tonic-gate size_t out_len; 7920Sstevel@tonic-gate /* LINTED */ 7930Sstevel@tonic-gate int statrc; 7940Sstevel@tonic-gate /* avoid excess audit_warnage */ 7950Sstevel@tonic-gate static int allsoftfull_warning = 0; 7965007Spaulson static int allhard_pause = 0; 7975007Spaulson static struct timeval next_allhard; 7985007Spaulson struct timeval now; 7990Sstevel@tonic-gate #if DEBUG 8000Sstevel@tonic-gate static char *last_file_written_to = NULL; 801*11704SJan.Friedel@Sun.COM static uint64_t last_sequence = 0; 802*11704SJan.Friedel@Sun.COM static uint64_t write_count = 0; 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate if ((last_sequence > 0) && (sequence != last_sequence + 1)) 805*11704SJan.Friedel@Sun.COM fprintf(dbfp, "binfile: buffer sequence=%llu but prev=%llu=n", 8065007Spaulson sequence, last_sequence); 8070Sstevel@tonic-gate last_sequence = sequence; 8080Sstevel@tonic-gate 809*11704SJan.Friedel@Sun.COM fprintf(dbfp, "binfile: input seq=%llu, len=%d\n", sequence, in_len); 8100Sstevel@tonic-gate #endif 8110Sstevel@tonic-gate *error = NULL; 8120Sstevel@tonic-gate /* 8130Sstevel@tonic-gate * lock is for activeDir, referenced by open_log() and close_log() 8140Sstevel@tonic-gate */ 8150Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 8166697Spr131582 8176697Spr131582 /* 8186697Spr131582 * If this would take us over the maximum size, open a new 8196697Spr131582 * file, unless maxsize is 0, in which case growth of the 8206697Spr131582 * audit log is unrestricted. 8216697Spr131582 */ 8226697Spr131582 if ((binfile_maxsize != 0) && 8236697Spr131582 ((binfile_cursize + in_len) > binfile_maxsize)) { 8246697Spr131582 DPRINT((dbfp, "binfile: maxsize exceeded, opening new audit " 8256697Spr131582 "file.\n")); 8266697Spr131582 openNewFile = 1; 8276697Spr131582 } 8286697Spr131582 8290Sstevel@tonic-gate while (rc == AUDITD_FAIL) { 8300Sstevel@tonic-gate open_status = 1; 8310Sstevel@tonic-gate if (openNewFile) { 8320Sstevel@tonic-gate open_status = open_log(activeDir); 8330Sstevel@tonic-gate if (open_status == 1) /* ok */ 8340Sstevel@tonic-gate openNewFile = 0; 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate /* 8370Sstevel@tonic-gate * consider "space ok" return and error return the same; 8380Sstevel@tonic-gate * a -1 means spacecheck couldn't check for space. 8390Sstevel@tonic-gate */ 8400Sstevel@tonic-gate if ((open_status == 1) && 8410Sstevel@tonic-gate (statrc = spacecheck(activeDir, fullness_state, 8420Sstevel@tonic-gate in_len)) != 0) { 8430Sstevel@tonic-gate #if DEBUG 8440Sstevel@tonic-gate DPRINT((dbfp, "binfile: returned from spacecheck\n")); 8450Sstevel@tonic-gate /* 8460Sstevel@tonic-gate * The last copy of last_file_written_to is 8470Sstevel@tonic-gate * never free'd, so there will be one open 8480Sstevel@tonic-gate * memory reference on exit. It's debug only. 8490Sstevel@tonic-gate */ 8500Sstevel@tonic-gate if ((last_file_written_to != NULL) && 8510Sstevel@tonic-gate (strcmp(last_file_written_to, 8520Sstevel@tonic-gate activeDir->dl_filename) != 0)) { 8530Sstevel@tonic-gate DPRINT((dbfp, "binfile: now writing to %s\n", 8540Sstevel@tonic-gate activeDir->dl_filename)); 8550Sstevel@tonic-gate free(last_file_written_to); 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate DPRINT((dbfp, "binfile: finished some debug stuff\n")); 8580Sstevel@tonic-gate last_file_written_to = 8590Sstevel@tonic-gate strdup(activeDir->dl_filename); 8600Sstevel@tonic-gate #endif 8610Sstevel@tonic-gate out_len = write(activeDir->dl_fd, input, in_len); 8620Sstevel@tonic-gate DPRINT((dbfp, "binfile: finished the write\n")); 8630Sstevel@tonic-gate 8646697Spr131582 binfile_cursize += out_len; 8656697Spr131582 8660Sstevel@tonic-gate if (out_len == in_len) { 8670Sstevel@tonic-gate DPRINT((dbfp, 868*11704SJan.Friedel@Sun.COM "binfile: write_count=%llu, sequence=%llu," 8690Sstevel@tonic-gate " l=%u\n", 8700Sstevel@tonic-gate ++write_count, sequence, out_len)); 8710Sstevel@tonic-gate allsoftfull_warning = 0; 8725007Spaulson activeDir->dl_flags = 0; 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate rc = AUDITD_SUCCESS; 8750Sstevel@tonic-gate break; 8765007Spaulson } else if (!(activeDir->dl_flags & HARD_WARNED)) { 8770Sstevel@tonic-gate DPRINT((dbfp, 878*11704SJan.Friedel@Sun.COM "binfile: write failed, sequence=%llu, " 8790Sstevel@tonic-gate "l=%u\n", sequence, out_len)); 8800Sstevel@tonic-gate DPRINT((dbfp, "hard warning sent.\n")); 8810Sstevel@tonic-gate __audit_dowarn("hard", activeDir->dl_dirname, 8820Sstevel@tonic-gate 0); 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate activeDir->dl_flags |= HARD_WARNED; 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate } else { 8870Sstevel@tonic-gate DPRINT((dbfp, "binfile: statrc=%d, fullness_state=%d\n", 8880Sstevel@tonic-gate statrc, fullness_state)); 8895007Spaulson if (!(activeDir->dl_flags & SOFT_WARNED) && 8905007Spaulson (activeDir->dl_space == SOFT_SPACE)) { 8910Sstevel@tonic-gate DPRINT((dbfp, "soft warning sent\n")); 8920Sstevel@tonic-gate __audit_dowarn("soft", 8930Sstevel@tonic-gate activeDir->dl_dirname, 0); 8940Sstevel@tonic-gate activeDir->dl_flags |= SOFT_WARNED; 8950Sstevel@tonic-gate } 8965007Spaulson if (!(activeDir->dl_flags & HARD_WARNED) && 8975007Spaulson (activeDir->dl_space == SPACE_FULL)) { 8980Sstevel@tonic-gate DPRINT((dbfp, "hard warning sent.\n")); 8990Sstevel@tonic-gate __audit_dowarn("hard", 9005007Spaulson activeDir->dl_dirname, 0); 9010Sstevel@tonic-gate activeDir->dl_flags |= HARD_WARNED; 9020Sstevel@tonic-gate } 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate DPRINT((dbfp, "binfile: activeDir=%s, next=%s\n", 9050Sstevel@tonic-gate activeDir->dl_dirname, activeDir->dl_next->dl_dirname)); 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate activeDir = activeDir->dl_next; 9085007Spaulson openNewFile = 1; 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate if (activeDir == startdir) { /* full circle */ 9110Sstevel@tonic-gate if (fullness_state == PLENTY_SPACE) { /* once */ 9120Sstevel@tonic-gate fullness_state = SOFT_SPACE; 9130Sstevel@tonic-gate if (allsoftfull_warning == 0) { 9140Sstevel@tonic-gate allsoftfull_warning++; 9150Sstevel@tonic-gate __audit_dowarn("allsoft", "", 0); 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate } else { /* full circle twice */ 9185007Spaulson if ((hung_count > 0) && !allhard_pause) { 9195007Spaulson allhard_pause = 1; 9205007Spaulson (void) gettimeofday(&next_allhard, 9215007Spaulson NULL); 9225007Spaulson next_allhard.tv_sec += ALLHARD_DELAY; 9235007Spaulson } 9245007Spaulson 9255007Spaulson if (allhard_pause) { 9265007Spaulson (void) gettimeofday(&now, NULL); 9275007Spaulson if (now.tv_sec >= next_allhard.tv_sec) { 9285007Spaulson allhard_pause = 0; 9295007Spaulson __audit_dowarn("allhard", "", 9305007Spaulson ++hung_count); 9315007Spaulson } 9325007Spaulson } else { 9335007Spaulson __audit_dowarn("allhard", "", 9345007Spaulson ++hung_count); 9355007Spaulson } 9360Sstevel@tonic-gate minfreeblocks = AVAIL_MIN; 9370Sstevel@tonic-gate rc = AUDITD_RETRY; 9380Sstevel@tonic-gate *error = strdup(gettext( 9390Sstevel@tonic-gate "all partitions full\n")); 94011411SSurya.Prakki@Sun.COM (void) __logpost(""); 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate } 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate return (rc); 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate /* 9510Sstevel@tonic-gate * the open function uses getacdir() and getacmin to determine which 9520Sstevel@tonic-gate * directories to use and when to switch. It takes no inputs. 9530Sstevel@tonic-gate * 9540Sstevel@tonic-gate * It may be called multiple times as auditd handles SIGHUP and SIGUSR1 9550Sstevel@tonic-gate * corresponding to the audit(1M) flags -s and -n 9560Sstevel@tonic-gate * 9570Sstevel@tonic-gate * kvlist is NULL only if auditd caught a SIGUSR1, so after the first 9580Sstevel@tonic-gate * time open is called, the reason is -s if kvlist != NULL and -n 9590Sstevel@tonic-gate * otherwise. 9600Sstevel@tonic-gate * 9610Sstevel@tonic-gate */ 9620Sstevel@tonic-gate 9630Sstevel@tonic-gate auditd_rc_t 9640Sstevel@tonic-gate auditd_plugin_open(const kva_t *kvlist, char **ret_list, char **error) 9650Sstevel@tonic-gate { 9660Sstevel@tonic-gate int rc = 0; 9670Sstevel@tonic-gate int status; 9680Sstevel@tonic-gate int reason; 9690Sstevel@tonic-gate char *dirlist; 9700Sstevel@tonic-gate char *minfree; 9716697Spr131582 char *maxsize; 9720Sstevel@tonic-gate kva_t *kv; 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate *error = NULL; 9750Sstevel@tonic-gate *ret_list = NULL; 9760Sstevel@tonic-gate kv = (kva_t *)kvlist; 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate if (am_open) { 9790Sstevel@tonic-gate if (kvlist == NULL) 9800Sstevel@tonic-gate reason = 1; /* audit -n */ 9810Sstevel@tonic-gate else 9820Sstevel@tonic-gate reason = 2; /* audit -s */ 9830Sstevel@tonic-gate } else { 9840Sstevel@tonic-gate reason = 0; /* initial open */ 9850Sstevel@tonic-gate #if DEBUG 9860Sstevel@tonic-gate dbfp = __auditd_debug_file_open(); 9870Sstevel@tonic-gate #endif 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate DPRINT((dbfp, "binfile: am_open=%d, reason=%d\n", am_open, reason)); 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate am_open = 1; 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate if (kvlist == NULL) { 9940Sstevel@tonic-gate dirlist = NULL; 9950Sstevel@tonic-gate minfree = NULL; 9966697Spr131582 maxsize = NULL; 9970Sstevel@tonic-gate } else { 9980Sstevel@tonic-gate dirlist = kva_match(kv, "p_dir"); 9990Sstevel@tonic-gate minfree = kva_match(kv, "p_minfree"); 10006697Spr131582 maxsize = kva_match(kv, "p_fsize"); 10010Sstevel@tonic-gate } 10020Sstevel@tonic-gate switch (reason) { 10030Sstevel@tonic-gate case 0: /* initial open */ 10040Sstevel@tonic-gate if (!binfile_is_open) 10050Sstevel@tonic-gate (void) pthread_mutex_init(&log_mutex, NULL); 10060Sstevel@tonic-gate binfile_is_open = 1; 10070Sstevel@tonic-gate openNewFile = 1; 10080Sstevel@tonic-gate /* FALLTHRU */ 10090Sstevel@tonic-gate case 2: /* audit -s */ 10106697Spr131582 /* handle p_fsize parameter */ 10116697Spr131582 save_maxsize(maxsize); 10126697Spr131582 10130Sstevel@tonic-gate fullness_state = PLENTY_SPACE; 10140Sstevel@tonic-gate status = loadauditlist(dirlist, minfree); 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate if (status == -1) { 101711411SSurya.Prakki@Sun.COM (void) __logpost(""); 10180Sstevel@tonic-gate *error = strdup(gettext("no directories configured")); 10190Sstevel@tonic-gate return (AUDITD_RETRY); 10200Sstevel@tonic-gate } else if (status == AUDITD_NO_MEMORY) { 102111411SSurya.Prakki@Sun.COM (void) __logpost(""); 10220Sstevel@tonic-gate *error = strdup(gettext("no memory")); 10230Sstevel@tonic-gate return (status); 10240Sstevel@tonic-gate } else { /* status is 0 or -2 (no change or changed) */ 10250Sstevel@tonic-gate hung_count = 0; 10260Sstevel@tonic-gate DPRINT((dbfp, "binfile: loadauditlist returned %d\n", 10275007Spaulson status)); 10280Sstevel@tonic-gate } 10290Sstevel@tonic-gate break; 10300Sstevel@tonic-gate case 1: /* audit -n */ 10310Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 10320Sstevel@tonic-gate if (open_log(activeDir) == 1) /* ok */ 10330Sstevel@tonic-gate openNewFile = 0; 10340Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 10350Sstevel@tonic-gate break; 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate rc = AUDITD_SUCCESS; 10390Sstevel@tonic-gate *ret_list = NULL; 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate return (rc); 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate auditd_rc_t 10450Sstevel@tonic-gate auditd_plugin_close(char **error) 10460Sstevel@tonic-gate { 10470Sstevel@tonic-gate *error = NULL; 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 10500Sstevel@tonic-gate close_log(activeDir, "", ""); 10510Sstevel@tonic-gate freedirlist(activeDir); 10520Sstevel@tonic-gate activeDir = NULL; 10530Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate DPRINT((dbfp, "binfile: closed\n")); 10560Sstevel@tonic-gate 105711700Sgww@eng.sun.com (void) __logpost(""); 105811700Sgww@eng.sun.com 10590Sstevel@tonic-gate if (binfile_is_open) { 10600Sstevel@tonic-gate (void) pthread_mutex_destroy(&log_mutex); 10610Sstevel@tonic-gate binfile_is_open = 0; 10620Sstevel@tonic-gate /* LINTED */ 10630Sstevel@tonic-gate } else { 10640Sstevel@tonic-gate DPRINT((dbfp, 10650Sstevel@tonic-gate "auditd_plugin_close() called when already closed.")); 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate am_open = 0; 10680Sstevel@tonic-gate return (AUDITD_SUCCESS); 10690Sstevel@tonic-gate } 1070