1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. 23 * 24 * private interfaces for auditd plugins and auditd. 25 */ 26 27 #include <bsm/audit.h> 28 #include <bsm/audit_record.h> 29 #include <bsm/audit_uevents.h> 30 #include <bsm/libbsm.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <libintl.h> 34 #include <pthread.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <sys/file.h> 39 #include <sys/stat.h> 40 #include <sys/types.h> 41 #include <syslog.h> 42 #include <unistd.h> 43 #include <wait.h> 44 #include "audit_plugin.h" 45 46 static char auditwarn[] = "/etc/security/audit_warn"; 47 static pthread_mutex_t syslog_lock; 48 49 static void 50 init_syslog_mutex() 51 { 52 (void) pthread_mutex_init(&syslog_lock, NULL); 53 } 54 55 /* 56 * audit_syslog() -- generate syslog messages from threads that use 57 * different severity, facility code, and application names. 58 * 59 * syslog(3C) is thread safe, but the set openlog() / syslog() / 60 * closelog() is not. 61 * 62 * Assumption: the app_name and facility code are paired, i.e., 63 * if the facility code for this call is the same as for the 64 * the previous, the app_name hasn't changed. 65 */ 66 void 67 __audit_syslog(const char *app_name, int flags, int facility, int severity, 68 const char *message) 69 { 70 static pthread_once_t once_control = PTHREAD_ONCE_INIT; 71 static int logopen = 0; 72 static int prev_facility = -1; 73 74 (void) pthread_once(&once_control, init_syslog_mutex); 75 76 (void) pthread_mutex_lock(&syslog_lock); 77 if (prev_facility != facility) { 78 if (logopen) 79 closelog(); 80 openlog(app_name, flags, facility); 81 syslog(severity, "%s", message); 82 (void) pthread_mutex_unlock(&syslog_lock); 83 } else { 84 syslog(severity, "%s", message); 85 (void) pthread_mutex_unlock(&syslog_lock); 86 } 87 } 88 89 /* 90 * __audit_dowarn - invoke the shell script auditwarn to notify the 91 * adminstrator about a given problem. 92 * parameters - 93 * option - what the problem is 94 * text - when used with options soft and hard: which file was being 95 * used when the filesystem filled up 96 * when used with the plugin option: error detail 97 * count - used with various options: how many times auditwarn has 98 * been called for this problem since it was last cleared. 99 */ 100 void 101 __audit_dowarn(char *option, char *text, int count) 102 { 103 pid_t pid; 104 int st; 105 char countstr[5]; 106 char warnstring[80]; 107 char empty[1] = ""; 108 109 if ((pid = fork1()) == -1) { 110 __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, 111 LOG_DAEMON, LOG_ALERT, gettext("audit_warn fork failed\n")); 112 return; 113 } 114 if (pid != 0) { 115 (void) waitpid(pid, &st, 0); 116 return; 117 } 118 (void) snprintf(countstr, 5, "%d", count); 119 if (text == NULL) 120 text = empty; 121 122 if (strcmp(option, "soft") == 0 || strcmp(option, "hard") == 0) 123 (void) execl(auditwarn, auditwarn, option, text, 0); 124 125 else if (strcmp(option, "allhard") == 0) 126 (void) execl(auditwarn, auditwarn, option, countstr, 0); 127 else if (strcmp(option, "plugin") == 0) 128 (void) execl(auditwarn, auditwarn, option, text, countstr, 0); 129 else 130 (void) execl(auditwarn, auditwarn, option, 0); 131 /* 132 * (execl failed) 133 */ 134 if (strcmp(option, "soft") == 0) 135 (void) snprintf(warnstring, 80, 136 gettext("soft limit in %s.\n"), text); 137 else if (strcmp(option, "hard") == 0) 138 (void) snprintf(warnstring, 80, 139 gettext("hard limit in %s.\n"), text); 140 else if (strcmp(option, "allhard") == 0) 141 (void) sprintf(warnstring, 142 gettext("All audit filesystems are full.\n")); 143 else 144 (void) snprintf(warnstring, 80, 145 gettext("error %s.\n"), option); 146 147 __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, LOG_AUTH, 148 LOG_ALERT, (const char *)warnstring); 149 150 exit(1); 151 } 152 153 /* 154 * __audit_dowarn2 - invoke the shell script auditwarn to notify the 155 * adminstrator about a given problem. 156 * parameters - 157 * option - what the problem is 158 * name - entity reporting the problem (ie, plugin name) 159 * error - error string 160 * text - when used with options soft and hard: which file was being 161 * used when the filesystem filled up 162 * when used with the plugin option: error detail 163 * count - used with various options: how many times auditwarn has 164 * been called for this problem since it was last cleared. 165 */ 166 void 167 __audit_dowarn2(char *option, char *name, char *error, char *text, int count) 168 { 169 pid_t pid; 170 int st; 171 char countstr[5]; 172 char warnstring[80]; 173 char empty[4] = "..."; 174 char none[3] = "--"; 175 176 if ((pid = fork()) == -1) { 177 __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, 178 LOG_DAEMON, LOG_ALERT, gettext("audit_warn fork failed\n")); 179 return; 180 } 181 if (pid != 0) { 182 (void) waitpid(pid, &st, 0); 183 return; 184 } 185 (void) snprintf(countstr, 5, "%d", count); 186 if ((text == NULL) || (*text == '\0')) 187 text = empty; 188 if ((name == NULL) || (*name == '\0')) 189 name = none; 190 191 (void) execl(auditwarn, auditwarn, option, name, error, text, 192 countstr, 0); 193 194 /* 195 * (execl failed) 196 */ 197 (void) snprintf(warnstring, 80, 198 gettext("%s plugin error: %s\n"), name, text); 199 200 __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, LOG_AUTH, 201 LOG_ALERT, (const char *)warnstring); 202 203 exit(1); 204 } 205 206 /* 207 * logpost - post the new audit log file name. 208 * 209 * Entry name = active audit.log file name 210 * NULL, if checking writability (auditd), 211 * changing audit log files, error, or exiting (binfile). 212 * 213 * Exit 0 = success 214 * 1 = system error -- errno 215 * audit_warn called with the specific error 216 * 217 */ 218 int 219 __logpost(char *name) 220 { 221 int lerrno; 222 223 if (unlink(BINFILE_FILE) != 0 && 224 errno != ENOENT) { 225 226 lerrno = errno; 227 __audit_dowarn("tmpfile", strerror(errno), 0); 228 errno = lerrno; 229 return (1); 230 } 231 if (name == NULL || *name == '\0') { 232 /* audit_binfile not active, no file pointer */ 233 return (0); 234 } 235 if (symlink(name, BINFILE_FILE) != 0) { 236 237 lerrno = errno; 238 __audit_dowarn("tmpfile", strerror(errno), 0); 239 errno = lerrno; 240 return (1); 241 } 242 243 return (0); 244 } 245 246 /* 247 * debug use - open a file for auditd and its plugins for debug 248 */ 249 FILE * 250 __auditd_debug_file_open() { 251 static FILE *fp = NULL; 252 253 if (fp != NULL) 254 return (fp); 255 if ((fp = fopen("/var/audit/dump", "aF")) == NULL) 256 (void) fprintf(stderr, "failed to open debug file: %s\n", 257 strerror(errno)); 258 259 return (fp); 260 } 261