perm_checker.c revision e16cb84e2324f05334d18dcf5956f20f44262b62
1e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project/*
2e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *
4e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * you may not use this file except in compliance with the License.
6e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * You may obtain a copy of the License at
7e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *
8e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *
10e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * See the License for the specific language governing permissions and
14e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * limitations under the License.
15e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project */
16e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
17e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project// A simple file permissions checker. See associated README.
18e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
19e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#define _GNU_SOURCE
20e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
21e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <stdio.h>
22e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <stdlib.h>
23e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <stdarg.h>
24e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <string.h>
25e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <ctype.h>
26e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <sys/types.h>
27e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <dirent.h>
28e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <errno.h>
29e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
30e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <sys/stat.h>
31e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <unistd.h>
32e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <time.h>
33e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
34e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <pwd.h>
35e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <grp.h>
36e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
37e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <linux/kdev_t.h>
38e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
39e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#define PERMS(M) (M & ~S_IFMT)
40e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#define MAX_NAME_LEN 4096
41e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#define MAX_UID_LEN 256
42e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#define MAX_GID_LEN MAX_UID_LEN
43e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
44e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectenum perm_rule_type {EXACT_FILE = 0, EXACT_DIR, WILDCARD, RECURSIVE,
45e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    NUM_PR_TYPES};
46e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
47e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstruct perm_rule {
48e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    char *rule_text;
49e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int rule_line;
50e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    char *spec;
51e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    mode_t min_mode;
52e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    mode_t max_mode;
53e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    uid_t min_uid;
54e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    uid_t max_uid;
55e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    gid_t min_gid;
56e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    gid_t max_gid;
57e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    enum perm_rule_type type;
58e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    struct perm_rule *next;
59e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project};
60e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
61e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projecttypedef struct perm_rule perm_rule_t;
62e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
63e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic perm_rule_t *rules[NUM_PR_TYPES];
64e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
65e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic uid_t str2uid(char *str, int line_num)
66e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{
67e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    struct passwd *pw;
68e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
69e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (isdigit(str[0]))
70e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return (uid_t) atol(str);
71e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
72e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!(pw = getpwnam(str))) {
73e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        printf("# ERROR # Invalid uid '%s' reading line %d\n", str, line_num);
74e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        exit(255);
75e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
76e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return pw->pw_uid;
77e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
78e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
79e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic gid_t str2gid(char *str, int line_num)
80e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{
81e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    struct group *gr;
82e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
83e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (isdigit(str[0]))
84e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return (uid_t) atol(str);
85e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
86e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!(gr = getgrnam(str))) {
87e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        printf("# ERROR # Invalid gid '%s' reading line %d\n", str, line_num);
88e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        exit(255);
89e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
90e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return gr->gr_gid;
91e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
92e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
93e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int read_rules(FILE *fp)
94e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{
95e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    char spec[MAX_NAME_LEN + 5];  // Allows for "/..." suffix + terminator
96e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    char min_uid_buf[MAX_UID_LEN + 1], max_uid_buf[MAX_UID_LEN + 1];
97e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    char min_gid_buf[MAX_GID_LEN + 1], max_gid_buf[MAX_GID_LEN + 1];
98e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    char rule_text_buf[MAX_NAME_LEN + 2*MAX_UID_LEN + 2*MAX_GID_LEN + 9];
99e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    unsigned long min_mode, max_mode;
100e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    perm_rule_t *pr;
101e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int res;
102e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int num_rules = 0, num_lines = 0;
103e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
104e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    // Note: Use of an unsafe C function here is OK, since this is a test
105e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    while ((res = fscanf(fp, "%s %lo %lo %s %s %s %s\n", spec,
106e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                         &min_mode, &max_mode, min_uid_buf, max_uid_buf,
107e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                         min_gid_buf, max_gid_buf)) != EOF) {
108e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        num_lines++;
109e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (res < 7) {
110e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            printf("# WARNING # Invalid rule on line number %d\n", num_lines);
111e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            continue;
112e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
113e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (!(pr = malloc(sizeof(perm_rule_t)))) {
114e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            printf("Out of memory.\n");
115e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            exit(255);
116e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
117e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (snprintf(rule_text_buf, sizeof(rule_text_buf),
118e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                     "%s %lo %lo %s %s %s %s", spec, min_mode, max_mode,
119e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                     min_uid_buf, max_uid_buf, min_gid_buf, max_gid_buf)
120e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                     >= (long int) sizeof(rule_text_buf)) {
121e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            // This should never happen, but just in case...
122e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            printf("# ERROR # Maximum length limits exceeded on line %d\n",
123e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                   num_lines);
124e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            exit(255);
125e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
126e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr->rule_text = strndup(rule_text_buf, sizeof(rule_text_buf));
127e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr->rule_line = num_lines;
128e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (strstr(spec, "/...")) {
129e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            pr->spec = strndup(spec, strlen(spec) - 3);
130e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            pr->type = RECURSIVE;
131e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        } else if (spec[strlen(spec) - 1] == '*') {
132e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            pr->spec = strndup(spec, strlen(spec) - 1);
133e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            pr->type = WILDCARD;
134e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        } else if (spec[strlen(spec) - 1] == '/') {
135e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            pr->spec = strdup(spec);
136e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            pr->type = EXACT_DIR;
137e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        } else {
138e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            pr->spec = strdup(spec);
139e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            pr->type = EXACT_FILE;
140e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
141e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if ((pr->spec == NULL) || (pr->rule_text == NULL)) {
142e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            printf("Out of memory.\n");
143e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            exit(255);
144e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
145e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr->min_mode = min_mode;
146e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr->max_mode = max_mode;
147e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr->min_uid = str2uid(min_uid_buf, num_lines);
148e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr->max_uid = str2uid(max_uid_buf, num_lines);
149e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr->min_gid = str2gid(min_gid_buf, num_lines);
150e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr->max_gid = str2gid(max_gid_buf, num_lines);
151e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
152e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        // Add the rule to the appropriate set
153e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr->next = rules[pr->type];
154e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        rules[pr->type] = pr;
155e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        num_rules++;
156e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#if 0  // Useful for debugging
157e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        printf("rule #%d: type = %d spec = %s min_mode = %o max_mode = %o "
158e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project               "min_uid = %d max_uid = %d min_gid = %d max_gid = %d\n",
159e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project               num_rules, pr->type, pr->spec, pr->min_mode, pr->max_mode,
160e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project               pr->min_uid, pr->max_uid, pr->min_gid, pr->max_gid);
161e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#endif
162e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
163e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return num_lines - num_rules;
164e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
165e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
166e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic void print_failed_rule(const perm_rule_t *pr)
167e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{
168e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    printf("# INFO # Failed rule #%d: %s\n", pr->rule_line, pr->rule_text);
169e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
170e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
171e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic void print_new_rule(const char *name, mode_t mode, uid_t uid, gid_t gid)
172e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{
173e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    struct passwd *pw;
174e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    struct group *gr;
175e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    gr = getgrgid(gid);
176e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    pw = getpwuid(uid);
177e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    printf("%s %4o %4o %s %d %s %d\n", name, mode, mode, pw->pw_name, uid,
178e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project           gr->gr_name, gid);
179e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
180e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
181e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project// Returns 1 if the rule passes, prints the failure and returns 0 if not
182e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int pass_rule(const perm_rule_t *pr, mode_t mode, uid_t uid, gid_t gid)
183e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{
184e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (((pr->min_mode & mode) == pr->min_mode) &&
185e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            ((pr->max_mode | mode) == pr->max_mode) &&
186e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            (pr->min_gid <= gid) && (pr->max_gid >= gid) &&
187e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            (pr->min_uid <= uid) && (pr->max_uid >= uid))
188e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return 1;
189e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    print_failed_rule(pr);
190e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return 0;
191e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
192e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
193e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project// Returns 0 on success
194e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int validate_file(const char *name, mode_t mode, uid_t uid, gid_t gid)
195e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{
196e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    perm_rule_t *pr;
197e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int rules_matched = 0;
198e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int retval = 0;
199e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
200e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    pr = rules[EXACT_FILE];
201e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    while (pr != NULL) {
202e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (strcmp(name, pr->spec) == 0) {
203e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            if (!pass_rule(pr, mode, uid, gid))
204e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                retval++;
205e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            else
206e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                rules_matched++;  // Exact match found
207e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
208e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr = pr->next;
209e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
210e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
211e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if ((retval + rules_matched) > 1)
212e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        printf("# WARNING # Multiple exact rules for file: %s\n", name);
213e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
214e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    // If any exact rule matched or failed, we are done with this file
215e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (retval)
216e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        print_new_rule(name, mode, uid, gid);
217e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (rules_matched || retval)
218e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return retval;
219e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
220e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    pr = rules[WILDCARD];
221e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    while (pr != NULL) {
222e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        // Check if the spec is a prefix of the filename, and that the file
223e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        // is actually in the same directory as the wildcard.
224e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if ((strstr(name, pr->spec) == name) &&
225e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                (!strchr(name + strlen(pr->spec), '/'))) {
226e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            if (!pass_rule(pr, mode, uid, gid))
227e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                retval++;
228e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            else
229e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                rules_matched++;
230e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
231e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr = pr->next;
232e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
233e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
234e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    pr = rules[RECURSIVE];
235e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    while (pr != NULL) {
236e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (strstr(name, pr->spec) == name) {
237e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            if (!pass_rule(pr, mode, uid, gid))
238e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                retval++;
239e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            else
240e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                rules_matched++;
241e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
242e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr = pr->next;
243e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
244e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
245e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!rules_matched)
246e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        retval++;  // In case no rules either matched or failed, be sure to fail
247e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
248e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (retval)
249e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        print_new_rule(name, mode, uid, gid);
250e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
251e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return retval;
252e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
253e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
254e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project// Returns 0 on success
255e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int validate_link(const char *name, mode_t mode, uid_t uid, gid_t gid)
256e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{
257e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    perm_rule_t *pr;
258e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int rules_matched = 0;
259e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int retval = 0;
260e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
261e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    // For now, we match links against "exact" file rules only
262e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    pr = rules[EXACT_FILE];
263e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    while (pr != NULL) {
264e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (strcmp(name, pr->spec) == 0) {
265e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            if (!pass_rule(pr, mode, uid, gid))
266e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                retval++;
267e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            else
268e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                rules_matched++;  // Exact match found
269e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
270e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr = pr->next;
271e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
272e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
273e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if ((retval + rules_matched) > 1)
274e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        printf("# WARNING # Multiple exact rules for link: %s\n", name);
275e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (retval)
276e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        print_new_rule(name, mode, uid, gid);
277e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
278e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    // Note: Unlike files, if no rules matches for links, retval = 0 (success).
279e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return retval;
280e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
281e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
282e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project// Returns 0 on success
283e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int validate_dir(const char *name, mode_t mode, uid_t uid, gid_t gid)
284e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{
285e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    perm_rule_t *pr;
286e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int rules_matched = 0;
287e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int retval = 0;
288e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
289e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    pr = rules[EXACT_DIR];
290e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    while (pr != NULL) {
291e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (strcmp(name, pr->spec) == 0) {
292e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            if (!pass_rule(pr, mode, uid, gid))
293e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                retval++;
294e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            else
295e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                rules_matched++;  // Exact match found
296e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
297e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr = pr->next;
298e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
299e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
300e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if ((retval + rules_matched) > 1)
301e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        printf("# WARNING # Multiple exact rules for directory: %s\n", name);
302e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
303e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    // If any exact rule matched or failed, we are done with this directory
304e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (retval)
305e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        print_new_rule(name, mode, uid, gid);
306e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (rules_matched || retval)
307e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return retval;
308e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
309e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    pr = rules[RECURSIVE];
310e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    while (pr != NULL) {
311e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (strstr(name, pr->spec) == name) {
312e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            if (!pass_rule(pr, mode, uid, gid))
313e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                retval++;
314e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            else
315e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                rules_matched++;
316e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
317e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        pr = pr->next;
318e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
319e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
320e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!rules_matched)
321e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        retval++;  // In case no rules either matched or failed, be sure to fail
322e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
323e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (retval)
324e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        print_new_rule(name, mode, uid, gid);
325e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
326e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return retval;
327e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
328e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
329e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project// Returns 0 on success
330e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int check_path(const char *name)
331e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{
332e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    char namebuf[MAX_NAME_LEN + 1];
333e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    char tmp[MAX_NAME_LEN + 1];
334e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    DIR *d;
335e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    struct dirent *de;
336e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    struct stat s;
337e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int err;
338e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int retval = 0;
339e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
340e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    err = lstat(name, &s);
341e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (err < 0) {
342e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (errno != ENOENT)
343e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        {
344e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            perror(name);
345e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            return 1;
346e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
347e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return 0;  // File doesn't exist anymore
348e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
349e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
350e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (S_ISDIR(s.st_mode)) {
351e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if (name[strlen(name) - 1] != '/')
352e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            snprintf(namebuf, sizeof(namebuf), "%s/", name);
353e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        else
354e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            snprintf(namebuf, sizeof(namebuf), "%s", name);
355e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
356e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        retval |= validate_dir(namebuf, PERMS(s.st_mode), s.st_uid, s.st_gid);
357e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        d = opendir(namebuf);
358e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        if(d == 0) {
359e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            printf("%s : opendir failed: %s\n", namebuf, strerror(errno));
360e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            return 1;
361e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
362e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
363e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        while ((de = readdir(d)) != 0) {
364e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
365e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project                continue;
366e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            snprintf(tmp, sizeof(tmp), "%s%s", namebuf, de->d_name);
367e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project            retval |= check_path(tmp);
368e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        }
369e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        closedir(d);
370e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return retval;
371e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    } else if (S_ISLNK(s.st_mode)) {
372e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return validate_link(name, PERMS(s.st_mode), s.st_uid, s.st_gid);
373e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    } else {
374e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return validate_file(name, PERMS(s.st_mode), s.st_uid, s.st_gid);
375e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
376e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
377e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
378e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectint main(int argc, char **argv)
379e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{
380e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    FILE *fp;
381e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    int i;
382e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
383e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    // Initialize ruleset pointers
384e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    for (i = 0; i < NUM_PR_TYPES; i++)
385e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        rules[i] = NULL;
386e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
387e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (!(fp = fopen("/etc/perm_checker.conf", "r"))) {
388e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        printf("Error opening /etc/perm_checker.conf\n");
389e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        exit(255);
390e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    }
391e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    read_rules(fp);
392e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    fclose(fp);
393e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
394e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    if (check_path("/"))
395e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project        return 255;
396e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
397e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    printf("Passed.\n");
398e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    return 0;
399e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
400