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 2008 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( 69 const char *app_name, 70 int flags, 71 int facility, 72 int severity, 73 const char *message) 74 { 75 static pthread_once_t once_control = PTHREAD_ONCE_INIT; 76 static int logopen = 0; 77 static int prev_facility = -1; 78 79 (void) pthread_once(&once_control, init_syslog_mutex); 80 81 (void) pthread_mutex_lock(&syslog_lock); 82 if (prev_facility != facility) { 83 if (logopen) 84 closelog(); 85 openlog(app_name, flags, facility); 86 syslog(severity, "%s", message); 87 (void) pthread_mutex_unlock(&syslog_lock); 88 } else { 89 syslog(severity, "%s", message); 90 (void) pthread_mutex_unlock(&syslog_lock); 91 } 92 } 93 94 /* 95 * __audit_dowarn - invoke the shell script auditwarn to notify the 96 * adminstrator about a given problem. 97 * parameters - 98 * option - what the problem is 99 * text - when used with options soft and hard: which file was being 100 * used when the filesystem filled up 101 * when used with the plugin option: error detail 102 * count - used with various options: how many times auditwarn has 103 * been called for this problem since it was last cleared. 104 */ 105 void 106 __audit_dowarn(char *option, char *text, int count) 107 { 108 pid_t pid; 109 int st; 110 char countstr[5]; 111 char warnstring[80]; 112 char empty[1] = ""; 113 114 if ((pid = fork1()) == -1) { 115 __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, 116 LOG_DAEMON, LOG_ALERT, gettext("audit_warn fork failed\n")); 117 return; 118 } 119 if (pid != 0) { 120 (void) waitpid(pid, &st, 0); 121 return; 122 } 123 (void) sprintf(countstr, "%d", count); 124 if (text == NULL) 125 text = empty; 126 127 if (strcmp(option, "soft") == 0 || strcmp(option, "hard") == 0) 128 (void) execl(auditwarn, auditwarn, option, text, 0); 129 130 else if (strcmp(option, "allhard") == 0 || 131 strcmp(option, "getacdir") == 0) 132 (void) execl(auditwarn, auditwarn, option, countstr, 0); 133 else if (strcmp(option, "plugin") == 0) 134 (void) execl(auditwarn, auditwarn, option, text, countstr, 0); 135 else 136 (void) execl(auditwarn, auditwarn, option, 0); 137 /* 138 * (execl failed) 139 */ 140 if (strcmp(option, "soft") == 0) 141 (void) sprintf(warnstring, 142 gettext("soft limit in %s.\n"), text); 143 else if (strcmp(option, "hard") == 0) 144 (void) sprintf(warnstring, 145 gettext("hard limit in %s.\n"), text); 146 else if (strcmp(option, "allhard") == 0) 147 (void) sprintf(warnstring, 148 gettext("All audit filesystems are full.\n")); 149 else if (strcmp(option, "getacmin") == 0) 150 (void) sprintf(warnstring, 151 gettext("audit_control minfree error.\n")); 152 else if (strcmp(option, "getacdir") == 0) 153 (void) sprintf(warnstring, 154 gettext("audit_control directory error.\n")); 155 else 156 (void) sprintf(warnstring, 157 gettext("error %s.\n"), option); 158 159 __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, LOG_AUTH, 160 LOG_ALERT, (const char *)warnstring); 161 162 exit(1); 163 } 164 165 /* 166 * __audit_dowarn2 - invoke the shell script auditwarn to notify the 167 * adminstrator about a given problem. 168 * parameters - 169 * option - what the problem is 170 * name - entity reporting the problem (ie, plugin name) 171 * error - error string 172 * text - when used with options soft and hard: which file was being 173 * used when the filesystem filled up 174 * when used with the plugin option: error detail 175 * count - used with various options: how many times auditwarn has 176 * been called for this problem since it was last cleared. 177 */ 178 void 179 __audit_dowarn2(char *option, char *name, char *error, char *text, int count) 180 { 181 pid_t pid; 182 int st; 183 char countstr[5]; 184 char warnstring[80]; 185 char empty[4] = "..."; 186 char none[3] = "--"; 187 188 if ((pid = fork()) == -1) { 189 __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, 190 LOG_DAEMON, LOG_ALERT, gettext("audit_warn fork failed\n")); 191 return; 192 } 193 if (pid != 0) { 194 (void) waitpid(pid, &st, 0); 195 return; 196 } 197 (void) sprintf(countstr, "%d", count); 198 if ((text == NULL) || (*text == '\0')) 199 text = empty; 200 if ((name == NULL) || (*name == '\0')) 201 name = none; 202 203 (void) execl(auditwarn, auditwarn, option, name, error, text, 204 countstr, 0); 205 206 /* 207 * (execl failed) 208 */ 209 (void) sprintf(warnstring, 210 gettext("audit_control plugin error: %s\n"), text); 211 212 __audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, LOG_AUTH, 213 LOG_ALERT, (const char *)warnstring); 214 215 exit(1); 216 } 217 218 /* 219 * logpost - post the new audit log file name to audit_data. 220 * 221 * This is not re-entrant code; it is called from auditd.c when 222 * audit_binfile.so is not running and from binfile after auditd 223 * is done. 224 */ 225 int 226 __logpost(char *name) 227 { 228 char buffer[MAXPATHLEN]; 229 char empty[] = ""; 230 231 static int first = 1; 232 static char auditdata[] = AUDITDATAFILE; 233 static int audit_data_fd; /* file descriptor of audit_data */ 234 235 if (first) { 236 first = 0; 237 /* 238 * Open the audit_data file. Use O_APPEND so that the contents 239 * are not destroyed if there is another auditd running. 240 */ 241 if ((audit_data_fd = open(auditdata, 242 O_RDWR | O_APPEND | O_CREAT, 0660)) < 0) { 243 __audit_dowarn("tmpfile", "", 0); 244 return (1); 245 } 246 } 247 if (name == NULL) 248 name = empty; 249 250 (void) snprintf(buffer, sizeof (buffer), "%d:%s\n", 251 (int)getpid(), name); 252 253 (void) ftruncate(audit_data_fd, (off_t)0); 254 (void) write(audit_data_fd, buffer, strlen(buffer)); 255 (void) fsync(audit_data_fd); 256 257 return (0); 258 } 259 260 /* 261 * debug use - open a file for auditd and its plugins for debug 262 */ 263 FILE * 264 __auditd_debug_file_open() { 265 static FILE *fp = NULL; 266 267 if (fp != NULL) 268 return (fp); 269 if ((fp = fopen("/var/audit/dump", "aF")) == NULL) 270 (void) fprintf(stderr, "failed to open debug file: %s\n", 271 strerror(errno)); 272 273 return (fp); 274 } 275