~ubuntu-branches/ubuntu/raring/apparmor/raring

« back to all changes in this revision

Viewing changes to parser/parser_policy.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2007-03-23 16:42:01 UTC
  • Revision ID: james.westby@ubuntu.com-20070323164201-jkax6f0oku087b7l
Tags: upstream-2.0.1+510.dfsg
ImportĀ upstreamĀ versionĀ 2.0.1+510.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: parser_policy.c 412 2007-02-27 02:29:16Z jrjohansen $ */
 
2
 
 
3
/*
 
4
 *   Copyright (c) 1999, 2000, 2002, 2003, 2004, 2005 NOVELL (All rights reserved)
 
5
 *
 
6
 *   This program is free software; you can redistribute it and/or
 
7
 *   modify it under the terms of version 2 of the GNU General Public
 
8
 *   License published by the Free Software Foundation.
 
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, contact Novell, Inc.
 
17
 */
 
18
 
 
19
#define _GNU_SOURCE     /* for strndup */
 
20
#include <stdio.h>
 
21
#include <stdlib.h>
 
22
#include <stdarg.h>
 
23
#include <search.h>
 
24
#include <string.h>
 
25
#include <libintl.h>
 
26
#define _(s) gettext(s)
 
27
 
 
28
#include "parser.h"
 
29
#include "parser_yacc.h"
 
30
 
 
31
/* #define DEBUG */
 
32
#ifdef DEBUG
 
33
#define PDEBUG(fmt, args...) printf("Lexer: " fmt, ## args)
 
34
#else
 
35
#define PDEBUG(fmt, args...)    /* Do nothing */
 
36
#endif
 
37
#define NPDEBUG(fmt, args...)   /* Do nothing */
 
38
 
 
39
void *policy_list = NULL;
 
40
 
 
41
static int codomain_compare(const void *a, const void *b)
 
42
{
 
43
        return strcmp(((struct codomain *) a)->name,
 
44
                      ((struct codomain *) b)->name);
 
45
}
 
46
 
 
47
void add_to_list(struct codomain *codomain)
 
48
{
 
49
        struct codomain **result;
 
50
 
 
51
        result = (struct codomain **) tsearch(codomain, &policy_list, codomain_compare);
 
52
        if (!result) {
 
53
                PERROR("Memory allocation error\n");
 
54
                exit(1);
 
55
        }
 
56
 
 
57
        if (*result != codomain) {
 
58
                PERROR("Multiple definitions for profile %s exist,"
 
59
                       "bailing out.\n", codomain->name);
 
60
                exit(1);
 
61
        }
 
62
}
 
63
 
 
64
void add_hat_to_policy(struct codomain *cod, struct codomain *hat)
 
65
{
 
66
        struct codomain **result;
 
67
 
 
68
        result = (struct codomain **) tsearch(hat, &(cod->hat_table), codomain_compare);
 
69
        if (!result) {
 
70
                PERROR("Memory allocation error\n");
 
71
                exit(1);
 
72
        }
 
73
 
 
74
        if (*result != hat) {
 
75
                PERROR("Multiple definitions for hat %s in profile %s exist,"
 
76
                       "bailing out.\n", hat->name, cod->name);
 
77
                exit(1);
 
78
        }
 
79
}
 
80
 
 
81
void add_entry_to_policy(struct codomain *cod, struct cod_entry *entry)
 
82
{
 
83
        entry->next = cod->entries;
 
84
        cod->entries = entry;
 
85
}
 
86
 
 
87
void add_netrule_to_policy(struct codomain *cod, struct cod_net_entry *net_entry)
 
88
{
 
89
        net_entry->next = cod->net_entries;
 
90
        cod->net_entries = net_entry;
 
91
}
 
92
 
 
93
static void __merge_rules(const void *nodep, const VISIT value,
 
94
                          const int __unused depth)
 
95
{
 
96
        struct codomain **t = (struct codomain **) nodep;
 
97
 
 
98
        if (value == preorder || value == endorder)
 
99
                return;
 
100
 
 
101
        if (!codomain_merge_rules(*t)) {
 
102
                PERROR(_("ERROR merging rules for profile %s, failed to load\n"),
 
103
                       (*t)->name);
 
104
                exit(1);
 
105
        }
 
106
}
 
107
 
 
108
int post_merge_rules(void)
 
109
{
 
110
        twalk(policy_list, __merge_rules);
 
111
        return 0;
 
112
}
 
113
 
 
114
int merge_hat_rules(struct codomain *cod)
 
115
{
 
116
        twalk(cod->hat_table, __merge_rules);
 
117
        return 0;
 
118
}
 
119
 
 
120
int die_if_any_regex(void);
 
121
static int die_if_any_hat_regex(struct codomain *cod);
 
122
static int any_regex_entries(struct cod_entry *entry_list);
 
123
 
 
124
/* only call if regex is not allowed */
 
125
static void __any_regex(const void *nodep, const VISIT value,
 
126
                        const int __unused depth)
 
127
{
 
128
        struct codomain **t = (struct codomain **) nodep;
 
129
 
 
130
        if (value == preorder || value == endorder)
 
131
                return;
 
132
 
 
133
        if (any_regex_entries((*t)->entries)) {
 
134
                PERROR(_("ERROR profile %s contains policy elements not usable with this kernel:\n"
 
135
                         "\t'*', '?', character ranges, and alternations are not allowed.\n"
 
136
                         "\t'**' may only be used at the end of a rule.\n"),
 
137
                        (*t)->name);
 
138
                exit(1);
 
139
        }
 
140
 
 
141
        die_if_any_hat_regex(*t);
 
142
}
 
143
 
 
144
/* only call if regex is not allowed */
 
145
int die_if_any_regex(void)
 
146
{
 
147
        twalk(policy_list, __any_regex);
 
148
        return 0;
 
149
}
 
150
 
 
151
/* only call if regex is not allowed */
 
152
static int die_if_any_hat_regex(struct codomain *cod)
 
153
{
 
154
        twalk(cod->hat_table, __any_regex);
 
155
        return 0;
 
156
}
 
157
 
 
158
static int any_regex_entries(struct cod_entry *entry_list)
 
159
{
 
160
        struct cod_entry *entry;
 
161
 
 
162
        list_for_each(entry_list, entry) {
 
163
                if (entry->pattern_type == ePatternRegex)
 
164
                        return TRUE;
 
165
        }
 
166
 
 
167
        return FALSE;
 
168
}
 
169
 
 
170
static void __process_regex(const void *nodep, const VISIT value,
 
171
                            const int __unused depth)
 
172
{
 
173
        struct codomain **t = (struct codomain **) nodep;
 
174
 
 
175
        if (value == preorder || value == endorder)
 
176
                return;
 
177
 
 
178
        if (process_regex(*t) != 0) {
 
179
                PERROR(_("ERROR processing regexs for profile %s, failed to load\n"),
 
180
                       (*t)->name);
 
181
                exit(1);
 
182
        }
 
183
}
 
184
 
 
185
int post_process_regex(void)
 
186
{
 
187
        twalk(policy_list, __process_regex);
 
188
        return 0;
 
189
}
 
190
 
 
191
int process_hat_regex(struct codomain *cod)
 
192
{
 
193
        twalk(cod->hat_table, __process_regex);
 
194
        return 0;
 
195
}
 
196
 
 
197
static void __process_variables(const void *nodep, const VISIT value,
 
198
                                const int __unused depth)
 
199
{
 
200
        struct codomain **t = (struct codomain **) nodep;
 
201
 
 
202
        if (value == preorder || value == endorder)
 
203
                return;
 
204
 
 
205
        if (process_variables(*t) != 0) {
 
206
                PERROR(_("ERROR expanding variables for profile %s, failed to load\n"),
 
207
                       (*t)->name);
 
208
                exit(1);
 
209
        }
 
210
}
 
211
 
 
212
int post_process_variables(void)
 
213
{
 
214
        twalk(policy_list, __process_variables);
 
215
        return 0;
 
216
}
 
217
 
 
218
int process_hat_variables(struct codomain *cod)
 
219
{
 
220
        twalk(cod->hat_table, __process_variables);
 
221
        return 0;
 
222
}
 
223
 
 
224
/* Yuck, is their no other way to pass arguments to a twalk action */
 
225
static int __load_option;
 
226
 
 
227
static void __load_policy(const void *nodep, const VISIT value,
 
228
                          const int __unused depth)
 
229
{
 
230
        struct codomain **t = (struct codomain **) nodep;
 
231
 
 
232
        if (value == preorder || value == endorder)
 
233
                return;
 
234
 
 
235
        if (load_codomain(__load_option, *t) != 0) {
 
236
                exit(1);
 
237
        }
 
238
}
 
239
 
 
240
int load_policy(int option)
 
241
{
 
242
        __load_option = option;
 
243
        twalk(policy_list, __load_policy);
 
244
        return 0;
 
245
}
 
246
 
 
247
/* Yuck, is their no other way to pass arguments to a twalk action */
 
248
static sd_serialize *__p;
 
249
 
 
250
static void __load_hat(const void *nodep, const VISIT value,
 
251
                       const int __unused depth)
 
252
{
 
253
        struct codomain **t = (struct codomain **) nodep;
 
254
 
 
255
        if (value == preorder || value == endorder)
 
256
                return;
 
257
 
 
258
        if (!sd_serialize_profile(__p, *t)) {
 
259
                PERROR(_("ERROR in profile %s, failed to load\n"),
 
260
                       (*t)->name);
 
261
                exit(1);
 
262
        }
 
263
}
 
264
 
 
265
int load_hats(sd_serialize *p, struct codomain *cod)
 
266
{
 
267
        __p = p;
 
268
        twalk(cod->hat_table, __load_hat);
 
269
        return 0;
 
270
}
 
271
 
 
272
static void __dump_policy(const void *nodep, const VISIT value,
 
273
                          const int __unused depth)
 
274
{
 
275
        struct codomain **t = (struct codomain **) nodep;
 
276
 
 
277
        if (value == preorder || value == endorder)
 
278
                return;
 
279
 
 
280
        debug_cod_list(*t);
 
281
}
 
282
 
 
283
void dump_policy(void)
 
284
{
 
285
        twalk(policy_list, __dump_policy);
 
286
}
 
287
 
 
288
void dump_policy_hats(struct codomain *cod)
 
289
{
 
290
        twalk(cod->hat_table, __dump_policy);
 
291
}
 
292
 
 
293
/* Gar */
 
294
static struct codomain *__dump_policy_name;
 
295
 
 
296
static void __dump_policy_hatnames(const void *nodep, const VISIT value,
 
297
                                const int __unused depth)
 
298
{
 
299
        struct codomain **t = (struct codomain **) nodep;
 
300
 
 
301
        if (value == preorder || value == endorder)
 
302
                return;
 
303
 
 
304
        printf("%s^%s\n", __dump_policy_name->name, (*t)->sub_name);
 
305
}
 
306
 
 
307
void dump_policy_hatnames(struct codomain *cod)
 
308
{
 
309
        __dump_policy_name = cod;
 
310
        twalk(cod->hat_table, __dump_policy_hatnames);
 
311
}
 
312
 
 
313
static void __dump_policy_names(const void *nodep, const VISIT value,
 
314
                                const int __unused depth)
 
315
{
 
316
        struct codomain **t = (struct codomain **) nodep;
 
317
 
 
318
        if (value == preorder || value == endorder)
 
319
                return;
 
320
 
 
321
        printf("%s\n", (*t)->name);
 
322
        dump_policy_hatnames(*t);
 
323
}
 
324
 
 
325
void dump_policy_names(void)
 
326
{
 
327
        twalk(policy_list, __dump_policy_names);
 
328
}
 
329
 
 
330
/* gar, more global arguments */
 
331
struct codomain *__hat_merge_policy;
 
332
 
 
333
static void __merge_hat(const void *nodep, const VISIT value,
 
334
                        const int __unused depth)
 
335
{
 
336
        struct codomain **t = (struct codomain **) nodep;
 
337
 
 
338
        if (value == preorder || value == endorder)
 
339
                return;
 
340
        add_hat_to_policy(__hat_merge_policy, (*t));
 
341
}
 
342
 
 
343
/* merge_hats: merges hat_table into hat_table owned by cod */
 
344
static void merge_hats(struct codomain *cod, void *hats)
 
345
{
 
346
        __hat_merge_policy = cod;
 
347
        twalk(hats, __merge_hat);
 
348
}
 
349
 
 
350
/* don't want to free the hat entries in the table, as they were pushed
 
351
 * onto the other table. */
 
352
static void empty_destroy(void __unused *nodep)
 
353
{
 
354
        return;
 
355
}
 
356
 
 
357
struct codomain *merge_policy(struct codomain *a, struct codomain *b)
 
358
{
 
359
        struct codomain *ret = a;
 
360
        struct cod_entry *last;
 
361
        struct cod_net_entry *lastnet;
 
362
        if (!a) {
 
363
                ret = b;
 
364
                goto out;
 
365
        }
 
366
        if (!b)
 
367
                goto out;
 
368
 
 
369
        if (a->name || b->name) {
 
370
                PERROR("ASSERT: policy merges shouldn't have names %s %s\n",
 
371
                       a->name ? a->name : "",
 
372
                       b->name ? b->name : "");
 
373
                exit(1);
 
374
        }
 
375
 
 
376
        if (a->entries) {
 
377
                list_last_entry(a->entries, last);
 
378
                last->next = b->entries;
 
379
        } else {
 
380
                a->entries = b->entries;
 
381
        }
 
382
        b->entries = NULL;
 
383
 
 
384
        if (a->net_entries) {
 
385
                list_last_entry(a->net_entries, lastnet);
 
386
                lastnet->next = b->net_entries;
 
387
        } else {
 
388
                a->net_entries = b->net_entries;
 
389
        }
 
390
        b->net_entries = NULL;
 
391
 
 
392
        a->flags.complain = a->flags.complain || b->flags.complain;
 
393
        a->flags.audit = a->flags.audit || b->flags.audit;
 
394
 
 
395
        a->capabilities = a->capabilities | b->capabilities;
 
396
        merge_hats(a, b->hat_table);
 
397
        tdestroy(b->hat_table, &empty_destroy);
 
398
        b->hat_table = NULL;
 
399
 
 
400
        free_policy(b);
 
401
out:
 
402
        return ret;
 
403
}
 
404
 
 
405
int post_process_policy(void)
 
406
{
 
407
        int retval = 0;
 
408
 
 
409
        retval = post_merge_rules();
 
410
        if (retval != 0) {
 
411
                PERROR(_("%s: Errors found in combining rules postprocessing. Aborting.\n"),
 
412
                       progname);
 
413
                return -1;
 
414
        }
 
415
 
 
416
        retval = post_process_variables();
 
417
        if (retval != 0) {
 
418
                PERROR(_("%s: Errors found during regex postprocess.  Aborting.\n"),
 
419
                       progname);
 
420
                return retval;
 
421
        }
 
422
 
 
423
        retval = post_process_regex();
 
424
        if (retval != 0) {
 
425
                PERROR(_("%s: Errors found during regex postprocess.  Aborting.\n"),
 
426
                       progname);
 
427
                return retval;
 
428
        }
 
429
 
 
430
        return retval;
 
431
}
 
432
 
 
433
void free_hat_entry(void *nodep)
 
434
{
 
435
        struct codomain *t = (struct codomain *)nodep;
 
436
        free_policy(t);
 
437
}
 
438
 
 
439
void free_hat_table(void *hat_table)
 
440
{
 
441
        if (hat_table)
 
442
                tdestroy(hat_table, &free_hat_entry);
 
443
}
 
444
 
 
445
void free_policy(struct codomain *cod)
 
446
{
 
447
        if (!cod)
 
448
                return;
 
449
        free_hat_table(cod->hat_table);
 
450
        free_cod_entries(cod->entries);
 
451
        free_net_entries(cod->net_entries);
 
452
        if (cod->dfarules)
 
453
                aare_delete_ruleset(cod->dfarules);
 
454
        if (cod->dfa)
 
455
                free(cod->dfa);
 
456
        free(cod);
 
457
}