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