2006-04-12 03:09:10 +00:00
|
|
|
/* $Id$ */
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
/*
|
2007-04-11 08:12:51 +00:00
|
|
|
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
|
|
|
* NOVELL (All rights reserved)
|
2006-04-11 21:52:54 +00:00
|
|
|
*
|
|
|
|
* 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 Novell, Inc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Handle subdomain 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 <name> which searches for the first occurance of name in the
|
|
|
|
subdomain 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/subdomain.d
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <libintl.h>
|
2006-10-10 21:36:10 +00:00
|
|
|
#include <dirent.h>
|
2006-04-11 21:52:54 +00:00
|
|
|
#include "parser.h"
|
|
|
|
#include "parser_include.h"
|
|
|
|
#define _(s) gettext(s)
|
|
|
|
|
|
|
|
/* An array of search directories, I sure hope 100's enough */
|
|
|
|
#define MAX_PATH 100
|
|
|
|
|
|
|
|
/* maximum depth of nesting */
|
|
|
|
#define MAX_NEST_LEVEL 100
|
|
|
|
|
|
|
|
/* Location of the subdomain.conf file */
|
|
|
|
#ifdef SUBDOMAIN_CONFDIR
|
|
|
|
#define SUBDOMAIN_CONF SUBDOMAIN_CONFDIR "/subdomain.conf"
|
|
|
|
#else /* !defined SUBDOMAIN_CONFDIR */
|
|
|
|
#define SUBDOMAIN_CONF "/etc/subdomain.conf"
|
|
|
|
#endif /* SUBDOMAIN_CONFDIR */
|
|
|
|
|
|
|
|
static char *path[MAX_PATH] = { NULL };
|
|
|
|
static int npath = 0;
|
|
|
|
|
|
|
|
static int fgetline(FILE * f, char *buffer, size_t len);
|
|
|
|
static int stripcomment(char *s);
|
|
|
|
static char *stripblanks(char *s);
|
|
|
|
|
|
|
|
/* default base directory is /etc/subdomain.d, it can be overriden
|
|
|
|
with the -b option. */
|
|
|
|
|
2009-07-24 07:35:39 +00:00
|
|
|
char *basedir;
|
2006-04-11 21:52:54 +00:00
|
|
|
static char *default_basedir = "/etc/apparmor.d";
|
|
|
|
static char *old_basedir = "/etc/subdomain.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;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = stat(old_basedir, &sbuf);
|
|
|
|
if (rc == 0 && S_ISDIR(sbuf.st_mode)) {
|
|
|
|
basedir = old_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) {
|
2006-09-26 18:01:06 +00:00
|
|
|
PERROR(_("Error: Out of memory.\n"));
|
2006-04-11 21:52:54 +00:00
|
|
|
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)) {
|
2006-09-26 18:01:06 +00:00
|
|
|
PERROR(_("Error: basedir %s is not a directory, skipping.\n"), t);
|
2006-04-11 21:52:54 +00:00
|
|
|
free(t);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
basedir = t;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add a directory to the search path. */
|
|
|
|
int add_search_dir(char *dir)
|
|
|
|
{
|
|
|
|
char *t;
|
|
|
|
if (npath >= MAX_PATH) {
|
2006-09-26 18:01:06 +00:00
|
|
|
PERROR(_("Error: Could not add directory %s to search path.\n"),
|
2006-04-11 21:52:54 +00:00
|
|
|
dir);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-04-28 03:26:57 +00:00
|
|
|
if (!dir || strlen(dir) <= 0)
|
2006-04-11 21:52:54 +00:00
|
|
|
return 1;
|
|
|
|
|
2007-05-24 22:07:39 +00:00
|
|
|
t = strdup(dir);
|
2006-04-11 21:52:54 +00:00
|
|
|
if (t == NULL) {
|
2006-09-26 18:01:06 +00:00
|
|
|
PERROR(_("Error: Could not allocate memory.\n"));
|
2006-04-11 21:52:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2007-05-24 22:07:39 +00:00
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
/*strip trailing /'s */
|
|
|
|
while (t[strlen(t) - 1] == '/')
|
|
|
|
t[strlen(t) - 1] = 0;
|
|
|
|
path[npath] = t;
|
|
|
|
npath++;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse Subdomain.conf and put the default dirs in place.
|
|
|
|
|
|
|
|
subdomain.conf is a shell sourcable file
|
|
|
|
we only parse entries starting with
|
|
|
|
SUBDOMAIN_PATH=
|
|
|
|
|
|
|
|
if there are multiple entries with SUBDOMAIN_PATH=
|
|
|
|
each will get added.
|
|
|
|
|
|
|
|
SUBDOMAIN_PATH=/etc/subdomain.d:/etc/subdomain.d/include
|
|
|
|
is the same as
|
|
|
|
SUBDOMAIN_PATH=/etc/subdomain.d
|
|
|
|
SUBDOMAIN_PATH=/etc/subdomain.d/include */
|
|
|
|
void parse_default_paths(void)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
char buf[1024];
|
|
|
|
char *t, *s;
|
|
|
|
int saved_npath = npath;
|
|
|
|
|
|
|
|
f = fopen(SUBDOMAIN_CONF, "r");
|
|
|
|
if (f == NULL)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
|
|
|
while (fgetline(f, buf, 1024)) {
|
|
|
|
if (stripcomment(buf) && (t = strstr(buf, "SUBDOMAIN_PATH="))) {
|
|
|
|
t += 15;
|
2009-07-24 11:56:07 +00:00
|
|
|
/* handle : separating path elements */
|
2006-04-11 21:52:54 +00:00
|
|
|
do {
|
|
|
|
s = strchr(t, ':');
|
|
|
|
if (s)
|
|
|
|
*s = 0;
|
|
|
|
if (!add_search_dir(stripblanks(t)))
|
|
|
|
break;
|
|
|
|
if (s)
|
|
|
|
t = s + 1;
|
|
|
|
} while (s != NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
/* if subdomain.conf doesn't set a base search dir set it to this */
|
|
|
|
out:
|
|
|
|
if (npath - saved_npath == 0) {
|
|
|
|
add_search_dir(basedir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-24 07:35:39 +00:00
|
|
|
FILE *search_path(char *filename, char **fullpath)
|
2006-10-10 21:36:10 +00:00
|
|
|
{
|
|
|
|
FILE *newf = NULL;
|
2009-07-24 07:35:39 +00:00
|
|
|
char *buf = NULL;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < npath; i++) {
|
|
|
|
if (asprintf(&buf, "%s/%s", path[i], filename) < 0) {
|
|
|
|
perror("asprintf");
|
|
|
|
exit(1);
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
2009-07-24 07:35:39 +00:00
|
|
|
newf = fopen(buf, "r");
|
2009-07-24 12:18:12 +00:00
|
|
|
if (newf && fullpath)
|
|
|
|
*fullpath = buf;
|
|
|
|
else
|
|
|
|
free(buf);
|
2009-07-24 07:35:39 +00:00
|
|
|
buf = NULL;
|
|
|
|
if (newf)
|
|
|
|
break;
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
2009-07-24 07:35:39 +00:00
|
|
|
return newf;
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* get a line from the file. If it is to long truncate it. */
|
|
|
|
static int fgetline(FILE * f, char *buffer, size_t len)
|
|
|
|
{
|
|
|
|
char *b = buffer;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
while (((c = fgetc(f)) != EOF) && (c != '\n')
|
|
|
|
&& (strlen(buffer) < len - 1)) {
|
|
|
|
*b = c;
|
|
|
|
b++;
|
|
|
|
}
|
|
|
|
*b = '\0';
|
|
|
|
if (c != EOF)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there is a comment null terminate the string,
|
|
|
|
return strlen of the stripped string*/
|
|
|
|
static int stripcomment(char *s)
|
|
|
|
{
|
|
|
|
char *t = s;
|
|
|
|
while (*s != '#' && *s != 0)
|
|
|
|
s++;
|
|
|
|
*s = 0;
|
|
|
|
|
|
|
|
return strlen(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *stripblanks(char *s)
|
|
|
|
{
|
|
|
|
char *c;
|
|
|
|
|
|
|
|
while (isspace(*s))
|
|
|
|
s++;
|
|
|
|
c = s;
|
|
|
|
while (!isspace(*s) && *s != 0)
|
|
|
|
s++;
|
|
|
|
*s = 0;
|
|
|
|
return c;
|
|
|
|
}
|
2010-06-04 18:47:44 -07:00
|
|
|
|
|
|
|
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(char *filename)
|
|
|
|
{
|
|
|
|
if (current_filename)
|
|
|
|
free(current_filename);
|
|
|
|
current_filename = strdup(filename ? filename : "stdin");
|
|
|
|
current_lineno = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void push_include_stack(char *filename)
|
|
|
|
{
|
|
|
|
struct include_stack_t *include = NULL;
|
|
|
|
|
|
|
|
include = 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(char *filename)
|
|
|
|
{
|
|
|
|
while (include_stack_head)
|
|
|
|
pop_include_stack();
|
|
|
|
|
|
|
|
start_include_position(filename);
|
|
|
|
}
|