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 5*5007Spaulson * Common Development and Distribution License (the "License"). 6*5007Spaulson * 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 /* 22*5007Spaulson * Copyright 2007 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 #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #define DEBUG 0 300Sstevel@tonic-gate 310Sstevel@tonic-gate #if DEBUG 320Sstevel@tonic-gate #define DPRINT(x) {fprintf x; } 330Sstevel@tonic-gate #else 340Sstevel@tonic-gate #define DPRINT(x) 350Sstevel@tonic-gate #endif 360Sstevel@tonic-gate 370Sstevel@tonic-gate /* 380Sstevel@tonic-gate * auditd_plugin_open(), auditd_plugin() and auditd_plugin_close() 390Sstevel@tonic-gate * implement a replacable library for use by auditd; they are a 400Sstevel@tonic-gate * project private interface and may change without notice. 410Sstevel@tonic-gate * 420Sstevel@tonic-gate */ 430Sstevel@tonic-gate 440Sstevel@tonic-gate #include <assert.h> 450Sstevel@tonic-gate #include <bsm/audit.h> 460Sstevel@tonic-gate #include <bsm/audit_record.h> 470Sstevel@tonic-gate #include <bsm/libbsm.h> 480Sstevel@tonic-gate #include <errno.h> 490Sstevel@tonic-gate #include <fcntl.h> 500Sstevel@tonic-gate #include <libintl.h> 510Sstevel@tonic-gate #include <netdb.h> 520Sstevel@tonic-gate #include <pthread.h> 530Sstevel@tonic-gate #include <secdb.h> 540Sstevel@tonic-gate #include <signal.h> 550Sstevel@tonic-gate #include <stdio.h> 560Sstevel@tonic-gate #include <stdlib.h> 570Sstevel@tonic-gate #include <string.h> 580Sstevel@tonic-gate #include <sys/param.h> 590Sstevel@tonic-gate #include <sys/types.h> 600Sstevel@tonic-gate #include <time.h> 610Sstevel@tonic-gate #include <tzfile.h> 620Sstevel@tonic-gate #include <unistd.h> 630Sstevel@tonic-gate #include <sys/vfs.h> 640Sstevel@tonic-gate #include <security/auditd.h> 650Sstevel@tonic-gate #include <audit_plugin.h> 660Sstevel@tonic-gate 670Sstevel@tonic-gate #define AUDIT_DATE_SZ 14 680Sstevel@tonic-gate #define AUDIT_FNAME_SZ 2 * AUDIT_DATE_SZ + 2 + MAXHOSTNAMELEN 690Sstevel@tonic-gate #define AUDIT_BAK_SZ 50 /* size of name of audit_data back-up file */ 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 80*5007Spaulson #define ALLHARD_DELAY 20 /* Call audit_warn(allhard) every 20 seconds */ 81*5007Spaulson 820Sstevel@tonic-gate 830Sstevel@tonic-gate /* 840Sstevel@tonic-gate * The directory list is a circular linked list. It is pointed into by 850Sstevel@tonic-gate * activeDir. Each element contains the pointer to the next 860Sstevel@tonic-gate * element, the directory pathname, a flag for how much space there is 870Sstevel@tonic-gate * in the directory's filesystem, and a file handle. Since a new 880Sstevel@tonic-gate * directory list can be created from auditd_plugin_open() while the 890Sstevel@tonic-gate * current list is in use, activeDir is protected by log_mutex. 900Sstevel@tonic-gate */ 910Sstevel@tonic-gate typedef struct dirlist_s dirlist_t; 920Sstevel@tonic-gate struct dirlist_s { 930Sstevel@tonic-gate dirlist_t *dl_next; 940Sstevel@tonic-gate int dl_space; 950Sstevel@tonic-gate int dl_flags; 960Sstevel@tonic-gate char *dl_dirname; 970Sstevel@tonic-gate char *dl_filename; /* file name (not path) if open */ 980Sstevel@tonic-gate int dl_fd; /* file handle, -1 unless open */ 990Sstevel@tonic-gate }; 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * Defines for dl_flags 1020Sstevel@tonic-gate */ 1030Sstevel@tonic-gate #define SOFT_WARNED 0x0001 /* already did soft warning for this dir */ 1040Sstevel@tonic-gate #define HARD_WARNED 0x0002 /* already did hard warning for this dir */ 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate #if DEBUG 1070Sstevel@tonic-gate static FILE *dbfp; /* debug file */ 1080Sstevel@tonic-gate #endif 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate static pthread_mutex_t log_mutex; 1110Sstevel@tonic-gate static int binfile_is_open = 0; 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate static int minfree = -1; 1140Sstevel@tonic-gate static int minfreeblocks; /* minfree in blocks */ 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate static dirlist_t *activeDir = NULL; /* current directory */ 117*5007Spaulson static dirlist_t *startdir; /* first dir in the ring */ 1180Sstevel@tonic-gate static int activeCount = 0; /* number of dirs in the ring */ 1190Sstevel@tonic-gate 120*5007Spaulson static int openNewFile = 0; /* need to open a new file */ 1210Sstevel@tonic-gate static int hung_count = 0; /* count of audit_warn hard */ 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate /* flag from audit_plugin_open to audit_plugin_close */ 1240Sstevel@tonic-gate static int am_open = 0; 1250Sstevel@tonic-gate /* preferred dir state */ 1260Sstevel@tonic-gate static int fullness_state = PLENTY_SPACE; 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate static int open_log(dirlist_t *); 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate static void 1310Sstevel@tonic-gate freedirlist(dirlist_t *head) 1320Sstevel@tonic-gate { 1330Sstevel@tonic-gate dirlist_t *n1, *n2; 1340Sstevel@tonic-gate /* 1350Sstevel@tonic-gate * Free up the old directory list if any 1360Sstevel@tonic-gate */ 1370Sstevel@tonic-gate if (head != NULL) { 1380Sstevel@tonic-gate n1 = head; 1390Sstevel@tonic-gate do { 1400Sstevel@tonic-gate n2 = n1->dl_next; 1410Sstevel@tonic-gate free(n1->dl_dirname); 1420Sstevel@tonic-gate free(n1->dl_filename); 1430Sstevel@tonic-gate free(n1); 1440Sstevel@tonic-gate n1 = n2; 1450Sstevel@tonic-gate } while (n1 != head); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate /* 1510Sstevel@tonic-gate * add to a linked list of directories available for writing 1520Sstevel@tonic-gate * 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate static int 1560Sstevel@tonic-gate growauditlist(dirlist_t **listhead, char *dirlist, 1570Sstevel@tonic-gate dirlist_t *endnode, int *count) 1580Sstevel@tonic-gate { 1590Sstevel@tonic-gate dirlist_t *node; 1600Sstevel@tonic-gate char *bs, *be; 1610Sstevel@tonic-gate dirlist_t **node_p; 1620Sstevel@tonic-gate char *dirname; 1630Sstevel@tonic-gate char *remainder; 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate DPRINT((dbfp, "binfile: dirlist=%s\n", dirlist)); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate if (*listhead == NULL) 1680Sstevel@tonic-gate node_p = listhead; 1690Sstevel@tonic-gate else 1700Sstevel@tonic-gate node_p = &(endnode->dl_next); 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate node = NULL; 1730Sstevel@tonic-gate while ((dirname = strtok_r(dirlist, ",", &remainder)) != NULL) { 1740Sstevel@tonic-gate dirlist = NULL; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate DPRINT((dbfp, "binfile: p_dir = %s\n", dirname)); 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate (*count)++; 1790Sstevel@tonic-gate node = malloc(sizeof (dirlist_t)); 1800Sstevel@tonic-gate if (node == NULL) 1810Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate node->dl_flags = 0; 1840Sstevel@tonic-gate node->dl_filename = NULL; 1850Sstevel@tonic-gate node->dl_fd = -1; 1860Sstevel@tonic-gate node->dl_space = PLENTY_SPACE; 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate node->dl_dirname = malloc((unsigned)strlen(dirname) + 1); 1890Sstevel@tonic-gate if (node->dl_dirname == NULL) 1900Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate bs = dirname; 1930Sstevel@tonic-gate while ((*bs == ' ') || (*bs == '\t')) /* trim blanks */ 1940Sstevel@tonic-gate bs++; 1950Sstevel@tonic-gate be = bs + strlen(bs) - 1; 1960Sstevel@tonic-gate while (be > bs) { /* trim trailing blanks */ 1970Sstevel@tonic-gate if ((*bs != ' ') && (*bs != '\t')) 1980Sstevel@tonic-gate break; 1990Sstevel@tonic-gate be--; 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate *(be + 1) = '\0'; 2020Sstevel@tonic-gate (void) strlcpy(node->dl_dirname, bs, AUDIT_FNAME_SZ); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate if (*listhead != NULL) 2050Sstevel@tonic-gate node->dl_next = *listhead; 2060Sstevel@tonic-gate else 2070Sstevel@tonic-gate node->dl_next = node; 2080Sstevel@tonic-gate *node_p = node; 2090Sstevel@tonic-gate node_p = &(node->dl_next); 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate return (0); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate /* 2160Sstevel@tonic-gate * create a linked list of directories available for writing 2170Sstevel@tonic-gate * 2180Sstevel@tonic-gate * if a list already exists, the two are compared and the new one is 2190Sstevel@tonic-gate * used only if it is different than the old. 2200Sstevel@tonic-gate * 2210Sstevel@tonic-gate * returns -2 for new or changed list, 0 for unchanged list and -1 for 2220Sstevel@tonic-gate * error. (Positive returns are for AUDITD_<error code> values) 2230Sstevel@tonic-gate * 2240Sstevel@tonic-gate */ 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate static int 2270Sstevel@tonic-gate loadauditlist(char *dirstr, char *minfreestr) 2280Sstevel@tonic-gate { 2290Sstevel@tonic-gate char buf[MAXPATHLEN]; 2300Sstevel@tonic-gate char *bs, *be; 2310Sstevel@tonic-gate dirlist_t *node, *n1, *n2; 2320Sstevel@tonic-gate dirlist_t **node_p; 2330Sstevel@tonic-gate dirlist_t *listhead = NULL; 2340Sstevel@tonic-gate dirlist_t *thisdir; 2350Sstevel@tonic-gate int acresult; 2360Sstevel@tonic-gate int node_count = 0; 2370Sstevel@tonic-gate int rc; 2380Sstevel@tonic-gate int temp_minfree; 2390Sstevel@tonic-gate au_acinfo_t *ach; 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate static dirlist_t *activeList = NULL; /* directory list */ 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate DPRINT((dbfp, "binfile: Loading audit list from auditcontrol\n")); 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate /* 2460Sstevel@tonic-gate * Build new directory list 2470Sstevel@tonic-gate */ 2480Sstevel@tonic-gate /* part 1 -- using pre Sol 10 audit_control directives */ 2490Sstevel@tonic-gate node_p = &listhead; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate ach = _openac(NULL); 2520Sstevel@tonic-gate if (ach == NULL) 2530Sstevel@tonic-gate return (-1); 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate /* at least one directory is needed */ 2560Sstevel@tonic-gate while ((acresult = _getacdir(ach, buf, sizeof (buf))) == 0 || 257*5007Spaulson acresult == 2 || acresult == -3) { 2580Sstevel@tonic-gate /* 2590Sstevel@tonic-gate * loop if the result is 0 (success), 2 (a warning 2600Sstevel@tonic-gate * that the audit_data file has been rewound), 2610Sstevel@tonic-gate * or -3 (a directory entry was found, but it 2620Sstevel@tonic-gate * was badly formatted. 2630Sstevel@tonic-gate */ 2640Sstevel@tonic-gate if (acresult == 0) { 2650Sstevel@tonic-gate /* 2660Sstevel@tonic-gate * A directory entry was found. 2670Sstevel@tonic-gate */ 2680Sstevel@tonic-gate node_count++; 2690Sstevel@tonic-gate node = malloc(sizeof (dirlist_t)); 2700Sstevel@tonic-gate if (node == NULL) 2710Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate node->dl_flags = 0; 2740Sstevel@tonic-gate node->dl_fd = -1; 2750Sstevel@tonic-gate node->dl_space = PLENTY_SPACE; 2760Sstevel@tonic-gate node->dl_filename = NULL; 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate node->dl_dirname = malloc((unsigned)strlen(buf) + 1); 2790Sstevel@tonic-gate if (node->dl_dirname == NULL) 2800Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate bs = buf; 2830Sstevel@tonic-gate while ((*bs == ' ') || (*bs == '\t')) 2840Sstevel@tonic-gate bs++; 2850Sstevel@tonic-gate be = bs + strlen(bs) - 1; 2860Sstevel@tonic-gate while (be > bs) { /* trim trailing blanks */ 2870Sstevel@tonic-gate if ((*bs != ' ') && (*bs != '\t')) 2880Sstevel@tonic-gate break; 2890Sstevel@tonic-gate be--; 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate *(be + 1) = '\0'; 2920Sstevel@tonic-gate (void) strlcpy(node->dl_dirname, bs, AUDIT_FNAME_SZ); 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate if (listhead != NULL) 2950Sstevel@tonic-gate node->dl_next = listhead; 2960Sstevel@tonic-gate else 2970Sstevel@tonic-gate node->dl_next = node; 2980Sstevel@tonic-gate *node_p = node; 2990Sstevel@tonic-gate node_p = &(node->dl_next); 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate } /* end of getacdir while */ 3020Sstevel@tonic-gate /* 3030Sstevel@tonic-gate * part 2 -- use directories and minfree from the (new as of Sol 10) 3040Sstevel@tonic-gate * plugin directive 3050Sstevel@tonic-gate */ 3060Sstevel@tonic-gate if (dirstr != NULL) { 3070Sstevel@tonic-gate if (node_count == 0) { 3080Sstevel@tonic-gate listhead = NULL; 3090Sstevel@tonic-gate node = NULL; 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate rc = growauditlist(&listhead, dirstr, node, &node_count); 3120Sstevel@tonic-gate if (rc) 3130Sstevel@tonic-gate return (rc); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate if (node_count == 0) { 3160Sstevel@tonic-gate /* 3170Sstevel@tonic-gate * there was a problem getting the directory 3180Sstevel@tonic-gate * list or remote host info from the audit_control file 3190Sstevel@tonic-gate * even though auditd thought there was at least 1 good 3200Sstevel@tonic-gate * entry 3210Sstevel@tonic-gate */ 3220Sstevel@tonic-gate DPRINT((dbfp, "binfile: " 3230Sstevel@tonic-gate "problem getting directory / libpath list " 3240Sstevel@tonic-gate "from audit_control.\n")); 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate _endac(ach); 3270Sstevel@tonic-gate return (-1); 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate #if DEBUG 3300Sstevel@tonic-gate /* print out directory list */ 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate if (listhead != NULL) { 3330Sstevel@tonic-gate fprintf(dbfp, "Directory list:\n\t%s\n", listhead->dl_dirname); 3340Sstevel@tonic-gate thisdir = listhead->dl_next; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate while (thisdir != listhead) { 3370Sstevel@tonic-gate fprintf(dbfp, "\t%s\n", thisdir->dl_dirname); 3380Sstevel@tonic-gate thisdir = thisdir->dl_next; 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate #endif /* DEBUG */ 3420Sstevel@tonic-gate thisdir = listhead; 3430Sstevel@tonic-gate /* 3440Sstevel@tonic-gate * See if the list has changed. 3450Sstevel@tonic-gate * If there was a change rc = 0 if no change, else 1 3460Sstevel@tonic-gate */ 3470Sstevel@tonic-gate rc = 0; /* no change */ 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate if (node_count == activeCount) { 3500Sstevel@tonic-gate n1 = listhead; 3510Sstevel@tonic-gate n2 = activeList; 3520Sstevel@tonic-gate do { 3530Sstevel@tonic-gate if (strcmp(n1->dl_dirname, n2->dl_dirname) != 0) { 3540Sstevel@tonic-gate DPRINT((dbfp, 3550Sstevel@tonic-gate "binfile: new dirname = %s\n" 3560Sstevel@tonic-gate "binfile: old dirname = %s\n", 3570Sstevel@tonic-gate n1->dl_dirname, 3580Sstevel@tonic-gate n2->dl_dirname)); 3590Sstevel@tonic-gate rc = -2; 3600Sstevel@tonic-gate break; 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate n1 = n1->dl_next; 3630Sstevel@tonic-gate n2 = n2->dl_next; 3640Sstevel@tonic-gate } while ((n1 != listhead) && (n2 != activeList)); 3650Sstevel@tonic-gate } else { 3660Sstevel@tonic-gate DPRINT((dbfp, "binfile: old dir count = %d\n" 3670Sstevel@tonic-gate "binfile: new dir count = %d\n", 3680Sstevel@tonic-gate activeCount, node_count)); 3690Sstevel@tonic-gate rc = -2; 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate if (rc == -2) { 3720Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 3730Sstevel@tonic-gate DPRINT((dbfp, "loadauditlist: close / open log\n")); 374*5007Spaulson if (open_log(listhead) == 0) { 3750Sstevel@tonic-gate openNewFile = 1; /* try again later */ 376*5007Spaulson } else { 377*5007Spaulson openNewFile = 0; 378*5007Spaulson } 3790Sstevel@tonic-gate freedirlist(activeList); /* old list */ 3800Sstevel@tonic-gate activeList = listhead; /* new list */ 381*5007Spaulson activeDir = startdir = thisdir; 3820Sstevel@tonic-gate activeCount = node_count; 3830Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 3840Sstevel@tonic-gate } else 3850Sstevel@tonic-gate freedirlist(listhead); 3860Sstevel@tonic-gate /* 3870Sstevel@tonic-gate * Get the minfree value. If minfree comes in via the attribute 3880Sstevel@tonic-gate * list, ignore the possibility it may also be listed on a separate 3890Sstevel@tonic-gate * audit_control line. 3900Sstevel@tonic-gate */ 3910Sstevel@tonic-gate if (minfreestr != NULL) 3920Sstevel@tonic-gate temp_minfree = atoi(minfreestr); 3930Sstevel@tonic-gate else if (!(_getacmin(ach, &temp_minfree) == 0)) 3940Sstevel@tonic-gate temp_minfree = 0; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate if ((temp_minfree < 0) || (temp_minfree > 100)) 3970Sstevel@tonic-gate temp_minfree = 0; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate if (minfree != temp_minfree) { 4000Sstevel@tonic-gate DPRINT((dbfp, "minfree: old = %d, new = %d\n", 4010Sstevel@tonic-gate minfree, temp_minfree)); 4020Sstevel@tonic-gate rc = -2; /* data change */ 4030Sstevel@tonic-gate minfree = temp_minfree; 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate _endac(ach); 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate return (rc); 4080Sstevel@tonic-gate } 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* 4120Sstevel@tonic-gate * getauditdate - get the current time (GMT) and put it in the form 4130Sstevel@tonic-gate * yyyymmddHHMMSS . 4140Sstevel@tonic-gate */ 4150Sstevel@tonic-gate static void 4160Sstevel@tonic-gate getauditdate(char *date) 4170Sstevel@tonic-gate { 4180Sstevel@tonic-gate struct timeval tp; 4190Sstevel@tonic-gate struct timezone tzp; 4200Sstevel@tonic-gate struct tm tm; 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate (void) gettimeofday(&tp, &tzp); 4230Sstevel@tonic-gate tm = *gmtime(&tp.tv_sec); 4240Sstevel@tonic-gate /* 4250Sstevel@tonic-gate * NOTE: if we want to use gmtime, we have to be aware that the 4260Sstevel@tonic-gate * structure only keeps the year as an offset from TM_YEAR_BASE. 4270Sstevel@tonic-gate * I have used TM_YEAR_BASE in this code so that if they change 4280Sstevel@tonic-gate * this base from 1900 to 2000, it will hopefully mean that this 4290Sstevel@tonic-gate * code does not have to change. TM_YEAR_BASE is defined in 4300Sstevel@tonic-gate * tzfile.h . 4310Sstevel@tonic-gate */ 4320Sstevel@tonic-gate (void) sprintf(date, "%.4d%.2d%.2d%.2d%.2d%.2d", 433*5007Spaulson tm.tm_year + TM_YEAR_BASE, tm.tm_mon + 1, tm.tm_mday, 434*5007Spaulson tm.tm_hour, tm.tm_min, tm.tm_sec); 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate /* 4400Sstevel@tonic-gate * write_file_token - put the file token into the audit log 4410Sstevel@tonic-gate */ 4420Sstevel@tonic-gate static int 4430Sstevel@tonic-gate write_file_token(int fd, char *name) 4440Sstevel@tonic-gate { 4450Sstevel@tonic-gate adr_t adr; /* xdr ptr */ 4460Sstevel@tonic-gate struct timeval tv; /* time now */ 4470Sstevel@tonic-gate char for_adr[AUDIT_FNAME_SZ + AUDIT_FNAME_SZ]; /* plenty of room */ 4480Sstevel@tonic-gate char token_id; 4490Sstevel@tonic-gate short i; 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate (void) gettimeofday(&tv, (struct timezone *)0); 4520Sstevel@tonic-gate i = strlen(name) + 1; 4530Sstevel@tonic-gate adr_start(&adr, for_adr); 4540Sstevel@tonic-gate #ifdef _LP64 4550Sstevel@tonic-gate token_id = AUT_OTHER_FILE64; 4560Sstevel@tonic-gate adr_char(&adr, &token_id, 1); 4570Sstevel@tonic-gate adr_int64(&adr, (int64_t *)& tv, 2); 4580Sstevel@tonic-gate #else 4590Sstevel@tonic-gate token_id = AUT_OTHER_FILE32; 4600Sstevel@tonic-gate adr_char(&adr, &token_id, 1); 4610Sstevel@tonic-gate adr_int32(&adr, (int32_t *)& tv, 2); 4620Sstevel@tonic-gate #endif 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate adr_short(&adr, &i, 1); 4650Sstevel@tonic-gate adr_char(&adr, name, i); 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate if (write(fd, for_adr, adr_count(&adr)) < 0) { 4680Sstevel@tonic-gate DPRINT((dbfp, "binfile: Bad write\n")); 4690Sstevel@tonic-gate return (errno); 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate return (0); 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate /* 4750Sstevel@tonic-gate * close_log - close the file if open. Also put the name of the 4760Sstevel@tonic-gate * new log file in the trailer, and rename the old file 4770Sstevel@tonic-gate * to oldname. The caller must hold log_mutext while calling 4780Sstevel@tonic-gate * close_log since any change to activeDir is a complete redo 4790Sstevel@tonic-gate * of all it points to. 4800Sstevel@tonic-gate * arguments - 4810Sstevel@tonic-gate * oldname - the new name for the file to be closed 4820Sstevel@tonic-gate * newname - the name of the new log file (for the trailer) 4830Sstevel@tonic-gate */ 4840Sstevel@tonic-gate static void 4850Sstevel@tonic-gate close_log(dirlist_t *currentdir, char *oname, char *newname) 4860Sstevel@tonic-gate { 4870Sstevel@tonic-gate char auditdate[AUDIT_DATE_SZ+1]; 4880Sstevel@tonic-gate char *name; 4890Sstevel@tonic-gate char oldname[AUDIT_FNAME_SZ+1]; 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate if ((currentdir == NULL) || (currentdir->dl_fd == -1)) 4920Sstevel@tonic-gate return; 4930Sstevel@tonic-gate /* 4940Sstevel@tonic-gate * If oldname is blank, we were called by auditd_plugin_close() 4950Sstevel@tonic-gate * instead of by open_log, so we need to update our name. 4960Sstevel@tonic-gate */ 4970Sstevel@tonic-gate (void) strlcpy(oldname, oname, AUDIT_FNAME_SZ); 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate if (strcmp(oldname, "") == 0) { 5000Sstevel@tonic-gate getauditdate(auditdate); 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate assert(currentdir->dl_filename != NULL); 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate (void) strlcpy(oldname, currentdir->dl_filename, 5050Sstevel@tonic-gate AUDIT_FNAME_SZ); 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate name = strrchr(oldname, '/') + 1; 5080Sstevel@tonic-gate (void) memcpy(name + AUDIT_DATE_SZ + 1, auditdate, 5090Sstevel@tonic-gate AUDIT_DATE_SZ); 5100Sstevel@tonic-gate } 5110Sstevel@tonic-gate /* 5120Sstevel@tonic-gate * Write the trailer record and rename and close the file. 5130Sstevel@tonic-gate * If any of the write, rename, or close fail, ignore it 5140Sstevel@tonic-gate * since there is not much else we can do and the next open() 5150Sstevel@tonic-gate * will trigger the necessary full directory logic. 5160Sstevel@tonic-gate * 5170Sstevel@tonic-gate * newname is "" if binfile is being closed down. 5180Sstevel@tonic-gate */ 5190Sstevel@tonic-gate (void) write_file_token(currentdir->dl_fd, newname); 5200Sstevel@tonic-gate if (currentdir->dl_fd >= 0) 5210Sstevel@tonic-gate (void) close(currentdir->dl_fd); 5220Sstevel@tonic-gate currentdir->dl_fd = -1; 5230Sstevel@tonic-gate (void) rename(currentdir->dl_filename, oldname); 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate DPRINT((dbfp, "binfile: Log closed %s\n", oldname)); 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate free(currentdir->dl_filename); 5280Sstevel@tonic-gate currentdir->dl_filename = NULL; 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate /* 5330Sstevel@tonic-gate * open_log - open a new file in the current directory. If a 5340Sstevel@tonic-gate * file is already open, close it. 5350Sstevel@tonic-gate * 5360Sstevel@tonic-gate * return 1 if ok, 0 if all directories are full. 5370Sstevel@tonic-gate * 5380Sstevel@tonic-gate * lastOpenDir - used to get the oldfile name (and change it), 5390Sstevel@tonic-gate * to close the oldfile. 5400Sstevel@tonic-gate * 5410Sstevel@tonic-gate * The caller must hold log_mutex while calling open_log. 5420Sstevel@tonic-gate * 5430Sstevel@tonic-gate */ 5440Sstevel@tonic-gate static int 5450Sstevel@tonic-gate open_log(dirlist_t *current_dir) 5460Sstevel@tonic-gate { 5470Sstevel@tonic-gate char auditdate[AUDIT_DATE_SZ + 1]; 5480Sstevel@tonic-gate char oldname[AUDIT_FNAME_SZ + 1] = ""; 5490Sstevel@tonic-gate char newname[AUDIT_FNAME_SZ + 1]; 5500Sstevel@tonic-gate char *name; /* pointer into oldname */ 5510Sstevel@tonic-gate int opened; 5520Sstevel@tonic-gate int error = 0; 5530Sstevel@tonic-gate int newfd = 0; 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate static char host[MAXHOSTNAMELEN + 1] = ""; 5560Sstevel@tonic-gate /* previous directory with open log file */ 5570Sstevel@tonic-gate static dirlist_t *lastOpenDir = NULL; 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate if (host[0] == '\0') 5600Sstevel@tonic-gate (void) gethostname(host, MAXHOSTNAMELEN); 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate /* Get a filename which does not already exist */ 5630Sstevel@tonic-gate opened = 0; 5640Sstevel@tonic-gate while (!opened) { 5650Sstevel@tonic-gate getauditdate(auditdate); 5660Sstevel@tonic-gate (void) snprintf(newname, AUDIT_FNAME_SZ, 5670Sstevel@tonic-gate "%s/%s.not_terminated.%s", 5680Sstevel@tonic-gate current_dir->dl_dirname, auditdate, host); 5690Sstevel@tonic-gate newfd = open(newname, 570832Sme23304 O_RDWR | O_APPEND | O_CREAT | O_EXCL, 0640); 5710Sstevel@tonic-gate if (newfd < 0) { 5720Sstevel@tonic-gate switch (errno) { 5730Sstevel@tonic-gate case EEXIST: 5740Sstevel@tonic-gate DPRINT((dbfp, 5750Sstevel@tonic-gate "open_log says duplicate for %s " 5760Sstevel@tonic-gate "(will try another)\n", newname)); 5770Sstevel@tonic-gate (void) sleep(1); 5780Sstevel@tonic-gate break; 5790Sstevel@tonic-gate default: 5800Sstevel@tonic-gate /* open failed */ 5810Sstevel@tonic-gate DPRINT((dbfp, 5820Sstevel@tonic-gate "open_log says full for %s: %s\n", 5830Sstevel@tonic-gate newname, strerror(errno))); 5840Sstevel@tonic-gate current_dir->dl_space = SPACE_FULL; 5850Sstevel@tonic-gate current_dir = current_dir->dl_next; 5860Sstevel@tonic-gate return (0); 5870Sstevel@tonic-gate } /* switch */ 5880Sstevel@tonic-gate } else 5890Sstevel@tonic-gate opened = 1; 5900Sstevel@tonic-gate } /* while */ 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate /* 5930Sstevel@tonic-gate * When we get here, we have opened our new log file. 5940Sstevel@tonic-gate * Now we need to update the name of the old file to 5950Sstevel@tonic-gate * store in this file's header. lastOpenDir may point 5960Sstevel@tonic-gate * to current_dir if the list is only one entry long and 5970Sstevel@tonic-gate * there is only one list. 5980Sstevel@tonic-gate */ 5990Sstevel@tonic-gate if ((lastOpenDir != NULL) && (lastOpenDir->dl_filename != NULL)) { 6000Sstevel@tonic-gate (void) strlcpy(oldname, lastOpenDir->dl_filename, 6010Sstevel@tonic-gate AUDIT_FNAME_SZ); 6020Sstevel@tonic-gate name = (char *)strrchr(oldname, '/') + 1; 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate (void) memcpy(name + AUDIT_DATE_SZ + 1, auditdate, 605*5007Spaulson AUDIT_DATE_SZ); 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate close_log(lastOpenDir, oldname, newname); 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate error = write_file_token(newfd, oldname); 6100Sstevel@tonic-gate if (error) { 6110Sstevel@tonic-gate /* write token failed */ 6120Sstevel@tonic-gate (void) close(newfd); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate current_dir->dl_space = SPACE_FULL; 6150Sstevel@tonic-gate current_dir->dl_fd = -1; 6160Sstevel@tonic-gate free(current_dir->dl_filename); 6170Sstevel@tonic-gate current_dir->dl_filename = NULL; 6180Sstevel@tonic-gate current_dir = current_dir->dl_next; 6190Sstevel@tonic-gate return (0); 6200Sstevel@tonic-gate } else { 6210Sstevel@tonic-gate lastOpenDir = current_dir; 6220Sstevel@tonic-gate current_dir->dl_fd = newfd; 6230Sstevel@tonic-gate current_dir->dl_filename = strdup(newname); 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate __logpost(newname); 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate DPRINT((dbfp, "binfile: Log opened: %s\n", newname)); 6280Sstevel@tonic-gate return (1); 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate } 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate #define IGNORE_SIZE 8192 6330Sstevel@tonic-gate /* 6340Sstevel@tonic-gate * spacecheck - determine whether the given directory's filesystem 6350Sstevel@tonic-gate * has the at least the space requested. Also set the space 6360Sstevel@tonic-gate * value in the directory list structure. If the caller 6370Sstevel@tonic-gate * passes other than PLENTY_SPACE or SOFT_SPACE, the caller should 6380Sstevel@tonic-gate * ignore the return value. Otherwise, 0 = less than the 6390Sstevel@tonic-gate * requested space is available, 1 = at least the requested space 6400Sstevel@tonic-gate * is available. 6410Sstevel@tonic-gate * 6420Sstevel@tonic-gate * log_mutex must be held by the caller 6430Sstevel@tonic-gate * 6440Sstevel@tonic-gate * -1 is returned if stat fails 6450Sstevel@tonic-gate * 6460Sstevel@tonic-gate * IGNORE_SIZE is one page (Sol 9 / 10 timeframe) and is the default 6470Sstevel@tonic-gate * buffer size written for Sol 9 and earlier. To keep the same accuracy 6480Sstevel@tonic-gate * for the soft limit check as before, spacecheck checks for space 6490Sstevel@tonic-gate * remaining IGNORE_SIZE bytes. This reduces the number of statvfs() 6500Sstevel@tonic-gate * calls and related math. 6510Sstevel@tonic-gate * 6520Sstevel@tonic-gate * globals - 6530Sstevel@tonic-gate * minfree - the soft limit, i.e., the % of filesystem to reserve 6540Sstevel@tonic-gate */ 6550Sstevel@tonic-gate static int 6560Sstevel@tonic-gate spacecheck(dirlist_t *thisdir, int test_limit, size_t next_buf_size) 6570Sstevel@tonic-gate { 6580Sstevel@tonic-gate struct statvfs sb; 6590Sstevel@tonic-gate static int ignore_size = 0; 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate ignore_size += next_buf_size; 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate if ((test_limit == PLENTY_SPACE) && (ignore_size < IGNORE_SIZE)) 6640Sstevel@tonic-gate return (1); 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate assert(thisdir != NULL); 6670Sstevel@tonic-gate 668*5007Spaulson if (statvfs(thisdir->dl_dirname, &sb) < 0) { 6690Sstevel@tonic-gate thisdir->dl_space = SPACE_FULL; 6700Sstevel@tonic-gate minfreeblocks = AVAIL_MIN; 6710Sstevel@tonic-gate return (-1); 6720Sstevel@tonic-gate } else { 6730Sstevel@tonic-gate minfreeblocks = ((minfree * sb.f_blocks) / 100) + AVAIL_MIN; 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate if (sb.f_bavail < AVAIL_MIN) 6760Sstevel@tonic-gate thisdir->dl_space = SPACE_FULL; 677*5007Spaulson else if (sb.f_bavail > minfreeblocks) { 678*5007Spaulson thisdir->dl_space = fullness_state = PLENTY_SPACE; 679*5007Spaulson ignore_size = 0; 680*5007Spaulson } else 6810Sstevel@tonic-gate thisdir->dl_space = SOFT_SPACE; 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate if (thisdir->dl_space == PLENTY_SPACE) 6840Sstevel@tonic-gate return (1); 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate return (thisdir->dl_space == test_limit); 6870Sstevel@tonic-gate } 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate /* 690*5007Spaulson * auditd_plugin() writes a buffer to the currently open file. The 691*5007Spaulson * global "openNewFile" is used to force a new log file for cases 692*5007Spaulson * such as the initial open, when minfree is reached or the current 693*5007Spaulson * file system fills up, and "audit -s" with changed audit_control 694*5007Spaulson * data. For "audit -n" a new log file is opened immediately in 695*5007Spaulson * auditd_plugin_open(). 6960Sstevel@tonic-gate * 6970Sstevel@tonic-gate * This function manages one or more audit directories as follows: 6980Sstevel@tonic-gate * 6990Sstevel@tonic-gate * If the current open file is in a directory that has not 7000Sstevel@tonic-gate * reached the soft limit, write the input data and return. 7010Sstevel@tonic-gate * 7020Sstevel@tonic-gate * Scan the list of directories for one which has not reached 7030Sstevel@tonic-gate * the soft limit; if one is found, write and return. Such 7040Sstevel@tonic-gate * a writable directory is in "PLENTY_SPACE" state. 7050Sstevel@tonic-gate * 7060Sstevel@tonic-gate * Scan the list of directories for one which has not reached 7070Sstevel@tonic-gate * the hard limit; if one is found, write and return. This 7080Sstevel@tonic-gate * directory in in "SOFT_SPACE" state. 7090Sstevel@tonic-gate * 7100Sstevel@tonic-gate * Oh, and if a write fails, handle it like a hard space limit. 7110Sstevel@tonic-gate * 7120Sstevel@tonic-gate * audit_warn (via __audit_dowarn()) is used to alert an operator 7130Sstevel@tonic-gate * at various levels of fullness. 7140Sstevel@tonic-gate */ 7150Sstevel@tonic-gate /* ARGSUSED */ 7160Sstevel@tonic-gate auditd_rc_t 7170Sstevel@tonic-gate auditd_plugin(const char *input, size_t in_len, uint32_t sequence, char **error) 7180Sstevel@tonic-gate { 7190Sstevel@tonic-gate auditd_rc_t rc = AUDITD_FAIL; 7200Sstevel@tonic-gate int open_status; 7210Sstevel@tonic-gate size_t out_len; 7220Sstevel@tonic-gate /* LINTED */ 7230Sstevel@tonic-gate int statrc; 7240Sstevel@tonic-gate /* avoid excess audit_warnage */ 7250Sstevel@tonic-gate static int allsoftfull_warning = 0; 726*5007Spaulson static int allhard_pause = 0; 727*5007Spaulson static struct timeval next_allhard; 728*5007Spaulson struct timeval now; 7290Sstevel@tonic-gate #if DEBUG 7300Sstevel@tonic-gate static char *last_file_written_to = NULL; 7310Sstevel@tonic-gate static uint32_t last_sequence = 0; 7320Sstevel@tonic-gate static uint32_t write_count = 0; 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate if ((last_sequence > 0) && (sequence != last_sequence + 1)) 7350Sstevel@tonic-gate fprintf(dbfp, "binfile: buffer sequence=%d but prev=%d=n", 736*5007Spaulson sequence, last_sequence); 7370Sstevel@tonic-gate last_sequence = sequence; 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate fprintf(dbfp, "binfile: input seq=%d, len=%d\n", 740*5007Spaulson sequence, in_len); 7410Sstevel@tonic-gate #endif 7420Sstevel@tonic-gate *error = NULL; 7430Sstevel@tonic-gate /* 7440Sstevel@tonic-gate * lock is for activeDir, referenced by open_log() and close_log() 7450Sstevel@tonic-gate */ 7460Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 7470Sstevel@tonic-gate while (rc == AUDITD_FAIL) { 7480Sstevel@tonic-gate open_status = 1; 7490Sstevel@tonic-gate if (openNewFile) { 7500Sstevel@tonic-gate open_status = open_log(activeDir); 7510Sstevel@tonic-gate if (open_status == 1) /* ok */ 7520Sstevel@tonic-gate openNewFile = 0; 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate /* 7550Sstevel@tonic-gate * consider "space ok" return and error return the same; 7560Sstevel@tonic-gate * a -1 means spacecheck couldn't check for space. 7570Sstevel@tonic-gate */ 7580Sstevel@tonic-gate if ((open_status == 1) && 7590Sstevel@tonic-gate (statrc = spacecheck(activeDir, fullness_state, 7600Sstevel@tonic-gate in_len)) != 0) { 7610Sstevel@tonic-gate #if DEBUG 7620Sstevel@tonic-gate DPRINT((dbfp, "binfile: returned from spacecheck\n")); 7630Sstevel@tonic-gate /* 7640Sstevel@tonic-gate * The last copy of last_file_written_to is 7650Sstevel@tonic-gate * never free'd, so there will be one open 7660Sstevel@tonic-gate * memory reference on exit. It's debug only. 7670Sstevel@tonic-gate */ 7680Sstevel@tonic-gate if ((last_file_written_to != NULL) && 7690Sstevel@tonic-gate (strcmp(last_file_written_to, 7700Sstevel@tonic-gate activeDir->dl_filename) != 0)) { 7710Sstevel@tonic-gate DPRINT((dbfp, "binfile: now writing to %s\n", 7720Sstevel@tonic-gate activeDir->dl_filename)); 7730Sstevel@tonic-gate free(last_file_written_to); 7740Sstevel@tonic-gate } 7750Sstevel@tonic-gate DPRINT((dbfp, "binfile: finished some debug stuff\n")); 7760Sstevel@tonic-gate last_file_written_to = 7770Sstevel@tonic-gate strdup(activeDir->dl_filename); 7780Sstevel@tonic-gate #endif 7790Sstevel@tonic-gate out_len = write(activeDir->dl_fd, input, in_len); 7800Sstevel@tonic-gate DPRINT((dbfp, "binfile: finished the write\n")); 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate if (out_len == in_len) { 7830Sstevel@tonic-gate DPRINT((dbfp, 7840Sstevel@tonic-gate "binfile: write_count=%u, sequence=%u," 7850Sstevel@tonic-gate " l=%u\n", 7860Sstevel@tonic-gate ++write_count, sequence, out_len)); 7870Sstevel@tonic-gate allsoftfull_warning = 0; 788*5007Spaulson activeDir->dl_flags = 0; 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate rc = AUDITD_SUCCESS; 7910Sstevel@tonic-gate break; 792*5007Spaulson } else if (!(activeDir->dl_flags & HARD_WARNED)) { 7930Sstevel@tonic-gate DPRINT((dbfp, 7940Sstevel@tonic-gate "binfile: write failed, sequence=%u, " 7950Sstevel@tonic-gate "l=%u\n", sequence, out_len)); 7960Sstevel@tonic-gate DPRINT((dbfp, "hard warning sent.\n")); 7970Sstevel@tonic-gate __audit_dowarn("hard", activeDir->dl_dirname, 7980Sstevel@tonic-gate 0); 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate activeDir->dl_flags |= HARD_WARNED; 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate } else { 8030Sstevel@tonic-gate DPRINT((dbfp, "binfile: statrc=%d, fullness_state=%d\n", 8040Sstevel@tonic-gate statrc, fullness_state)); 805*5007Spaulson if (!(activeDir->dl_flags & SOFT_WARNED) && 806*5007Spaulson (activeDir->dl_space == SOFT_SPACE)) { 8070Sstevel@tonic-gate DPRINT((dbfp, "soft warning sent\n")); 8080Sstevel@tonic-gate __audit_dowarn("soft", 8090Sstevel@tonic-gate activeDir->dl_dirname, 0); 8100Sstevel@tonic-gate activeDir->dl_flags |= SOFT_WARNED; 8110Sstevel@tonic-gate } 812*5007Spaulson if (!(activeDir->dl_flags & HARD_WARNED) && 813*5007Spaulson (activeDir->dl_space == SPACE_FULL)) { 8140Sstevel@tonic-gate DPRINT((dbfp, "hard warning sent.\n")); 8150Sstevel@tonic-gate __audit_dowarn("hard", 816*5007Spaulson activeDir->dl_dirname, 0); 8170Sstevel@tonic-gate activeDir->dl_flags |= HARD_WARNED; 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate DPRINT((dbfp, "binfile: activeDir=%s, next=%s\n", 8210Sstevel@tonic-gate activeDir->dl_dirname, activeDir->dl_next->dl_dirname)); 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate activeDir = activeDir->dl_next; 824*5007Spaulson openNewFile = 1; 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate if (activeDir == startdir) { /* full circle */ 8270Sstevel@tonic-gate if (fullness_state == PLENTY_SPACE) { /* once */ 8280Sstevel@tonic-gate fullness_state = SOFT_SPACE; 8290Sstevel@tonic-gate if (allsoftfull_warning == 0) { 8300Sstevel@tonic-gate allsoftfull_warning++; 8310Sstevel@tonic-gate __audit_dowarn("allsoft", "", 0); 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate } else { /* full circle twice */ 834*5007Spaulson if ((hung_count > 0) && !allhard_pause) { 835*5007Spaulson allhard_pause = 1; 836*5007Spaulson (void) gettimeofday(&next_allhard, 837*5007Spaulson NULL); 838*5007Spaulson next_allhard.tv_sec += ALLHARD_DELAY; 839*5007Spaulson } 840*5007Spaulson 841*5007Spaulson if (allhard_pause) { 842*5007Spaulson (void) gettimeofday(&now, NULL); 843*5007Spaulson if (now.tv_sec >= next_allhard.tv_sec) { 844*5007Spaulson allhard_pause = 0; 845*5007Spaulson __audit_dowarn("allhard", "", 846*5007Spaulson ++hung_count); 847*5007Spaulson } 848*5007Spaulson } else { 849*5007Spaulson __audit_dowarn("allhard", "", 850*5007Spaulson ++hung_count); 851*5007Spaulson } 8520Sstevel@tonic-gate minfreeblocks = AVAIL_MIN; 8530Sstevel@tonic-gate rc = AUDITD_RETRY; 8540Sstevel@tonic-gate *error = strdup(gettext( 8550Sstevel@tonic-gate "all partitions full\n")); 8560Sstevel@tonic-gate __logpost(""); 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate } 8590Sstevel@tonic-gate } 8600Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate return (rc); 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate /* 8670Sstevel@tonic-gate * the open function uses getacdir() and getacmin to determine which 8680Sstevel@tonic-gate * directories to use and when to switch. It takes no inputs. 8690Sstevel@tonic-gate * 8700Sstevel@tonic-gate * It may be called multiple times as auditd handles SIGHUP and SIGUSR1 8710Sstevel@tonic-gate * corresponding to the audit(1M) flags -s and -n 8720Sstevel@tonic-gate * 8730Sstevel@tonic-gate * kvlist is NULL only if auditd caught a SIGUSR1, so after the first 8740Sstevel@tonic-gate * time open is called, the reason is -s if kvlist != NULL and -n 8750Sstevel@tonic-gate * otherwise. 8760Sstevel@tonic-gate * 8770Sstevel@tonic-gate */ 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate auditd_rc_t 8800Sstevel@tonic-gate auditd_plugin_open(const kva_t *kvlist, char **ret_list, char **error) 8810Sstevel@tonic-gate { 8820Sstevel@tonic-gate int rc = 0; 8830Sstevel@tonic-gate int status; 8840Sstevel@tonic-gate int reason; 8850Sstevel@tonic-gate char *dirlist; 8860Sstevel@tonic-gate char *minfree; 8870Sstevel@tonic-gate kva_t *kv; 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate *error = NULL; 8900Sstevel@tonic-gate *ret_list = NULL; 8910Sstevel@tonic-gate kv = (kva_t *)kvlist; 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate if (am_open) { 8940Sstevel@tonic-gate if (kvlist == NULL) 8950Sstevel@tonic-gate reason = 1; /* audit -n */ 8960Sstevel@tonic-gate else 8970Sstevel@tonic-gate reason = 2; /* audit -s */ 8980Sstevel@tonic-gate } else { 8990Sstevel@tonic-gate reason = 0; /* initial open */ 9000Sstevel@tonic-gate #if DEBUG 9010Sstevel@tonic-gate dbfp = __auditd_debug_file_open(); 9020Sstevel@tonic-gate #endif 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate DPRINT((dbfp, "binfile: am_open=%d, reason=%d\n", am_open, reason)); 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate am_open = 1; 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate if (kvlist == NULL) { 9090Sstevel@tonic-gate dirlist = NULL; 9100Sstevel@tonic-gate minfree = NULL; 9110Sstevel@tonic-gate } else { 9120Sstevel@tonic-gate dirlist = kva_match(kv, "p_dir"); 9130Sstevel@tonic-gate minfree = kva_match(kv, "p_minfree"); 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate switch (reason) { 9160Sstevel@tonic-gate case 0: /* initial open */ 9170Sstevel@tonic-gate if (!binfile_is_open) 9180Sstevel@tonic-gate (void) pthread_mutex_init(&log_mutex, NULL); 9190Sstevel@tonic-gate binfile_is_open = 1; 9200Sstevel@tonic-gate openNewFile = 1; 9210Sstevel@tonic-gate /* FALLTHRU */ 9220Sstevel@tonic-gate case 2: /* audit -s */ 9230Sstevel@tonic-gate fullness_state = PLENTY_SPACE; 9240Sstevel@tonic-gate status = loadauditlist(dirlist, minfree); 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate if (status == -1) { 9270Sstevel@tonic-gate __logpost(""); 9280Sstevel@tonic-gate *error = strdup(gettext("no directories configured")); 9290Sstevel@tonic-gate return (AUDITD_RETRY); 9300Sstevel@tonic-gate } else if (status == AUDITD_NO_MEMORY) { 9310Sstevel@tonic-gate __logpost(""); 9320Sstevel@tonic-gate *error = strdup(gettext("no memory")); 9330Sstevel@tonic-gate return (status); 9340Sstevel@tonic-gate } else { /* status is 0 or -2 (no change or changed) */ 9350Sstevel@tonic-gate hung_count = 0; 9360Sstevel@tonic-gate DPRINT((dbfp, "binfile: loadauditlist returned %d\n", 937*5007Spaulson status)); 9380Sstevel@tonic-gate } 9390Sstevel@tonic-gate break; 9400Sstevel@tonic-gate case 1: /* audit -n */ 9410Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 9420Sstevel@tonic-gate if (open_log(activeDir) == 1) /* ok */ 9430Sstevel@tonic-gate openNewFile = 0; 9440Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 9450Sstevel@tonic-gate break; 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate rc = AUDITD_SUCCESS; 9490Sstevel@tonic-gate *ret_list = NULL; 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate return (rc); 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate auditd_rc_t 9550Sstevel@tonic-gate auditd_plugin_close(char **error) 9560Sstevel@tonic-gate { 9570Sstevel@tonic-gate *error = NULL; 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 9600Sstevel@tonic-gate close_log(activeDir, "", ""); 9610Sstevel@tonic-gate freedirlist(activeDir); 9620Sstevel@tonic-gate activeDir = NULL; 9630Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate DPRINT((dbfp, "binfile: closed\n")); 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate if (binfile_is_open) { 9680Sstevel@tonic-gate (void) pthread_mutex_destroy(&log_mutex); 9690Sstevel@tonic-gate binfile_is_open = 0; 9700Sstevel@tonic-gate /* LINTED */ 9710Sstevel@tonic-gate } else { 9720Sstevel@tonic-gate DPRINT((dbfp, 9730Sstevel@tonic-gate "auditd_plugin_close() called when already closed.")); 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate am_open = 0; 9760Sstevel@tonic-gate return (AUDITD_SUCCESS); 9770Sstevel@tonic-gate } 978