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
init_syslog_mutex()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
__audit_syslog(const char * app_name,int flags,int facility,int severity,const char * message)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
__audit_dowarn(char * option,char * text,int count)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
__audit_dowarn2(char * option,char * name,char * error,char * text,int count)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
__logpost(char * name)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 *
__auditd_debug_file_open()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