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

« back to all changes in this revision

Viewing changes to new_audispd/audispd-pconfig.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-pconfig.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
 
 
24
#include "config.h"
 
25
#include <string.h>
 
26
#include <stdio.h>
 
27
#include <fcntl.h>
 
28
#include <sys/stat.h>
 
29
#include <errno.h>
 
30
#include <unistd.h>
 
31
#include <stdlib.h>
 
32
#include <libgen.h>
 
33
#include "audispd-pconfig.h"
 
34
#include "private.h"
 
35
 
 
36
/* Local prototypes */
 
37
struct nv_pair
 
38
{
 
39
        const char *name;
 
40
        const char *value;
 
41
        const char *option;
 
42
};
 
43
 
 
44
struct kw_pair 
 
45
{
 
46
        const char *name;
 
47
        int (*parser)(struct nv_pair *, int, plugin_conf_t *);
 
48
        int max_options;
 
49
};
 
50
 
 
51
struct nv_list
 
52
 
53
        const char *name;
 
54
        int option;
 
55
};
 
56
 
 
57
static char *get_line(FILE *f, char *buf);
 
58
static int nv_split(char *buf, struct nv_pair *nv);
 
59
static const struct kw_pair *kw_lookup(const char *val);
 
60
static int active_parser(struct nv_pair *nv, int line, 
 
61
                plugin_conf_t *config);
 
62
static int direction_parser(struct nv_pair *nv, int line, 
 
63
                plugin_conf_t *config);
 
64
static int path_parser(struct nv_pair *nv, int line, 
 
65
                plugin_conf_t *config);
 
66
static int service_type_parser(struct nv_pair *nv, int line, 
 
67
                plugin_conf_t *config);
 
68
static int args_parser(struct nv_pair *nv, int line, 
 
69
                plugin_conf_t *config);
 
70
static int format_parser(struct nv_pair *nv, int line, 
 
71
                plugin_conf_t *config);
 
72
static int sanity_check(plugin_conf_t *config, const char *file);
 
73
 
 
74
static const struct kw_pair keywords[] = 
 
75
{
 
76
  {"active",                   active_parser,                   0 },
 
77
  {"direction",                direction_parser,                0 },
 
78
  {"path",                     path_parser,                     0 },
 
79
  {"type",                     service_type_parser,             0 },
 
80
  {"args",                     args_parser,                     2 },
 
81
  {"format",                   format_parser,                   0 },
 
82
  { NULL,                      NULL }
 
83
};
 
84
 
 
85
static const struct nv_list active[] =
 
86
{
 
87
  {"yes",  A_YES },
 
88
  {"no",   A_NO },
 
89
  { NULL,  0 }
 
90
};
 
91
 
 
92
static const struct nv_list directions[] =
 
93
{
 
94
  {"in",   D_IN },
 
95
  {"out",  D_OUT },
 
96
  { NULL,  0 }
 
97
};
 
98
 
 
99
static const struct nv_list service_type[] =
 
100
{
 
101
  {"ondemand", S_ONDEMAND },
 
102
  {"builtin",  S_BUILTIN },
 
103
  {"always",   S_ALWAYS },
 
104
  { NULL,  0 }
 
105
};
 
106
 
 
107
static const struct nv_list formats[] =
 
108
{
 
109
  {"binary",  F_BINARY },
 
110
  {"string",  F_STRING },
 
111
  { NULL,  0 }
 
112
};
 
113
 
 
114
/*
 
115
 * Set everything to its default value
 
116
*/
 
117
void clear_pconfig(plugin_conf_t *config)
 
118
{
 
119
        int i;
 
120
 
 
121
        config->active = A_NO;
 
122
        config->direction = D_UNSET;
 
123
        config->path = NULL;
 
124
        config->type = S_ONDEMAND;
 
125
        for (i=0; i< (MAX_PLUGIN_ARGS + 2); i++)
 
126
                config->args[i] = NULL;
 
127
        config->format = F_STRING;
 
128
}
 
129
 
 
130
int load_pconfig(plugin_conf_t *config, const char *file)
 
131
{
 
132
        int fd, rc, mode, lineno = 1;
 
133
        struct stat st;
 
134
        FILE *f;
 
135
        char buf[128];
 
136
 
 
137
        clear_pconfig(config);
 
138
 
 
139
        /* open the file */
 
140
        mode = O_RDONLY;
 
141
        rc = open(file, mode);
 
142
        if (rc < 0) {
 
143
                if (errno != ENOENT) {
 
144
                        audit_msg(LOG_ERR, "Error opening %s (%s)", file,
 
145
                                strerror(errno));
 
146
                        return 1;
 
147
                }
 
148
                audit_msg(LOG_WARNING,
 
149
                        "Config file %s doesn't exist, skipping", file);
 
150
                return 0;
 
151
        }
 
152
        fd = rc;
 
153
 
 
154
        /* check the file's permissions: owned by root, not world writable,
 
155
         * not symlink.
 
156
         */
 
157
        audit_msg(LOG_DEBUG, "Config file %s opened for parsing", 
 
158
                        file);
 
159
        if (fstat(fd, &st) < 0) {
 
160
                audit_msg(LOG_ERR, "Error fstat'ing config file (%s)", 
 
161
                        strerror(errno));
 
162
                close(fd);
 
163
                return 1;
 
164
        }
 
165
        if (st.st_uid != 0) {
 
166
                audit_msg(LOG_ERR, "Error - %s isn't owned by root", 
 
167
                        file);
 
168
                close(fd);
 
169
                return 1;
 
170
        }
 
171
        if ((st.st_mode & S_IWOTH) == S_IWOTH) {
 
172
                audit_msg(LOG_ERR, "Error - %s is world writable", 
 
173
                        file);
 
174
                close(fd);
 
175
                return 1;
 
176
        }
 
177
        if (!S_ISREG(st.st_mode)) {
 
178
                audit_msg(LOG_ERR, "Error - %s is not a regular file", 
 
179
                        file);
 
180
                close(fd);
 
181
                return 1;
 
182
        }
 
183
 
 
184
        /* it's ok, read line by line */
 
185
        f = fdopen(fd, "r");
 
186
        if (f == NULL) {
 
187
                audit_msg(LOG_ERR, "Error - fdopen failed (%s)", 
 
188
                        strerror(errno));
 
189
                close(fd);
 
190
                return 1;
 
191
        }
 
192
 
 
193
        while (get_line(f, buf)) {
 
194
                // convert line into name-value pair
 
195
                const struct kw_pair *kw;
 
196
                struct nv_pair nv;
 
197
                rc = nv_split(buf, &nv);
 
198
                switch (rc) {
 
199
                        case 0: // fine
 
200
                                break;
 
201
                        case 1: // not the right number of tokens.
 
202
                                audit_msg(LOG_ERR, 
 
203
                                "Wrong number of arguments for line %d in %s", 
 
204
                                        lineno, file);
 
205
                                break;
 
206
                        case 2: // no '=' sign
 
207
                                audit_msg(LOG_ERR, 
 
208
                                        "Missing equal sign for line %d in %s", 
 
209
                                        lineno, file);
 
210
                                break;
 
211
                        default: // something else went wrong... 
 
212
                                audit_msg(LOG_ERR, 
 
213
                                        "Unknown error for line %d in %s", 
 
214
                                        lineno, file);
 
215
                                break;
 
216
                }
 
217
                if (nv.name == NULL) {
 
218
                        lineno++;
 
219
                        continue;
 
220
                }
 
221
                if (nv.value == NULL) {
 
222
                        fclose(f);
 
223
                        return 1;
 
224
                }
 
225
 
 
226
                /* identify keyword or error */
 
227
                kw = kw_lookup(nv.name);
 
228
                if (kw->name == NULL) {
 
229
                        audit_msg(LOG_ERR, 
 
230
                                "Unknown keyword \"%s\" in line %d of %s", 
 
231
                                nv.name, lineno, file);
 
232
                        fclose(f);
 
233
                        return 1;
 
234
                }
 
235
 
 
236
                /* Check number of options */
 
237
                if (kw->max_options == 0 && nv.option != NULL) {
 
238
                        audit_msg(LOG_ERR, 
 
239
                                "Keyword \"%s\" has invalid option "
 
240
                                "\"%s\" in line %d of %s", 
 
241
                                nv.name, nv.option, lineno, file);
 
242
                        fclose(f);
 
243
                        return 1;
 
244
                }
 
245
 
 
246
                /* dispatch to keyword's local parser */
 
247
                rc = kw->parser(&nv, lineno, config);
 
248
                if (rc != 0) {
 
249
                        fclose(f);
 
250
                        return 1; // local parser puts message out
 
251
                }
 
252
 
 
253
                lineno++;
 
254
        }
 
255
 
 
256
        fclose(f);
 
257
        if (lineno > 1)
 
258
                return sanity_check(config, file);
 
259
        return 0;
 
260
}
 
261
 
 
262
static char *get_line(FILE *f, char *buf)
 
263
{
 
264
        if (fgets_unlocked(buf, 128, f)) {
 
265
                /* remove newline */
 
266
                char *ptr = strchr(buf, 0x0a);
 
267
                if (ptr)
 
268
                        *ptr = 0;
 
269
                return buf;
 
270
        }
 
271
        return NULL;
 
272
}
 
273
 
 
274
static int nv_split(char *buf, struct nv_pair *nv)
 
275
{
 
276
        /* Get the name part */
 
277
        char *ptr;
 
278
 
 
279
        nv->name = NULL;
 
280
        nv->value = NULL;
 
281
        nv->option = NULL;
 
282
        ptr = strtok(buf, " ");
 
283
        if (ptr == NULL)
 
284
                return 0; /* If there's nothing, go to next line */
 
285
        if (ptr[0] == '#')
 
286
                return 0; /* If there's a comment, go to next line */
 
287
        nv->name = ptr;
 
288
 
 
289
        /* Check for a '=' */
 
290
        ptr = strtok(NULL, " ");
 
291
        if (ptr == NULL)
 
292
                return 1;
 
293
        if (strcmp(ptr, "=") != 0)
 
294
                return 2;
 
295
 
 
296
        /* get the value */
 
297
        ptr = strtok(NULL, " ");
 
298
        if (ptr == NULL)
 
299
                return 1;
 
300
        nv->value = ptr;
 
301
 
 
302
        /* See if there's an option */
 
303
        ptr = strtok(NULL, " ");
 
304
        if (ptr) {
 
305
                nv->option = ptr;
 
306
 
 
307
                /* Make sure there's nothing else */
 
308
                ptr = strtok(NULL, " ");
 
309
                if (ptr)
 
310
                        return 1;
 
311
        }
 
312
 
 
313
        /* Everything is OK */
 
314
        return 0;
 
315
}
 
316
 
 
317
static const struct kw_pair *kw_lookup(const char *val)
 
318
{
 
319
        int i = 0;
 
320
        while (keywords[i].name != NULL) {
 
321
                if (strcasecmp(keywords[i].name, val) == 0)
 
322
                        break;
 
323
                i++;
 
324
        }
 
325
        return &keywords[i];
 
326
}
 
327
 
 
328
static int active_parser(struct nv_pair *nv, int line, 
 
329
                plugin_conf_t *config)
 
330
{
 
331
        int i;
 
332
 
 
333
        for (i=0; active[i].name != NULL; i++) {
 
334
                if (strcasecmp(nv->value, active[i].name) == 0) {
 
335
                        config->active = active[i].option;
 
336
                        return 0;
 
337
                }
 
338
        }
 
339
        audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
 
340
        return 1;
 
341
}
 
342
 
 
343
static int direction_parser(struct nv_pair *nv, int line, 
 
344
                plugin_conf_t *config)
 
345
{
 
346
        int i;
 
347
 
 
348
        for (i=0; directions[i].name != NULL; i++) {
 
349
                if (strcasecmp(nv->value, directions[i].name) == 0) {
 
350
                        config->direction = directions[i].option;
 
351
                        return 0;
 
352
                }
 
353
        }
 
354
        audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
 
355
        return 1;
 
356
}
 
357
 
 
358
static int path_parser(struct nv_pair *nv, int line,
 
359
        plugin_conf_t *config)
 
360
{
 
361
        char *dir = NULL, *tdir, *base;
 
362
        int fd;
 
363
        struct stat buf;
 
364
 
 
365
        if (nv->value == NULL) {
 
366
                config->path = NULL;
 
367
                return 0;
 
368
        }
 
369
 
 
370
        if (strncasecmp(nv->value, "builtin_", 8) == 0) {
 
371
                config->path = strdup(nv->value);
 
372
                return 0;
 
373
        }
 
374
 
 
375
        /* split name into dir and basename. */
 
376
        tdir = strdup(nv->value);
 
377
        if (tdir)
 
378
                dir = dirname(tdir);
 
379
        if (dir == NULL || strlen(dir) < 4) { //  '/var' is shortest dirname
 
380
                free(tdir);
 
381
                audit_msg(LOG_ERR,
 
382
                        "The directory name: %s is too short - line %d",
 
383
                        dir, line);
 
384
                return 1;
 
385
        }
 
386
 
 
387
        free((void *)tdir);
 
388
        base = basename((char *)nv->value);
 
389
        if (base == 0 || strlen(base) == 0) {
 
390
                audit_msg(LOG_ERR, "The file name: %s is too short - line %d",
 
391
                        base, line);
 
392
                return 1;
 
393
        }
 
394
        /* if the file exists, see that its regular, owned by root,
 
395
         * and not world anything */
 
396
        fd = open(nv->value, O_RDONLY);
 
397
        if (fd < 0) {
 
398
                audit_msg(LOG_ERR, "Unable to open %s (%s)", nv->value,
 
399
                        strerror(errno));
 
400
                return 1;
 
401
        }
 
402
        if (fstat(fd, &buf) < 0) {
 
403
                audit_msg(LOG_ERR, "Unable to stat %s (%s)", nv->value,
 
404
                        strerror(errno));
 
405
                close(fd);
 
406
                return 1;
 
407
        }
 
408
        close(fd);
 
409
        if (!S_ISREG(buf.st_mode)) {
 
410
                audit_msg(LOG_ERR, "%s is not a regular file", nv->value);
 
411
                return 1;
 
412
        }
 
413
        if (buf.st_uid != 0) {
 
414
                audit_msg(LOG_ERR, "%s is not owned by root", nv->value);
 
415
                return 1;
 
416
        }
 
417
        if ((buf.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP)) !=
 
418
                           (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP)) {
 
419
                audit_msg(LOG_ERR, "%s permissions should be 0750", nv->value);
 
420
                return 1;
 
421
        }
 
422
        free((void *)config->path);
 
423
        config->path = strdup(nv->value);
 
424
        if (config->path == NULL)
 
425
                return 1;
 
426
        return 0;
 
427
}
 
428
 
 
429
static int service_type_parser(struct nv_pair *nv, int line, 
 
430
                plugin_conf_t *config)
 
431
{
 
432
        int i;
 
433
 
 
434
        for (i=0; service_type[i].name != NULL; i++) {
 
435
                if (strcasecmp(nv->value, service_type[i].name) == 0) {
 
436
                        config->type = service_type[i].option;
 
437
                        return 0;
 
438
                }
 
439
        }
 
440
        audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
 
441
        return 1;
 
442
}
 
443
 
 
444
static int args_parser(struct nv_pair *nv, int line,
 
445
        plugin_conf_t *config)
 
446
{
 
447
        int i;
 
448
 
 
449
        for (i=0; i < (MAX_PLUGIN_ARGS + 2); i++) {
 
450
                free((void *)config->args[i]);
 
451
                config->args[i] = NULL;
 
452
        }
 
453
 
 
454
        config->args[1] = strdup(nv->value);
 
455
        if (nv->option)
 
456
                config->args[2] = strdup(nv->option);
 
457
        return 0;
 
458
}
 
459
 
 
460
static int format_parser(struct nv_pair *nv, int line, 
 
461
                plugin_conf_t *config)
 
462
{
 
463
        int i;
 
464
 
 
465
        for (i=0; formats[i].name != NULL; i++) {
 
466
                if (strcasecmp(nv->value, formats[i].name) == 0) {
 
467
                        config->format = formats[i].option;
 
468
                        return 0;
 
469
                }
 
470
        }
 
471
        audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
 
472
        return 1;
 
473
}
 
474
 
 
475
/*
 
476
 * This function is where we do the integrated check of the audispd config
 
477
 * options. At this point, all fields have been read. Returns 0 if no
 
478
 * problems and 1 if problems detected.
 
479
 */
 
480
static int sanity_check(plugin_conf_t *config, const char *file)
 
481
{
 
482
        /* Error checking */
 
483
        if (config->active == A_YES && config->path == NULL) {
 
484
                audit_msg(LOG_ERR, 
 
485
                    "Error - plugin (%s) is active but no path given", file);
 
486
                return 1;
 
487
        }
 
488
        return 0;
 
489
}
 
490
 
 
491
void free_pconfig(plugin_conf_t *config)
 
492
{
 
493
        int i;
 
494
 
 
495
        for (i=0; i < (MAX_PLUGIN_ARGS + 2); i++)
 
496
                free(config->args[i]);
 
497
        free((void *)config->path);
 
498
}
 
499