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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
[https://bugzilla.novell.com/show_bug.cgi?id=172061]
This (updated) patch to trunk adds support for Px and Ux (toggle
bprm_secure on exec) in the parser, As requested, lowercase p and u
corresponds to an unfiltered environmnet on exec, uppercase will filter
the environment. It applies after the 'm' patch.
As a side effect, I tried to reduce the use of hardcoded characters in
the debugging statements -- there are still a few warnings that have
hard coded letters in them; not sure I can fix them all.
This version issues a warning for every unsafe ux and issues a single
warning for the first 'R', 'W', 'X', 'L', and 'I' it encounters,
except when the "-q" or "--quiet" flag , "--remove" profile flag, or
"-N" report names flags are passed. Unfortunately, it made the logic
somewhat more convoluted. Wordsmithing improvements welcome.
2006-08-04 17:14:49 +00:00
|
|
|
#include <stdarg.h>
|
2006-04-11 21:52:54 +00:00
|
|
|
#include <getopt.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <mntent.h>
|
|
|
|
#include <libintl.h>
|
|
|
|
#include <locale.h>
|
|
|
|
#define _(s) gettext(s)
|
|
|
|
|
|
|
|
/* enable the following line to get voluminous debug info */
|
|
|
|
/* #define DEBUG */
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
|
|
|
#include "parser.h"
|
|
|
|
#include "parser_version.h"
|
|
|
|
#include "parser_include.h"
|
|
|
|
|
|
|
|
#define MODULE_NAME "apparmor"
|
|
|
|
#define OLD_MODULE_NAME "subdomain"
|
|
|
|
#define PROC_MODULES "/proc/modules"
|
|
|
|
#define DEFAULT_APPARMORFS "/sys/kernel/security/" MODULE_NAME
|
2006-04-18 17:15:05 +00:00
|
|
|
#define MATCH_STRING "/sys/kernel/security/" MODULE_NAME "/matching"
|
2008-09-10 08:42:49 +00:00
|
|
|
#define FLAGS_FILE "/sys/kernel/security/" MODULE_NAME "/features"
|
2006-04-11 21:52:54 +00:00
|
|
|
#define MOUNTED_FS "/proc/mounts"
|
2006-04-18 17:15:05 +00:00
|
|
|
#define PCRE "pattern=pcre"
|
2007-02-27 02:29:16 +00:00
|
|
|
#define AADFA "pattern=aadfa"
|
2006-04-11 21:52:54 +00:00
|
|
|
|
2009-07-24 07:35:39 +00:00
|
|
|
#define UNPRIVILEGED_OPS (debug || option == OPTION_STDOUT || names_only || \
|
2006-04-11 21:52:54 +00:00
|
|
|
dump_vars || dump_expanded_vars)
|
|
|
|
|
|
|
|
const char *parser_title = "Novell/SUSE AppArmor parser";
|
|
|
|
const char *parser_copyright = "Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006 Novell Inc.";
|
|
|
|
|
|
|
|
char *progname;
|
[https://bugzilla.novell.com/show_bug.cgi?id=172061]
This (updated) patch to trunk adds support for Px and Ux (toggle
bprm_secure on exec) in the parser, As requested, lowercase p and u
corresponds to an unfiltered environmnet on exec, uppercase will filter
the environment. It applies after the 'm' patch.
As a side effect, I tried to reduce the use of hardcoded characters in
the debugging statements -- there are still a few warnings that have
hard coded letters in them; not sure I can fix them all.
This version issues a warning for every unsafe ux and issues a single
warning for the first 'R', 'W', 'X', 'L', and 'I' it encounters,
except when the "-q" or "--quiet" flag , "--remove" profile flag, or
"-N" report names flags are passed. Unfortunately, it made the logic
somewhat more convoluted. Wordsmithing improvements welcome.
2006-08-04 17:14:49 +00:00
|
|
|
int option = OPTION_ADD;
|
2009-07-24 07:35:39 +00:00
|
|
|
int opt_force_complain = 0;
|
2008-06-09 10:00:28 +00:00
|
|
|
int binary_input = 0;
|
2006-04-11 21:52:54 +00:00
|
|
|
int names_only = 0;
|
|
|
|
int dump_vars = 0;
|
|
|
|
int dump_expanded_vars = 0;
|
2009-11-11 10:56:04 -08:00
|
|
|
int conf_verbose = 0;
|
[https://bugzilla.novell.com/show_bug.cgi?id=172061]
This (updated) patch to trunk adds support for Px and Ux (toggle
bprm_secure on exec) in the parser, As requested, lowercase p and u
corresponds to an unfiltered environmnet on exec, uppercase will filter
the environment. It applies after the 'm' patch.
As a side effect, I tried to reduce the use of hardcoded characters in
the debugging statements -- there are still a few warnings that have
hard coded letters in them; not sure I can fix them all.
This version issues a warning for every unsafe ux and issues a single
warning for the first 'R', 'W', 'X', 'L', and 'I' it encounters,
except when the "-q" or "--quiet" flag , "--remove" profile flag, or
"-N" report names flags are passed. Unfortunately, it made the logic
somewhat more convoluted. Wordsmithing improvements welcome.
2006-08-04 17:14:49 +00:00
|
|
|
int conf_quiet = 0;
|
2009-11-11 10:56:04 -08:00
|
|
|
int kernel_load = 1;
|
2009-07-24 07:36:09 +00:00
|
|
|
int show_cache = 0;
|
2009-08-19 14:44:40 +00:00
|
|
|
int skip_cache = 0;
|
|
|
|
int skip_read_cache = 0;
|
2009-07-24 07:36:09 +00:00
|
|
|
int write_cache = 0;
|
2009-06-10 15:37:27 +00:00
|
|
|
#ifdef FORCE_READ_IMPLIES_EXEC
|
|
|
|
int read_implies_exec = 1;
|
|
|
|
#else
|
|
|
|
int read_implies_exec = 0;
|
|
|
|
#endif
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
char *subdomainbase = NULL;
|
2006-04-18 17:15:05 +00:00
|
|
|
char *match_string = NULL;
|
2008-09-10 08:42:49 +00:00
|
|
|
char *flags_string = NULL;
|
2007-03-30 17:32:00 +00:00
|
|
|
int regex_type = AARE_DFA;
|
2009-11-11 10:56:04 -08:00
|
|
|
int perms_create = 0; /* perms contain create flag */
|
2007-11-16 09:18:48 +00:00
|
|
|
char *profile_namespace = NULL;
|
2008-09-10 08:42:49 +00:00
|
|
|
int flag_changehat_version = FLAG_CHANGEHAT_1_5;
|
|
|
|
|
[https://bugzilla.novell.com/show_bug.cgi?id=172061]
This (updated) patch to trunk adds support for Px and Ux (toggle
bprm_secure on exec) in the parser, As requested, lowercase p and u
corresponds to an unfiltered environmnet on exec, uppercase will filter
the environment. It applies after the 'm' patch.
As a side effect, I tried to reduce the use of hardcoded characters in
the debugging statements -- there are still a few warnings that have
hard coded letters in them; not sure I can fix them all.
This version issues a warning for every unsafe ux and issues a single
warning for the first 'R', 'W', 'X', 'L', and 'I' it encounters,
except when the "-q" or "--quiet" flag , "--remove" profile flag, or
"-N" report names flags are passed. Unfortunately, it made the logic
somewhat more convoluted. Wordsmithing improvements welcome.
2006-08-04 17:14:49 +00:00
|
|
|
extern int current_lineno;
|
2006-04-11 21:52:54 +00:00
|
|
|
|
2009-07-24 07:35:39 +00:00
|
|
|
/* per-profile settings */
|
|
|
|
int force_complain = 0;
|
|
|
|
char *profilename = NULL;
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
struct option long_options[] = {
|
|
|
|
{"add", 0, 0, 'a'},
|
2008-06-09 10:00:28 +00:00
|
|
|
{"binary", 0, 0, 'B'},
|
2006-04-11 21:52:54 +00:00
|
|
|
{"base", 1, 0, 'b'},
|
|
|
|
{"debug", 0, 0, 'd'},
|
|
|
|
{"subdomainfs", 0, 0, 'f'},
|
|
|
|
{"help", 0, 0, 'h'},
|
|
|
|
{"replace", 0, 0, 'r'},
|
|
|
|
{"reload", 0, 0, 'r'}, /* undocumented reload option == replace */
|
2009-11-11 10:56:04 -08:00
|
|
|
{"version", 0, 0, 'V'},
|
2006-04-11 21:52:54 +00:00
|
|
|
{"complain", 0, 0, 'C'},
|
2009-03-12 15:21:46 +00:00
|
|
|
{"Complain", 0, 0, 'C'}, /* Erk, apparently documented as --Complain */
|
2006-04-11 21:52:54 +00:00
|
|
|
{"dump-variables", 0, 0, 'D'},
|
|
|
|
{"dump-expanded-variables", 0, 0, 'E'},
|
|
|
|
{"Include", 1, 0, 'I'},
|
|
|
|
{"remove", 0, 0, 'R'},
|
2008-06-09 22:15:28 +00:00
|
|
|
{"names", 0, 0, 'N'},
|
2006-04-11 21:52:54 +00:00
|
|
|
{"stdout", 0, 0, 'S'},
|
2006-04-18 17:15:05 +00:00
|
|
|
{"match-string", 1, 0, 'm'},
|
[https://bugzilla.novell.com/show_bug.cgi?id=172061]
This (updated) patch to trunk adds support for Px and Ux (toggle
bprm_secure on exec) in the parser, As requested, lowercase p and u
corresponds to an unfiltered environmnet on exec, uppercase will filter
the environment. It applies after the 'm' patch.
As a side effect, I tried to reduce the use of hardcoded characters in
the debugging statements -- there are still a few warnings that have
hard coded letters in them; not sure I can fix them all.
This version issues a warning for every unsafe ux and issues a single
warning for the first 'R', 'W', 'X', 'L', and 'I' it encounters,
except when the "-q" or "--quiet" flag , "--remove" profile flag, or
"-N" report names flags are passed. Unfortunately, it made the logic
somewhat more convoluted. Wordsmithing improvements welcome.
2006-08-04 17:14:49 +00:00
|
|
|
{"quiet", 0, 0, 'q'},
|
2009-11-11 10:56:04 -08:00
|
|
|
{"skip-kernel-load", 0, 0, 'Q'},
|
|
|
|
{"verbose", 0, 0, 'v'},
|
2007-11-16 09:18:48 +00:00
|
|
|
{"namespace", 1, 0, 'n'},
|
2009-06-10 15:37:27 +00:00
|
|
|
{"readimpliesX", 0, 0, 'X'},
|
2009-07-24 07:36:09 +00:00
|
|
|
{"skip-cache", 0, 0, 'K'},
|
2009-08-19 14:44:40 +00:00
|
|
|
{"skip-read-cache", 0, 0, 'T'},
|
2009-07-24 07:36:09 +00:00
|
|
|
{"write-cache", 0, 0, 'W'},
|
|
|
|
{"show-cache", 0, 0, 'k'},
|
2006-04-11 21:52:54 +00:00
|
|
|
{NULL, 0, 0, 0},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int debug = 0;
|
|
|
|
|
|
|
|
static void display_version(void)
|
|
|
|
{
|
|
|
|
printf("%s version " PARSER_VERSION "\n%s\n", parser_title,
|
|
|
|
parser_copyright);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void display_usage(char *command)
|
|
|
|
{
|
|
|
|
display_version();
|
|
|
|
printf("\nUsage: %s [options] [profile]\n\n"
|
|
|
|
"Options:\n"
|
|
|
|
"--------\n"
|
|
|
|
"-a, --add Add apparmor definitions [default]\n"
|
|
|
|
"-r, --replace Replace apparmor definitions\n"
|
|
|
|
"-R, --remove Remove apparmor definitions\n"
|
|
|
|
"-C, --Complain Force the profile into complain mode\n"
|
2008-06-09 22:15:28 +00:00
|
|
|
"-B, --binary Input is precompiled profile\n"
|
|
|
|
"-N, --names Dump names of profiles in input.\n"
|
|
|
|
"-S, --stdout Dump compiled profile to stdout\n"
|
2006-04-11 21:52:54 +00:00
|
|
|
"-b n, --base n Set base dir and cwd\n"
|
2008-06-09 22:15:28 +00:00
|
|
|
"-I n, --Include n Add n to the search path\n"
|
2006-04-11 21:52:54 +00:00
|
|
|
"-f n, --subdomainfs n Set location of apparmor filesystem\n"
|
[https://bugzilla.novell.com/show_bug.cgi?id=172061]
This (updated) patch to trunk adds support for Px and Ux (toggle
bprm_secure on exec) in the parser, As requested, lowercase p and u
corresponds to an unfiltered environmnet on exec, uppercase will filter
the environment. It applies after the 'm' patch.
As a side effect, I tried to reduce the use of hardcoded characters in
the debugging statements -- there are still a few warnings that have
hard coded letters in them; not sure I can fix them all.
This version issues a warning for every unsafe ux and issues a single
warning for the first 'R', 'W', 'X', 'L', and 'I' it encounters,
except when the "-q" or "--quiet" flag , "--remove" profile flag, or
"-N" report names flags are passed. Unfortunately, it made the logic
somewhat more convoluted. Wordsmithing improvements welcome.
2006-08-04 17:14:49 +00:00
|
|
|
"-m n, --match-string n Use only match features n\n"
|
2007-11-16 09:18:48 +00:00
|
|
|
"-n n, --namespace n Set Namespace for the profile\n"
|
2009-06-10 15:37:27 +00:00
|
|
|
"-X, --readimpliesX Map profile read permissions to mr\n"
|
2009-07-24 07:36:09 +00:00
|
|
|
"-k, --show-cache Report cache hit/miss details\n"
|
|
|
|
"-K, --skip-cache Do not attempt to load or save cached profiles\n"
|
2009-08-19 14:44:40 +00:00
|
|
|
"-T, --skip-read-cache Do not attempt to load cached profiles\n"
|
|
|
|
"-W, --write-cache Save cached profile (force with -T)\n"
|
2008-06-11 20:19:36 +00:00
|
|
|
"-q, --quiet Don't emit warnings\n"
|
2009-11-11 10:56:04 -08:00
|
|
|
"-v, --verbose Show profile nams as they load\n"
|
|
|
|
"-Q, --skip-kernel-load Do everything except loading into kernel\n"
|
|
|
|
"-V, --version Display version info and exit\n"
|
2008-06-09 22:15:28 +00:00
|
|
|
"-d, --debug Debug apparmor definitions\n"
|
|
|
|
"-h, --help Display this text and exit\n"
|
2008-06-11 20:19:36 +00:00
|
|
|
,command);
|
[https://bugzilla.novell.com/show_bug.cgi?id=172061]
This (updated) patch to trunk adds support for Px and Ux (toggle
bprm_secure on exec) in the parser, As requested, lowercase p and u
corresponds to an unfiltered environmnet on exec, uppercase will filter
the environment. It applies after the 'm' patch.
As a side effect, I tried to reduce the use of hardcoded characters in
the debugging statements -- there are still a few warnings that have
hard coded letters in them; not sure I can fix them all.
This version issues a warning for every unsafe ux and issues a single
warning for the first 'R', 'W', 'X', 'L', and 'I' it encounters,
except when the "-q" or "--quiet" flag , "--remove" profile flag, or
"-N" report names flags are passed. Unfortunately, it made the logic
somewhat more convoluted. Wordsmithing improvements welcome.
2006-08-04 17:14:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void pwarn(char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list arg;
|
|
|
|
char *newfmt;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (conf_quiet || names_only || option == OPTION_REMOVE)
|
|
|
|
return;
|
|
|
|
|
2006-08-04 17:20:16 +00:00
|
|
|
rc = asprintf(&newfmt, _("Warning (%s line %d): %s"),
|
[https://bugzilla.novell.com/show_bug.cgi?id=172061]
This (updated) patch to trunk adds support for Px and Ux (toggle
bprm_secure on exec) in the parser, As requested, lowercase p and u
corresponds to an unfiltered environmnet on exec, uppercase will filter
the environment. It applies after the 'm' patch.
As a side effect, I tried to reduce the use of hardcoded characters in
the debugging statements -- there are still a few warnings that have
hard coded letters in them; not sure I can fix them all.
This version issues a warning for every unsafe ux and issues a single
warning for the first 'R', 'W', 'X', 'L', and 'I' it encounters,
except when the "-q" or "--quiet" flag , "--remove" profile flag, or
"-N" report names flags are passed. Unfortunately, it made the logic
somewhat more convoluted. Wordsmithing improvements welcome.
2006-08-04 17:14:49 +00:00
|
|
|
profilename ? profilename : "stdin",
|
|
|
|
current_lineno,
|
|
|
|
fmt);
|
|
|
|
if (!newfmt)
|
|
|
|
return;
|
|
|
|
|
|
|
|
va_start(arg, fmt);
|
|
|
|
vfprintf(stderr, newfmt, arg);
|
|
|
|
va_end(arg);
|
2009-07-24 13:24:53 +00:00
|
|
|
|
|
|
|
free(newfmt);
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int process_args(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int c, o;
|
|
|
|
int count = 0;
|
[https://bugzilla.novell.com/show_bug.cgi?id=172061]
This (updated) patch to trunk adds support for Px and Ux (toggle
bprm_secure on exec) in the parser, As requested, lowercase p and u
corresponds to an unfiltered environmnet on exec, uppercase will filter
the environment. It applies after the 'm' patch.
As a side effect, I tried to reduce the use of hardcoded characters in
the debugging statements -- there are still a few warnings that have
hard coded letters in them; not sure I can fix them all.
This version issues a warning for every unsafe ux and issues a single
warning for the first 'R', 'W', 'X', 'L', and 'I' it encounters,
except when the "-q" or "--quiet" flag , "--remove" profile flag, or
"-N" report names flags are passed. Unfortunately, it made the logic
somewhat more convoluted. Wordsmithing improvements welcome.
2006-08-04 17:14:49 +00:00
|
|
|
option = OPTION_ADD;
|
2006-04-11 21:52:54 +00:00
|
|
|
|
2009-11-11 10:56:04 -08:00
|
|
|
while ((c = getopt_long(argc, argv, "adf:hrRVvI:b:BCDENSm:qQn:XKTWk", long_options, &o)) != -1)
|
2006-04-11 21:52:54 +00:00
|
|
|
{
|
|
|
|
switch (c) {
|
|
|
|
case 0:
|
|
|
|
PERROR("Assert, in getopt_long handling\n");
|
|
|
|
display_usage(progname);
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
count++;
|
|
|
|
option = OPTION_ADD;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
debug++;
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
display_usage(progname);
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
count++;
|
|
|
|
option = OPTION_REPLACE;
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
count++;
|
|
|
|
option = OPTION_REMOVE;
|
|
|
|
break;
|
2009-11-11 10:56:04 -08:00
|
|
|
case 'V':
|
2006-04-11 21:52:54 +00:00
|
|
|
display_version();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case 'I':
|
|
|
|
add_search_dir(optarg);
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
set_base_dir(optarg);
|
|
|
|
break;
|
2008-06-09 10:00:28 +00:00
|
|
|
case 'B':
|
|
|
|
binary_input =1;
|
|
|
|
break;
|
2006-04-11 21:52:54 +00:00
|
|
|
case 'C':
|
2009-07-24 07:35:39 +00:00
|
|
|
opt_force_complain = 1;
|
2006-04-11 21:52:54 +00:00
|
|
|
break;
|
|
|
|
case 'N':
|
|
|
|
names_only = 1;
|
2009-07-24 07:36:09 +00:00
|
|
|
skip_cache = 1;
|
2006-04-11 21:52:54 +00:00
|
|
|
break;
|
|
|
|
case 'S':
|
|
|
|
count++;
|
|
|
|
option = OPTION_STDOUT;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
subdomainbase = strndup(optarg, PATH_MAX);
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
dump_vars = 1;
|
2009-07-24 07:36:09 +00:00
|
|
|
skip_cache = 1;
|
2006-04-11 21:52:54 +00:00
|
|
|
break;
|
|
|
|
case 'E':
|
|
|
|
dump_expanded_vars = 1;
|
2009-07-24 07:36:09 +00:00
|
|
|
skip_cache = 1;
|
2006-04-11 21:52:54 +00:00
|
|
|
break;
|
2006-04-18 17:15:05 +00:00
|
|
|
case 'm':
|
|
|
|
match_string = strdup(optarg);
|
|
|
|
break;
|
[https://bugzilla.novell.com/show_bug.cgi?id=172061]
This (updated) patch to trunk adds support for Px and Ux (toggle
bprm_secure on exec) in the parser, As requested, lowercase p and u
corresponds to an unfiltered environmnet on exec, uppercase will filter
the environment. It applies after the 'm' patch.
As a side effect, I tried to reduce the use of hardcoded characters in
the debugging statements -- there are still a few warnings that have
hard coded letters in them; not sure I can fix them all.
This version issues a warning for every unsafe ux and issues a single
warning for the first 'R', 'W', 'X', 'L', and 'I' it encounters,
except when the "-q" or "--quiet" flag , "--remove" profile flag, or
"-N" report names flags are passed. Unfortunately, it made the logic
somewhat more convoluted. Wordsmithing improvements welcome.
2006-08-04 17:14:49 +00:00
|
|
|
case 'q':
|
2009-11-11 10:56:04 -08:00
|
|
|
conf_verbose = 0;
|
[https://bugzilla.novell.com/show_bug.cgi?id=172061]
This (updated) patch to trunk adds support for Px and Ux (toggle
bprm_secure on exec) in the parser, As requested, lowercase p and u
corresponds to an unfiltered environmnet on exec, uppercase will filter
the environment. It applies after the 'm' patch.
As a side effect, I tried to reduce the use of hardcoded characters in
the debugging statements -- there are still a few warnings that have
hard coded letters in them; not sure I can fix them all.
This version issues a warning for every unsafe ux and issues a single
warning for the first 'R', 'W', 'X', 'L', and 'I' it encounters,
except when the "-q" or "--quiet" flag , "--remove" profile flag, or
"-N" report names flags are passed. Unfortunately, it made the logic
somewhat more convoluted. Wordsmithing improvements welcome.
2006-08-04 17:14:49 +00:00
|
|
|
conf_quiet = 1;
|
|
|
|
break;
|
2009-11-11 10:56:04 -08:00
|
|
|
case 'v':
|
|
|
|
conf_verbose = 1;
|
|
|
|
conf_quiet = 0;
|
|
|
|
break;
|
2007-11-16 09:18:48 +00:00
|
|
|
case 'n':
|
|
|
|
profile_namespace = strdup(optarg);
|
|
|
|
break;
|
2009-06-10 15:37:27 +00:00
|
|
|
case 'X':
|
|
|
|
read_implies_exec = 1;
|
|
|
|
break;
|
2009-07-24 07:36:09 +00:00
|
|
|
case 'K':
|
|
|
|
skip_cache = 1;
|
|
|
|
break;
|
|
|
|
case 'k':
|
|
|
|
show_cache = 1;
|
|
|
|
break;
|
|
|
|
case 'W':
|
|
|
|
write_cache = 1;
|
|
|
|
break;
|
2009-08-19 14:44:40 +00:00
|
|
|
case 'T':
|
|
|
|
skip_read_cache = 1;
|
|
|
|
break;
|
2009-11-11 10:56:04 -08:00
|
|
|
case 'Q':
|
|
|
|
kernel_load = 0;
|
|
|
|
break;
|
2006-04-11 21:52:54 +00:00
|
|
|
default:
|
|
|
|
display_usage(progname);
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count > 1) {
|
2009-07-24 07:35:39 +00:00
|
|
|
PERROR("%s: Too many actions given on the command line.\n",
|
2006-04-11 21:52:54 +00:00
|
|
|
progname);
|
2009-07-24 07:35:39 +00:00
|
|
|
display_usage(progname);
|
|
|
|
exit(1);
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PDEBUG("optind = %d argc = %d\n", optind, argc);
|
2009-07-24 07:35:39 +00:00
|
|
|
return optind;
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline char *try_subdomainfs_mountpoint(const char *mntpnt,
|
|
|
|
const char *path)
|
|
|
|
{
|
|
|
|
char *proposed_base = NULL;
|
|
|
|
char *retval = NULL;
|
|
|
|
struct stat buf;
|
|
|
|
|
2008-06-11 20:19:36 +00:00
|
|
|
if (asprintf(&proposed_base, "%s%s", mntpnt, path)<0 || !proposed_base) {
|
2006-04-11 21:52:54 +00:00
|
|
|
PERROR(_("%s: Could not allocate memory for subdomainbase mount point\n"),
|
|
|
|
progname);
|
|
|
|
exit(ENOMEM);
|
|
|
|
}
|
|
|
|
if (stat(proposed_base, &buf) == 0) {
|
|
|
|
retval = proposed_base;
|
|
|
|
} else {
|
|
|
|
free(proposed_base);
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2007-02-27 02:29:16 +00:00
|
|
|
int find_subdomainfs_mountpoint(void)
|
2006-04-11 21:52:54 +00:00
|
|
|
{
|
|
|
|
FILE *mntfile;
|
|
|
|
struct mntent *mntpt;
|
|
|
|
|
2007-02-27 02:29:16 +00:00
|
|
|
if ((mntfile = setmntent(MOUNTED_FS, "r"))) {
|
|
|
|
while ((mntpt = getmntent(mntfile))) {
|
|
|
|
char *proposed = NULL;
|
|
|
|
if (strcmp(mntpt->mnt_type, "securityfs") == 0) {
|
|
|
|
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "/" MODULE_NAME);
|
|
|
|
if (proposed != NULL) {
|
|
|
|
subdomainbase = proposed;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "/" OLD_MODULE_NAME);
|
|
|
|
if (proposed != NULL) {
|
|
|
|
subdomainbase = proposed;
|
|
|
|
break;
|
|
|
|
}
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
2007-02-27 02:29:16 +00:00
|
|
|
if (strcmp(mntpt->mnt_type, "subdomainfs") == 0) {
|
|
|
|
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "");
|
|
|
|
if (proposed != NULL) {
|
|
|
|
subdomainbase = proposed;
|
|
|
|
break;
|
|
|
|
}
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
|
|
|
}
|
2007-02-27 02:29:16 +00:00
|
|
|
endmntent(mntfile);
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!subdomainbase) {
|
2007-02-27 02:29:16 +00:00
|
|
|
struct stat buf;
|
|
|
|
if (stat(DEFAULT_APPARMORFS, &buf) == -1) {
|
|
|
|
PERROR(_("Warning: unable to find a suitable fs in %s, is it "
|
|
|
|
"mounted?\nUse --subdomainfs to override.\n"),
|
|
|
|
MOUNTED_FS);
|
|
|
|
} else {
|
|
|
|
subdomainbase = DEFAULT_APPARMORFS;
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-27 02:29:16 +00:00
|
|
|
return (subdomainbase == NULL);
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
|
|
|
|
2007-02-27 02:29:16 +00:00
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
int have_enough_privilege(void)
|
|
|
|
{
|
|
|
|
uid_t uid, euid;
|
|
|
|
|
|
|
|
uid = getuid();
|
|
|
|
euid = geteuid();
|
|
|
|
|
|
|
|
if (uid != 0 && euid != 0) {
|
|
|
|
PERROR(_("%s: Sorry. You need root privileges to run this program.\n\n"),
|
|
|
|
progname);
|
|
|
|
display_usage(progname);
|
|
|
|
return EPERM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uid != 0 && euid == 0) {
|
|
|
|
PERROR(_("%s: Warning! You've set this program setuid root.\n"
|
|
|
|
"Anybody who can run this program can update "
|
|
|
|
"your AppArmor profiles.\n\n"), progname);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-04-18 17:15:05 +00:00
|
|
|
/* match_string == NULL --> no match_string available
|
|
|
|
match_string != NULL --> either a matching string specified on the
|
|
|
|
command line, or the kernel supplied a match string */
|
|
|
|
static void get_match_string(void) {
|
|
|
|
|
2007-07-18 14:22:59 +00:00
|
|
|
FILE *ms = NULL;
|
|
|
|
|
2006-04-18 17:15:05 +00:00
|
|
|
/* has process_args() already assigned a match string? */
|
|
|
|
if (match_string)
|
2007-02-27 02:29:16 +00:00
|
|
|
goto out;
|
2006-04-18 17:15:05 +00:00
|
|
|
|
2007-07-18 14:22:59 +00:00
|
|
|
ms = fopen(MATCH_STRING, "r");
|
2006-04-18 17:15:05 +00:00
|
|
|
if (!ms)
|
|
|
|
return;
|
|
|
|
|
|
|
|
match_string = malloc(1000);
|
|
|
|
if (!match_string) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!fgets(match_string, 1000, ms)) {
|
|
|
|
free(match_string);
|
|
|
|
match_string = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2007-02-27 02:29:16 +00:00
|
|
|
if (match_string) {
|
|
|
|
if (strstr(match_string, PCRE))
|
|
|
|
regex_type = AARE_PCRE;
|
|
|
|
|
|
|
|
if (strstr(match_string, AADFA))
|
|
|
|
regex_type = AARE_DFA;
|
2009-11-11 10:56:04 -08:00
|
|
|
|
|
|
|
if (strstr(match_string, " perms=c"))
|
|
|
|
perms_create = 1;
|
2007-02-27 02:29:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ms)
|
|
|
|
fclose(ms);
|
2006-04-18 17:15:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-11-11 10:56:04 -08:00
|
|
|
static void get_flags_string(char **flags, char *flags_file) {
|
2008-09-10 08:42:49 +00:00
|
|
|
char *pos;
|
2009-11-11 10:56:04 -08:00
|
|
|
FILE *f = NULL;
|
|
|
|
|
|
|
|
/* abort if missing or already set */
|
|
|
|
if (!flags || *flags) return;
|
|
|
|
|
|
|
|
f = fopen(flags_file, "r");
|
2008-09-10 08:42:49 +00:00
|
|
|
if (!f)
|
|
|
|
return;
|
|
|
|
|
2009-11-11 10:56:04 -08:00
|
|
|
*flags = malloc(1024);
|
|
|
|
if (!*flags)
|
2008-09-10 08:42:49 +00:00
|
|
|
goto fail;
|
|
|
|
|
2009-11-11 10:56:04 -08:00
|
|
|
if (!fgets(*flags, 1024, f))
|
2008-09-10 08:42:49 +00:00
|
|
|
goto fail;
|
|
|
|
|
|
|
|
fclose(f);
|
2009-11-11 10:56:04 -08:00
|
|
|
pos = strstr(*flags, "change_hat=");
|
2008-09-10 08:42:49 +00:00
|
|
|
if (pos) {
|
|
|
|
if (strncmp(pos, "change_hat=1.4", 14) == 0)
|
|
|
|
flag_changehat_version = FLAG_CHANGEHAT_1_4;
|
|
|
|
//fprintf(stderr, "flags string: %s\n", flags_string);
|
|
|
|
//fprintf(stderr, "changehat %d\n", flag_changehat_version);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
fail:
|
2009-11-11 10:56:04 -08:00
|
|
|
free(*flags);
|
|
|
|
*flags = NULL;
|
2008-09-10 08:42:49 +00:00
|
|
|
if (f)
|
|
|
|
fclose(f);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-04-18 17:15:05 +00:00
|
|
|
/* return 1 --> PCRE should work fine
|
|
|
|
return 0 --> no PCRE support */
|
2007-02-27 02:29:16 +00:00
|
|
|
static int regex_support(void) {
|
2006-04-18 17:15:05 +00:00
|
|
|
/* no match string, predates (or postdates?) the split matching
|
|
|
|
module design */
|
|
|
|
if (!match_string)
|
|
|
|
return 1;
|
|
|
|
|
2007-02-27 02:29:16 +00:00
|
|
|
if (regex_type != AARE_NONE)
|
2006-04-18 17:15:05 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-09 10:00:28 +00:00
|
|
|
int process_binary(int option, char *profilename)
|
|
|
|
{
|
|
|
|
char *buffer = NULL;
|
|
|
|
int retval = 0, size = 0, asize = 0, rsize;
|
|
|
|
int chunksize = 1 << 14;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (profilename) {
|
|
|
|
fd = open(profilename, O_RDONLY);
|
|
|
|
if (fd == -1) {
|
|
|
|
PERROR(_("Error: Could not read profile %s: %s.\n"),
|
|
|
|
profilename, strerror(errno));
|
|
|
|
exit(errno);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fd = dup(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (asize - size == 0) {
|
|
|
|
buffer = realloc(buffer, chunksize);
|
|
|
|
asize = chunksize;
|
|
|
|
chunksize <<= 1;
|
|
|
|
if (!buffer) {
|
|
|
|
PERROR(_("Memory allocation error."));
|
|
|
|
exit(errno);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rsize = read(fd, buffer + size, asize - size);
|
|
|
|
if (rsize)
|
|
|
|
size += rsize;
|
|
|
|
} while (rsize > 0);
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (rsize == 0)
|
|
|
|
retval = sd_load_buffer(option, buffer, size);
|
|
|
|
else
|
|
|
|
retval = rsize;
|
|
|
|
|
|
|
|
free(buffer);
|
|
|
|
|
2009-11-11 10:56:04 -08:00
|
|
|
if (conf_verbose) {
|
2009-07-24 07:35:39 +00:00
|
|
|
switch (option) {
|
|
|
|
case OPTION_ADD:
|
|
|
|
printf(_("Cached load succeeded for \"%s\".\n"),
|
|
|
|
profilename ? profilename : "stdin");
|
|
|
|
break;
|
|
|
|
case OPTION_REPLACE:
|
|
|
|
printf(_("Cached reload succeeded for \"%s\".\n"),
|
|
|
|
profilename ? profilename : "stdin");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-09 10:00:28 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2009-07-24 07:35:39 +00:00
|
|
|
void reset_parser(void)
|
|
|
|
{
|
|
|
|
free_aliases();
|
|
|
|
free_symtabs();
|
|
|
|
free_policies();
|
|
|
|
reset_regex();
|
|
|
|
}
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
int process_profile(int option, char *profilename)
|
|
|
|
{
|
2009-07-24 07:35:39 +00:00
|
|
|
struct stat stat_text;
|
|
|
|
struct stat stat_bin;
|
2006-04-11 21:52:54 +00:00
|
|
|
int retval = 0;
|
2009-07-24 07:36:09 +00:00
|
|
|
char * cachename = NULL;
|
|
|
|
char * cachetemp = NULL;
|
2006-04-11 21:52:54 +00:00
|
|
|
|
2009-07-24 07:35:39 +00:00
|
|
|
/* per-profile states */
|
|
|
|
force_complain = opt_force_complain;
|
|
|
|
|
|
|
|
if ( profilename ) {
|
|
|
|
if ( !(yyin = fopen(profilename, "r")) ) {
|
|
|
|
PERROR(_("Error: Could not read profile %s: %s.\n"),
|
|
|
|
profilename, strerror(errno));
|
|
|
|
exit(errno);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2009-11-11 10:56:04 -08:00
|
|
|
PERROR("%s: cannot use or update cache, disable, or force-complain via stdin\n", progname);
|
2009-07-24 07:35:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( profilename && option != OPTION_REMOVE ) {
|
|
|
|
/* make decisions about disabled or complain-mode profiles */
|
|
|
|
char *target = NULL;
|
|
|
|
char *basename = strrchr(profilename, '/');
|
|
|
|
if (basename) basename++;
|
|
|
|
else basename = profilename;
|
|
|
|
|
|
|
|
if (asprintf(&target, "%s/%s/%s", basedir, "disable", basename)<0) {
|
|
|
|
perror("asprintf");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (access(target, R_OK) == 0) {
|
2009-11-11 10:56:04 -08:00
|
|
|
if (!conf_quiet)
|
|
|
|
PERROR("Skipping profile in %s/disable: %s\n", basedir, basename);
|
2009-07-24 07:35:39 +00:00
|
|
|
free(target);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
free(target);
|
|
|
|
|
|
|
|
if (asprintf(&target, "%s/%s/%s", basedir, "force-complain", basename)<0) {
|
|
|
|
perror("asprintf");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (access(target, R_OK) == 0) {
|
2009-11-11 10:56:04 -08:00
|
|
|
if (!conf_quiet)
|
|
|
|
PERROR("Warning: found %s in %s/force-complain, forcing complain mode\n", basename, basedir);
|
2009-07-24 07:35:39 +00:00
|
|
|
force_complain = 1;
|
|
|
|
}
|
|
|
|
free(target);
|
2009-07-24 07:36:09 +00:00
|
|
|
|
|
|
|
if (!force_complain && !skip_cache) {
|
|
|
|
fstat(fileno(yyin), &stat_text);
|
|
|
|
if (asprintf(&cachename, "%s/%s/%s", basedir, "cache", basename)<0) {
|
|
|
|
perror("asprintf");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
/* Load a binary cache if it exists and is newest */
|
2009-08-19 14:44:40 +00:00
|
|
|
if (!skip_read_cache &&
|
|
|
|
stat(cachename, &stat_bin) == 0 &&
|
2009-07-24 07:36:09 +00:00
|
|
|
stat_bin.st_size > 0 &&
|
2009-11-11 15:08:09 -08:00
|
|
|
(stat_bin.st_mtim.tv_sec > stat_text.st_ctim.tv_sec ||
|
|
|
|
(stat_bin.st_mtim.tv_sec == stat_text.st_ctim.tv_sec &&
|
|
|
|
stat_bin.st_mtim.tv_nsec >= stat_text.st_ctim.tv_nsec))) {
|
2009-07-24 07:36:09 +00:00
|
|
|
if (show_cache) PERROR("Cache hit: %s\n", cachename);
|
|
|
|
retval = process_binary(option, cachename);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (write_cache) {
|
|
|
|
/* Otherwise, set up to save a cached copy */
|
|
|
|
if (asprintf(&cachetemp, "%s/%s/%s-XXXXXX", basedir, "cache", basename)<0) {
|
|
|
|
perror("asprintf");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if ( (cache_fd = mkstemp(cachetemp)) < 0) {
|
|
|
|
perror("mkstemp");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-07-24 07:35:39 +00:00
|
|
|
}
|
|
|
|
|
2009-07-24 07:36:09 +00:00
|
|
|
if (show_cache)
|
|
|
|
PERROR("Cache miss: %s\n", profilename ? profilename : "stdin");
|
|
|
|
|
2009-07-24 07:35:39 +00:00
|
|
|
if (yyin) yyrestart(yyin);
|
|
|
|
reset_parser();
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
retval = yyparse();
|
|
|
|
if (retval != 0)
|
|
|
|
goto out;
|
|
|
|
|
2008-06-09 21:15:17 +00:00
|
|
|
if (names_only) {
|
|
|
|
dump_policy_names();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
retval = post_process_policy();
|
|
|
|
if (retval != 0) {
|
|
|
|
PERROR(_("%s: Errors found in file. Aborting.\n"), progname);
|
2009-07-24 07:35:39 +00:00
|
|
|
goto out;
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dump_vars) {
|
|
|
|
dump_symtab();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (dump_expanded_vars) {
|
|
|
|
dump_expanded_symtab();
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debug > 0) {
|
2009-03-12 16:05:19 +00:00
|
|
|
printf("----- Debugging built structures -----\n");
|
|
|
|
dump_policy();
|
2006-04-11 21:52:54 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2007-02-27 02:29:16 +00:00
|
|
|
if (!regex_support()) {
|
2006-04-18 17:15:05 +00:00
|
|
|
die_if_any_regex();
|
|
|
|
}
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
retval = load_policy(option);
|
|
|
|
|
|
|
|
out:
|
2009-07-24 07:36:09 +00:00
|
|
|
if (cachetemp) {
|
|
|
|
/* Only install the generate cache file if it parsed correctly
|
|
|
|
and did not have write/close errors */
|
|
|
|
int useable_cache = (cache_fd != -1 && retval == 0);
|
|
|
|
if (cache_fd != -1) {
|
|
|
|
if (close(cache_fd)) useable_cache = 0;
|
|
|
|
cache_fd = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (useable_cache) {
|
|
|
|
rename(cachetemp, cachename);
|
|
|
|
if (show_cache)
|
|
|
|
PERROR("Wrote cache: %s\n", cachename);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
unlink(cachetemp);
|
|
|
|
if (show_cache)
|
|
|
|
PERROR("Removed cache attempt: %s\n", cachetemp);
|
|
|
|
}
|
|
|
|
free(cachetemp);
|
|
|
|
}
|
|
|
|
if (cachename) free(cachename);
|
2006-04-11 21:52:54 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2009-11-11 10:56:04 -08:00
|
|
|
static void setup_flags(void)
|
|
|
|
{
|
|
|
|
char *cache_features_path = NULL;
|
|
|
|
char *cache_flags = NULL;
|
|
|
|
|
|
|
|
/* Get the match string to determine type of regex support needed */
|
|
|
|
get_match_string();
|
|
|
|
/* Get kernel features string */
|
|
|
|
get_flags_string(&flags_string, FLAGS_FILE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Deal with cache directory versioning:
|
|
|
|
* - If cache/.features is missing, create it if --write-cache.
|
|
|
|
* - If cache/.features exists, and does not match flags_string,
|
|
|
|
* force cache reading/writing off.
|
|
|
|
*/
|
|
|
|
if (asprintf(&cache_features_path, "%s/cache/.features", basedir) == -1) {
|
|
|
|
perror("asprintf");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
get_flags_string(&cache_flags, cache_features_path);
|
|
|
|
if (cache_flags) {
|
|
|
|
if (strcmp(flags_string, cache_flags) != 0) {
|
|
|
|
if (show_cache) PERROR("Cache read/write disabled: %s does not match %s\n", FLAGS_FILE, cache_features_path);
|
|
|
|
write_cache = 0;
|
|
|
|
skip_read_cache = 1;
|
|
|
|
}
|
|
|
|
free(cache_flags);
|
|
|
|
cache_flags = NULL;
|
|
|
|
}
|
|
|
|
else if (write_cache) {
|
|
|
|
FILE * f = NULL;
|
|
|
|
int failure = 0;
|
|
|
|
|
|
|
|
f = fopen(cache_features_path, "w");
|
|
|
|
if (!f) failure = 1;
|
|
|
|
else {
|
|
|
|
if (fwrite(flags_string, strlen(flags_string), 1, f) != 1 ) {
|
|
|
|
failure = 1;
|
|
|
|
}
|
|
|
|
if (fclose(f) != 0) failure = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (failure) {
|
|
|
|
if (show_cache) PERROR("Cache write disabled: cannot write to %s\n", cache_features_path);
|
|
|
|
write_cache = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(cache_features_path);
|
|
|
|
}
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int retval;
|
2009-07-24 07:35:39 +00:00
|
|
|
int i;
|
|
|
|
int optind;
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
/* name of executable, for error reporting and usage display */
|
|
|
|
progname = argv[0];
|
|
|
|
|
|
|
|
init_base_dir();
|
|
|
|
|
2009-07-24 07:35:39 +00:00
|
|
|
optind = process_args(argc, argv);
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
setlocale(LC_MESSAGES, "");
|
|
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
|
|
textdomain(PACKAGE);
|
|
|
|
|
|
|
|
/* Check to see if we have superuser rights, if we're not
|
|
|
|
* debugging */
|
|
|
|
if (!(UNPRIVILEGED_OPS) && ((retval = have_enough_privilege()))) {
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2007-02-27 02:29:16 +00:00
|
|
|
/* Check to make sure there is an interface to load policy */
|
|
|
|
if (!(UNPRIVILEGED_OPS) && (subdomainbase == NULL) &&
|
|
|
|
(retval = find_subdomainfs_mountpoint())) {
|
2006-04-11 21:52:54 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2009-07-24 07:35:39 +00:00
|
|
|
if (!binary_input) parse_default_paths();
|
|
|
|
|
2009-11-11 10:56:04 -08:00
|
|
|
setup_flags();
|
|
|
|
|
2009-07-24 07:35:39 +00:00
|
|
|
retval = 0;
|
|
|
|
for (i = optind; retval == 0 && i <= argc; i++) {
|
|
|
|
if (i < argc && !(profilename = strdup(argv[i]))) {
|
|
|
|
perror("strdup");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* skip stdin if we've seen other command line arguments */
|
|
|
|
if (i == argc && optind != argc)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (binary_input) {
|
|
|
|
retval = process_binary(option, profilename);
|
|
|
|
} else {
|
|
|
|
retval = process_profile(option, profilename);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (profilename) free(profilename);
|
|
|
|
profilename = NULL;
|
2008-06-09 10:00:28 +00:00
|
|
|
}
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|