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

« back to all changes in this revision

Viewing changes to new_audispd/audispd-config.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-config.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 <ctype.h>
 
34
#include "audispd-config.h"
 
35
#include "private.h"
 
36
 
 
37
/* Local prototypes */
 
38
struct nv_pair
 
39
{
 
40
        const char *name;
 
41
        const char *value;
 
42
        const char *option;
 
43
};
 
44
 
 
45
struct kw_pair 
 
46
{
 
47
        const char *name;
 
48
        int (*parser)(struct nv_pair *, int, daemon_conf_t *);
 
49
        int max_options;
 
50
};
 
51
 
 
52
struct nv_list
 
53
 
54
        const char *name;
 
55
        int option;
 
56
};
 
57
 
 
58
static char *get_line(FILE *f, char *buf);
 
59
static int nv_split(char *buf, struct nv_pair *nv);
 
60
static const struct kw_pair *kw_lookup(const char *val);
 
61
static int q_depth_parser(struct nv_pair *nv, int line, 
 
62
                daemon_conf_t *config);
 
63
static int name_format_parser(struct nv_pair *nv, int line, 
 
64
                daemon_conf_t *config);
 
65
static int name_parser(struct nv_pair *nv, int line, 
 
66
                daemon_conf_t *config);
 
67
static int sanity_check(daemon_conf_t *config, const char *file);
 
68
 
 
69
static const struct kw_pair keywords[] = 
 
70
{
 
71
  {"q_depth",                  q_depth_parser,                  0 },
 
72
  {"name_format",              name_format_parser,              0 },
 
73
  {"name",                     name_parser,                     0 },
 
74
  { NULL,                      NULL }
 
75
};
 
76
 
 
77
static const struct nv_list node_name_formats[] =
 
78
{
 
79
  {"none",      N_NONE },
 
80
  {"hostname",  N_HOSTNAME },
 
81
  {"fqd",       N_FQD },
 
82
  {"numeric",   N_NUMERIC },
 
83
  {"user",      N_USER },
 
84
  { NULL,  0 }
 
85
};
 
86
 
 
87
/*
 
88
 * Set everything to its default value
 
89
*/
 
90
void clear_config(daemon_conf_t *config)
 
91
{
 
92
        config->q_depth = 10;
 
93
        config->node_name_format = N_NONE;
 
94
        config->name = NULL;
 
95
}
 
96
 
 
97
int load_config(daemon_conf_t *config, const char *file)
 
98
{
 
99
        int fd, rc, mode, lineno = 1;
 
100
        struct stat st;
 
101
        FILE *f;
 
102
        char buf[128];
 
103
 
 
104
        clear_config(config);
 
105
 
 
106
        /* open the file */
 
107
        mode = O_RDONLY;
 
108
        rc = open(file, mode);
 
109
        if (rc < 0) {
 
110
                if (errno != ENOENT) {
 
111
                        audit_msg(LOG_ERR, "Error opening %s (%s)", file,
 
112
                                strerror(errno));
 
113
                        return 1;
 
114
                }
 
115
                audit_msg(LOG_WARNING,
 
116
                        "Config file %s doesn't exist, skipping", file);
 
117
                return 0;
 
118
        }
 
119
        fd = rc;
 
120
 
 
121
        /* check the file's permissions: owned by root, not world writable,
 
122
         * not symlink.
 
123
         */
 
124
        audit_msg(LOG_DEBUG, "Config file %s opened for parsing", 
 
125
                        file);
 
126
        if (fstat(fd, &st) < 0) {
 
127
                audit_msg(LOG_ERR, "Error fstat'ing config file (%s)", 
 
128
                        strerror(errno));
 
129
                close(fd);
 
130
                return 1;
 
131
        }
 
132
        if (st.st_uid != 0) {
 
133
                audit_msg(LOG_ERR, "Error - %s isn't owned by root", 
 
134
                        file);
 
135
                close(fd);
 
136
                return 1;
 
137
        }
 
138
        if ((st.st_mode & S_IWOTH) == S_IWOTH) {
 
139
                audit_msg(LOG_ERR, "Error - %s is world writable", 
 
140
                        file);
 
141
                close(fd);
 
142
                return 1;
 
143
        }
 
144
        if (!S_ISREG(st.st_mode)) {
 
145
                audit_msg(LOG_ERR, "Error - %s is not a regular file", 
 
146
                        file);
 
147
                close(fd);
 
148
                return 1;
 
149
        }
 
150
 
 
151
        /* it's ok, read line by line */
 
152
        f = fdopen(fd, "r");
 
153
        if (f == NULL) {
 
154
                audit_msg(LOG_ERR, "Error - fdopen failed (%s)", 
 
155
                        strerror(errno));
 
156
                close(fd);
 
157
                return 1;
 
158
        }
 
159
 
 
160
        while (get_line(f, buf)) {
 
161
                // convert line into name-value pair
 
162
                const struct kw_pair *kw;
 
163
                struct nv_pair nv;
 
164
                rc = nv_split(buf, &nv);
 
165
                switch (rc) {
 
166
                        case 0: // fine
 
167
                                break;
 
168
                        case 1: // not the right number of tokens.
 
169
                                audit_msg(LOG_ERR, 
 
170
                                "Wrong number of arguments for line %d in %s", 
 
171
                                        lineno, file);
 
172
                                break;
 
173
                        case 2: // no '=' sign
 
174
                                audit_msg(LOG_ERR, 
 
175
                                        "Missing equal sign for line %d in %s", 
 
176
                                        lineno, file);
 
177
                                break;
 
178
                        default: // something else went wrong... 
 
179
                                audit_msg(LOG_ERR, 
 
180
                                        "Unknown error for line %d in %s", 
 
181
                                        lineno, file);
 
182
                                break;
 
183
                }
 
184
                if (nv.name == NULL) {
 
185
                        lineno++;
 
186
                        continue;
 
187
                }
 
188
                if (nv.value == NULL) {
 
189
                        fclose(f);
 
190
                        return 1;
 
191
                }
 
192
 
 
193
                /* identify keyword or error */
 
194
                kw = kw_lookup(nv.name);
 
195
                if (kw->name == NULL) {
 
196
                        audit_msg(LOG_ERR, 
 
197
                                "Unknown keyword \"%s\" in line %d of %s", 
 
198
                                nv.name, lineno, file);
 
199
                        fclose(f);
 
200
                        return 1;
 
201
                }
 
202
 
 
203
                /* Check number of options */
 
204
                if (kw->max_options == 0 && nv.option != NULL) {
 
205
                        audit_msg(LOG_ERR, 
 
206
                                "Keyword \"%s\" has invalid option "
 
207
                                "\"%s\" in line %d of %s", 
 
208
                                nv.name, nv.option, lineno, file);
 
209
                        fclose(f);
 
210
                        return 1;
 
211
                }
 
212
 
 
213
                /* dispatch to keyword's local parser */
 
214
                rc = kw->parser(&nv, lineno, config);
 
215
                if (rc != 0) {
 
216
                        fclose(f);
 
217
                        return 1; // local parser puts message out
 
218
                }
 
219
 
 
220
                lineno++;
 
221
        }
 
222
 
 
223
        fclose(f);
 
224
        if (lineno > 1)
 
225
                return sanity_check(config, file);
 
226
        return 0;
 
227
}
 
228
 
 
229
static char *get_line(FILE *f, char *buf)
 
230
{
 
231
        if (fgets_unlocked(buf, 128, f)) {
 
232
                /* remove newline */
 
233
                char *ptr = strchr(buf, 0x0a);
 
234
                if (ptr)
 
235
                        *ptr = 0;
 
236
                return buf;
 
237
        }
 
238
        return NULL;
 
239
}
 
240
 
 
241
static int nv_split(char *buf, struct nv_pair *nv)
 
242
{
 
243
        /* Get the name part */
 
244
        char *ptr;
 
245
 
 
246
        nv->name = NULL;
 
247
        nv->value = NULL;
 
248
        nv->option = NULL;
 
249
        ptr = strtok(buf, " ");
 
250
        if (ptr == NULL)
 
251
                return 0; /* If there's nothing, go to next line */
 
252
        if (ptr[0] == '#')
 
253
                return 0; /* If there's a comment, go to next line */
 
254
        nv->name = ptr;
 
255
 
 
256
        /* Check for a '=' */
 
257
        ptr = strtok(NULL, " ");
 
258
        if (ptr == NULL)
 
259
                return 1;
 
260
        if (strcmp(ptr, "=") != 0)
 
261
                return 2;
 
262
 
 
263
        /* get the value */
 
264
        ptr = strtok(NULL, " ");
 
265
        if (ptr == NULL)
 
266
                return 1;
 
267
        nv->value = ptr;
 
268
 
 
269
        /* See if there's an option */
 
270
        ptr = strtok(NULL, " ");
 
271
        if (ptr) {
 
272
                nv->option = ptr;
 
273
 
 
274
                /* Make sure there's nothing else */
 
275
                ptr = strtok(NULL, " ");
 
276
                if (ptr)
 
277
                        return 1;
 
278
        }
 
279
 
 
280
        /* Everything is OK */
 
281
        return 0;
 
282
}
 
283
 
 
284
static const struct kw_pair *kw_lookup(const char *val)
 
285
{
 
286
        int i = 0;
 
287
        while (keywords[i].name != NULL) {
 
288
                if (strcasecmp(keywords[i].name, val) == 0)
 
289
                        break;
 
290
                i++;
 
291
        }
 
292
        return &keywords[i];
 
293
}
 
294
 
 
295
static int q_depth_parser(struct nv_pair *nv, int line, 
 
296
                daemon_conf_t *config)
 
297
{
 
298
        const char *ptr = nv->value;
 
299
        unsigned long i;
 
300
 
 
301
        /* check that all chars are numbers */
 
302
        for (i=0; ptr[i]; i++) {
 
303
                if (!isdigit(ptr[i])) {
 
304
                        audit_msg(LOG_ERR,
 
305
                                "Value %s should only be numbers - line %d",
 
306
                                nv->value, line);
 
307
                        return 1;
 
308
                }
 
309
        }
 
310
 
 
311
        /* convert to unsigned long */
 
312
        errno = 0;
 
313
        i = strtoul(nv->value, NULL, 10);
 
314
        if (errno) {
 
315
                audit_msg(LOG_ERR,
 
316
                        "Error converting string to a number (%s) - line %d",
 
317
                        strerror(errno), line);
 
318
                return 1;
 
319
        }
 
320
        if (i > 99999) {
 
321
                audit_msg(LOG_ERR, "q_depth must be 99999 or less");
 
322
                return 1;
 
323
        }
 
324
        config->q_depth = i;
 
325
        return 0;
 
326
 
 
327
}
 
328
 
 
329
static int name_format_parser(struct nv_pair *nv, int line, 
 
330
                daemon_conf_t *config)
 
331
{
 
332
        int i;
 
333
 
 
334
        for (i=0; node_name_formats[i].name != NULL; i++) {
 
335
                if (strcasecmp(nv->value, node_name_formats[i].name) == 0) {
 
336
                        config->node_name_format = node_name_formats[i].option;
 
337
                        return 0;
 
338
                }
 
339
        }
 
340
        audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
 
341
        return 1;
 
342
}
 
343
 
 
344
static int name_parser(struct nv_pair *nv, int line, 
 
345
                daemon_conf_t *config)
 
346
{
 
347
        if (nv->value == NULL)
 
348
                config->name = NULL;
 
349
        else
 
350
                config->name = strdup(nv->value);
 
351
        return 0;
 
352
}
 
353
 
 
354
/*
 
355
 * This function is where we do the integrated check of the audispd config
 
356
 * options. At this point, all fields have been read. Returns 0 if no
 
357
 * problems and 1 if problems detected.
 
358
 */
 
359
static int sanity_check(daemon_conf_t *config, const char *file)
 
360
{
 
361
        /* Error checking */
 
362
        if (config->node_name_format == N_USER && config->name == NULL) {
 
363
                audit_msg(LOG_ERR, 
 
364
            "Error - node_name_format is user supplied but none given (%s)",
 
365
                        file);
 
366
                return 1;
 
367
        }
 
368
        return 0;
 
369
}
 
370
 
 
371
void free_config(daemon_conf_t *config)
 
372
{
 
373
        free(config->name);
 
374
}
 
375