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