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 3918d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish#define DEFAULT_CONFIG_FILE "/data/local/perm_checker.conf" 4018d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 41e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#define PERMS(M) (M & ~S_IFMT) 42e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#define MAX_NAME_LEN 4096 43e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#define MAX_UID_LEN 256 44e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#define MAX_GID_LEN MAX_UID_LEN 45e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 4618d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfishstatic char *config_file; 4718d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfishstatic char *executable_file; 4818d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 49e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectenum perm_rule_type {EXACT_FILE = 0, EXACT_DIR, WILDCARD, RECURSIVE, 50e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project NUM_PR_TYPES}; 51e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 52e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstruct perm_rule { 53e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project char *rule_text; 54e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int rule_line; 55e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project char *spec; 56e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project mode_t min_mode; 57e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project mode_t max_mode; 58e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project uid_t min_uid; 59e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project uid_t max_uid; 60e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project gid_t min_gid; 61e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project gid_t max_gid; 62e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project enum perm_rule_type type; 63e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project struct perm_rule *next; 64e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}; 65e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 66e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projecttypedef struct perm_rule perm_rule_t; 67e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 68e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic perm_rule_t *rules[NUM_PR_TYPES]; 69e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 70e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic uid_t str2uid(char *str, int line_num) 71e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 72e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project struct passwd *pw; 73e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 74e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (isdigit(str[0])) 75e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return (uid_t) atol(str); 76e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 77e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (!(pw = getpwnam(str))) { 78e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project printf("# ERROR # Invalid uid '%s' reading line %d\n", str, line_num); 79e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project exit(255); 80e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 81e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return pw->pw_uid; 82e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 83e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 84e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic gid_t str2gid(char *str, int line_num) 85e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 86e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project struct group *gr; 87e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 88e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (isdigit(str[0])) 89e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return (uid_t) atol(str); 90e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 91e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (!(gr = getgrnam(str))) { 92e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project printf("# ERROR # Invalid gid '%s' reading line %d\n", str, line_num); 93e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project exit(255); 94e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 95e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return gr->gr_gid; 96e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 97e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 9818d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfishstatic void add_rule(int line_num, char *spec, 9918d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish unsigned long min_mode, unsigned long max_mode, 10018d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish char *min_uid_buf, char *max_uid_buf, 10118d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish char *min_gid_buf, char *max_gid_buf) { 10218d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 10318d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish char rule_text_buf[MAX_NAME_LEN + 2*MAX_UID_LEN + 2*MAX_GID_LEN + 9]; 10418d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish perm_rule_t *pr = malloc(sizeof(perm_rule_t)); 10518d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish if (!pr) { 10618d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish printf("Out of memory.\n"); 10718d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish exit(255); 10818d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish } 10918d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish if (snprintf(rule_text_buf, sizeof(rule_text_buf), 11018d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish "%s %lo %lo %s %s %s %s", spec, min_mode, max_mode, 11118d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish min_uid_buf, max_uid_buf, min_gid_buf, max_gid_buf) 11218d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish >= (long int) sizeof(rule_text_buf)) { 11318d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish // This should never happen, but just in case... 11418d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish printf("# ERROR # Maximum length limits exceeded on line %d\n", 11518d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish line_num); 11618d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish exit(255); 11718d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish } 11818d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->rule_text = strndup(rule_text_buf, sizeof(rule_text_buf)); 11918d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->rule_line = line_num; 12018d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish if (strstr(spec, "/...")) { 12118d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->spec = strndup(spec, strlen(spec) - 3); 12218d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->type = RECURSIVE; 12318d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish } else if (spec[strlen(spec) - 1] == '*') { 12418d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->spec = strndup(spec, strlen(spec) - 1); 12518d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->type = WILDCARD; 12618d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish } else if (spec[strlen(spec) - 1] == '/') { 12718d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->spec = strdup(spec); 12818d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->type = EXACT_DIR; 12918d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish } else { 13018d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->spec = strdup(spec); 13118d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->type = EXACT_FILE; 13218d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish } 13318d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish if ((pr->spec == NULL) || (pr->rule_text == NULL)) { 13418d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish printf("Out of memory.\n"); 13518d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish exit(255); 13618d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish } 13718d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->min_mode = min_mode; 13818d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->max_mode = max_mode; 13918d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->min_uid = str2uid(min_uid_buf, line_num); 14018d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->max_uid = str2uid(max_uid_buf, line_num); 14118d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->min_gid = str2gid(min_gid_buf, line_num); 14218d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->max_gid = str2gid(max_gid_buf, line_num); 14318d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 14418d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish // Add the rule to the appropriate set 14518d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->next = rules[pr->type]; 14618d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish rules[pr->type] = pr; 14718d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish#if 0 // Useful for debugging 14818d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish printf("rule #%d: type = %d spec = %s min_mode = %o max_mode = %o " 14918d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish "min_uid = %d max_uid = %d min_gid = %d max_gid = %d\n", 15018d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish num_rules, pr->type, pr->spec, pr->min_mode, pr->max_mode, 15118d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish pr->min_uid, pr->max_uid, pr->min_gid, pr->max_gid); 15218d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish#endif 15318d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish} 15418d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 155e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int read_rules(FILE *fp) 156e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 157e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project char spec[MAX_NAME_LEN + 5]; // Allows for "/..." suffix + terminator 158e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project char min_uid_buf[MAX_UID_LEN + 1], max_uid_buf[MAX_UID_LEN + 1]; 159e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project char min_gid_buf[MAX_GID_LEN + 1], max_gid_buf[MAX_GID_LEN + 1]; 160e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project unsigned long min_mode, max_mode; 161e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int res; 162e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int num_rules = 0, num_lines = 0; 163e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 164e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project // Note: Use of an unsafe C function here is OK, since this is a test 165e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project while ((res = fscanf(fp, "%s %lo %lo %s %s %s %s\n", spec, 166e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project &min_mode, &max_mode, min_uid_buf, max_uid_buf, 167e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project min_gid_buf, max_gid_buf)) != EOF) { 168e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project num_lines++; 169e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (res < 7) { 170e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project printf("# WARNING # Invalid rule on line number %d\n", num_lines); 171e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project continue; 172e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 17318d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish add_rule(num_lines, spec, 17418d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish min_mode, max_mode, 17518d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish min_uid_buf, max_uid_buf, 17618d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish min_gid_buf, max_gid_buf); 177e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project num_rules++; 178e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 17918d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 18018d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish // Automatically add a rule to match this executable itself 18118d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish add_rule(-1, executable_file, 18218d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 000, 0777, 18318d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish "root", "shell", 18418d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish "root", "shell"); 18518d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 18618d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish // Automatically add a rule to match the configuration file 18718d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish add_rule(-1, config_file, 18818d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 000, 0777, 18918d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish "root", "shell", 19018d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish "root", "shell"); 19118d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 192e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return num_lines - num_rules; 193e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 194e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 195e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic void print_failed_rule(const perm_rule_t *pr) 196e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 197e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project printf("# INFO # Failed rule #%d: %s\n", pr->rule_line, pr->rule_text); 198e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 199e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 200e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic void print_new_rule(const char *name, mode_t mode, uid_t uid, gid_t gid) 201e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 202e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project struct passwd *pw; 203e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project struct group *gr; 204e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project gr = getgrgid(gid); 205e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pw = getpwuid(uid); 206e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project printf("%s %4o %4o %s %d %s %d\n", name, mode, mode, pw->pw_name, uid, 207e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project gr->gr_name, gid); 208e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 209e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 210e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project// Returns 1 if the rule passes, prints the failure and returns 0 if not 211e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int pass_rule(const perm_rule_t *pr, mode_t mode, uid_t uid, gid_t gid) 212e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 213e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (((pr->min_mode & mode) == pr->min_mode) && 214e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project ((pr->max_mode | mode) == pr->max_mode) && 215e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project (pr->min_gid <= gid) && (pr->max_gid >= gid) && 216e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project (pr->min_uid <= uid) && (pr->max_uid >= uid)) 217e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return 1; 218e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project print_failed_rule(pr); 219e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return 0; 220e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 221e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 222e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project// Returns 0 on success 223e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int validate_file(const char *name, mode_t mode, uid_t uid, gid_t gid) 224e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 225e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project perm_rule_t *pr; 226e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int rules_matched = 0; 227e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int retval = 0; 228e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 229e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = rules[EXACT_FILE]; 230e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project while (pr != NULL) { 231e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (strcmp(name, pr->spec) == 0) { 232e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (!pass_rule(pr, mode, uid, gid)) 233e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project retval++; 234e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project else 235e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project rules_matched++; // Exact match found 236e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 237e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = pr->next; 238e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 239e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 240e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if ((retval + rules_matched) > 1) 241e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project printf("# WARNING # Multiple exact rules for file: %s\n", name); 242e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 243e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project // If any exact rule matched or failed, we are done with this file 244e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (retval) 245e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project print_new_rule(name, mode, uid, gid); 246e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (rules_matched || retval) 247e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return retval; 248e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 249e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = rules[WILDCARD]; 250e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project while (pr != NULL) { 251e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project // Check if the spec is a prefix of the filename, and that the file 252e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project // is actually in the same directory as the wildcard. 253e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if ((strstr(name, pr->spec) == name) && 254e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project (!strchr(name + strlen(pr->spec), '/'))) { 255e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (!pass_rule(pr, mode, uid, gid)) 256e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project retval++; 257e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project else 258e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project rules_matched++; 259e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 260e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = pr->next; 261e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 262e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 263e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = rules[RECURSIVE]; 264e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project while (pr != NULL) { 265e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (strstr(name, pr->spec) == name) { 266e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (!pass_rule(pr, mode, uid, gid)) 267e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project retval++; 268e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project else 269e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project rules_matched++; 270e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 271e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = pr->next; 272e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 273e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 274e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (!rules_matched) 275e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project retval++; // In case no rules either matched or failed, be sure to fail 276e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 277e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (retval) 278e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project print_new_rule(name, mode, uid, gid); 279e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 280e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return retval; 281e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 282e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 283e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project// Returns 0 on success 284e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int validate_link(const char *name, mode_t mode, uid_t uid, gid_t gid) 285e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 286e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project perm_rule_t *pr; 287e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int rules_matched = 0; 288e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int retval = 0; 289e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 290e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project // For now, we match links against "exact" file rules only 291e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = rules[EXACT_FILE]; 292e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project while (pr != NULL) { 293e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (strcmp(name, pr->spec) == 0) { 294e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (!pass_rule(pr, mode, uid, gid)) 295e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project retval++; 296e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project else 297e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project rules_matched++; // Exact match found 298e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 299e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = pr->next; 300e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 301e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 302e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if ((retval + rules_matched) > 1) 303e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project printf("# WARNING # Multiple exact rules for link: %s\n", name); 304e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (retval) 305e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project print_new_rule(name, mode, uid, gid); 30618d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 307e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project // Note: Unlike files, if no rules matches for links, retval = 0 (success). 308e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return retval; 309e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 310e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 311e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project// Returns 0 on success 312e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int validate_dir(const char *name, mode_t mode, uid_t uid, gid_t gid) 313e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 314e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project perm_rule_t *pr; 315e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int rules_matched = 0; 316e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int retval = 0; 317e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 318e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = rules[EXACT_DIR]; 319e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project while (pr != NULL) { 320e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (strcmp(name, pr->spec) == 0) { 321e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (!pass_rule(pr, mode, uid, gid)) 322e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project retval++; 323e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project else 324e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project rules_matched++; // Exact match found 325e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 326e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = pr->next; 327e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 328e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 329e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if ((retval + rules_matched) > 1) 330e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project printf("# WARNING # Multiple exact rules for directory: %s\n", name); 331e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 332e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project // If any exact rule matched or failed, we are done with this directory 333e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (retval) 334e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project print_new_rule(name, mode, uid, gid); 335e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (rules_matched || retval) 336e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return retval; 337e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 338e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = rules[RECURSIVE]; 339e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project while (pr != NULL) { 340e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (strstr(name, pr->spec) == name) { 341e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (!pass_rule(pr, mode, uid, gid)) 342e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project retval++; 343e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project else 344e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project rules_matched++; 345e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 346e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project pr = pr->next; 347e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 348e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 349e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (!rules_matched) 350e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project retval++; // In case no rules either matched or failed, be sure to fail 351e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 352e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (retval) 353e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project print_new_rule(name, mode, uid, gid); 354e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 355e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return retval; 356e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 357e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 358e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project// Returns 0 on success 359e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectstatic int check_path(const char *name) 360e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 361e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project char namebuf[MAX_NAME_LEN + 1]; 362e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project char tmp[MAX_NAME_LEN + 1]; 363e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project DIR *d; 364e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project struct dirent *de; 365e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project struct stat s; 366e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int err; 367e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int retval = 0; 368e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 369e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project err = lstat(name, &s); 370e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (err < 0) { 371e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (errno != ENOENT) 372e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project { 373e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project perror(name); 374e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return 1; 375e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 376e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return 0; // File doesn't exist anymore 377e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 378e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 379e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (S_ISDIR(s.st_mode)) { 380e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (name[strlen(name) - 1] != '/') 381e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project snprintf(namebuf, sizeof(namebuf), "%s/", name); 382e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project else 383e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project snprintf(namebuf, sizeof(namebuf), "%s", name); 384e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 385e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project retval |= validate_dir(namebuf, PERMS(s.st_mode), s.st_uid, s.st_gid); 386e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project d = opendir(namebuf); 387e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if(d == 0) { 388e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project printf("%s : opendir failed: %s\n", namebuf, strerror(errno)); 389e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return 1; 390e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 391e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 392e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project while ((de = readdir(d)) != 0) { 393e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) 394e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project continue; 395e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project snprintf(tmp, sizeof(tmp), "%s%s", namebuf, de->d_name); 396e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project retval |= check_path(tmp); 397e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 398e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project closedir(d); 399e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return retval; 400e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } else if (S_ISLNK(s.st_mode)) { 401e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return validate_link(name, PERMS(s.st_mode), s.st_uid, s.st_gid); 402e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } else { 403e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return validate_file(name, PERMS(s.st_mode), s.st_uid, s.st_gid); 404e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 405e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 406e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 407e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectint main(int argc, char **argv) 408e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project{ 409e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project FILE *fp; 410e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project int i; 411e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 41218d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish if (argc > 2) { 41318d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish printf("\nSyntax: %s [configfilename]\n", argv[0]); 41418d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish } 41518d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish config_file = (argc == 2) ? argv[1] : DEFAULT_CONFIG_FILE; 41618d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish executable_file = argv[0]; 41718d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 418e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project // Initialize ruleset pointers 419e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project for (i = 0; i < NUM_PR_TYPES; i++) 420e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project rules[i] = NULL; 421e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 42218d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish if (!(fp = fopen(config_file, "r"))) { 42318d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish printf("Error opening %s\n", config_file); 424e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project exit(255); 425e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project } 426e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project read_rules(fp); 427e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project fclose(fp); 428e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project 429e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project if (check_path("/")) 430e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return 255; 43118d9c5da994b8741877e999653f93fc6df1d6310Shabsi Walfish 432e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project printf("Passed.\n"); 433e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project return 0; 434e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project} 435