/* * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 * NOVELL (All rights reserved) * Copyright (c) 2010 - 2012 * Canonical Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, contact Canonical, Ltd. */ /* Handle apparmor includes, as a straight forward preprocessing phase. While we are at it we will strip comments. Why? because it made it easier. We support 2 types of includes #include which searches for the first occurrence of name in the apparmor directory path. #include "name" which will search for a relative or absolute pathed file -p : preprocess only. Dump output to stdout -I path : add a path to be search by #include < > -b path : set the base path to something other than /etc/apparmor.d */ #include #include #include #include #include #include #include #include #include #include #include #include "lib.h" #include "parser.h" #include "parser_include.h" /* An array of search directories, I sure hope 100's enough */ #define MAX_PATH 100 /* maximum depth of nesting */ #define MAX_NEST_LEVEL 100 static char *path[MAX_PATH] = { NULL }; static int npath = 0; /* default base directory is /etc/apparmor.d, it can be overridden with the -b option. */ const char *basedir; static const char *default_basedir = "/etc/apparmor.d"; /* set up basedir so that it can be overridden/used later. */ void init_base_dir(void) { int rc; struct stat sbuf; /* basedir should always start out NULL; if not, something's * wrong.*/ assert(basedir == NULL); rc = stat(default_basedir, &sbuf); if (rc == 0 && S_ISDIR(sbuf.st_mode)) { basedir = default_basedir; return; } } /* Set the base dir. Used to change default path for relative includes */ void set_base_dir(char *dir) { char *t; int i, rc; struct stat sbuf; t = strndup(dir, PATH_MAX); if (!t) { PERROR(_("Error: Out of memory.\n")); return; } /*strip trailing /'s */ for (i = strlen(t) - 1; i >= 0 && t[i] == '/'; i--) t[i] = 0; rc = stat(t, &sbuf); if (rc == -1 || !S_ISDIR(sbuf.st_mode)) { PERROR(_("Error: basedir %s is not a directory, skipping.\n"), t); free(t); return; } basedir = t; return; } /* Add a directory to the search path. */ int add_search_dir(const char *dir) { char *t; size_t len; if (npath >= MAX_PATH) { PERROR(_("Error: Could not add directory %s to search path.\n"), dir); return 0; } if (!dir) return 1; len = strlen(dir); if (len == 0) return 1; t = strdup(dir); if (t == NULL) { PERROR(_("Error: Could not allocate memory.\n")); return 0; } /*strip trailing /'s */ while (len > 0 && t[--len] == '/') t[len] = '\0'; path[npath] = t; npath++; return 1; } void parse_default_paths(void) { add_search_dir(basedir); } FILE *search_path(char *filename, char **fullpath, bool *skip) { FILE *newf = NULL; char *buf = NULL; int i; for (i = 0; i < npath; i++) { if (asprintf(&buf, "%s/%s", path[i], filename) < 0) { perror("asprintf"); exit(1); } if (g_includecache->find(buf)) { /* hit do not want to re-include */ *skip = true; free(buf); return NULL; } newf = fopen(buf, "r"); if (newf) { /* ignore failing to insert into cache */ (void) g_includecache->insert(buf); if (fullpath) *fullpath = buf; else free(buf); break; } free(buf); buf = NULL; } *skip = false; return newf; } struct include_stack_t { char *filename; int lineno; struct include_stack_t *next; }; struct include_stack_t *include_stack_head = NULL; static void start_include_position(const char *filename) { if (current_filename) free(current_filename); current_filename = strdup(filename ? filename : "stdin"); current_lineno = 1; } void push_include_stack(const char *filename) { struct include_stack_t *include = NULL; include = (struct include_stack_t *) malloc(sizeof(*include)); if (!include) { perror("malloc of included file stack tracker"); /* failures in this area are non-fatal */ return; } include->filename = strdup(current_filename); include->lineno = current_lineno; include->next = include_stack_head; include_stack_head = include; start_include_position(filename); } void pop_include_stack(void) { struct include_stack_t *include = NULL; if (!include_stack_head) return; include = include_stack_head; include_stack_head = include->next; if (current_filename) free(current_filename); current_filename = include->filename; current_lineno = include->lineno; free(include); } void reset_include_stack(const char *filename) { while (include_stack_head) pop_include_stack(); start_include_position(filename); }