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 * private interfaces for auditd plugins and auditd. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #include <bsm/audit.h> 31*0Sstevel@tonic-gate #include <bsm/audit_record.h> 32*0Sstevel@tonic-gate #include <bsm/audit_uevents.h> 33*0Sstevel@tonic-gate #include <bsm/libbsm.h> 34*0Sstevel@tonic-gate #include <errno.h> 35*0Sstevel@tonic-gate #include <fcntl.h> 36*0Sstevel@tonic-gate #include <libintl.h> 37*0Sstevel@tonic-gate #include <pthread.h> 38*0Sstevel@tonic-gate #include <stdio.h> 39*0Sstevel@tonic-gate #include <stdlib.h> 40*0Sstevel@tonic-gate #include <string.h> 41*0Sstevel@tonic-gate #include <sys/file.h> 42*0Sstevel@tonic-gate #include <sys/stat.h> 43*0Sstevel@tonic-gate #include <sys/types.h> 44*0Sstevel@tonic-gate #include <syslog.h> 45*0Sstevel@tonic-gate #include <unistd.h> 46*0Sstevel@tonic-gate #include <wait.h> 47*0Sstevel@tonic-gate #include "audit_plugin.h" 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate static char auditwarn[] = "/etc/security/audit_warn"; 50*0Sstevel@tonic-gate static pthread_mutex_t syslog_lock; 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate static void 53*0Sstevel@tonic-gate init_syslog_mutex() 54*0Sstevel@tonic-gate { 55*0Sstevel@tonic-gate (void) pthread_mutex_init(&syslog_lock, NULL); 56*0Sstevel@tonic-gate } 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate /* 59*0Sstevel@tonic-gate * audit_syslog() -- generate syslog messages from threads that use 60*0Sstevel@tonic-gate * different severity, facility code, and application names. 61*0Sstevel@tonic-gate * 62*0Sstevel@tonic-gate * The syslog() call does NOT use its format capability since the 63*0Sstevel@tonic-gate * format string is used for generating the ID, and I want equal 64*0Sstevel@tonic-gate * ID's to really be equal. 65*0Sstevel@tonic-gate * 66*0Sstevel@tonic-gate * syslog(3C) is thread safe, but the set openlog() / syslog() / 67*0Sstevel@tonic-gate * closelog() is not. 68*0Sstevel@tonic-gate * 69*0Sstevel@tonic-gate * Assumption: the app_name and facility code are paired, i.e., 70*0Sstevel@tonic-gate * if the facility code for this call is the same as for the 71*0Sstevel@tonic-gate * the previous, the app_name hasn't changed. 72*0Sstevel@tonic-gate */ 73*0Sstevel@tonic-gate void 74*0Sstevel@tonic-gate __audit_syslog( 75*0Sstevel@tonic-gate const char *app_name, 76*0Sstevel@tonic-gate int flags, 77*0Sstevel@tonic-gate int facility, 78*0Sstevel@tonic-gate int severity, 79*0Sstevel@tonic-gate const char *message) 80*0Sstevel@tonic-gate { 81*0Sstevel@tonic-gate pthread_once_t once_control = PTHREAD_ONCE_INIT; 82*0Sstevel@tonic-gate static int logopen = 0; 83*0Sstevel@tonic-gate static int prev_facility = -1; 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate (void) pthread_once(&once_control, init_syslog_mutex); 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate (void) pthread_mutex_lock(&syslog_lock); 88*0Sstevel@tonic-gate if (prev_facility != facility) { 89*0Sstevel@tonic-gate if (logopen) 90*0Sstevel@tonic-gate closelog(); 91*0Sstevel@tonic-gate openlog(app_name, flags, facility); 92*0Sstevel@tonic-gate syslog(severity, message); 93*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&syslog_lock); 94*0Sstevel@tonic-gate } else { 95*0Sstevel@tonic-gate syslog(severity, message); 96*0Sstevel@tonic-gate (void) pthread_mutex_unlock(&syslog_lock); 97*0Sstevel@tonic-gate } 98*0Sstevel@tonic-gate } 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate /* 101*0Sstevel@tonic-gate * __audit_dowarn - invoke the shell script auditwarn to notify the 102*0Sstevel@tonic-gate * adminstrator about a given problem. 103*0Sstevel@tonic-gate * parameters - 104*0Sstevel@tonic-gate * option - what the problem is 105*0Sstevel@tonic-gate * text - when used with options soft and hard: which file was being 106*0Sstevel@tonic-gate * used when the filesystem filled up 107*0Sstevel@tonic-gate * when used with the plugin option: error detail 108*0Sstevel@tonic-gate * count - used with various options: how many times auditwarn has 109*0Sstevel@tonic-gate * been called for this problem since it was last cleared. 110*0Sstevel@tonic-gate */ 111*0Sstevel@tonic-gate void 112*0Sstevel@tonic-gate __audit_dowarn(char *option, char *text, int count) 113*0Sstevel@tonic-gate { 114*0Sstevel@tonic-gate pid_t pid; 115*0Sstevel@tonic-gate int st; 116*0Sstevel@tonic-gate char countstr[5]; 117*0Sstevel@tonic-gate char warnstring[80]; 118*0Sstevel@tonic-gate char empty[1] = ""; 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate if ((pid = fork1()) == -1) { 121*0Sstevel@tonic-gate __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, 122*0Sstevel@tonic-gate LOG_DAEMON, LOG_ALERT, gettext("audit_warn fork failed\n")); 123*0Sstevel@tonic-gate return; 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate if (pid != 0) { 126*0Sstevel@tonic-gate (void) waitpid(pid, &st, 0); 127*0Sstevel@tonic-gate return; 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate (void) sprintf(countstr, "%d", count); 130*0Sstevel@tonic-gate if (text == NULL) 131*0Sstevel@tonic-gate text = empty; 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate if (strcmp(option, "soft") == 0 || strcmp(option, "hard") == 0) 134*0Sstevel@tonic-gate (void) execl(auditwarn, auditwarn, option, text, 0); 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate else if (strcmp(option, "allhard") == 0 || 137*0Sstevel@tonic-gate strcmp(option, "getacdir") == 0) 138*0Sstevel@tonic-gate (void) execl(auditwarn, auditwarn, option, countstr, 0); 139*0Sstevel@tonic-gate else if (strcmp(option, "plugin") == 0) 140*0Sstevel@tonic-gate (void) execl(auditwarn, auditwarn, option, text, countstr, 0); 141*0Sstevel@tonic-gate else 142*0Sstevel@tonic-gate (void) execl(auditwarn, auditwarn, option, 0); 143*0Sstevel@tonic-gate /* 144*0Sstevel@tonic-gate * (execl failed) 145*0Sstevel@tonic-gate */ 146*0Sstevel@tonic-gate if (strcmp(option, "soft") == 0) 147*0Sstevel@tonic-gate (void) sprintf(warnstring, 148*0Sstevel@tonic-gate gettext("soft limit in %s.\n"), text); 149*0Sstevel@tonic-gate else if (strcmp(option, "hard") == 0) 150*0Sstevel@tonic-gate (void) sprintf(warnstring, 151*0Sstevel@tonic-gate gettext("hard limit in %s.\n"), text); 152*0Sstevel@tonic-gate else if (strcmp(option, "allhard") == 0) 153*0Sstevel@tonic-gate (void) sprintf(warnstring, 154*0Sstevel@tonic-gate gettext("All audit filesystems are full.\n")); 155*0Sstevel@tonic-gate else if (strcmp(option, "getacmin") == 0) 156*0Sstevel@tonic-gate (void) sprintf(warnstring, 157*0Sstevel@tonic-gate gettext("audit_control minfree error.\n")); 158*0Sstevel@tonic-gate else if (strcmp(option, "getacdir") == 0) 159*0Sstevel@tonic-gate (void) sprintf(warnstring, 160*0Sstevel@tonic-gate gettext("audit_control directory error.\n")); 161*0Sstevel@tonic-gate else 162*0Sstevel@tonic-gate (void) sprintf(warnstring, 163*0Sstevel@tonic-gate gettext("error %s.\n"), option); 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, LOG_AUTH, 166*0Sstevel@tonic-gate LOG_ALERT, (const char *)warnstring); 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate exit(1); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate /* 172*0Sstevel@tonic-gate * __audit_dowarn2 - invoke the shell script auditwarn to notify the 173*0Sstevel@tonic-gate * adminstrator about a given problem. 174*0Sstevel@tonic-gate * parameters - 175*0Sstevel@tonic-gate * option - what the problem is 176*0Sstevel@tonic-gate * name - entity reporting the problem (ie, plugin name) 177*0Sstevel@tonic-gate * error - error string 178*0Sstevel@tonic-gate * text - when used with options soft and hard: which file was being 179*0Sstevel@tonic-gate * used when the filesystem filled up 180*0Sstevel@tonic-gate * when used with the plugin option: error detail 181*0Sstevel@tonic-gate * count - used with various options: how many times auditwarn has 182*0Sstevel@tonic-gate * been called for this problem since it was last cleared. 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate void 185*0Sstevel@tonic-gate __audit_dowarn2(char *option, char *name, char *error, char *text, int count) 186*0Sstevel@tonic-gate { 187*0Sstevel@tonic-gate pid_t pid; 188*0Sstevel@tonic-gate int st; 189*0Sstevel@tonic-gate char countstr[5]; 190*0Sstevel@tonic-gate char warnstring[80]; 191*0Sstevel@tonic-gate char empty[4] = "..."; 192*0Sstevel@tonic-gate char none[3] = "--"; 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate if ((pid = fork()) == -1) { 195*0Sstevel@tonic-gate __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, 196*0Sstevel@tonic-gate LOG_DAEMON, LOG_ALERT, gettext("audit_warn fork failed\n")); 197*0Sstevel@tonic-gate return; 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate if (pid != 0) { 200*0Sstevel@tonic-gate (void) waitpid(pid, &st, 0); 201*0Sstevel@tonic-gate return; 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate (void) sprintf(countstr, "%d", count); 204*0Sstevel@tonic-gate if ((text == NULL) || (*text == '\0')) 205*0Sstevel@tonic-gate text = empty; 206*0Sstevel@tonic-gate if ((name == NULL) || (*name == '\0')) 207*0Sstevel@tonic-gate name = none; 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate (void) execl(auditwarn, auditwarn, option, name, error, text, 210*0Sstevel@tonic-gate countstr, 0); 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate /* 213*0Sstevel@tonic-gate * (execl failed) 214*0Sstevel@tonic-gate */ 215*0Sstevel@tonic-gate (void) sprintf(warnstring, 216*0Sstevel@tonic-gate gettext("audit_control plugin error: %s\n"), text); 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, LOG_AUTH, 219*0Sstevel@tonic-gate LOG_ALERT, (const char *)warnstring); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate exit(1); 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* 225*0Sstevel@tonic-gate * logpost - post the new audit log file name to audit_data. 226*0Sstevel@tonic-gate * 227*0Sstevel@tonic-gate * This is not re-entrant code; it is called from auditd.c when 228*0Sstevel@tonic-gate * audit_binfile.so is not running and from binfile after auditd 229*0Sstevel@tonic-gate * is done. 230*0Sstevel@tonic-gate */ 231*0Sstevel@tonic-gate int 232*0Sstevel@tonic-gate __logpost(char *name) 233*0Sstevel@tonic-gate { 234*0Sstevel@tonic-gate char buffer[MAXPATHLEN]; 235*0Sstevel@tonic-gate char empty[] = ""; 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate static int first = 1; 238*0Sstevel@tonic-gate static char auditdata[] = AUDITDATAFILE; 239*0Sstevel@tonic-gate static int audit_data_fd; /* file descriptor of audit_data */ 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate if (first) { 242*0Sstevel@tonic-gate first = 0; 243*0Sstevel@tonic-gate /* 244*0Sstevel@tonic-gate * Open the audit_data file. Use O_APPEND so that the contents 245*0Sstevel@tonic-gate * are not destroyed if there is another auditd running. 246*0Sstevel@tonic-gate */ 247*0Sstevel@tonic-gate if ((audit_data_fd = open(auditdata, 248*0Sstevel@tonic-gate O_RDWR | O_APPEND | O_CREAT, 0660)) < 0) { 249*0Sstevel@tonic-gate __audit_dowarn("tmpfile", "", 0); 250*0Sstevel@tonic-gate return (1); 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate if (name == NULL) 254*0Sstevel@tonic-gate name = empty; 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate (void) snprintf(buffer, sizeof (buffer), "%d:%s\n", 257*0Sstevel@tonic-gate (int)getpid(), name); 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate (void) ftruncate(audit_data_fd, (off_t)0); 260*0Sstevel@tonic-gate (void) write(audit_data_fd, buffer, strlen(buffer)); 261*0Sstevel@tonic-gate (void) fsync(audit_data_fd); 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate return (0); 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate /* 267*0Sstevel@tonic-gate * debug use - open a file for auditd and its plugins for debug 268*0Sstevel@tonic-gate */ 269*0Sstevel@tonic-gate FILE * 270*0Sstevel@tonic-gate __auditd_debug_file_open() { 271*0Sstevel@tonic-gate static FILE *fp = NULL; 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate if (fp != NULL) 274*0Sstevel@tonic-gate return (fp); 275*0Sstevel@tonic-gate if ((fp = fopen("/var/audit/dump", "a")) == NULL) 276*0Sstevel@tonic-gate (void) fprintf(stderr, "failed to open debug file: %s\n", 277*0Sstevel@tonic-gate strerror(errno)); 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate return (fp); 280*0Sstevel@tonic-gate } 281