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