~ubuntu-branches/ubuntu/maverick/audit/maverick

« back to all changes in this revision

Viewing changes to new_audispd/audispd.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2007-06-29 13:05:14 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070629130514-z798cz4lebiahj5w
Tags: 1.5.4-0ubuntu1
* New upstream version.
* debian/patches/audit-1.5.1-dist.patch:
  * update so that it applies for 1.5.4.
* debian/control:
  * update Maintainer and XSBC-Original-Maintainer fields.
* debian/rules:
  * enable apparmor support: add --with-apparmor to configure options.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* audispd.c --
 
2
 * Copyright 2007 Red Hat Inc., Durham, North Carolina.
 
3
 * All Rights Reserved.
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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
 
18
 *
 
19
 * Authors:
 
20
 *   Steve Grubb <sgrubb@redhat.com>
 
21
 */
 
22
 
 
23
#include "config.h"
 
24
#include <stdio.h>
 
25
#include <unistd.h>
 
26
#include <stdlib.h>
 
27
#include <signal.h>
 
28
#include <errno.h>
 
29
#include <string.h>
 
30
#include <sys/wait.h>
 
31
#include <pthread.h>
 
32
#include <dirent.h>
 
33
#include <fcntl.h>
 
34
#include <pthread.h>
 
35
#include <sys/poll.h>
 
36
 
 
37
#include "audispd-config.h"
 
38
#include "audispd-pconfig.h"
 
39
#include "audispd-llist.h"
 
40
#include "audispd-builtins.h"
 
41
#include "queue.h"
 
42
#include "libaudit.h"
 
43
 
 
44
/* Global Data */
 
45
volatile int stop = 0;
 
46
volatile int hup = 0;
 
47
 
 
48
/* Local data */
 
49
static daemon_conf_t daemon_config;
 
50
static conf_llist plugin_conf;
 
51
static int audit_fd;
 
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/";
 
56
 
 
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);
 
61
 
 
62
/*
 
63
 * SIGTERM handler
 
64
 */
 
65
static void term_handler( int sig )
 
66
{
 
67
        stop = 1;
 
68
}
 
69
 
 
70
/*
 
71
 * SIGCHLD handler
 
72
 */
 
73
static void child_handler( int sig )
 
74
{
 
75
        ;
 
76
}
 
77
 
 
78
/*
 
79
 * SIGHUP handler: re-read config
 
80
 */
 
81
static void hup_handler( int sig )
 
82
{
 
83
        hup = 1;
 
84
}
 
85
 
 
86
/*
 
87
 * SIGALRM handler - help force exit when terminating daemon
 
88
 */
 
89
static void alarm_handler( int sig )
 
90
{
 
91
        pthread_cancel(inbound_thread);
 
92
        abort();
 
93
}
 
94
 
 
95
int main(int argc, char *argv[])
 
96
{
 
97
        lnode *conf;
 
98
        struct sigaction sa;
 
99
        DIR *d;
 
100
        int i, rc;
 
101
 
 
102
#ifndef DEBUG
 
103
        /* Make sure we are root */
 
104
        if (getuid() != 0) {
 
105
                fprintf(stderr, "You must be root to run this program.\n");
 
106
                return 4;
 
107
        }
 
108
#endif
 
109
        set_aumessage_mode(MSG_SYSLOG, DBG_YES);
 
110
 
 
111
        /* Register sighandlers */
 
112
        sa.sa_flags = 0 ;
 
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 );
 
127
 
 
128
        // move stdin to its own fd
 
129
        audit_fd = dup(0);
 
130
        fcntl(audit_fd, F_SETFD, FD_CLOEXEC);
 
131
 
 
132
        // setup message pipe for children
 
133
        socketpair(AF_UNIX, SOCK_STREAM, 0, plug_pipe);
 
134
 
 
135
        // Make all descriptors point to dev null
 
136
        i = open("/dev/null", O_RDWR);
 
137
        if (i >= 0) {
 
138
                dup2(0, i);
 
139
                dup2(1, i);
 
140
                dup2(2, i);
 
141
                close(i);
 
142
        }
 
143
 
 
144
        // init the daemon's config
 
145
        rc = load_config(&daemon_config, config_file);
 
146
        if (rc) 
 
147
                return 6;
 
148
 
 
149
        // init plugin list
 
150
        plist_create(&plugin_conf);
 
151
 
 
152
        // read configs
 
153
        d = opendir(plugin_dir);
 
154
        if (d) {
 
155
                struct dirent *e;
 
156
 
 
157
                while ((e = readdir(d))) {
 
158
                        plugin_conf_t config;
 
159
                        char fname[PATH_MAX];
 
160
 
 
161
                        if (e->d_name[0] == '.')
 
162
                                continue;
 
163
 
 
164
                        snprintf(fname, sizeof(fname), "%s%s",
 
165
                                plugin_dir, e->d_name);
 
166
 
 
167
                        clear_pconfig(&config);
 
168
                        if (load_pconfig(&config, fname) == 0) {
 
169
                                // push onto config list
 
170
                                plist_append(&plugin_conf, &config);
 
171
                        }
 
172
                }
 
173
                closedir(d);
 
174
        }
 
175
 
 
176
        // if no plugins - exit
 
177
        if (plist_count(&plugin_conf) == 0) {
 
178
                syslog(LOG_ERR, "No plugins found, exiting");
 
179
                return 0;
 
180
        }
 
181
 
 
182
        // spawn children
 
183
        plist_first(&plugin_conf);
 
184
        conf = plist_get_cur(&plugin_conf);
 
185
        if (conf && conf->p) {
 
186
                do {
 
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));
 
193
                                }
 
194
                        }
 
195
                } while ((conf = plist_next(&plugin_conf)));
 
196
        }
 
197
 
 
198
        // Close the parent's read side
 
199
        close(plug_pipe[0]);
 
200
        plug_pipe[0] = -1;
 
201
        fcntl(plug_pipe[1], F_SETFD, FD_CLOEXEC); // Avoid leaking this
 
202
 
 
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);
 
207
 
 
208
        // Create inbound thread
 
209
        pthread_create(&inbound_thread, NULL, inbound_thread_main, NULL); 
 
210
 
 
211
        // Start event loop
 
212
        event_loop();
 
213
 
 
214
        /* Give it 5 seconds to clear the queue */
 
215
        alarm(5);
 
216
        pthread_join(inbound_thread, NULL);
 
217
 
 
218
        // Cleanup builtin plugins
 
219
        destroy_af_unix();
 
220
        destroy_syslog();
 
221
 
 
222
        // Release configs
 
223
        plist_first(&plugin_conf);
 
224
        conf = plist_get_cur(&plugin_conf);
 
225
        while (conf) {
 
226
                free_pconfig(conf->p);
 
227
                conf = plist_next(&plugin_conf);
 
228
        }
 
229
        plist_clear(&plugin_conf);
 
230
 
 
231
        // Cleanup the queue
 
232
        destroy_queue();
 
233
 
 
234
        return 0;
 
235
}
 
236
 
 
237
static int safe_exec(const char *exe)
 
238
{
 
239
        char *argv[2];
 
240
        int pid;
 
241
 
 
242
        pid = fork();
 
243
        if (pid > 0)
 
244
                return 0;       // Parent...normal exit
 
245
        if (pid < 0) 
 
246
                return -1;      // Failed to fork
 
247
 
 
248
        // Set up comm with child
 
249
        dup2(plug_pipe[0], 0);
 
250
        close(plug_pipe[0]);
 
251
        close(plug_pipe[1]);
 
252
 
 
253
        /* Child */
 
254
        argv[0] = (char *)exe;
 
255
        argv[1] = NULL;
 
256
        execve(exe, argv, NULL);
 
257
        exit(1);                // Failed to exec
 
258
}
 
259
 
 
260
static void event_loop(void)
 
261
{
 
262
        char *name = NULL, tmp_name[255];
 
263
 
 
264
        switch (daemon_config.node_name_format)
 
265
        {
 
266
                case N_HOSTNAME:
 
267
                        if (gethostname(tmp_name, sizeof(tmp_name))) {
 
268
                                syslog(LOG_ERR, "Unable to get machine name");
 
269
                                name = strdup("?");
 
270
                        } else
 
271
                                name = strdup(tmp_name);
 
272
                        break;
 
273
                case N_USER:
 
274
                        if (daemon_config.name)
 
275
                                name = strdup(daemon_config.name);
 
276
                        else {
 
277
                                syslog(LOG_ERR, "User defined name missing");
 
278
                                name = strdup("?");
 
279
                        }
 
280
                        break;
 
281
        }
 
282
 
 
283
        while (stop == 0) {
 
284
                event_t *e;
 
285
                const char *type;
 
286
                char *v, unknown[32];
 
287
 
 
288
                e = dequeue();
 
289
                if (e == NULL)
 
290
                        continue;
 
291
 
 
292
                type = audit_msg_type_to_name(e->hdr.type);
 
293
                if (type == NULL) {
 
294
                        snprintf(unknown, sizeof(unknown),
 
295
                                "UNKNOWN[%d]", e->hdr.type);
 
296
                        type = unknown;
 
297
                }
 
298
 
 
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);
 
302
                } else
 
303
                        asprintf(&v, "type=%s msg=%.*s", 
 
304
                                type, e->hdr.size, e->data);
 
305
 
 
306
                // Got event, now distribute it to the plugins
 
307
                send_af_unix(v);
 
308
                send_syslog(v);
 
309
//              write(plug_pipe[1], data);
 
310
 
 
311
                // Done with the memory...release it
 
312
                free(v);
 
313
                free(e);
 
314
        }
 
315
        free(name);
 
316
}
 
317
 
 
318
// inbound thread - enqueue inbound data to intermediate table
 
319
static void *inbound_thread_main(void *arg)
 
320
{
 
321
        int rc;
 
322
        struct pollfd pfd[1];
 
323
 
 
324
        pfd[0].fd = audit_fd;
 
325
        pfd[0].events = POLLIN;
 
326
 
 
327
        while (stop == 0) {
 
328
                do {
 
329
                        rc = poll(pfd, 1, 500); /* .5 second */
 
330
                } while (rc < 0 && errno == EAGAIN && stop == 0);
 
331
                if (rc == 0)
 
332
                        continue;
 
333
 
 
334
                // Event readable...
 
335
                if (rc > 0) {
 
336
                        struct iovec vec[2];
 
337
                        event_t *e = malloc(sizeof(event_t));
 
338
                        if (e == NULL) {
 
339
                                continue;
 
340
                        }
 
341
                        memset(e, 0, sizeof(event_t));
 
342
 
 
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);
 
346
 
 
347
                        // Next payload
 
348
                        vec[1].iov_base = &e->data;
 
349
                        vec[1].iov_len = MAX_AUDIT_MESSAGE_LENGTH;
 
350
 
 
351
                        do {
 
352
                                rc = readv(audit_fd, vec, 2);
 
353
                        } while (rc < 0 && errno == EINTR);
 
354
                        if (rc > 0) 
 
355
                                enqueue(e);
 
356
                }
 
357
        }
 
358
        // make sure event loop wakes up
 
359
        nudge_queue();
 
360
        return NULL;
 
361
}
 
362