~apparmor-dev/apparmor/apparmor-ubuntu-citrain-trusty

« back to all changes in this revision

Viewing changes to parser/parser_main.c

  • Committer: Seth Arnold
  • Date: 2014-03-12 02:05:16 UTC
  • mto: This revision was merged to the branch mainline in revision 1496.
  • Revision ID: seth.arnold@canonical.com-20140312020516-zjike3pmw6hi861h
[ Jamie Strandboge ]
 * debian/debhelper/dh_apparmor: exit with error if aa-easyprof does not
   exist
 * debian/control: drop Depends on apparmor-easyprof to Suggests for
   dh-apparmor
[ Seth Arnold, Jamie Strandboge, Steve Beattie, John Johansen, Tyler Hicks ]
* New upstream snapshot (LP: #1278702, #1061693, #1285653) dropping very
  large Ubuntu delta and fixing the following bugs:
  - Adjust fonts abstraction for libthai (LP: #1278702)
  - Support translated XDG user directories (LP: #1061693)
  - Adjust abstractions/web-data to include /var/www/html (LP: #1285653)
    Refresh 0002-add-debian-integration-to-lighttpd.patch to include
    /etc/lighttpd/conf-available/*.conf
  - Adjust debian/libapparmor1.symbols to reflect new upstream versioning
    for the aa_query_label() function
  - Raise exceptions in Python bindings when something fails
* ship new Python replacements for previous Perl-based tools
  - debian/apparmor-utils.install: remove usr/share/perl5/Immunix/*.pm and add
    usr/sbin/aa-autodep, usr/sbin/aa-cleanprof and usr/sbin/aa-mergeprof
  - debian/control:
    + remove various Perl dependencies
    + add python-apparmor and python3-apparmor
    + python3-apparmor Breaks: apparmor-easyprof to move the file since it
      ships dist-packages/apparmor/__init__.py now
  - debian/apparmor-utils.manpages: ship new manpages for aa-cleanprof and
    aa-mergeprof
  - debian/rules: build and install Python tools
* debian/apparmor.install:
  - install apparmorfs, dovecot, kernelvars, securityfs, sys,
    and xdg-user-dirs tunables and xdg-user-dirs.d directory
* debian/apparmor.dirs:
  - install /etc/apparmor.d/tunables/xdg-user-dirs.d
* debian/apparmor.postinst: create xdg-user-dirs.d
* debian/apparmor.postrm: remove xdg-user-dirs.d
* Remaining patches:
  - 0001-add-chromium-browser.patch
  - 0002-add-debian-integration-to-lighttpd.patch
  - 0003-ubuntu-manpage-updates.patch
  - 0004-libapparmor-layout-deb.patch (renamed from 0008)
  - 0005-libapparmor-mention-dbus-method-in-getcon-man.patch (renamed from
    0068)
  - 0006-etc-writable.patch (renamed from 0070)
  - 0007-aa-utils_are_bilingual.patch (renamed from 0077)
  - 0008-remove-ptrace.patch
  - 0009-convert-to-rules.patch
  - 0010-list-fns.patch
  - 0011-parse-mode.patch
  - 0012-add-decimal-interp.patch
  - 0013-policy_mediates.patch
  - 0014-fix-failpath.patch
  - 0015-feature_file.patch
  - 0016-fix-network.patch
  - 0017-aare-to-class.patch
  - 0018-add-mediation-unix.patch
  - 0019-parser_version.patch
  - 0020-caching.patch
  - 0021-label-class.patch
  - 0022-signal.patch
  - 0023-fix-lexer-debug.patch
  - 0024-ptrace.patch
  - 0025-use-diff-encode.patch
  - 0026-fix-serialize.patch
  - 0027-fix-af.patch
  - 0028-opt_arg.patch
  - 0029-tests-cond-dbus.patch
  - 0030-tests.diff
* Move manpages from libapparmor1 to libapparmor-dev
  - debian/libapparmor-dev.manpages: install aa_change_hat.2,
    aa_change_profile.2, aa_find_mountpoint.2, aa_getcon.2
  - debian/control: libapparmor-dev Replaces: and Breaks: libapparmor1
* Move /usr/lib/python3/dist-packages/apparmor/__init__.py from
  apparmor-easyprof to python3-apparmor
  - debian/control: python3-apparmor Breaks: apparmor-easyprof
  - debian/apparmor-easyprof.install: remove
    usr/lib/python*.*/site-packages/apparmor*
* New profiles and abstractions:
  - debian/apparmor.install: tunables/dovecot, tunables/kernelvars,
    tunables/xdg-user-dirs, tunables/xdg-user-dirs.d
* Test merge from upstream new pyutils branch (rev 2385)

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 *   Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
3
3
 *   NOVELL (All rights reserved)
4
4
 *
5
 
 *   Copyright (c) 2010 - 2012
 
5
 *   Copyright (c) 2010 - 2013
6
6
 *   Canonical Ltd. (All rights reserved)
7
7
 *
8
8
 *   This program is free software; you can redistribute it and/or
24
24
#include <string.h>
25
25
#include <stdlib.h>
26
26
#include <stdarg.h>
 
27
#include <stddef.h>
27
28
#include <getopt.h>
28
29
#include <errno.h>
29
30
#include <fcntl.h>
30
 
#include <mntent.h>
31
31
#include <libintl.h>
32
32
#include <locale.h>
33
33
#include <dirent.h>
41
41
#include <sys/sysctl.h>
42
42
#include <sys/types.h>
43
43
#include <sys/stat.h>
 
44
#include <sys/apparmor.h>
44
45
 
 
46
#include "lib.h"
45
47
#include "parser.h"
46
48
#include "parser_version.h"
47
49
#include "parser_include.h"
62
64
const char *parser_title        = "AppArmor parser";
63
65
const char *parser_copyright    = "Copyright (C) 1999-2008 Novell Inc.\nCopyright 2009-2012 Canonical Ltd.";
64
66
 
65
 
char *progname;
66
67
int opt_force_complain = 0;
67
68
int binary_input = 0;
68
69
int dump_vars = 0;
71
72
int skip_cache = 0;
72
73
int skip_read_cache = 0;
73
74
int write_cache = 0;
 
75
int cond_clear_cache = 1;               /* only applies if write is set */
 
76
int force_clear_cache = 0;              /* force clearing regargless of state */
 
77
int create_cache_dir = 0;               /* create the cache dir if missing? */
74
78
int preprocess_only = 0;
75
79
int skip_mode_force = 0;
76
80
struct timespec mru_tstamp;
77
81
 
78
 
#define FLAGS_STRING_SIZE 1024
 
82
#define FLAGS_STRING_SIZE 8192
79
83
char *match_string = NULL;
80
84
char *flags_string = NULL;
81
85
char *cacheloc = NULL;
83
87
/* per-profile settings */
84
88
int force_complain = 0;
85
89
 
 
90
/* Make sure to update BOTH the short and long_options */
 
91
static const char *short_options = "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkL:O:po:";
86
92
struct option long_options[] = {
87
93
        {"add",                 0, 0, 'a'},
88
94
        {"binary",              0, 0, 'B'},
89
95
        {"base",                1, 0, 'b'},
90
 
        {"subdomainfs",         0, 0, 'f'},
 
96
        {"subdomainfs",         1, 0, 'f'},
91
97
        {"help",                2, 0, 'h'},
92
98
        {"replace",             0, 0, 'r'},
93
99
        {"reload",              0, 0, 'r'},     /* undocumented reload option == replace */
109
115
        {"skip-read-cache",     0, 0, 'T'},
110
116
        {"write-cache",         0, 0, 'W'},
111
117
        {"show-cache",          0, 0, 'k'},
 
118
        {"skip-bad-cache",      0, 0, 129},     /* no short option */
 
119
        {"purge-cache",         0, 0, 130},     /* no short option */
 
120
        {"create-cache-dir",    0, 0, 131},     /* no short option */
112
121
        {"cache-loc",           1, 0, 'L'},
113
122
        {"debug",               0, 0, 'd'},
114
123
        {"dump",                1, 0, 'D'},
127
136
               parser_copyright);
128
137
}
129
138
 
130
 
static void display_usage(char *command)
 
139
static void display_usage(const char *command)
131
140
{
132
141
        display_version();
133
142
        printf("\nUsage: %s [options] [profile]\n\n"
151
160
               "-K, --skip-cache        Do not attempt to load or save cached profiles\n"
152
161
               "-T, --skip-read-cache   Do not attempt to load cached profiles\n"
153
162
               "-W, --write-cache       Save cached profile (force with -T)\n"
 
163
               "    --skip-bad-cache    Don't clear cache if out of sync\n"
 
164
               "    --purge-cache       Clear cache regardless of its state\n"
 
165
               "    --create-cache-dir  Create the cache dir if missing\n"
154
166
               "-L, --cache-loc n       Set the location of the profile cache\n"
155
167
               "-q, --quiet             Don't emit warnings\n"
156
168
               "-v, --verbose           Show profile names as they load\n"
184
196
          DFA_DUMP_SIMPLE_TREE },
185
197
        { 1, "stats", "Dump all compile stats",
186
198
          DFA_DUMP_TREE_STATS | DFA_DUMP_STATS | DFA_DUMP_TRANS_STATS |
187
 
          DFA_DUMP_EQUIV_STATS },
 
199
          DFA_DUMP_EQUIV_STATS | DFA_DUMP_DIFF_STATS },
188
200
        { 1, "progress", "Dump progress for all compile phases",
189
201
          DFA_DUMP_PROGRESS | DFA_DUMP_STATS | DFA_DUMP_TRANS_PROGRESS |
190
 
          DFA_DUMP_TRANS_STATS },
 
202
          DFA_DUMP_TRANS_STATS | DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
191
203
        { 1, "dfa-progress", "Dump dfa creation as in progress",
192
204
          DFA_DUMP_PROGRESS | DFA_DUMP_STATS },
193
205
        { 1, "dfa-stats", "Dump dfa creation stats", DFA_DUMP_STATS },
212
224
        { 1, "equiv-stats", "Dump equivance class stats",
213
225
          DFA_DUMP_EQUIV_STATS },
214
226
        { 1, "equiv", "Dump equivance class", DFA_DUMP_EQUIV },
 
227
        { 1, "diff-encode", "Dump differential encoding",
 
228
          DFA_DUMP_DIFF_ENCODE },
 
229
        { 1, "diff-stats", "Dump differential encoding stats",
 
230
          DFA_DUMP_DIFF_STATS },
 
231
        { 1, "diff-progress", "Dump progress of differential encoding",
 
232
          DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
215
233
        { 0, NULL, NULL, 0 },
216
234
};
217
235
 
218
236
optflag_table_t optflag_table[] = {
219
237
        { 2, "0", "no optimizations",
220
238
          DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE |
221
 
          DFA_CONTROL_MINIMIZE | DFA_CONTROL_REMOVE_UNREACHABLE
 
239
          DFA_CONTROL_MINIMIZE | DFA_CONTROL_REMOVE_UNREACHABLE |
 
240
          DFA_CONTROL_DIFF_ENCODE
222
241
        },
223
242
        { 1, "equiv", "use equivalent classes", DFA_CONTROL_EQUIV },
224
243
        { 1, "expr-normalize", "expression tree normalization",
230
249
        { 2, "expr-right-simplify", "right simplification first",
231
250
          DFA_CONTROL_TREE_LEFT },
232
251
        { 1, "minimize", "dfa state minimization", DFA_CONTROL_MINIMIZE },
233
 
        { 1, "hash-trans", "minimization - hash transitions during setup",
234
 
          DFA_CONTROL_MINIMIZE_HASH_TRANS },
235
252
        { 1, "filter-deny", "filter out deny information from final dfa",
236
253
          DFA_CONTROL_FILTER_DENY },
237
254
        { 1, "remove-unreachable", "dfa unreachable state removal",
241
258
          DFA_CONTROL_TRANS_HIGH },
242
259
        { 2, "compress-fast", "do faster dfa transition table compression",
243
260
          DFA_CONTROL_TRANS_HIGH },
 
261
        { 1, "diff-encode", "Differentially encode transitions",
 
262
          DFA_CONTROL_DIFF_ENCODE },
244
263
        { 0, NULL, NULL, 0 },
245
264
};
246
265
 
288
307
        return 0;
289
308
}
290
309
 
291
 
static void display_dump(char *command)
 
310
static void display_dump(const char *command)
292
311
{
293
312
        display_version();
294
313
        printf("\n%s: --dump [Option]\n\n"
300
319
        print_flag_table(dumpflag_table);
301
320
}
302
321
 
303
 
static void display_optimize(char *command)
 
322
static void display_optimize(const char *command)
304
323
{
305
324
        display_version();
306
325
        printf("\n%s: -O [Option]\n\n"
449
468
                skip_cache = 1;
450
469
                break;
451
470
        case 'N':
 
471
                count++;
452
472
                names_only = 1;
453
473
                skip_cache = 1;
 
474
                kernel_load = 0;
454
475
                break;
455
476
        case 'S':
456
477
                count++;
510
531
                conf_quiet = 0;
511
532
                break;
512
533
        case 'n':
513
 
                profile_namespace = strdup(optarg);
 
534
                profile_ns = strdup(optarg);
514
535
                break;
515
536
        case 'X':
516
537
                read_implies_exec = 1;
527
548
        case 'T':
528
549
                skip_read_cache = 1;
529
550
                break;
 
551
        case 129:
 
552
                cond_clear_cache = 0;
 
553
                break;
 
554
        case 130:
 
555
                force_clear_cache = 1;
 
556
                break;
 
557
        case 131:
 
558
                create_cache_dir = 1;
 
559
                break;
530
560
        case 'L':
531
561
                cacheloc = strdup(optarg);
532
562
                break;
542
572
                break;
543
573
        default:
544
574
                display_usage(progname);
545
 
                exit(0);
 
575
                exit(1);
546
576
                break;
547
577
        }
548
578
 
555
585
        int count = 0;
556
586
        option = OPTION_ADD;
557
587
 
558
 
        while ((c = getopt_long(argc, argv, "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkO:po:", long_options, &o)) != -1)
 
588
        while ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1)
559
589
        {
560
590
                count += process_arg(c, optarg);
561
591
        }
583
613
 
584
614
        while ((c = getopt_long_file(f, long_options, &optarg, &o)) != -1)
585
615
                process_arg(c, optarg);
 
616
        fclose(f);
586
617
        return 1;
587
618
}
588
619
 
589
 
static inline char *try_subdomainfs_mountpoint(const char *mntpnt,
590
 
                                               const char *path)
591
 
{
592
 
        char *proposed_base = NULL;
593
 
        char *retval = NULL;
594
 
        struct stat buf;
595
 
 
596
 
        if (asprintf(&proposed_base, "%s%s", mntpnt, path)<0 || !proposed_base) {
597
 
                PERROR(_("%s: Could not allocate memory for subdomainbase mount point\n"),
598
 
                       progname);
599
 
                exit(ENOMEM);
600
 
        }
601
 
        if (stat(proposed_base, &buf) == 0) {
602
 
                retval = proposed_base;
603
 
        } else {
604
 
                free(proposed_base);
605
 
        }
606
 
        return retval;
607
 
}
608
620
 
609
621
int find_subdomainfs_mountpoint(void)
610
622
{
611
 
        FILE *mntfile;
612
 
        struct mntent *mntpt;
613
 
 
614
 
        if ((mntfile = setmntent(MOUNTED_FS, "r"))) {
615
 
                while ((mntpt = getmntent(mntfile))) {
616
 
                        char *proposed = NULL;
617
 
                        if (strcmp(mntpt->mnt_type, "securityfs") == 0) {
618
 
                                proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "/" MODULE_NAME);
619
 
                                if (proposed != NULL) {
620
 
                                        subdomainbase = proposed;
621
 
                                        break;
622
 
                                }
623
 
                                proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "/" OLD_MODULE_NAME);
624
 
                                if (proposed != NULL) {
625
 
                                        subdomainbase = proposed;
626
 
                                        break;
627
 
                                }
628
 
                        }
629
 
                        if (strcmp(mntpt->mnt_type, "subdomainfs") == 0) {
630
 
                                proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "");
631
 
                                if (proposed != NULL) {
632
 
                                        subdomainbase = proposed;
633
 
                                        break;
634
 
                                }
635
 
                        }
636
 
                }
637
 
                endmntent(mntfile);
638
 
        }
639
 
 
640
 
        if (!subdomainbase) {
 
623
        if (aa_find_mountpoint(&subdomainbase) == -1) {
641
624
                struct stat buf;
642
625
                if (stat(DEFAULT_APPARMORFS, &buf) == -1) {
643
626
                PERROR(_("Warning: unable to find a suitable fs in %s, is it "
644
627
                         "mounted?\nUse --subdomainfs to override.\n"),
645
628
                       MOUNTED_FS);
646
629
                } else {
647
 
                        subdomainbase = DEFAULT_APPARMORFS;
 
630
                        subdomainbase = strdup(DEFAULT_APPARMORFS);
648
631
                }
649
632
        }
650
633
 
651
634
        return (subdomainbase == NULL);
652
635
}
653
636
 
654
 
 
655
637
int have_enough_privilege(void)
656
638
{
657
639
        uid_t uid, euid;
692
674
        return pos + i;
693
675
}
694
676
 
 
677
struct features_struct {
 
678
        char **buffer;
 
679
        int size;
 
680
        char *pos;
 
681
};
 
682
 
 
683
static int features_dir_cb(DIR *dir, const char *name, struct stat *st,
 
684
                           void *data)
 
685
{
 
686
        struct features_struct *fst = (struct features_struct *) data;
 
687
 
 
688
        /* skip dot files and files with no name */
 
689
        if (*name == '.' || !strlen(name))
 
690
                return 0;
 
691
 
 
692
        fst->pos = snprintf_buffer(*fst->buffer, fst->pos, fst->size, "%s {", name);
 
693
 
 
694
        if (S_ISREG(st->st_mode)) {
 
695
                int len, file;
 
696
                int remaining = fst->size - (fst->pos - *fst->buffer);
 
697
                if (!(file = openat(dirfd(dir), name, O_RDONLY))) {
 
698
                        PDEBUG("Could not open '%s'", name);
 
699
                        return -1;
 
700
                }
 
701
                PDEBUG("Opened features \"%s\"\n", name);
 
702
                if (st->st_size > remaining) {
 
703
                        PDEBUG("Feature buffer full.");
 
704
                        return -1;
 
705
                }
 
706
 
 
707
                do {
 
708
                        len = read(file, fst->pos, remaining);
 
709
                        if (len > 0) {
 
710
                                remaining -= len;
 
711
                                fst->pos += len;
 
712
                                *fst->pos = 0;
 
713
                        }
 
714
                } while (len > 0);
 
715
                if (len < 0) {
 
716
                        PDEBUG("Error reading feature file '%s'\n", name);
 
717
                        return -1;
 
718
                }
 
719
                close(file);
 
720
        } else if (S_ISDIR(st->st_mode)) {
 
721
                if (dirat_for_each(dir, name, fst, features_dir_cb))
 
722
                        return -1;
 
723
        }
 
724
 
 
725
        fst->pos = snprintf_buffer(*fst->buffer, fst->pos, fst->size, "}\n");
 
726
 
 
727
        return 0;
 
728
}
 
729
 
695
730
static char *handle_features_dir(const char *filename, char **buffer, int size,
696
731
                                 char *pos)
697
732
{
698
 
        DIR *dir = NULL;
699
 
        char *dirent_path = NULL;
700
 
        struct dirent *dirent;
701
 
        struct stat my_stat;
702
 
        int len;
 
733
        struct features_struct fst = { buffer, size, pos };
703
734
 
704
 
        PDEBUG("Opened features directory \"%s\"\n", filename);
705
 
        if (!(dir = opendir(filename))) {
706
 
                PDEBUG("opendir failed '%s'", filename);
 
735
        if (dirat_for_each(NULL, filename, &fst, features_dir_cb)) {
 
736
                PDEBUG("Failed evaluating .features\n");
707
737
                exit(1);
708
738
        }
709
739
 
710
 
        while ((dirent = readdir(dir)) != NULL) {
711
 
                int name_len;
712
 
                /* skip dotfiles silently. */
713
 
                if (dirent->d_name[0] == '.')
714
 
                        continue;
715
 
 
716
 
                if (dirent_path)
717
 
                        free(dirent_path);
718
 
                if (asprintf(&dirent_path, "%s/%s", filename, dirent->d_name) < 0)
719
 
                {
720
 
                        PERROR(_("Memory allocation error."));
721
 
                        exit(1);
722
 
                }
723
 
 
724
 
                name_len = strlen(dirent->d_name);
725
 
                if (!name_len)
726
 
                        continue;
727
 
 
728
 
                if (stat(dirent_path, &my_stat)) {
729
 
                        PERROR(_("stat failed for '%s'"), dirent_path);
730
 
                        exit(1);
731
 
                }
732
 
 
733
 
                pos = snprintf_buffer(*buffer, pos, size, "%s {", dirent->d_name);
734
 
                if (S_ISREG(my_stat.st_mode)) {
735
 
                        int file;
736
 
                        int remaining = size - (pos - *buffer);
737
 
                        if (!(file = open(dirent_path, O_RDONLY))) {
738
 
                                PDEBUG("Could not open '%s' in '%s'", dirent_path, filename);
739
 
                                exit(1);
740
 
                                break;
741
 
                        }
742
 
                        PDEBUG("Opened features \"%s\" in \"%s\"\n", dirent_path, filename);
743
 
                        if (my_stat.st_size > remaining) {
744
 
                                PERROR(_("Feature buffer full."));
745
 
                                exit(1);
746
 
                        }
747
 
 
748
 
                        do {
749
 
                                len = read(file, pos, remaining);
750
 
                                if (len > 0) {
751
 
                                        remaining -= len;
752
 
                                        pos += len;
753
 
                                        *pos = 0;
754
 
                                }
755
 
                        } while (len > 0);
756
 
                        if (len < 0) {
757
 
                                PDEBUG("Error reading feature file '%s'\n",
758
 
                                       dirent_path);
759
 
                                exit(1);
760
 
                        }
761
 
                        close(file);
762
 
 
763
 
                } else if (S_ISDIR(my_stat.st_mode)) {
764
 
                        pos = handle_features_dir(dirent_path, buffer, size,
765
 
                                                  pos);
766
 
                        if (!pos)
767
 
                                break;
768
 
 
769
 
                }
770
 
 
771
 
                pos = snprintf_buffer(*buffer, pos, size, "}\n");
772
 
        }
773
 
        if (dirent_path)
774
 
                free(dirent_path);
775
 
        closedir(dir);
776
 
 
777
 
        return pos;
 
740
        return fst.pos;
778
741
}
779
742
 
780
743
/* match_string == NULL --> no match_string available
794
757
 
795
758
        if (S_ISDIR(stat_file.st_mode)) {
796
759
                /* if we have a features directory default to */
797
 
                regex_type = AARE_DFA;
798
760
                perms_create = 1;
799
761
 
800
 
                flags_string = malloc(FLAGS_STRING_SIZE);
 
762
                flags_string = (char *) malloc(FLAGS_STRING_SIZE);
801
763
                handle_features_dir(FLAGS_FILE, &flags_string, FLAGS_STRING_SIZE, flags_string);
802
764
                if (strstr(flags_string, "network"))
803
765
                        kernel_supports_network = 1;
805
767
                        kernel_supports_network = 0;
806
768
                if (strstr(flags_string, "mount"))
807
769
                        kernel_supports_mount = 1;
 
770
                if (strstr(flags_string, "dbus"))
 
771
                        kernel_supports_dbus = 1;
808
772
                return;
809
773
        }
810
774
 
812
776
        if (!ms)
813
777
                goto out;
814
778
 
815
 
        match_string = malloc(1000);
 
779
        match_string = (char *) malloc(1000);
816
780
        if (!match_string) {
817
781
                goto out;
818
782
        }
824
788
 
825
789
out:
826
790
        if (match_string) {
827
 
                if (strstr(match_string, AADFA))
828
 
                        regex_type = AARE_DFA;
829
 
 
830
791
                if (strstr(match_string, " perms=c"))
831
792
                        perms_create = 1;
832
793
        } else {
833
 
                /* no match string default to 2.6.36 version which doesn't
834
 
                 * have a match string
835
 
                 */
836
 
                regex_type = AARE_DFA;
837
794
                perms_create = 1;
838
795
                kernel_supports_network = 0;
839
796
        }
843
800
        return;
844
801
}
845
802
 
846
 
static void get_flags_string(char **flags, char *flags_file) {
 
803
static void get_flags_string(char **flags, const char *flags_file) {
847
804
        char *pos;
848
805
        FILE *f = NULL;
849
806
        size_t size;
856
813
        if (!f)
857
814
                return;
858
815
 
859
 
        *flags = malloc(FLAGS_STRING_SIZE);
 
816
        *flags = (char *) malloc(FLAGS_STRING_SIZE);
860
817
        if (!*flags)
861
818
                goto fail;
862
819
 
866
823
        (*flags)[size] = 0;
867
824
 
868
825
        fclose(f);
869
 
        pos = strstr(*flags, "change_hat=");
870
 
        if (pos) {
871
 
                if (strncmp(pos, "change_hat=1.4", 14) == 0)
872
 
                        flag_changehat_version = FLAG_CHANGEHAT_1_4;
873
 
//fprintf(stderr, "flags string: %s\n", flags_string);
874
 
//fprintf(stderr, "changehat %d\n", flag_changehat_version);
875
 
        }
876
826
        return;
877
827
 
878
828
fail:
883
833
        return;
884
834
}
885
835
 
886
 
int process_binary(int option, char *profilename)
 
836
int process_binary(int option, const char *profilename)
887
837
{
888
838
        char *buffer = NULL;
889
839
        int retval = 0, size = 0, asize = 0, rsize;
903
853
 
904
854
        do {
905
855
                if (asize - size == 0) {
906
 
                        buffer = realloc(buffer, chunksize);
 
856
                  buffer = (char *) realloc(buffer, chunksize);
907
857
                        asize = chunksize;
908
858
                        chunksize <<= 1;
909
859
                        if (!buffer) {
944
894
        return retval;
945
895
}
946
896
 
947
 
void reset_parser(char *filename)
 
897
void reset_parser(const char *filename)
948
898
{
949
899
        memset(&mru_tstamp, 0, sizeof(mru_tstamp));
950
900
        free_aliases();
989
939
                mru_tstamp = stat_file.st_ctim;
990
940
}
991
941
 
992
 
int process_profile(int option, char *profilename)
 
942
int process_profile(int option, const char *profilename)
993
943
{
994
944
        struct stat stat_bin;
995
945
        int retval = 0;
996
946
        char * cachename = NULL;
997
947
        char * cachetemp = NULL;
998
 
        char *basename = NULL;
 
948
        const char *basename = NULL;
999
949
        FILE *cmd;
1000
950
 
1001
951
        /* per-profile states */
1060
1010
         * TODO: Add support for embedded namespace defines if they aren't
1061
1011
         *       removed from the language.
1062
1012
         */
1063
 
        if (profile_namespace)
 
1013
        if (profile_ns)
1064
1014
                skip_cache = 1;
1065
1015
 
1066
1016
        /* Do secondary test to see if cached binary profile is good,
1071
1021
         */
1072
1022
        if ((profilename && option != OPTION_REMOVE) && !force_complain &&
1073
1023
            !skip_cache) {
1074
 
                if (cacheloc) {
1075
 
                        cachename = strdup(cacheloc);
1076
 
                        if (!cachename) {
1077
 
                                PERROR(_("Memory allocation error."));
1078
 
                                exit(1);
1079
 
                        }
1080
 
                } else if (asprintf(&cachename, "%s/%s/%s", basedir, "cache", basename)<0) {
 
1024
                if (asprintf(&cachename, "%s/%s", cacheloc, basename)<0) {
1081
1025
                        PERROR(_("Memory allocation error."));
1082
1026
                        exit(1);
1083
1027
                }
1092
1036
                }
1093
1037
                if (write_cache) {
1094
1038
                        /* Otherwise, set up to save a cached copy */
1095
 
                        if (asprintf(&cachetemp, "%s/%s/%s-XXXXXX", basedir, "cache", basename)<0) {
 
1039
                        if (asprintf(&cachetemp, "%s-XXXXXX", cachename)<0) {
1096
1040
                                perror("asprintf");
1097
1041
                                exit(1);
1098
1042
                        }
1150
1094
                }
1151
1095
 
1152
1096
                if (useable_cache) {
1153
 
                        rename(cachetemp, cachename);
1154
 
                        if (show_cache)
 
1097
                        if (rename(cachetemp, cachename) < 0) {
 
1098
                                pwarn("Warning failed to write cache: %s\n", cachename);
 
1099
                                unlink(cachetemp);
 
1100
                        }
 
1101
                        else if (show_cache)
1155
1102
                                PERROR("Wrote cache: %s\n", cachename);
1156
1103
                }
1157
1104
                else {
1165
1112
        return retval;
1166
1113
}
1167
1114
 
 
1115
/* data - name of parent dir */
 
1116
static int profile_dir_cb(__unused DIR *dir, const char *name, struct stat *st,
 
1117
                          void *data)
 
1118
{
 
1119
        int rc = 0;
 
1120
 
 
1121
        if (!S_ISDIR(st->st_mode) && !is_blacklisted(name, NULL)) {
 
1122
                const char *dirname = (const char *)data;
 
1123
                char *path;
 
1124
                if (asprintf(&path, "%s/%s", dirname, name) < 0)
 
1125
                        PERROR(_("Out of memory"));
 
1126
                rc = process_profile(option, path);
 
1127
                free(path);
 
1128
        }
 
1129
        return rc;
 
1130
}
 
1131
 
 
1132
/* data - name of parent dir */
 
1133
static int binary_dir_cb(__unused DIR *dir, const char *name, struct stat *st,
 
1134
                         void *data)
 
1135
{
 
1136
        int rc = 0;
 
1137
 
 
1138
        if (!S_ISDIR(st->st_mode) && !is_blacklisted(name, NULL)) {
 
1139
                const char *dirname = (const char *)data;
 
1140
                char *path;
 
1141
                if (asprintf(&path, "%s/%s", dirname, name) < 0)
 
1142
                        PERROR(_("Out of memory"));
 
1143
                rc = process_binary(option, path);
 
1144
                free(path);
 
1145
        }
 
1146
        return rc;
 
1147
}
 
1148
 
 
1149
static int clear_cache_cb(DIR *dir, const char *path, struct stat *st,
 
1150
                          __unused void *data)
 
1151
{
 
1152
        /* remove regular files */
 
1153
        if (S_ISREG(st->st_mode))
 
1154
                return unlinkat(dirfd(dir), path, 0);
 
1155
 
 
1156
        /* do nothing with other file types */
 
1157
        return 0;
 
1158
}
 
1159
 
 
1160
static int clear_cache_files(const char *path)
 
1161
{
 
1162
        return dirat_for_each(NULL, path, NULL, clear_cache_cb);
 
1163
}
 
1164
 
 
1165
static int create_cache(const char *cachedir, const char *path,
 
1166
                        const char *features)
 
1167
{
 
1168
        struct stat stat_file;
 
1169
        FILE * f = NULL;
 
1170
 
 
1171
        if (clear_cache_files(cacheloc) != 0)
 
1172
                goto error;
 
1173
 
 
1174
create_file:
 
1175
        f = fopen(path, "w");
 
1176
        if (f) {
 
1177
                if (fwrite(features, strlen(features), 1, f) != 1 )
 
1178
                        goto error;
 
1179
 
 
1180
                fclose(f);
 
1181
 
 
1182
 
 
1183
                return 0;
 
1184
        }
 
1185
 
 
1186
error:
 
1187
        /* does the dir exist? */
 
1188
        if (stat(cachedir, &stat_file) == -1 && create_cache_dir) {
 
1189
                if (mkdir(cachedir, 0700) == 0)
 
1190
                        goto create_file;
 
1191
                if (show_cache)
 
1192
                        PERROR(_("Can't create cache directory: %s\n"), cachedir);
 
1193
        } else if (!S_ISDIR(stat_file.st_mode)) {
 
1194
                if (show_cache)
 
1195
                        PERROR(_("File in cache directory location: %s\n"), cachedir);
 
1196
        } else {
 
1197
                if (show_cache)
 
1198
                        PERROR(_("Can't update cache directory: %s\n"), cachedir);
 
1199
        }
 
1200
 
 
1201
        if (show_cache)
 
1202
                PERROR("Cache write disabled: cannot create %s\n", path);
 
1203
        write_cache = 0;
 
1204
 
 
1205
        return -1;
 
1206
}
 
1207
 
1168
1208
static void setup_flags(void)
1169
1209
{
1170
1210
        char *cache_features_path = NULL;
1182
1222
                write_cache = 0;
1183
1223
                skip_read_cache = 1;
1184
1224
                return;
1185
 
        }
 
1225
        } else if (strstr(flags_string, "network"))
 
1226
                kernel_supports_network = 1;
 
1227
        else
 
1228
                kernel_supports_network = 0;
 
1229
 
 
1230
 
1186
1231
 
1187
1232
        /*
1188
1233
         * Deal with cache directory versioning:
1190
1235
         *  - If cache/.features exists, and does not match flags_string,
1191
1236
         *    force cache reading/writing off.
1192
1237
         */
1193
 
        if (asprintf(&cache_features_path, "%s/cache/.features", basedir) == -1) {
1194
 
                perror("asprintf");
 
1238
        if (asprintf(&cache_features_path, "%s/.features", cacheloc) == -1) {
 
1239
                PERROR(_("Memory allocation error."));
1195
1240
                exit(1);
1196
1241
        }
1197
1242
 
1198
1243
        get_flags_string(&cache_flags, cache_features_path);
1199
1244
        if (cache_flags) {
1200
1245
                if (strcmp(flags_string, cache_flags) != 0) {
1201
 
                        if (show_cache) PERROR("Cache read/write disabled: %s does not match %s\n", FLAGS_FILE, cache_features_path);
1202
 
                        write_cache = 0;
1203
 
                        skip_read_cache = 1;
 
1246
                        if (write_cache && cond_clear_cache) {
 
1247
                                if (create_cache(cacheloc, cache_features_path,
 
1248
                                                 flags_string))
 
1249
                                        skip_read_cache = 1;
 
1250
                        } else {
 
1251
                                if (show_cache)
 
1252
                                        PERROR("Cache read/write disabled: %s does not match %s\n", FLAGS_FILE, cache_features_path);
 
1253
                                write_cache = 0;
 
1254
                                skip_read_cache = 1;
 
1255
                        }
1204
1256
                }
1205
1257
                free(cache_flags);
1206
1258
                cache_flags = NULL;
1207
 
        }
1208
 
        else if (write_cache) {
1209
 
                FILE * f = NULL;
1210
 
                int failure = 0;
1211
 
 
1212
 
                f = fopen(cache_features_path, "w");
1213
 
                if (!f) failure = 1;
1214
 
                else {
1215
 
                        if (fwrite(flags_string, strlen(flags_string), 1, f) != 1 ) {
1216
 
                                failure = 1;
1217
 
                        }
1218
 
                        if (fclose(f) != 0) failure = 1;
1219
 
                }
1220
 
 
1221
 
                if (failure) {
1222
 
                        if (show_cache) PERROR("Cache write disabled: cannot write to %s\n", cache_features_path);
1223
 
                        write_cache = 0;
1224
 
                }
 
1259
        } else if (write_cache) {
 
1260
                create_cache(cacheloc, cache_features_path, flags_string);
1225
1261
        }
1226
1262
 
1227
1263
        free(cache_features_path);
1251
1287
                return retval;
1252
1288
        }
1253
1289
 
 
1290
        /* create the cacheloc once and use it everywhere */
 
1291
        if (!cacheloc) {
 
1292
                if (asprintf(&cacheloc, "%s/cache", basedir) == -1) {
 
1293
                        PERROR(_("Memory allocation error."));
 
1294
                        exit(1);
 
1295
                }
 
1296
        }
 
1297
 
 
1298
        if (force_clear_cache) 
 
1299
                exit(clear_cache_files(cacheloc));
 
1300
 
1254
1301
        /* Check to make sure there is an interface to load policy */
1255
1302
        if (!(UNPRIVILEGED_OPS) && (subdomainbase == NULL) &&
1256
1303
            (retval = find_subdomainfs_mountpoint())) {
1263
1310
 
1264
1311
        retval = 0;
1265
1312
        for (i = optind; retval == 0 && i <= argc; i++) {
 
1313
                struct stat stat_file;
 
1314
 
1266
1315
                if (i < argc && !(profilename = strdup(argv[i]))) {
1267
1316
                        perror("strdup");
1268
1317
                        return -1;
1271
1320
                if (i == argc && optind != argc)
1272
1321
                        continue;
1273
1322
 
1274
 
                if (binary_input) {
 
1323
                if (profilename && stat(profilename, &stat_file) == -1) {
 
1324
                        PERROR("File %s not found, skipping...\n", profilename);
 
1325
                        continue;
 
1326
                }
 
1327
 
 
1328
                if (profilename && S_ISDIR(stat_file.st_mode)) {
 
1329
                        int (*cb)(DIR *dir, const char *name, struct stat *st,
 
1330
                                  void *data);
 
1331
                        cb = binary_input ? binary_dir_cb : profile_dir_cb;
 
1332
                        if (dirat_for_each(NULL, profilename, profilename, cb)) {
 
1333
                                PDEBUG("Failed loading profiles from %s\n",
 
1334
                                       profilename);
 
1335
                                exit(1);
 
1336
                        }
 
1337
                } else if (binary_input) {
1275
1338
                        retval = process_binary(option, profilename);
1276
1339
                } else {
1277
1340
                        retval = process_profile(option, profilename);