mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 06:16:03 +00:00
allow multiple profiles to be parsed from the command line
Signed-Off-By: Kees Cook <kees.cook@canonical.com>
This commit is contained in:
@@ -67,67 +67,16 @@ static char *path[MAX_PATH] = { NULL };
|
||||
static int npath = 0;
|
||||
|
||||
static int fgetline(FILE * f, char *buffer, size_t len);
|
||||
static int getincludestr(char **inc, int c, FILE *f, int line, char *name,
|
||||
FILE *out);
|
||||
static int stripcomment(char *s);
|
||||
static char *stripblanks(char *s);
|
||||
static int preprocess(FILE *f, char *name, FILE * out, int nest);
|
||||
|
||||
int preprocess_only;
|
||||
|
||||
/* default base directory is /etc/subdomain.d, it can be overriden
|
||||
with the -b option. */
|
||||
|
||||
static char *basedir;
|
||||
char *basedir;
|
||||
static char *default_basedir = "/etc/apparmor.d";
|
||||
static char *old_basedir = "/etc/subdomain.d";
|
||||
|
||||
/* start parsing. */
|
||||
int do_include_preprocessing(char *profilename)
|
||||
{
|
||||
int retval = 0;
|
||||
FILE *tmp, *profile = NULL;
|
||||
|
||||
if (profilename) {
|
||||
profile = fopen(profilename, "r");
|
||||
if (!profile) {
|
||||
PERROR(_("Error: Could not read profile %s: %s.\n"),
|
||||
profilename, strerror(errno));
|
||||
exit(errno);
|
||||
}
|
||||
} else {
|
||||
profile = stdin;
|
||||
}
|
||||
|
||||
/* Change to the base dir */
|
||||
chdir(basedir);
|
||||
|
||||
if (preprocess_only) {
|
||||
retval = preprocess(profile, profilename ? profilename : "stdin",
|
||||
stdout, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp = tmpfile();
|
||||
if (!tmp) {
|
||||
PERROR(_("Error: Could not allocate temporary file.\n"));
|
||||
exit(10);
|
||||
}
|
||||
|
||||
retval = preprocess(profile, profilename ? profilename : "stdin",
|
||||
tmp, 0);
|
||||
|
||||
rewind(tmp);
|
||||
|
||||
dup2(fileno(tmp), 0); /* stdin */
|
||||
fclose(tmp);
|
||||
|
||||
out:
|
||||
if (profilename)
|
||||
fclose(profile);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* set up basedir so that it can be overridden/used later. */
|
||||
void init_base_dir(void)
|
||||
@@ -258,233 +207,24 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
const char incword[] = "include";
|
||||
|
||||
/* getincludestr:
|
||||
* returns !0 if error occurred
|
||||
* include string (or not) is returned in 'inc'
|
||||
*/
|
||||
static int getincludestr(char **inc, int c, FILE *f, int line, char *name,
|
||||
FILE *out)
|
||||
{
|
||||
char *b;
|
||||
size_t i = 0, a;
|
||||
int d;
|
||||
int retval = 0;
|
||||
|
||||
*inc = NULL;
|
||||
|
||||
if (c != '#')
|
||||
return retval;
|
||||
|
||||
/* we either have a comment or an include, either process the include
|
||||
or strip the comment to the eol. Leave the eol char so line count
|
||||
gets properly incremented. */
|
||||
|
||||
for (i = 0; i < strlen(incword); i++) {
|
||||
c = fgetc(f);
|
||||
if (c == EOF || c == '\n' || c != incword[i]) {
|
||||
ungetc(c, f);
|
||||
goto comment;
|
||||
}
|
||||
}
|
||||
|
||||
/* found "#include" now search for the file name to include */
|
||||
b = malloc(2048);
|
||||
if (!b) {
|
||||
PERROR(_("Error: Could not allocate buffer for include at line %d in %s.\n"),
|
||||
line, name);
|
||||
retval = 1;
|
||||
goto comment;
|
||||
}
|
||||
|
||||
c = fgetc(f);
|
||||
if (!isspace(c)) {
|
||||
ungetc(c, f);
|
||||
goto comment;
|
||||
}
|
||||
|
||||
while ((c = fgetc(f)) != EOF && c != '\n' && isspace(c))
|
||||
/* eat whitespace */ ;
|
||||
if (c != '\"' && c != '<') {
|
||||
free(b);
|
||||
PERROR(_("Error: Bad include at line %d in %s.\n"), line, name);
|
||||
if (c == '\n')
|
||||
ungetc(c, f);
|
||||
retval = 1;
|
||||
goto comment;
|
||||
}
|
||||
|
||||
b[0] = c;
|
||||
i = 1;
|
||||
while ((d = fgetc(f)) != EOF && d != '\n'
|
||||
&& d != (c == '<' ? '>' : '\"') && i < 2048)
|
||||
b[i++] = d;
|
||||
|
||||
if (d == (c == '<' ? '>' : '\"')) {
|
||||
b[i] = 0;
|
||||
*inc = b;
|
||||
return retval;
|
||||
}
|
||||
|
||||
free(b);
|
||||
PERROR(_("Error: Bad include at line %d in %s.\n"), line, name);
|
||||
ungetc(d, f);
|
||||
retval = 1;
|
||||
/* fall through to comment - this makes trailing stuff a comment */
|
||||
|
||||
comment:
|
||||
fputc('#', out);
|
||||
for (a = 0; a < i; a++) {
|
||||
fputc(incword[a], out);
|
||||
}
|
||||
while ((c = fgetc(f)) != EOF && c != '\n')
|
||||
fputc(c, out);
|
||||
if (c == '\n')
|
||||
ungetc(c, f);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Find the include file or directory by searching the path. */
|
||||
static int process_include(char *inc, char *name, int line, FILE *out, int nest)
|
||||
FILE *search_path(char *filename, char **fullpath)
|
||||
{
|
||||
FILE *newf = NULL;
|
||||
int retval = 0;
|
||||
char *buf;
|
||||
struct stat my_stat;
|
||||
int err;
|
||||
|
||||
if (*inc == '\"') {
|
||||
buf = strdup(inc + 1);
|
||||
if (buf)
|
||||
newf = fopen(buf, "r");
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < npath; i++) {
|
||||
if (asprintf(&buf, "%s/%s", path[i], inc + 1) != -1) {
|
||||
newf = fopen(buf, "r");
|
||||
if (newf)
|
||||
break;
|
||||
free(buf);
|
||||
}
|
||||
buf = 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);
|
||||
}
|
||||
newf = fopen(buf, "r");
|
||||
if (newf && fullpath) *fullpath = buf;
|
||||
else free(buf);
|
||||
buf = NULL;
|
||||
if (newf)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!newf) {
|
||||
PERROR(_("Error: #include %s%c not found at line %d in %s.\n"),
|
||||
inc,
|
||||
*inc == '<' ? '>' : '\"',
|
||||
line,
|
||||
name);
|
||||
retval = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = fstat(fileno(newf), &my_stat);
|
||||
if (err) {
|
||||
retval = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (S_ISREG(my_stat.st_mode)) {
|
||||
err = preprocess(newf, inc + 1, out, nest + 1);
|
||||
if (err)
|
||||
retval = err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (S_ISDIR(my_stat.st_mode)) {
|
||||
DIR *dir = NULL;
|
||||
struct dirent *dirent;
|
||||
|
||||
/* XXX - fdopendir not available in glibc < 2.4 */
|
||||
/* dir = fdopendir(fileno(newf)); */
|
||||
fclose(newf);
|
||||
dir = opendir(buf);
|
||||
if (!dir) {
|
||||
retval = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while ((dirent = readdir(dir)) != NULL) {
|
||||
char *dirbuf;
|
||||
/* skip dotfiles. */
|
||||
if (dirent->d_name[0] == '.')
|
||||
continue;
|
||||
asprintf(&dirbuf, "%s/%s", buf, dirent->d_name);
|
||||
err = stat(dirbuf, &my_stat);
|
||||
if (err) {
|
||||
retval = errno;
|
||||
free(dirbuf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (S_ISREG(my_stat.st_mode)) {
|
||||
newf = fopen(dirbuf, "r");
|
||||
if (newf) {
|
||||
err = preprocess(newf, inc + 1, out, nest + 1);
|
||||
if (err)
|
||||
retval = err;
|
||||
fclose(newf);
|
||||
} else {
|
||||
retval = errno;
|
||||
}
|
||||
}
|
||||
free(dirbuf);
|
||||
}
|
||||
newf = NULL;
|
||||
closedir(dir);
|
||||
}
|
||||
out:
|
||||
if (buf)
|
||||
free(buf);
|
||||
if (newf)
|
||||
fclose(newf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int preprocess(FILE * f, char *name, FILE * out, int nest)
|
||||
{
|
||||
int line = 1;
|
||||
int c;
|
||||
int retval = 0;
|
||||
char *inc = NULL;
|
||||
char *cwd;
|
||||
|
||||
if (nest > MAX_NEST_LEVEL) {
|
||||
PERROR(_("Error: Exceeded %d levels of includes. Not processing %s include.\n"),
|
||||
MAX_NEST_LEVEL, name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nest == 0) {
|
||||
fprintf(out, "\n#source %s\n", name);
|
||||
} else {
|
||||
fprintf(out, "\n#included %s\n", name);
|
||||
}
|
||||
|
||||
while ((c = fgetc(f)) != EOF) {
|
||||
int err = getincludestr(&inc, c, f, line, name, out);
|
||||
if (err)
|
||||
retval = err;
|
||||
if (inc) {
|
||||
cwd = get_current_dir_name();
|
||||
err = process_include(inc, name, line, out, nest);
|
||||
if (err)
|
||||
retval = err;
|
||||
chdir(cwd);
|
||||
free(cwd);
|
||||
free(inc);
|
||||
} else {
|
||||
if (c != '#')
|
||||
fputc(c, out);
|
||||
if (c == '\n')
|
||||
line++;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
return newf;
|
||||
}
|
||||
|
||||
/* get a line from the file. If it is to long truncate it. */
|
||||
|
Reference in New Issue
Block a user