2
* Copyright 2007 Red Hat Inc., Durham, North Carolina.
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
* Steve Grubb <sgrubb@redhat.com>
37
#include "audispd-config.h"
38
#include "audispd-pconfig.h"
39
#include "audispd-llist.h"
40
#include "audispd-builtins.h"
45
volatile int stop = 0;
49
static daemon_conf_t daemon_config;
50
static conf_llist plugin_conf;
52
static int plug_pipe[2] = {-1, -1};
53
static pthread_t inbound_thread;
54
static const char *config_file = "/etc/audisp/audispd.conf";
55
static const char *plugin_dir = "/etc/audisp/plugins.d/";
57
/* Local function prototypes */
58
static void event_loop(void);
59
static int safe_exec(const char *exe);
60
static void *inbound_thread_main(void *arg);
65
static void term_handler( int sig )
73
static void child_handler( int sig )
79
* SIGHUP handler: re-read config
81
static void hup_handler( int sig )
87
* SIGALRM handler - help force exit when terminating daemon
89
static void alarm_handler( int sig )
91
pthread_cancel(inbound_thread);
95
int main(int argc, char *argv[])
103
/* Make sure we are root */
105
fprintf(stderr, "You must be root to run this program.\n");
109
set_aumessage_mode(MSG_SYSLOG, DBG_YES);
111
/* Register sighandlers */
113
sigemptyset( &sa.sa_mask ) ;
114
/* Ignore all signals by default */
115
sa.sa_handler = SIG_IGN;
116
for (i=1; i<NSIG; i++)
117
sigaction( i, &sa, NULL );
118
/* Set handler for the ones we care about */
119
sa.sa_handler = term_handler;
120
sigaction( SIGTERM, &sa, NULL );
121
sa.sa_handler = hup_handler;
122
sigaction( SIGHUP, &sa, NULL );
123
sa.sa_handler = alarm_handler;
124
sigaction( SIGALRM, &sa, NULL );
125
sa.sa_handler = child_handler;
126
sigaction( SIGCHLD, &sa, NULL );
128
// move stdin to its own fd
130
fcntl(audit_fd, F_SETFD, FD_CLOEXEC);
132
// setup message pipe for children
133
socketpair(AF_UNIX, SOCK_STREAM, 0, plug_pipe);
135
// Make all descriptors point to dev null
136
i = open("/dev/null", O_RDWR);
144
// init the daemon's config
145
rc = load_config(&daemon_config, config_file);
150
plist_create(&plugin_conf);
153
d = opendir(plugin_dir);
157
while ((e = readdir(d))) {
158
plugin_conf_t config;
159
char fname[PATH_MAX];
161
if (e->d_name[0] == '.')
164
snprintf(fname, sizeof(fname), "%s%s",
165
plugin_dir, e->d_name);
167
clear_pconfig(&config);
168
if (load_pconfig(&config, fname) == 0) {
169
// push onto config list
170
plist_append(&plugin_conf, &config);
176
// if no plugins - exit
177
if (plist_count(&plugin_conf) == 0) {
178
syslog(LOG_ERR, "No plugins found, exiting");
183
plist_first(&plugin_conf);
184
conf = plist_get_cur(&plugin_conf);
185
if (conf && conf->p) {
187
if (conf->p && conf->p->active == A_YES) {
188
if (conf->p->type == S_BUILTIN)
189
start_builtin(conf->p);
190
else if (safe_exec(conf->p->path)) {
191
syslog(LOG_ERR, "Error running %s (%s)",
192
conf->p->path, strerror(errno));
195
} while ((conf = plist_next(&plugin_conf)));
198
// Close the parent's read side
201
fcntl(plug_pipe[1], F_SETFD, FD_CLOEXEC); // Avoid leaking this
203
// Let the queue initialize
204
init_queue(daemon_config.q_depth);
205
syslog(LOG_NOTICE, "audispd initialized with q_depth=%d",
206
daemon_config.q_depth);
208
// Create inbound thread
209
pthread_create(&inbound_thread, NULL, inbound_thread_main, NULL);
214
/* Give it 5 seconds to clear the queue */
216
pthread_join(inbound_thread, NULL);
218
// Cleanup builtin plugins
223
plist_first(&plugin_conf);
224
conf = plist_get_cur(&plugin_conf);
226
free_pconfig(conf->p);
227
conf = plist_next(&plugin_conf);
229
plist_clear(&plugin_conf);
237
static int safe_exec(const char *exe)
244
return 0; // Parent...normal exit
246
return -1; // Failed to fork
248
// Set up comm with child
249
dup2(plug_pipe[0], 0);
254
argv[0] = (char *)exe;
256
execve(exe, argv, NULL);
257
exit(1); // Failed to exec
260
static void event_loop(void)
262
char *name = NULL, tmp_name[255];
264
switch (daemon_config.node_name_format)
267
if (gethostname(tmp_name, sizeof(tmp_name))) {
268
syslog(LOG_ERR, "Unable to get machine name");
271
name = strdup(tmp_name);
274
if (daemon_config.name)
275
name = strdup(daemon_config.name);
277
syslog(LOG_ERR, "User defined name missing");
286
char *v, unknown[32];
292
type = audit_msg_type_to_name(e->hdr.type);
294
snprintf(unknown, sizeof(unknown),
295
"UNKNOWN[%d]", e->hdr.type);
299
if (daemon_config.node_name_format != N_NONE) {
300
asprintf(&v, "node=%s type=%s msg=%.*s",
301
name, type, e->hdr.size, e->data);
303
asprintf(&v, "type=%s msg=%.*s",
304
type, e->hdr.size, e->data);
306
// Got event, now distribute it to the plugins
309
// write(plug_pipe[1], data);
311
// Done with the memory...release it
318
// inbound thread - enqueue inbound data to intermediate table
319
static void *inbound_thread_main(void *arg)
322
struct pollfd pfd[1];
324
pfd[0].fd = audit_fd;
325
pfd[0].events = POLLIN;
329
rc = poll(pfd, 1, 500); /* .5 second */
330
} while (rc < 0 && errno == EAGAIN && stop == 0);
337
event_t *e = malloc(sizeof(event_t));
341
memset(e, 0, sizeof(event_t));
343
/* Get header first. it is fixed size */
344
vec[0].iov_base = &e->hdr;
345
vec[0].iov_len = sizeof(struct audit_dispatcher_header);
348
vec[1].iov_base = &e->data;
349
vec[1].iov_len = MAX_AUDIT_MESSAGE_LENGTH;
352
rc = readv(audit_fd, vec, 2);
353
} while (rc < 0 && errno == EINTR);
358
// make sure event loop wakes up