Imported Upstream version 2.4.3
[platform/upstream/audit.git] / audisp / audispd-builtins.c
1 /*
2 * audispd-builtins.c - some common builtin plugins
3 * Copyright (c) 2007,2010,2013 Red Hat Inc., Durham, North Carolina.
4 * All Rights Reserved. 
5 *
6 * This software may be freely redistributed and/or modified under the
7 * terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * Authors:
21 *   Steve Grubb <sgrubb@redhat.com>
22 */
23
24 #include "config.h"
25 #include <string.h>
26 #include <dirent.h>
27 #include <libgen.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <sys/un.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include "audispd-pconfig.h"
36 #include "audispd-builtins.h"
37
38 // Local data
39 static volatile int sock = -1, conn = -1;
40 static int syslog_started = 0, priority;
41 static char *path = NULL;
42
43 // Local prototypes
44 static void init_af_unix(const plugin_conf_t *conf);
45 static void init_syslog(const plugin_conf_t *conf);
46
47
48 void start_builtin(plugin_conf_t *conf)
49 {
50         if (strcasecmp("builtin_af_unix", conf->path) == 0) {
51                 conf->type = S_AF_UNIX;
52                 init_af_unix(conf);
53         } else if (strcasecmp("builtin_syslog", conf->path) == 0) {
54                 conf->type = S_SYSLOG;
55                 init_syslog(conf);
56         } else
57                 syslog(LOG_ERR, "Unknown builtin %s", conf->path);
58 }
59
60 void stop_builtin(plugin_conf_t *conf)
61 {
62         if (conf->type == S_AF_UNIX)
63                 destroy_af_unix();
64         else if (conf->type == S_SYSLOG)
65                 destroy_syslog();
66         else
67                 syslog(LOG_ERR, "Unknown builtin %s", conf->path);
68 }
69
70 static void af_unix_accept(int fd)
71 {
72         int cmd;
73
74         do {
75                 conn = accept(fd, NULL, NULL);
76         } while (conn < 0 && errno == EINTR);
77
78         // De-register since this is intended to be one listener
79         if (conn >= 0)
80                 remove_event(fd);
81         cmd = fcntl(conn, F_GETFD);
82         fcntl(conn, F_SETFD, cmd|FD_CLOEXEC);
83 }
84
85 static int create_af_unix_socket(const char *path, int mode)
86 {
87         struct sockaddr_un addr;
88         socklen_t len;
89         int rc, cmd;
90
91         sock = socket(PF_UNIX, SOCK_STREAM, 0);
92         if (sock < 0) {
93                 syslog(LOG_ERR, "Couldn't open af_unix socket (%s)",
94                                 strerror(errno));
95                 return -1;
96         }
97         memset(&addr, 0, sizeof(addr));
98         addr.sun_family = AF_UNIX;
99         strcpy(&addr.sun_path[0], path);
100         len = sizeof(addr);
101         rc = bind(sock, (const struct sockaddr *)&addr, len);
102         if (rc < 0) {
103                 syslog(LOG_ERR, "Couldn't bind af_unix socket (%s)",
104                                 strerror(errno));
105                 destroy_af_unix();
106                 return -1;
107         }
108         if (mode != -1) { 
109                 rc = chmod(path, mode);
110                 if (rc < 0) {
111                         syslog(LOG_ERR, "Couldn't chmod %s to %04o (%s)",
112                                 path, mode, strerror(errno));
113                         destroy_af_unix();
114                         return -1;
115                 }
116         }
117
118         // Put socket in nonblock mode
119         cmd = fcntl(sock, F_GETFL);
120         fcntl(sock, F_SETFL, cmd|FNDELAY);
121
122         // don't leak the descriptor
123         cmd = fcntl(sock, F_GETFD);
124         fcntl(sock, F_SETFD, cmd|FD_CLOEXEC);
125
126         // Make socket listening...won't block
127         (void)listen(sock, 5);
128
129         // Register socket with poll
130         add_event(sock, af_unix_accept);
131         return 0;
132 }
133
134 static void init_af_unix(const plugin_conf_t *conf)
135 {
136         int i = 1, mode = -1;
137         char *base = NULL;
138
139         // while args
140         while (conf->args[i]) {
141                 int rc, bad = 0;
142
143                 // is all nums - do mode
144                 base = conf->args[i];
145                 while (*base) {
146                         if (!isdigit(*base)) {
147                                 bad = 1;
148                                 break;
149                         }
150                         base++;
151                 }
152                 if (!bad) {
153                         errno = 0;
154                         mode = strtoul(conf->args[i], NULL, 8);
155                         if (errno) {
156                                 syslog(LOG_ERR, "Error converting %s (%s)",
157                                         conf->args[i], strerror(errno));
158                                 mode = -1;
159                                 bad = 1;
160                         } else if (path) {
161                                 rc = chmod(path, mode);
162                                 if (rc < 0) {
163                                         syslog(LOG_ERR,
164                                             "Couldn't chmod %s to %04o (%s)",
165                                                 conf->args[i], mode,
166                                                 strerror(errno));
167                                         destroy_af_unix();
168                                         return;
169                                 }
170                         }
171                 } else {
172                         // else check for '/'
173                         base = strchr(conf->args[i], '/');
174                         if (base) {
175                                 // get dirname
176                                 DIR *d;
177                                 char *dir = strdup(conf->args[i]);
178                                 base = dirname(dir);
179                                 d = opendir(base);
180                                 if (d) {
181                                         closedir(d);
182                                         unlink(conf->args[i]);
183                                         if (create_af_unix_socket(
184                                                     conf->args[i], mode)<0) {
185                                                 free(dir);
186                                                 return;
187                                         }
188                                         path = strdup(conf->args[i]);
189                                         bad = 0;
190                                 } else
191                                         syslog(LOG_ERR, "Couldn't open %s (%s)",
192                                                 base, strerror(errno));
193                                 free(dir);
194                         } else 
195                                 syslog(LOG_ERR, "Malformed path %s",
196                                         conf->args[i]);
197                 }
198                 if (bad) {
199                         destroy_af_unix();
200                         return;
201                 }
202                 i++;
203         }
204         syslog(LOG_INFO, "af_unix plugin initialized");
205 }
206
207 void send_af_unix_string(const char *s, unsigned int len)
208 {
209         if (sock < 0) 
210                 return;
211
212         if (conn >= 0) {
213                 int rc;
214                 do {
215                         rc = write(conn, s, len);
216                 } while (rc < 0 && errno == EINTR);
217                 if (rc < 0 && errno == EPIPE) {
218                         close(conn);
219                         conn = -1;
220                         add_event(sock, af_unix_accept);
221                 }
222         } 
223 }
224
225 void send_af_unix_binary(event_t *e)
226 {
227         if (sock < 0) 
228                 return;
229
230         if (conn >= 0) {
231                 int rc;
232                 struct iovec vec[2];
233
234                 vec[0].iov_base = &e->hdr;
235                 vec[0].iov_len = sizeof(struct audit_dispatcher_header);
236                 vec[1].iov_base = e->data;
237                 vec[1].iov_len = MAX_AUDIT_MESSAGE_LENGTH;
238                 do {
239                         rc = writev(conn, vec, 2);
240                 } while (rc < 0 && errno == EINTR);
241                 if (rc < 0 && errno == EPIPE) {
242                         close(conn);
243                         conn = -1;
244                         add_event(sock, af_unix_accept);
245                 }
246         } 
247 }
248
249 void destroy_af_unix(void)
250 {
251         if (conn >= 0) {
252                 close(conn);
253                 conn = -1;
254         }
255         if (sock >= 0) {
256                 close(sock);
257                 sock = -1;
258         }
259         if (path) {
260                 unlink(path);
261                 free(path);
262                 path = NULL;
263         }
264 }
265
266 static void init_syslog(const plugin_conf_t *conf)
267 {
268         int i, facility = LOG_USER;
269         priority = LOG_INFO;
270
271         for (i = 1; i<3; i++) {
272                 if (conf->args[i]) {
273                         if (strcasecmp(conf->args[i], "LOG_DEBUG") == 0)
274                                 priority = LOG_DEBUG;
275                         else if (strcasecmp(conf->args[i], "LOG_INFO") == 0)
276                                 priority = LOG_INFO;
277                         else if (strcasecmp(conf->args[i], "LOG_NOTICE") == 0)
278                                 priority = LOG_NOTICE;
279                         else if (strcasecmp(conf->args[i], "LOG_WARNING") == 0)
280                                 priority = LOG_WARNING;
281                         else if (strcasecmp(conf->args[i], "LOG_ERR") == 0)
282                                 priority = LOG_ERR;
283                         else if (strcasecmp(conf->args[i], "LOG_CRIT") == 0)
284                                 priority = LOG_CRIT;
285                         else if (strcasecmp(conf->args[i], "LOG_ALERT") == 0)
286                                 priority = LOG_ALERT;
287                         else if (strcasecmp(conf->args[i], "LOG_EMERG") == 0)
288                                 priority = LOG_EMERG;
289                         else if (strcasecmp(conf->args[i], "LOG_LOCAL0") == 0)
290                                 facility = LOG_LOCAL0;
291                         else if (strcasecmp(conf->args[i], "LOG_LOCAL1") == 0)
292                                 facility = LOG_LOCAL1;
293                         else if (strcasecmp(conf->args[i], "LOG_LOCAL2") == 0)
294                                 facility = LOG_LOCAL2;
295                         else if (strcasecmp(conf->args[i], "LOG_LOCAL3") == 0)
296                                 facility = LOG_LOCAL3;
297                         else if (strcasecmp(conf->args[i], "LOG_LOCAL4") == 0)
298                                 facility = LOG_LOCAL4;
299                         else if (strcasecmp(conf->args[i], "LOG_LOCAL5") == 0)
300                                 facility = LOG_LOCAL5;
301                         else if (strcasecmp(conf->args[i], "LOG_LOCAL6") == 0)
302                                 facility = LOG_LOCAL6;
303                         else if (strcasecmp(conf->args[i], "LOG_LOCAL7") == 0)
304                                 facility = LOG_LOCAL7;
305                         else {
306                                 syslog(LOG_ERR, 
307                                         "Unknown log priority/facility %s",
308                                         conf->args[i]);
309                                 syslog_started = 0;
310                                 return;
311                         }
312                 }
313         }
314         syslog(LOG_INFO, "syslog plugin initialized");
315         if (facility != LOG_USER)
316                 openlog("audispd", 0, facility);
317         syslog_started = 1;
318 }
319
320 void send_syslog(const char *s)
321 {
322         if (syslog_started) 
323                 syslog(priority, "%s", s);
324 }
325
326 void destroy_syslog(void)
327 {
328         syslog_started = 0;
329 }
330