1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate * 26*0Sstevel@tonic-gate * write binary audit records directly to a file. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #define DEBUG 0 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #if DEBUG 33*0Sstevel@tonic-gate #define DPRINT(x) {fprintf x; } 34*0Sstevel@tonic-gate #else 35*0Sstevel@tonic-gate #define DPRINT(x) 36*0Sstevel@tonic-gate #endif 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate /* 39*0Sstevel@tonic-gate * auditd_plugin_open(), auditd_plugin() and auditd_plugin_close() 40*0Sstevel@tonic-gate * implement a replacable library for use by auditd; they are a 41*0Sstevel@tonic-gate * project private interface and may change without notice. 42*0Sstevel@tonic-gate * 43*0Sstevel@tonic-gate */ 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate #include <assert.h> 46*0Sstevel@tonic-gate #include <bsm/audit.h> 47*0Sstevel@tonic-gate #include <bsm/audit_record.h> 48*0Sstevel@tonic-gate #include <bsm/libbsm.h> 49*0Sstevel@tonic-gate #include <errno.h> 50*0Sstevel@tonic-gate #include <fcntl.h> 51*0Sstevel@tonic-gate #include <libintl.h> 52*0Sstevel@tonic-gate #include <netdb.h> 53*0Sstevel@tonic-gate #include <pthread.h> 54*0Sstevel@tonic-gate #include <secdb.h> 55*0Sstevel@tonic-gate #include <signal.h> 56*0Sstevel@tonic-gate #include <stdio.h> 57*0Sstevel@tonic-gate #include <stdlib.h> 58*0Sstevel@tonic-gate #include <string.h> 59*0Sstevel@tonic-gate #include <sys/param.h> 60*0Sstevel@tonic-gate #include <sys/types.h> 61*0Sstevel@tonic-gate #include <time.h> 62*0Sstevel@tonic-gate #include <tzfile.h> 63*0Sstevel@tonic-gate #include <unistd.h> 64*0Sstevel@tonic-gate #include <sys/vfs.h> 65*0Sstevel@tonic-gate #include <security/auditd.h> 66*0Sstevel@tonic-gate #include <audit_plugin.h> 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate #define AUDIT_DATE_SZ 14 69*0Sstevel@tonic-gate #define AUDIT_FNAME_SZ 2 * AUDIT_DATE_SZ + 2 + MAXHOSTNAMELEN 70*0Sstevel@tonic-gate #define AUDIT_BAK_SZ 50 /* size of name of audit_data back-up file */ 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* per-directory status */ 73*0Sstevel@tonic-gate #define SOFT_SPACE 0 /* minfree or less space available */ 74*0Sstevel@tonic-gate #define PLENTY_SPACE 1 /* more than minfree available */ 75*0Sstevel@tonic-gate #define SPACE_FULL 2 /* out of space */ 76*0Sstevel@tonic-gate #define STAY_FULL 3 /* unusable file system */ 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate #define AVAIL_MIN 50 /* If there are less that this number */ 79*0Sstevel@tonic-gate /* of blocks avail, the filesystem is */ 80*0Sstevel@tonic-gate /* presumed full. */ 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate /* 84*0Sstevel@tonic-gate * The directory list is a circular linked list. It is pointed into by 85*0Sstevel@tonic-gate * activeDir. Each element contains the pointer to the next 86*0Sstevel@tonic-gate * element, the directory pathname, a flag for how much space there is 87*0Sstevel@tonic-gate * in the directory's filesystem, and a file handle. Since a new 88*0Sstevel@tonic-gate * directory list can be created from auditd_plugin_open() while the 89*0Sstevel@tonic-gate * current list is in use, activeDir is protected by log_mutex. 90*0Sstevel@tonic-gate */ 91*0Sstevel@tonic-gate typedef struct dirlist_s dirlist_t; 92*0Sstevel@tonic-gate struct dirlist_s { 93*0Sstevel@tonic-gate dirlist_t *dl_next; 94*0Sstevel@tonic-gate int dl_space; 95*0Sstevel@tonic-gate int dl_flags; 96*0Sstevel@tonic-gate char *dl_dirname; 97*0Sstevel@tonic-gate char *dl_filename; /* file name (not path) if open */ 98*0Sstevel@tonic-gate int dl_fd; /* file handle, -1 unless open */ 99*0Sstevel@tonic-gate }; 100*0Sstevel@tonic-gate /* 101*0Sstevel@tonic-gate * Defines for dl_flags 102*0Sstevel@tonic-gate */ 103*0Sstevel@tonic-gate #define SOFT_WARNED 0x0001 /* already did soft warning for this dir */ 104*0Sstevel@tonic-gate #define HARD_WARNED 0x0002 /* already did hard warning for this dir */ 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate #if DEBUG 107*0Sstevel@tonic-gate static FILE *dbfp; /* debug file */ 108*0Sstevel@tonic-gate #endif 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate static pthread_mutex_t log_mutex; 111*0Sstevel@tonic-gate static int binfile_is_open = 0; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate static int minfree = -1; 114*0Sstevel@tonic-gate static int minfreeblocks; /* minfree in blocks */ 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate static dirlist_t *activeDir = NULL; /* current directory */ 117*0Sstevel@tonic-gate static int activeCount = 0; /* number of dirs in the ring */ 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate static int openNewFile = 1; /* need to open a new file */ 120*0Sstevel@tonic-gate static int hung_count = 0; /* count of audit_warn hard */ 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate /* flag from audit_plugin_open to audit_plugin_close */ 123*0Sstevel@tonic-gate static int am_open = 0; 124*0Sstevel@tonic-gate /* preferred dir state */ 125*0Sstevel@tonic-gate static int fullness_state = PLENTY_SPACE; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate static int open_log(dirlist_t *); 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate static void 130*0Sstevel@tonic-gate freedirlist(dirlist_t *head) 131*0Sstevel@tonic-gate { 132*0Sstevel@tonic-gate dirlist_t *n1, *n2; 133*0Sstevel@tonic-gate /* 134*0Sstevel@tonic-gate * Free up the old directory list if any 135*0Sstevel@tonic-gate */ 136*0Sstevel@tonic-gate if (head != NULL) { 137*0Sstevel@tonic-gate n1 = head; 138*0Sstevel@tonic-gate do { 139*0Sstevel@tonic-gate n2 = n1->dl_next; 140*0Sstevel@tonic-gate free(n1->dl_dirname); 141*0Sstevel@tonic-gate free(n1->dl_filename); 142*0Sstevel@tonic-gate free(n1); 143*0Sstevel@tonic-gate n1 = n2; 144*0Sstevel@tonic-gate } while (n1 != head); 145*0Sstevel@tonic-gate } 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate /* 150*0Sstevel@tonic-gate * add to a linked list of directories available for writing 151*0Sstevel@tonic-gate * 152*0Sstevel@tonic-gate */ 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate static int 155*0Sstevel@tonic-gate growauditlist(dirlist_t **listhead, char *dirlist, 156*0Sstevel@tonic-gate dirlist_t *endnode, int *count) 157*0Sstevel@tonic-gate { 158*0Sstevel@tonic-gate dirlist_t *node; 159*0Sstevel@tonic-gate char *bs, *be; 160*0Sstevel@tonic-gate dirlist_t **node_p; 161*0Sstevel@tonic-gate char *dirname; 162*0Sstevel@tonic-gate char *remainder; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: dirlist=%s\n", dirlist)); 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate if (*listhead == NULL) 167*0Sstevel@tonic-gate node_p = listhead; 168*0Sstevel@tonic-gate else 169*0Sstevel@tonic-gate node_p = &(endnode->dl_next); 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate node = NULL; 172*0Sstevel@tonic-gate while ((dirname = strtok_r(dirlist, ",", &remainder)) != NULL) { 173*0Sstevel@tonic-gate dirlist = NULL; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: p_dir = %s\n", dirname)); 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate (*count)++; 178*0Sstevel@tonic-gate node = malloc(sizeof (dirlist_t)); 179*0Sstevel@tonic-gate if (node == NULL) 180*0Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate node->dl_flags = 0; 183*0Sstevel@tonic-gate node->dl_filename = NULL; 184*0Sstevel@tonic-gate node->dl_fd = -1; 185*0Sstevel@tonic-gate node->dl_space = PLENTY_SPACE; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate node->dl_dirname = malloc((unsigned)strlen(dirname) + 1); 188*0Sstevel@tonic-gate if (node->dl_dirname == NULL) 189*0Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate bs = dirname; 192*0Sstevel@tonic-gate while ((*bs == ' ') || (*bs == '\t')) /* trim blanks */ 193*0Sstevel@tonic-gate bs++; 194*0Sstevel@tonic-gate be = bs + strlen(bs) - 1; 195*0Sstevel@tonic-gate while (be > bs) { /* trim trailing blanks */ 196*0Sstevel@tonic-gate if ((*bs != ' ') && (*bs != '\t')) 197*0Sstevel@tonic-gate break; 198*0Sstevel@tonic-gate be--; 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate *(be + 1) = '\0'; 201*0Sstevel@tonic-gate (void) strlcpy(node->dl_dirname, bs, AUDIT_FNAME_SZ); 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate if (*listhead != NULL) 204*0Sstevel@tonic-gate node->dl_next = *listhead; 205*0Sstevel@tonic-gate else 206*0Sstevel@tonic-gate node->dl_next = node; 207*0Sstevel@tonic-gate *node_p = node; 208*0Sstevel@tonic-gate node_p = &(node->dl_next); 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate return (0); 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate /* 215*0Sstevel@tonic-gate * create a linked list of directories available for writing 216*0Sstevel@tonic-gate * 217*0Sstevel@tonic-gate * if a list already exists, the two are compared and the new one is 218*0Sstevel@tonic-gate * used only if it is different than the old. 219*0Sstevel@tonic-gate * 220*0Sstevel@tonic-gate * returns -2 for new or changed list, 0 for unchanged list and -1 for 221*0Sstevel@tonic-gate * error. (Positive returns are for AUDITD_<error code> values) 222*0Sstevel@tonic-gate * 223*0Sstevel@tonic-gate */ 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate static int 226*0Sstevel@tonic-gate loadauditlist(char *dirstr, char *minfreestr) 227*0Sstevel@tonic-gate { 228*0Sstevel@tonic-gate char buf[MAXPATHLEN]; 229*0Sstevel@tonic-gate char *bs, *be; 230*0Sstevel@tonic-gate dirlist_t *node, *n1, *n2; 231*0Sstevel@tonic-gate dirlist_t **node_p; 232*0Sstevel@tonic-gate dirlist_t *listhead = NULL; 233*0Sstevel@tonic-gate dirlist_t *thisdir; 234*0Sstevel@tonic-gate int acresult; 235*0Sstevel@tonic-gate int node_count = 0; 236*0Sstevel@tonic-gate int rc; 237*0Sstevel@tonic-gate int temp_minfree; 238*0Sstevel@tonic-gate au_acinfo_t *ach; 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate static dirlist_t *activeList = NULL; /* directory list */ 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: Loading audit list from auditcontrol\n")); 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate /* 245*0Sstevel@tonic-gate * Build new directory list 246*0Sstevel@tonic-gate */ 247*0Sstevel@tonic-gate /* part 1 -- using pre Sol 10 audit_control directives */ 248*0Sstevel@tonic-gate node_p = &listhead; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate ach = _openac(NULL); 251*0Sstevel@tonic-gate if (ach == NULL) 252*0Sstevel@tonic-gate return (-1); 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate /* at least one directory is needed */ 255*0Sstevel@tonic-gate while ((acresult = _getacdir(ach, buf, sizeof (buf))) == 0 || 256*0Sstevel@tonic-gate acresult == 2 || acresult == -3) { 257*0Sstevel@tonic-gate /* 258*0Sstevel@tonic-gate * loop if the result is 0 (success), 2 (a warning 259*0Sstevel@tonic-gate * that the audit_data file has been rewound), 260*0Sstevel@tonic-gate * or -3 (a directory entry was found, but it 261*0Sstevel@tonic-gate * was badly formatted. 262*0Sstevel@tonic-gate */ 263*0Sstevel@tonic-gate if (acresult == 0) { 264*0Sstevel@tonic-gate /* 265*0Sstevel@tonic-gate * A directory entry was found. 266*0Sstevel@tonic-gate */ 267*0Sstevel@tonic-gate node_count++; 268*0Sstevel@tonic-gate node = malloc(sizeof (dirlist_t)); 269*0Sstevel@tonic-gate if (node == NULL) 270*0Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate node->dl_flags = 0; 273*0Sstevel@tonic-gate node->dl_fd = -1; 274*0Sstevel@tonic-gate node->dl_space = PLENTY_SPACE; 275*0Sstevel@tonic-gate node->dl_filename = NULL; 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate node->dl_dirname = malloc((unsigned)strlen(buf) + 1); 278*0Sstevel@tonic-gate if (node->dl_dirname == NULL) 279*0Sstevel@tonic-gate return (AUDITD_NO_MEMORY); 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate bs = buf; 282*0Sstevel@tonic-gate while ((*bs == ' ') || (*bs == '\t')) 283*0Sstevel@tonic-gate bs++; 284*0Sstevel@tonic-gate be = bs + strlen(bs) - 1; 285*0Sstevel@tonic-gate while (be > bs) { /* trim trailing blanks */ 286*0Sstevel@tonic-gate if ((*bs != ' ') && (*bs != '\t')) 287*0Sstevel@tonic-gate break; 288*0Sstevel@tonic-gate be--; 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate *(be + 1) = '\0'; 291*0Sstevel@tonic-gate (void) strlcpy(node->dl_dirname, bs, AUDIT_FNAME_SZ); 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate if (listhead != NULL) 294*0Sstevel@tonic-gate node->dl_next = listhead; 295*0Sstevel@tonic-gate else 296*0Sstevel@tonic-gate node->dl_next = node; 297*0Sstevel@tonic-gate *node_p = node; 298*0Sstevel@tonic-gate node_p = &(node->dl_next); 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate } /* end of getacdir while */ 301*0Sstevel@tonic-gate /* 302*0Sstevel@tonic-gate * part 2 -- use directories and minfree from the (new as of Sol 10) 303*0Sstevel@tonic-gate * plugin directive 304*0Sstevel@tonic-gate */ 305*0Sstevel@tonic-gate if (dirstr != NULL) { 306*0Sstevel@tonic-gate if (node_count == 0) { 307*0Sstevel@tonic-gate listhead = NULL; 308*0Sstevel@tonic-gate node = NULL; 309*0Sstevel@tonic-gate } 310*0Sstevel@tonic-gate rc = growauditlist(&listhead, dirstr, node, &node_count); 311*0Sstevel@tonic-gate if (rc) 312*0Sstevel@tonic-gate return (rc); 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate if (node_count == 0) { 315*0Sstevel@tonic-gate /* 316*0Sstevel@tonic-gate * there was a problem getting the directory 317*0Sstevel@tonic-gate * list or remote host info from the audit_control file 318*0Sstevel@tonic-gate * even though auditd thought there was at least 1 good 319*0Sstevel@tonic-gate * entry 320*0Sstevel@tonic-gate */ 321*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: " 322*0Sstevel@tonic-gate "problem getting directory / libpath list " 323*0Sstevel@tonic-gate "from audit_control.\n")); 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate _endac(ach); 326*0Sstevel@tonic-gate return (-1); 327*0Sstevel@tonic-gate } 328*0Sstevel@tonic-gate #if DEBUG 329*0Sstevel@tonic-gate /* print out directory list */ 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate if (listhead != NULL) { 332*0Sstevel@tonic-gate fprintf(dbfp, "Directory list:\n\t%s\n", listhead->dl_dirname); 333*0Sstevel@tonic-gate thisdir = listhead->dl_next; 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate while (thisdir != listhead) { 336*0Sstevel@tonic-gate fprintf(dbfp, "\t%s\n", thisdir->dl_dirname); 337*0Sstevel@tonic-gate thisdir = thisdir->dl_next; 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate #endif /* DEBUG */ 341*0Sstevel@tonic-gate thisdir = listhead; 342*0Sstevel@tonic-gate /* 343*0Sstevel@tonic-gate * See if the list has changed. 344*0Sstevel@tonic-gate * If there was a change rc = 0 if no change, else 1 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate rc = 0; /* no change */ 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate if (node_count == activeCount) { 349*0Sstevel@tonic-gate n1 = listhead; 350*0Sstevel@tonic-gate n2 = activeList; 351*0Sstevel@tonic-gate do { 352*0Sstevel@tonic-gate if (strcmp(n1->dl_dirname, n2->dl_dirname) != 0) { 353*0Sstevel@tonic-gate DPRINT((dbfp, 354*0Sstevel@tonic-gate "binfile: new dirname = %s\n" 355*0Sstevel@tonic-gate "binfile: old dirname = %s\n", 356*0Sstevel@tonic-gate n1->dl_dirname, 357*0Sstevel@tonic-gate n2->dl_dirname)); 358*0Sstevel@tonic-gate rc = -2; 359*0Sstevel@tonic-gate break; 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate n1 = n1->dl_next; 362*0Sstevel@tonic-gate n2 = n2->dl_next; 363*0Sstevel@tonic-gate } while ((n1 != listhead) && (n2 != activeList)); 364*0Sstevel@tonic-gate } else { 365*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: old dir count = %d\n" 366*0Sstevel@tonic-gate "binfile: new dir count = %d\n", 367*0Sstevel@tonic-gate activeCount, node_count)); 368*0Sstevel@tonic-gate rc = -2; 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate if (rc == -2) { 371*0Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 372*0Sstevel@tonic-gate DPRINT((dbfp, "loadauditlist: close / open log\n")); 373*0Sstevel@tonic-gate if (open_log(listhead) == 0) 374*0Sstevel@tonic-gate openNewFile = 1; /* try again later */ 375*0Sstevel@tonic-gate freedirlist(activeList); /* old list */ 376*0Sstevel@tonic-gate activeList = listhead; /* new list */ 377*0Sstevel@tonic-gate activeDir = thisdir; 378*0Sstevel@tonic-gate activeCount = node_count; 379*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 380*0Sstevel@tonic-gate } else 381*0Sstevel@tonic-gate freedirlist(listhead); 382*0Sstevel@tonic-gate /* 383*0Sstevel@tonic-gate * Get the minfree value. If minfree comes in via the attribute 384*0Sstevel@tonic-gate * list, ignore the possibility it may also be listed on a separate 385*0Sstevel@tonic-gate * audit_control line. 386*0Sstevel@tonic-gate */ 387*0Sstevel@tonic-gate if (minfreestr != NULL) 388*0Sstevel@tonic-gate temp_minfree = atoi(minfreestr); 389*0Sstevel@tonic-gate else if (!(_getacmin(ach, &temp_minfree) == 0)) 390*0Sstevel@tonic-gate temp_minfree = 0; 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate if ((temp_minfree < 0) || (temp_minfree > 100)) 393*0Sstevel@tonic-gate temp_minfree = 0; 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate if (minfree != temp_minfree) { 396*0Sstevel@tonic-gate DPRINT((dbfp, "minfree: old = %d, new = %d\n", 397*0Sstevel@tonic-gate minfree, temp_minfree)); 398*0Sstevel@tonic-gate rc = -2; /* data change */ 399*0Sstevel@tonic-gate minfree = temp_minfree; 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate _endac(ach); 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate return (rc); 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate /* 408*0Sstevel@tonic-gate * getauditdate - get the current time (GMT) and put it in the form 409*0Sstevel@tonic-gate * yyyymmddHHMMSS . 410*0Sstevel@tonic-gate */ 411*0Sstevel@tonic-gate static void 412*0Sstevel@tonic-gate getauditdate(char *date) 413*0Sstevel@tonic-gate { 414*0Sstevel@tonic-gate struct timeval tp; 415*0Sstevel@tonic-gate struct timezone tzp; 416*0Sstevel@tonic-gate struct tm tm; 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate (void) gettimeofday(&tp, &tzp); 419*0Sstevel@tonic-gate tm = *gmtime(&tp.tv_sec); 420*0Sstevel@tonic-gate /* 421*0Sstevel@tonic-gate * NOTE: if we want to use gmtime, we have to be aware that the 422*0Sstevel@tonic-gate * structure only keeps the year as an offset from TM_YEAR_BASE. 423*0Sstevel@tonic-gate * I have used TM_YEAR_BASE in this code so that if they change 424*0Sstevel@tonic-gate * this base from 1900 to 2000, it will hopefully mean that this 425*0Sstevel@tonic-gate * code does not have to change. TM_YEAR_BASE is defined in 426*0Sstevel@tonic-gate * tzfile.h . 427*0Sstevel@tonic-gate */ 428*0Sstevel@tonic-gate (void) sprintf(date, "%.4d%.2d%.2d%.2d%.2d%.2d", 429*0Sstevel@tonic-gate tm.tm_year + TM_YEAR_BASE, tm.tm_mon + 1, tm.tm_mday, 430*0Sstevel@tonic-gate tm.tm_hour, tm.tm_min, tm.tm_sec); 431*0Sstevel@tonic-gate } 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate /* 436*0Sstevel@tonic-gate * write_file_token - put the file token into the audit log 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate static int 439*0Sstevel@tonic-gate write_file_token(int fd, char *name) 440*0Sstevel@tonic-gate { 441*0Sstevel@tonic-gate adr_t adr; /* xdr ptr */ 442*0Sstevel@tonic-gate struct timeval tv; /* time now */ 443*0Sstevel@tonic-gate char for_adr[AUDIT_FNAME_SZ + AUDIT_FNAME_SZ]; /* plenty of room */ 444*0Sstevel@tonic-gate char token_id; 445*0Sstevel@tonic-gate short i; 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate (void) gettimeofday(&tv, (struct timezone *)0); 448*0Sstevel@tonic-gate i = strlen(name) + 1; 449*0Sstevel@tonic-gate adr_start(&adr, for_adr); 450*0Sstevel@tonic-gate #ifdef _LP64 451*0Sstevel@tonic-gate token_id = AUT_OTHER_FILE64; 452*0Sstevel@tonic-gate adr_char(&adr, &token_id, 1); 453*0Sstevel@tonic-gate adr_int64(&adr, (int64_t *)& tv, 2); 454*0Sstevel@tonic-gate #else 455*0Sstevel@tonic-gate token_id = AUT_OTHER_FILE32; 456*0Sstevel@tonic-gate adr_char(&adr, &token_id, 1); 457*0Sstevel@tonic-gate adr_int32(&adr, (int32_t *)& tv, 2); 458*0Sstevel@tonic-gate #endif 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate adr_short(&adr, &i, 1); 461*0Sstevel@tonic-gate adr_char(&adr, name, i); 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate if (write(fd, for_adr, adr_count(&adr)) < 0) { 464*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: Bad write\n")); 465*0Sstevel@tonic-gate return (errno); 466*0Sstevel@tonic-gate } 467*0Sstevel@tonic-gate return (0); 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate /* 471*0Sstevel@tonic-gate * close_log - close the file if open. Also put the name of the 472*0Sstevel@tonic-gate * new log file in the trailer, and rename the old file 473*0Sstevel@tonic-gate * to oldname. The caller must hold log_mutext while calling 474*0Sstevel@tonic-gate * close_log since any change to activeDir is a complete redo 475*0Sstevel@tonic-gate * of all it points to. 476*0Sstevel@tonic-gate * arguments - 477*0Sstevel@tonic-gate * oldname - the new name for the file to be closed 478*0Sstevel@tonic-gate * newname - the name of the new log file (for the trailer) 479*0Sstevel@tonic-gate */ 480*0Sstevel@tonic-gate static void 481*0Sstevel@tonic-gate close_log(dirlist_t *currentdir, char *oname, char *newname) 482*0Sstevel@tonic-gate { 483*0Sstevel@tonic-gate char auditdate[AUDIT_DATE_SZ+1]; 484*0Sstevel@tonic-gate char *name; 485*0Sstevel@tonic-gate char oldname[AUDIT_FNAME_SZ+1]; 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate if ((currentdir == NULL) || (currentdir->dl_fd == -1)) 488*0Sstevel@tonic-gate return; 489*0Sstevel@tonic-gate /* 490*0Sstevel@tonic-gate * If oldname is blank, we were called by auditd_plugin_close() 491*0Sstevel@tonic-gate * instead of by open_log, so we need to update our name. 492*0Sstevel@tonic-gate */ 493*0Sstevel@tonic-gate (void) strlcpy(oldname, oname, AUDIT_FNAME_SZ); 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate if (strcmp(oldname, "") == 0) { 496*0Sstevel@tonic-gate getauditdate(auditdate); 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate assert(currentdir->dl_filename != NULL); 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate (void) strlcpy(oldname, currentdir->dl_filename, 501*0Sstevel@tonic-gate AUDIT_FNAME_SZ); 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate name = strrchr(oldname, '/') + 1; 504*0Sstevel@tonic-gate (void) memcpy(name + AUDIT_DATE_SZ + 1, auditdate, 505*0Sstevel@tonic-gate AUDIT_DATE_SZ); 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate /* 508*0Sstevel@tonic-gate * Write the trailer record and rename and close the file. 509*0Sstevel@tonic-gate * If any of the write, rename, or close fail, ignore it 510*0Sstevel@tonic-gate * since there is not much else we can do and the next open() 511*0Sstevel@tonic-gate * will trigger the necessary full directory logic. 512*0Sstevel@tonic-gate * 513*0Sstevel@tonic-gate * newname is "" if binfile is being closed down. 514*0Sstevel@tonic-gate */ 515*0Sstevel@tonic-gate (void) write_file_token(currentdir->dl_fd, newname); 516*0Sstevel@tonic-gate if (currentdir->dl_fd >= 0) 517*0Sstevel@tonic-gate (void) close(currentdir->dl_fd); 518*0Sstevel@tonic-gate currentdir->dl_fd = -1; 519*0Sstevel@tonic-gate (void) rename(currentdir->dl_filename, oldname); 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: Log closed %s\n", oldname)); 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate free(currentdir->dl_filename); 524*0Sstevel@tonic-gate currentdir->dl_filename = NULL; 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate /* 529*0Sstevel@tonic-gate * open_log - open a new file in the current directory. If a 530*0Sstevel@tonic-gate * file is already open, close it. 531*0Sstevel@tonic-gate * 532*0Sstevel@tonic-gate * return 1 if ok, 0 if all directories are full. 533*0Sstevel@tonic-gate * 534*0Sstevel@tonic-gate * lastOpenDir - used to get the oldfile name (and change it), 535*0Sstevel@tonic-gate * to close the oldfile. 536*0Sstevel@tonic-gate * 537*0Sstevel@tonic-gate * The caller must hold log_mutex while calling open_log. 538*0Sstevel@tonic-gate * 539*0Sstevel@tonic-gate */ 540*0Sstevel@tonic-gate static int 541*0Sstevel@tonic-gate open_log(dirlist_t *current_dir) 542*0Sstevel@tonic-gate { 543*0Sstevel@tonic-gate char auditdate[AUDIT_DATE_SZ + 1]; 544*0Sstevel@tonic-gate char oldname[AUDIT_FNAME_SZ + 1] = ""; 545*0Sstevel@tonic-gate char newname[AUDIT_FNAME_SZ + 1]; 546*0Sstevel@tonic-gate char *name; /* pointer into oldname */ 547*0Sstevel@tonic-gate int opened; 548*0Sstevel@tonic-gate int error = 0; 549*0Sstevel@tonic-gate int newfd = 0; 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate static char host[MAXHOSTNAMELEN + 1] = ""; 552*0Sstevel@tonic-gate /* previous directory with open log file */ 553*0Sstevel@tonic-gate static dirlist_t *lastOpenDir = NULL; 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate if (host[0] == '\0') 556*0Sstevel@tonic-gate (void) gethostname(host, MAXHOSTNAMELEN); 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate /* Get a filename which does not already exist */ 559*0Sstevel@tonic-gate opened = 0; 560*0Sstevel@tonic-gate while (!opened) { 561*0Sstevel@tonic-gate getauditdate(auditdate); 562*0Sstevel@tonic-gate (void) snprintf(newname, AUDIT_FNAME_SZ, 563*0Sstevel@tonic-gate "%s/%s.not_terminated.%s", 564*0Sstevel@tonic-gate current_dir->dl_dirname, auditdate, host); 565*0Sstevel@tonic-gate newfd = open(newname, 566*0Sstevel@tonic-gate O_RDWR | O_APPEND | O_CREAT | O_EXCL, 0600); 567*0Sstevel@tonic-gate if (newfd < 0) { 568*0Sstevel@tonic-gate switch (errno) { 569*0Sstevel@tonic-gate case EEXIST: 570*0Sstevel@tonic-gate DPRINT((dbfp, 571*0Sstevel@tonic-gate "open_log says duplicate for %s " 572*0Sstevel@tonic-gate "(will try another)\n", newname)); 573*0Sstevel@tonic-gate (void) sleep(1); 574*0Sstevel@tonic-gate break; 575*0Sstevel@tonic-gate default: 576*0Sstevel@tonic-gate /* open failed */ 577*0Sstevel@tonic-gate DPRINT((dbfp, 578*0Sstevel@tonic-gate "open_log says full for %s: %s\n", 579*0Sstevel@tonic-gate newname, strerror(errno))); 580*0Sstevel@tonic-gate current_dir->dl_space = SPACE_FULL; 581*0Sstevel@tonic-gate current_dir = current_dir->dl_next; 582*0Sstevel@tonic-gate return (0); 583*0Sstevel@tonic-gate } /* switch */ 584*0Sstevel@tonic-gate } else 585*0Sstevel@tonic-gate opened = 1; 586*0Sstevel@tonic-gate } /* while */ 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate /* 589*0Sstevel@tonic-gate * When we get here, we have opened our new log file. 590*0Sstevel@tonic-gate * Now we need to update the name of the old file to 591*0Sstevel@tonic-gate * store in this file's header. lastOpenDir may point 592*0Sstevel@tonic-gate * to current_dir if the list is only one entry long and 593*0Sstevel@tonic-gate * there is only one list. 594*0Sstevel@tonic-gate */ 595*0Sstevel@tonic-gate if ((lastOpenDir != NULL) && (lastOpenDir->dl_filename != NULL)) { 596*0Sstevel@tonic-gate (void) strlcpy(oldname, lastOpenDir->dl_filename, 597*0Sstevel@tonic-gate AUDIT_FNAME_SZ); 598*0Sstevel@tonic-gate name = (char *)strrchr(oldname, '/') + 1; 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate (void) memcpy(name + AUDIT_DATE_SZ + 1, auditdate, 601*0Sstevel@tonic-gate AUDIT_DATE_SZ); 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate close_log(lastOpenDir, oldname, newname); 604*0Sstevel@tonic-gate } 605*0Sstevel@tonic-gate error = write_file_token(newfd, oldname); 606*0Sstevel@tonic-gate if (error) { 607*0Sstevel@tonic-gate /* write token failed */ 608*0Sstevel@tonic-gate (void) close(newfd); 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate current_dir->dl_space = SPACE_FULL; 611*0Sstevel@tonic-gate current_dir->dl_fd = -1; 612*0Sstevel@tonic-gate free(current_dir->dl_filename); 613*0Sstevel@tonic-gate current_dir->dl_filename = NULL; 614*0Sstevel@tonic-gate current_dir = current_dir->dl_next; 615*0Sstevel@tonic-gate return (0); 616*0Sstevel@tonic-gate } else { 617*0Sstevel@tonic-gate lastOpenDir = current_dir; 618*0Sstevel@tonic-gate current_dir->dl_fd = newfd; 619*0Sstevel@tonic-gate current_dir->dl_filename = strdup(newname); 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate __logpost(newname); 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: Log opened: %s\n", newname)); 624*0Sstevel@tonic-gate return (1); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate #define IGNORE_SIZE 8192 629*0Sstevel@tonic-gate /* 630*0Sstevel@tonic-gate * spacecheck - determine whether the given directory's filesystem 631*0Sstevel@tonic-gate * has the at least the space requested. Also set the space 632*0Sstevel@tonic-gate * value in the directory list structure. If the caller 633*0Sstevel@tonic-gate * passes other than PLENTY_SPACE or SOFT_SPACE, the caller should 634*0Sstevel@tonic-gate * ignore the return value. Otherwise, 0 = less than the 635*0Sstevel@tonic-gate * requested space is available, 1 = at least the requested space 636*0Sstevel@tonic-gate * is available. 637*0Sstevel@tonic-gate * 638*0Sstevel@tonic-gate * log_mutex must be held by the caller 639*0Sstevel@tonic-gate * 640*0Sstevel@tonic-gate * -1 is returned if stat fails 641*0Sstevel@tonic-gate * 642*0Sstevel@tonic-gate * IGNORE_SIZE is one page (Sol 9 / 10 timeframe) and is the default 643*0Sstevel@tonic-gate * buffer size written for Sol 9 and earlier. To keep the same accuracy 644*0Sstevel@tonic-gate * for the soft limit check as before, spacecheck checks for space 645*0Sstevel@tonic-gate * remaining IGNORE_SIZE bytes. This reduces the number of statvfs() 646*0Sstevel@tonic-gate * calls and related math. 647*0Sstevel@tonic-gate * 648*0Sstevel@tonic-gate * globals - 649*0Sstevel@tonic-gate * minfree - the soft limit, i.e., the % of filesystem to reserve 650*0Sstevel@tonic-gate */ 651*0Sstevel@tonic-gate static int 652*0Sstevel@tonic-gate spacecheck(dirlist_t *thisdir, int test_limit, size_t next_buf_size) 653*0Sstevel@tonic-gate { 654*0Sstevel@tonic-gate struct statvfs sb; 655*0Sstevel@tonic-gate static int ignore_size = 0; 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate ignore_size += next_buf_size; 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate if ((test_limit == PLENTY_SPACE) && (ignore_size < IGNORE_SIZE)) 660*0Sstevel@tonic-gate return (1); 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate assert(thisdir != NULL); 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate if (thisdir->dl_space == STAY_FULL) { 665*0Sstevel@tonic-gate thisdir->dl_space = SPACE_FULL; 666*0Sstevel@tonic-gate minfreeblocks = AVAIL_MIN; 667*0Sstevel@tonic-gate } else if (statvfs(thisdir->dl_dirname, &sb) < 0) { 668*0Sstevel@tonic-gate thisdir->dl_space = SPACE_FULL; 669*0Sstevel@tonic-gate minfreeblocks = AVAIL_MIN; 670*0Sstevel@tonic-gate return (-1); 671*0Sstevel@tonic-gate } else { 672*0Sstevel@tonic-gate minfreeblocks = ((minfree * sb.f_blocks) / 100) + AVAIL_MIN; 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate if (sb.f_bavail < AVAIL_MIN) 675*0Sstevel@tonic-gate thisdir->dl_space = SPACE_FULL; 676*0Sstevel@tonic-gate else if (sb.f_bavail > minfreeblocks) 677*0Sstevel@tonic-gate thisdir->dl_space = PLENTY_SPACE; 678*0Sstevel@tonic-gate else 679*0Sstevel@tonic-gate thisdir->dl_space = SOFT_SPACE; 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate if (thisdir->dl_space == PLENTY_SPACE) 682*0Sstevel@tonic-gate return (1); 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate return (thisdir->dl_space == test_limit); 685*0Sstevel@tonic-gate } 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate /* 688*0Sstevel@tonic-gate * auditd_plugin() writes a buffer to the currently open file The 689*0Sstevel@tonic-gate * global "openNewFile" is used to force a new log file for the 690*0Sstevel@tonic-gate * initial open; for "audit -s" with changed audit_control data or 691*0Sstevel@tonic-gate * "audit -n" the new log file is opened immediately. 692*0Sstevel@tonic-gate * 693*0Sstevel@tonic-gate * This function manages one or more audit directories as follows: 694*0Sstevel@tonic-gate * 695*0Sstevel@tonic-gate * If the current open file is in a directory that has not 696*0Sstevel@tonic-gate * reached the soft limit, write the input data and return. 697*0Sstevel@tonic-gate * 698*0Sstevel@tonic-gate * Scan the list of directories for one which has not reached 699*0Sstevel@tonic-gate * the soft limit; if one is found, write and return. Such 700*0Sstevel@tonic-gate * a writable directory is in "PLENTY_SPACE" state. 701*0Sstevel@tonic-gate * 702*0Sstevel@tonic-gate * Scan the list of directories for one which has not reached 703*0Sstevel@tonic-gate * the hard limit; if one is found, write and return. This 704*0Sstevel@tonic-gate * directory in in "SOFT_SPACE" state. 705*0Sstevel@tonic-gate * 706*0Sstevel@tonic-gate * Oh, and if a write fails, handle it like a hard space limit. 707*0Sstevel@tonic-gate * 708*0Sstevel@tonic-gate * audit_warn (via __audit_dowarn()) is used to alert an operator 709*0Sstevel@tonic-gate * at various levels of fullness. 710*0Sstevel@tonic-gate */ 711*0Sstevel@tonic-gate /* ARGSUSED */ 712*0Sstevel@tonic-gate auditd_rc_t 713*0Sstevel@tonic-gate auditd_plugin(const char *input, size_t in_len, uint32_t sequence, char **error) 714*0Sstevel@tonic-gate { 715*0Sstevel@tonic-gate auditd_rc_t rc = AUDITD_FAIL; 716*0Sstevel@tonic-gate dirlist_t *startdir; 717*0Sstevel@tonic-gate int open_status; 718*0Sstevel@tonic-gate size_t out_len; 719*0Sstevel@tonic-gate /* LINTED */ 720*0Sstevel@tonic-gate int statrc; 721*0Sstevel@tonic-gate /* avoid excess audit_warnage */ 722*0Sstevel@tonic-gate static int somesoftfull_warning = 0; 723*0Sstevel@tonic-gate static int allsoftfull_warning = 0; 724*0Sstevel@tonic-gate #if DEBUG 725*0Sstevel@tonic-gate static char *last_file_written_to = NULL; 726*0Sstevel@tonic-gate static uint32_t last_sequence = 0; 727*0Sstevel@tonic-gate static uint32_t write_count = 0; 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate if ((last_sequence > 0) && (sequence != last_sequence + 1)) 730*0Sstevel@tonic-gate fprintf(dbfp, "binfile: buffer sequence=%d but prev=%d=n", 731*0Sstevel@tonic-gate sequence, last_sequence); 732*0Sstevel@tonic-gate last_sequence = sequence; 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate fprintf(dbfp, "binfile: input seq=%d, len=%d\n", 735*0Sstevel@tonic-gate sequence, in_len); 736*0Sstevel@tonic-gate #endif 737*0Sstevel@tonic-gate *error = NULL; 738*0Sstevel@tonic-gate /* 739*0Sstevel@tonic-gate * lock is for activeDir, referenced by open_log() and close_log() 740*0Sstevel@tonic-gate */ 741*0Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 742*0Sstevel@tonic-gate startdir = activeDir; 743*0Sstevel@tonic-gate while (rc == AUDITD_FAIL) { 744*0Sstevel@tonic-gate open_status = 1; 745*0Sstevel@tonic-gate if (openNewFile) { 746*0Sstevel@tonic-gate open_status = open_log(activeDir); 747*0Sstevel@tonic-gate if (open_status == 1) /* ok */ 748*0Sstevel@tonic-gate openNewFile = 0; 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate /* 751*0Sstevel@tonic-gate * consider "space ok" return and error return the same; 752*0Sstevel@tonic-gate * a -1 means spacecheck couldn't check for space. 753*0Sstevel@tonic-gate */ 754*0Sstevel@tonic-gate if ((open_status == 1) && 755*0Sstevel@tonic-gate (statrc = spacecheck(activeDir, fullness_state, 756*0Sstevel@tonic-gate in_len)) != 0) { 757*0Sstevel@tonic-gate #if DEBUG 758*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: returned from spacecheck\n")); 759*0Sstevel@tonic-gate /* 760*0Sstevel@tonic-gate * The last copy of last_file_written_to is 761*0Sstevel@tonic-gate * never free'd, so there will be one open 762*0Sstevel@tonic-gate * memory reference on exit. It's debug only. 763*0Sstevel@tonic-gate */ 764*0Sstevel@tonic-gate if ((last_file_written_to != NULL) && 765*0Sstevel@tonic-gate (strcmp(last_file_written_to, 766*0Sstevel@tonic-gate activeDir->dl_filename) != 0)) { 767*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: now writing to %s\n", 768*0Sstevel@tonic-gate activeDir->dl_filename)); 769*0Sstevel@tonic-gate free(last_file_written_to); 770*0Sstevel@tonic-gate } 771*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: finished some debug stuff\n")); 772*0Sstevel@tonic-gate last_file_written_to = 773*0Sstevel@tonic-gate strdup(activeDir->dl_filename); 774*0Sstevel@tonic-gate #endif 775*0Sstevel@tonic-gate out_len = write(activeDir->dl_fd, input, in_len); 776*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: finished the write\n")); 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate if (out_len == in_len) { 779*0Sstevel@tonic-gate DPRINT((dbfp, 780*0Sstevel@tonic-gate "binfile: write_count=%u, sequence=%u," 781*0Sstevel@tonic-gate " l=%u\n", 782*0Sstevel@tonic-gate ++write_count, sequence, out_len)); 783*0Sstevel@tonic-gate allsoftfull_warning = 0; 784*0Sstevel@tonic-gate if (fullness_state == PLENTY_SPACE) 785*0Sstevel@tonic-gate somesoftfull_warning = 0; 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate rc = AUDITD_SUCCESS; 788*0Sstevel@tonic-gate break; 789*0Sstevel@tonic-gate } else if (!activeDir->dl_flags & HARD_WARNED) { 790*0Sstevel@tonic-gate DPRINT((dbfp, 791*0Sstevel@tonic-gate "binfile: write failed, sequence=%u, " 792*0Sstevel@tonic-gate "l=%u\n", sequence, out_len)); 793*0Sstevel@tonic-gate DPRINT((dbfp, "hard warning sent.\n")); 794*0Sstevel@tonic-gate __audit_dowarn("hard", activeDir->dl_dirname, 795*0Sstevel@tonic-gate 0); 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate activeDir->dl_flags |= HARD_WARNED; 798*0Sstevel@tonic-gate } 799*0Sstevel@tonic-gate } else { 800*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: statrc=%d, fullness_state=%d\n", 801*0Sstevel@tonic-gate statrc, fullness_state)); 802*0Sstevel@tonic-gate somesoftfull_warning++; 803*0Sstevel@tonic-gate if ((somesoftfull_warning <= activeCount) && 804*0Sstevel@tonic-gate !(activeDir->dl_flags & SOFT_WARNED)) { 805*0Sstevel@tonic-gate DPRINT((dbfp, "soft warning sent\n")); 806*0Sstevel@tonic-gate __audit_dowarn("soft", 807*0Sstevel@tonic-gate activeDir->dl_dirname, 0); 808*0Sstevel@tonic-gate activeDir->dl_flags |= SOFT_WARNED; 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate if (!activeDir->dl_flags & HARD_WARNED) { 811*0Sstevel@tonic-gate DPRINT((dbfp, "hard warning sent.\n")); 812*0Sstevel@tonic-gate __audit_dowarn("hard", 813*0Sstevel@tonic-gate activeDir->dl_dirname, 0); 814*0Sstevel@tonic-gate activeDir->dl_flags |= HARD_WARNED; 815*0Sstevel@tonic-gate } 816*0Sstevel@tonic-gate } 817*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: activeDir=%s, next=%s\n", 818*0Sstevel@tonic-gate activeDir->dl_dirname, activeDir->dl_next->dl_dirname)); 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate activeDir = activeDir->dl_next; 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gate if (activeDir == startdir) { /* full circle */ 823*0Sstevel@tonic-gate if (fullness_state == PLENTY_SPACE) { /* once */ 824*0Sstevel@tonic-gate fullness_state = SOFT_SPACE; 825*0Sstevel@tonic-gate if (allsoftfull_warning == 0) { 826*0Sstevel@tonic-gate allsoftfull_warning++; 827*0Sstevel@tonic-gate __audit_dowarn("allsoft", "", 0); 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate } else { /* full circle twice */ 830*0Sstevel@tonic-gate __audit_dowarn("allhard", "", ++hung_count); 831*0Sstevel@tonic-gate minfreeblocks = AVAIL_MIN; 832*0Sstevel@tonic-gate rc = AUDITD_RETRY; 833*0Sstevel@tonic-gate *error = strdup(gettext( 834*0Sstevel@tonic-gate "all partitions full\n")); 835*0Sstevel@tonic-gate __logpost(""); 836*0Sstevel@tonic-gate } 837*0Sstevel@tonic-gate } 838*0Sstevel@tonic-gate } 839*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate return (rc); 842*0Sstevel@tonic-gate } 843*0Sstevel@tonic-gate 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate /* 846*0Sstevel@tonic-gate * the open function uses getacdir() and getacmin to determine which 847*0Sstevel@tonic-gate * directories to use and when to switch. It takes no inputs. 848*0Sstevel@tonic-gate * 849*0Sstevel@tonic-gate * It may be called multiple times as auditd handles SIGHUP and SIGUSR1 850*0Sstevel@tonic-gate * corresponding to the audit(1M) flags -s and -n 851*0Sstevel@tonic-gate * 852*0Sstevel@tonic-gate * kvlist is NULL only if auditd caught a SIGUSR1, so after the first 853*0Sstevel@tonic-gate * time open is called, the reason is -s if kvlist != NULL and -n 854*0Sstevel@tonic-gate * otherwise. 855*0Sstevel@tonic-gate * 856*0Sstevel@tonic-gate */ 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate auditd_rc_t 859*0Sstevel@tonic-gate auditd_plugin_open(const kva_t *kvlist, char **ret_list, char **error) 860*0Sstevel@tonic-gate { 861*0Sstevel@tonic-gate int rc = 0; 862*0Sstevel@tonic-gate int status; 863*0Sstevel@tonic-gate int reason; 864*0Sstevel@tonic-gate char *dirlist; 865*0Sstevel@tonic-gate char *minfree; 866*0Sstevel@tonic-gate kva_t *kv; 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate *error = NULL; 869*0Sstevel@tonic-gate *ret_list = NULL; 870*0Sstevel@tonic-gate kv = (kva_t *)kvlist; 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate if (am_open) { 873*0Sstevel@tonic-gate if (kvlist == NULL) 874*0Sstevel@tonic-gate reason = 1; /* audit -n */ 875*0Sstevel@tonic-gate else 876*0Sstevel@tonic-gate reason = 2; /* audit -s */ 877*0Sstevel@tonic-gate } else { 878*0Sstevel@tonic-gate reason = 0; /* initial open */ 879*0Sstevel@tonic-gate #if DEBUG 880*0Sstevel@tonic-gate dbfp = __auditd_debug_file_open(); 881*0Sstevel@tonic-gate #endif 882*0Sstevel@tonic-gate } 883*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: am_open=%d, reason=%d\n", am_open, reason)); 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate am_open = 1; 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate if (kvlist == NULL) { 888*0Sstevel@tonic-gate dirlist = NULL; 889*0Sstevel@tonic-gate minfree = NULL; 890*0Sstevel@tonic-gate } else { 891*0Sstevel@tonic-gate dirlist = kva_match(kv, "p_dir"); 892*0Sstevel@tonic-gate minfree = kva_match(kv, "p_minfree"); 893*0Sstevel@tonic-gate } 894*0Sstevel@tonic-gate switch (reason) { 895*0Sstevel@tonic-gate case 0: /* initial open */ 896*0Sstevel@tonic-gate if (!binfile_is_open) 897*0Sstevel@tonic-gate (void) pthread_mutex_init(&log_mutex, NULL); 898*0Sstevel@tonic-gate binfile_is_open = 1; 899*0Sstevel@tonic-gate openNewFile = 1; 900*0Sstevel@tonic-gate /* FALLTHRU */ 901*0Sstevel@tonic-gate case 2: /* audit -s */ 902*0Sstevel@tonic-gate fullness_state = PLENTY_SPACE; 903*0Sstevel@tonic-gate status = loadauditlist(dirlist, minfree); 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate if (status == -1) { 906*0Sstevel@tonic-gate __logpost(""); 907*0Sstevel@tonic-gate *error = strdup(gettext("no directories configured")); 908*0Sstevel@tonic-gate return (AUDITD_RETRY); 909*0Sstevel@tonic-gate } else if (status == AUDITD_NO_MEMORY) { 910*0Sstevel@tonic-gate __logpost(""); 911*0Sstevel@tonic-gate *error = strdup(gettext("no memory")); 912*0Sstevel@tonic-gate return (status); 913*0Sstevel@tonic-gate } else { /* status is 0 or -2 (no change or changed) */ 914*0Sstevel@tonic-gate hung_count = 0; 915*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: loadauditlist returned %d\n", 916*0Sstevel@tonic-gate status)); 917*0Sstevel@tonic-gate } 918*0Sstevel@tonic-gate break; 919*0Sstevel@tonic-gate case 1: /* audit -n */ 920*0Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 921*0Sstevel@tonic-gate if (open_log(activeDir) == 1) /* ok */ 922*0Sstevel@tonic-gate openNewFile = 0; 923*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 924*0Sstevel@tonic-gate break; 925*0Sstevel@tonic-gate } 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate rc = AUDITD_SUCCESS; 928*0Sstevel@tonic-gate *ret_list = NULL; 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate return (rc); 931*0Sstevel@tonic-gate } 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate auditd_rc_t 934*0Sstevel@tonic-gate auditd_plugin_close(char **error) 935*0Sstevel@tonic-gate { 936*0Sstevel@tonic-gate *error = NULL; 937*0Sstevel@tonic-gate 938*0Sstevel@tonic-gate (void) pthread_mutex_lock(&log_mutex); 939*0Sstevel@tonic-gate close_log(activeDir, "", ""); 940*0Sstevel@tonic-gate freedirlist(activeDir); 941*0Sstevel@tonic-gate activeDir = NULL; 942*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&log_mutex); 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate DPRINT((dbfp, "binfile: closed\n")); 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate if (binfile_is_open) { 947*0Sstevel@tonic-gate (void) pthread_mutex_destroy(&log_mutex); 948*0Sstevel@tonic-gate binfile_is_open = 0; 949*0Sstevel@tonic-gate /* LINTED */ 950*0Sstevel@tonic-gate } else { 951*0Sstevel@tonic-gate DPRINT((dbfp, 952*0Sstevel@tonic-gate "auditd_plugin_close() called when already closed.")); 953*0Sstevel@tonic-gate } 954*0Sstevel@tonic-gate am_open = 0; 955*0Sstevel@tonic-gate return (AUDITD_SUCCESS); 956*0Sstevel@tonic-gate } 957