mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-24 02:57:14 +00:00
aa-status: allow filtering processes and profiles based on mode
Add the basic infrastructure for adding regex based filters and allow filtering process and profiles by mode based on a user supplied filter. Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
parent
840807cacc
commit
33464a7a3f
@ -19,6 +19,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
#include <sys/apparmor.h>
|
#include <sys/apparmor.h>
|
||||||
#include <sys/apparmor_private.h>
|
#include <sys/apparmor_private.h>
|
||||||
@ -80,12 +81,13 @@ static void free_processes(struct process *processes, size_t n) {
|
|||||||
#define SHOW_PROFILES 1
|
#define SHOW_PROFILES 1
|
||||||
#define SHOW_PROCESSES 2
|
#define SHOW_PROCESSES 2
|
||||||
|
|
||||||
static int verbose = 0;
|
static int verbose = 1;
|
||||||
int opt_show = SHOW_PROFILES | SHOW_PROCESSES;
|
int opt_show = SHOW_PROFILES | SHOW_PROCESSES;
|
||||||
bool opt_json = false;
|
bool opt_json = false;
|
||||||
bool opt_pretty = false;
|
bool opt_pretty = false;
|
||||||
bool opt_count = false;
|
bool opt_count = false;
|
||||||
const char *opt_mode = NULL;
|
const char *opt_mode = ".*";
|
||||||
|
|
||||||
|
|
||||||
const char *profile_statuses[] = {"enforce", "complain", "kill", "unconfined"};
|
const char *profile_statuses[] = {"enforce", "complain", "kill", "unconfined"};
|
||||||
const char *process_statuses[] = {"enforce", "complain", "kill", "unconfined", "mixed"};
|
const char *process_statuses[] = {"enforce", "complain", "kill", "unconfined", "mixed"};
|
||||||
@ -208,7 +210,7 @@ static int compare_profiles(const void *a, const void *b) {
|
|||||||
* filter_profiles - create a filtered profile list
|
* filter_profiles - create a filtered profile list
|
||||||
* @profiles: list of profiles
|
* @profiles: list of profiles
|
||||||
* @n: number of elements in @profiles
|
* @n: number of elements in @profiles
|
||||||
* @filter: string to match against profile mode, if NULL no filter
|
* @mode_filter: filter for the mode
|
||||||
* @filtered: return: new list of profiles that match the filter
|
* @filtered: return: new list of profiles that match the filter
|
||||||
* @nfiltered: return: number of elements in @filtered
|
* @nfiltered: return: number of elements in @filtered
|
||||||
*
|
*
|
||||||
@ -216,7 +218,7 @@ static int compare_profiles(const void *a, const void *b) {
|
|||||||
*/
|
*/
|
||||||
static int filter_profiles(struct profile *profiles,
|
static int filter_profiles(struct profile *profiles,
|
||||||
size_t n,
|
size_t n,
|
||||||
const char *filter,
|
regex_t *mode_filter,
|
||||||
struct profile **filtered,
|
struct profile **filtered,
|
||||||
size_t *nfiltered)
|
size_t *nfiltered)
|
||||||
{
|
{
|
||||||
@ -227,7 +229,7 @@ static int filter_profiles(struct profile *profiles,
|
|||||||
*nfiltered = 0;
|
*nfiltered = 0;
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
if (filter == NULL || strcmp(profiles[i].status, filter) == 0) {
|
if (regexec(mode_filter, profiles[i].status, 0, NULL, 0) == 0) {
|
||||||
struct profile *_filtered = realloc(*filtered, (*nfiltered + 1) * sizeof(**filtered));
|
struct profile *_filtered = realloc(*filtered, (*nfiltered + 1) * sizeof(**filtered));
|
||||||
if (_filtered == NULL) {
|
if (_filtered == NULL) {
|
||||||
free_profiles(*filtered, *nfiltered);
|
free_profiles(*filtered, *nfiltered);
|
||||||
@ -379,7 +381,7 @@ exit:
|
|||||||
* filter_processes: create a new filtered process list by applying @filter
|
* filter_processes: create a new filtered process list by applying @filter
|
||||||
* @processes: list of processes to filter
|
* @processes: list of processes to filter
|
||||||
* @n: number of entries in @processes
|
* @n: number of entries in @processes
|
||||||
* @filter: mode string to filter @processes against, if NULL no filter
|
* @mode_filter: regex to filter @processes modes against
|
||||||
* @filtered: return: new list of processes matching filter
|
* @filtered: return: new list of processes matching filter
|
||||||
* @nfiltered: number of entries in @filtered
|
* @nfiltered: number of entries in @filtered
|
||||||
*
|
*
|
||||||
@ -387,7 +389,7 @@ exit:
|
|||||||
*/
|
*/
|
||||||
static int filter_processes(struct process *processes,
|
static int filter_processes(struct process *processes,
|
||||||
size_t n,
|
size_t n,
|
||||||
const char *filter,
|
regex_t *mode_filter,
|
||||||
struct process **filtered,
|
struct process **filtered,
|
||||||
size_t *nfiltered)
|
size_t *nfiltered)
|
||||||
{
|
{
|
||||||
@ -398,7 +400,7 @@ static int filter_processes(struct process *processes,
|
|||||||
*nfiltered = 0;
|
*nfiltered = 0;
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
if (filter == NULL || strcmp(processes[i].mode, filter) == 0) {
|
if (regexec(mode_filter, processes[i].mode, 0, NULL, 0) == 0) {
|
||||||
struct process *_filtered = realloc(*filtered, (*nfiltered + 1) * sizeof(**filtered));
|
struct process *_filtered = realloc(*filtered, (*nfiltered + 1) * sizeof(**filtered));
|
||||||
if (_filtered == NULL) {
|
if (_filtered == NULL) {
|
||||||
free_processes(*filtered, *nfiltered);
|
free_processes(*filtered, *nfiltered);
|
||||||
@ -422,20 +424,20 @@ static int filter_processes(struct process *processes,
|
|||||||
/**
|
/**
|
||||||
* simple_filtered_count - count the number of profiles with mode == filter
|
* simple_filtered_count - count the number of profiles with mode == filter
|
||||||
* @outf: output file destination
|
* @outf: output file destination
|
||||||
* @filter: mode string to filter profiles on
|
* @mode_filter: mode string to filter profiles on
|
||||||
* @profiles: profiles list to filter
|
* @profiles: profiles list to filter
|
||||||
* @nprofiles: number of entries in @profiles
|
* @nprofiles: number of entries in @profiles
|
||||||
*
|
*
|
||||||
* Return: 0 on success, else shell error code
|
* Return: 0 on success, else shell error code
|
||||||
*/
|
*/
|
||||||
static int simple_filtered_count(FILE *outf, const char *filter,
|
static int simple_filtered_count(FILE *outf, regex_t *mode_filter,
|
||||||
struct profile *profiles, size_t nprofiles)
|
struct profile *profiles, size_t nprofiles)
|
||||||
{
|
{
|
||||||
struct profile *filtered = NULL;
|
struct profile *filtered = NULL;
|
||||||
size_t nfiltered;
|
size_t nfiltered;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = filter_profiles(profiles, nprofiles, filter,
|
ret = filter_profiles(profiles, nprofiles, mode_filter,
|
||||||
&filtered, &nfiltered);
|
&filtered, &nfiltered);
|
||||||
fprintf(outf, "%zd\n", nfiltered);
|
fprintf(outf, "%zd\n", nfiltered);
|
||||||
free_profiles(filtered, nfiltered);
|
free_profiles(filtered, nfiltered);
|
||||||
@ -446,19 +448,20 @@ static int simple_filtered_count(FILE *outf, const char *filter,
|
|||||||
/**
|
/**
|
||||||
* simple_filtered_process_count - count processes with mode == filter
|
* simple_filtered_process_count - count processes with mode == filter
|
||||||
* @outf: output file destination
|
* @outf: output file destination
|
||||||
* @filter: mode string to filter processes on
|
* @mode_filter: mode string to filter processes on
|
||||||
* @processes: process list to filter
|
* @processes: process list to filter
|
||||||
* @nprocesses: number of entries in @processes
|
* @nprocesses: number of entries in @processes
|
||||||
*
|
*
|
||||||
* Return: 0 on success, else shell error code
|
* Return: 0 on success, else shell error code
|
||||||
*/
|
*/
|
||||||
static int simple_filtered_process_count(FILE *outf, const char *filter,
|
static int simple_filtered_process_count(FILE *outf, regex_t *mode_filter,
|
||||||
struct process *processes, size_t nprocesses) {
|
struct process *processes, size_t nprocesses) {
|
||||||
struct process *filtered = NULL;
|
struct process *filtered = NULL;
|
||||||
size_t nfiltered;
|
size_t nfiltered;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = filter_processes(processes, nprocesses, filter, &filtered, &nfiltered);
|
ret = filter_processes(processes, nprocesses, mode_filter, &filtered,
|
||||||
|
&nfiltered);
|
||||||
fprintf(outf, "%zd\n", nfiltered);
|
fprintf(outf, "%zd\n", nfiltered);
|
||||||
free_processes(filtered, nfiltered);
|
free_processes(filtered, nfiltered);
|
||||||
|
|
||||||
@ -496,7 +499,7 @@ static void json_footer(FILE *outf)
|
|||||||
*
|
*
|
||||||
* Return: 0 on success, else shell error
|
* Return: 0 on success, else shell error
|
||||||
*/
|
*/
|
||||||
static int detailed_profiles(FILE *outf, const char *filter, bool json,
|
static int detailed_profiles(FILE *outf, regex_t *mode_filter, bool json,
|
||||||
struct profile *profiles, size_t nprofiles) {
|
struct profile *profiles, size_t nprofiles) {
|
||||||
int ret;
|
int ret;
|
||||||
size_t i;
|
size_t i;
|
||||||
@ -510,10 +513,20 @@ static int detailed_profiles(FILE *outf, const char *filter, bool json,
|
|||||||
for (i = 0; i < ARRAY_SIZE(profile_statuses); i++) {
|
for (i = 0; i < ARRAY_SIZE(profile_statuses); i++) {
|
||||||
size_t nfiltered = 0, j;
|
size_t nfiltered = 0, j;
|
||||||
struct profile *filtered = NULL;
|
struct profile *filtered = NULL;
|
||||||
if (filter && strcmp(filter, profile_statuses[i]) != 0)
|
regex_t sub_filter;
|
||||||
|
if (regexec(mode_filter, profile_statuses[i], 0, NULL, 0) == REG_NOMATCH)
|
||||||
/* skip processing for entries that don't match filter*/
|
/* skip processing for entries that don't match filter*/
|
||||||
continue;
|
continue;
|
||||||
ret = filter_profiles(profiles, nprofiles, profile_statuses[i], &filtered, &nfiltered);
|
/* need sub_filter as we want to split on matches to specific
|
||||||
|
* status
|
||||||
|
*/
|
||||||
|
if (regcomp(&sub_filter, profile_statuses[i], REG_NOSUB) != 0) {
|
||||||
|
dfprintf(stderr, "Error: failed to compile sub filter '%s'\n",
|
||||||
|
profile_statuses[i]);
|
||||||
|
return AA_EXIT_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
ret = filter_profiles(profiles, nprofiles, &sub_filter, &filtered, &nfiltered);
|
||||||
|
regfree(&sub_filter);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -542,14 +555,14 @@ static int detailed_profiles(FILE *outf, const char *filter, bool json,
|
|||||||
/**
|
/**
|
||||||
* detailed_processses - output a detailed listing of apparmor process status
|
* detailed_processses - output a detailed listing of apparmor process status
|
||||||
* @outf: output file
|
* @outf: output file
|
||||||
* @filter: mode filter
|
* @mode_filter: mode filter regex
|
||||||
* @json: whether output should be in json format
|
* @json: whether output should be in json format
|
||||||
* @processes: list of processes to output
|
* @processes: list of processes to output
|
||||||
* @nprocesses: number of processes in @processes
|
* @nprocesses: number of processes in @processes
|
||||||
*
|
*
|
||||||
* Return: 0 on success, else shell error
|
* Return: 0 on success, else shell error
|
||||||
*/
|
*/
|
||||||
static int detailed_processes(FILE *outf, const char *filter, bool json,
|
static int detailed_processes(FILE *outf, regex_t *mode_filter, bool json,
|
||||||
struct process *processes, size_t nprocesses) {
|
struct process *processes, size_t nprocesses) {
|
||||||
int ret;
|
int ret;
|
||||||
size_t i;
|
size_t i;
|
||||||
@ -563,10 +576,20 @@ static int detailed_processes(FILE *outf, const char *filter, bool json,
|
|||||||
for (i = 0; i < ARRAY_SIZE(process_statuses); i++) {
|
for (i = 0; i < ARRAY_SIZE(process_statuses); i++) {
|
||||||
size_t nfiltered = 0, j;
|
size_t nfiltered = 0, j;
|
||||||
struct process *filtered = NULL;
|
struct process *filtered = NULL;
|
||||||
if (filter && strcmp(filter, process_statuses[i]) != 0)
|
regex_t sub_filter;
|
||||||
|
if (regexec(mode_filter, process_statuses[i], 0, NULL, 0) == REG_NOMATCH)
|
||||||
/* skip processing for entries that don't match filter*/
|
/* skip processing for entries that don't match filter*/
|
||||||
continue;
|
continue;
|
||||||
ret = filter_processes(processes, nprocesses, process_statuses[i], &filtered, &nfiltered);
|
/* need sub_filter as we want to split on matches to specific
|
||||||
|
* status
|
||||||
|
*/
|
||||||
|
if (regcomp(&sub_filter, process_statuses[i], REG_NOSUB) != 0) {
|
||||||
|
dfprintf(stderr, "Error: failed to compile sub filter '%s'\n",
|
||||||
|
profile_statuses[i]);
|
||||||
|
return AA_EXIT_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
ret = filter_processes(processes, nprocesses, &sub_filter, &filtered, &nfiltered);
|
||||||
|
regfree(&sub_filter);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
@ -618,6 +641,43 @@ exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int print_legacy(const char *command)
|
||||||
|
{
|
||||||
|
printf("Usage: %s [OPTIONS]\n"
|
||||||
|
"Legacy options and their equivalent command\n"
|
||||||
|
" --profiled --count --profiles\n"
|
||||||
|
" --enforced --count --profiles --mode=enforced\n"
|
||||||
|
" --complaining --count --profiles --mode=complain\n"
|
||||||
|
" --kill --count --profiles --mode=kill\n"
|
||||||
|
" --special-unconfined --count --profiles --mode=unconfined\n"
|
||||||
|
" --process-mixed --count --ps --mode=mixed\n",
|
||||||
|
command);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int usage_filters(void)
|
||||||
|
{
|
||||||
|
long unsigned int i;
|
||||||
|
|
||||||
|
printf("Usage of filters\n"
|
||||||
|
"Filters are used to reduce the output of information to only\n"
|
||||||
|
"those entries that will match the filter. Filters use posix\n"
|
||||||
|
"regular expression syntax. The possible values for exes that\n"
|
||||||
|
"support filters are below\n\n"
|
||||||
|
" --mode: regular expression to match the profile mode"
|
||||||
|
" modes: enforce, complain, kill, unconfined, mixed\n"
|
||||||
|
);
|
||||||
|
for (i = 0; i < ARRAY_SIZE(process_statuses); i++) {
|
||||||
|
printf("%s%s", i ? ", " : "", process_statuses[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int print_usage(const char *command, bool error)
|
static int print_usage(const char *command, bool error)
|
||||||
{
|
{
|
||||||
int status = EXIT_SUCCESS;
|
int status = EXIT_SUCCESS;
|
||||||
@ -634,16 +694,13 @@ static int print_usage(const char *command, bool error)
|
|||||||
" --enabled returns error code if AppArmor not enabled\n"
|
" --enabled returns error code if AppArmor not enabled\n"
|
||||||
" --show=X What information to show. {profiles,processes,all}\n"
|
" --show=X What information to show. {profiles,processes,all}\n"
|
||||||
" --count print the number of entries. Implies --quiet\n"
|
" --count print the number of entries. Implies --quiet\n"
|
||||||
" --profiled prints the number of loaded policies\n"
|
" --mode=filter regular expression to match profile modes. see filters\n"
|
||||||
" --enforced prints the number of loaded enforcing policies\n"
|
" or a regular expression\n"
|
||||||
" --complaining prints the number of loaded non-enforcing policies\n"
|
|
||||||
" --kill prints the number of loaded enforcing policies that kill tasks on policy violations\n"
|
|
||||||
" --special-unconfined prints the number of loaded non-enforcing policies in the special unconfined mode\n"
|
|
||||||
" --process-mixed prints the number processes with mixed profile modes\n"
|
|
||||||
" --json displays multiple data points in machine-readable JSON format\n"
|
" --json displays multiple data points in machine-readable JSON format\n"
|
||||||
" --pretty-json same data as --json, formatted for human consumption as well\n"
|
" --pretty-json same data as --json, formatted for human consumption as well\n"
|
||||||
" --verbose (default) displays multiple data points about loaded policy set\n"
|
" --verbose (default) displays data points about loaded policy set\n"
|
||||||
" --help this message\n",
|
" -h [(legacy|filter)] this message, or info on the specified option\n"
|
||||||
|
" --help[=(legacy|filter)] this message, or info on the specified option\n",
|
||||||
command);
|
command);
|
||||||
|
|
||||||
exit(status);
|
exit(status);
|
||||||
@ -667,7 +724,7 @@ static int print_usage(const char *command, bool error)
|
|||||||
#define ARG_VERBOSE 'v'
|
#define ARG_VERBOSE 'v'
|
||||||
#define ARG_HELP 'h'
|
#define ARG_HELP 'h'
|
||||||
|
|
||||||
static char **parse_args(int argc, char **argv)
|
static int parse_args(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int opt;
|
int opt;
|
||||||
struct option long_opts[] = {
|
struct option long_opts[] = {
|
||||||
@ -681,9 +738,10 @@ static char **parse_args(int argc, char **argv)
|
|||||||
{"json", no_argument, 0, ARG_JSON},
|
{"json", no_argument, 0, ARG_JSON},
|
||||||
{"pretty-json", no_argument, 0, ARG_PRETTY},
|
{"pretty-json", no_argument, 0, ARG_PRETTY},
|
||||||
{"verbose", no_argument, 0, ARG_VERBOSE},
|
{"verbose", no_argument, 0, ARG_VERBOSE},
|
||||||
{"help", no_argument, 0, ARG_HELP},
|
{"help", 2, 0, ARG_HELP},
|
||||||
{"count", no_argument, 0, ARG_COUNT},
|
{"count", no_argument, 0, ARG_COUNT},
|
||||||
{"show", 1, 0, ARG_SHOW},
|
{"show", 1, 0, ARG_SHOW},
|
||||||
|
{"mode", 1, 0, ARG_MODE},
|
||||||
{NULL, 0, 0, 0},
|
{NULL, 0, 0, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -699,34 +757,50 @@ static char **parse_args(int argc, char **argv)
|
|||||||
/* default opt_show */
|
/* default opt_show */
|
||||||
break;
|
break;
|
||||||
case ARG_HELP:
|
case ARG_HELP:
|
||||||
|
if (!optarg) {
|
||||||
print_usage(argv[0], false);
|
print_usage(argv[0], false);
|
||||||
|
} else if (strcmp(optarg, "legacy") == 0) {
|
||||||
|
print_legacy(argv[0]);
|
||||||
|
} else if (strcmp(optarg, "filters") == 0) {
|
||||||
|
usage_filters();
|
||||||
|
} else {
|
||||||
|
dfprintf(stderr, "Error: Invalid --help option '%s'.\n", optarg);
|
||||||
|
print_usage(argv[0], true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ARG_PROFILED:
|
case ARG_PROFILED:
|
||||||
|
verbose = false;
|
||||||
opt_count = true;
|
opt_count = true;
|
||||||
opt_show = SHOW_PROFILES;
|
opt_show = SHOW_PROFILES;
|
||||||
/* default opt_mode */
|
/* default opt_mode */
|
||||||
break;
|
break;
|
||||||
case ARG_ENFORCED:
|
case ARG_ENFORCED:
|
||||||
|
verbose = false;
|
||||||
opt_count = true;
|
opt_count = true;
|
||||||
opt_show = SHOW_PROFILES;
|
opt_show = SHOW_PROFILES;
|
||||||
opt_mode = "enforce";
|
opt_mode = "enforce";
|
||||||
break;
|
break;
|
||||||
case ARG_COMPLAIN:
|
case ARG_COMPLAIN:
|
||||||
|
verbose = false;
|
||||||
opt_count = true;
|
opt_count = true;
|
||||||
opt_show = SHOW_PROFILES;
|
opt_show = SHOW_PROFILES;
|
||||||
opt_mode = "complain";
|
opt_mode = "complain";
|
||||||
break;
|
break;
|
||||||
case ARG_UNCONFINED:
|
case ARG_UNCONFINED:
|
||||||
|
verbose = false;
|
||||||
opt_count = true;
|
opt_count = true;
|
||||||
opt_show = SHOW_PROFILES;
|
opt_show = SHOW_PROFILES;
|
||||||
opt_mode = "unconfined";
|
opt_mode = "unconfined";
|
||||||
break;
|
break;
|
||||||
case ARG_KILL:
|
case ARG_KILL:
|
||||||
|
verbose = false;
|
||||||
opt_count = true;
|
opt_count = true;
|
||||||
opt_show = SHOW_PROFILES;
|
opt_show = SHOW_PROFILES;
|
||||||
opt_mode = "kill";
|
opt_mode = "kill";
|
||||||
break;
|
break;
|
||||||
case ARG_PS_MIXED:
|
case ARG_PS_MIXED:
|
||||||
|
verbose = false;
|
||||||
opt_count = true;
|
opt_count = true;
|
||||||
opt_show = SHOW_PROCESSES;
|
opt_show = SHOW_PROCESSES;
|
||||||
opt_mode = "mixed";
|
opt_mode = "mixed";
|
||||||
@ -757,6 +831,10 @@ static char **parse_args(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ARG_MODE:
|
||||||
|
opt_mode = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dfprintf(stderr, "Error: Invalid command.\n");
|
dfprintf(stderr, "Error: Invalid command.\n");
|
||||||
print_usage(argv[0], true);
|
print_usage(argv[0], true);
|
||||||
@ -764,8 +842,7 @@ static char **parse_args(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return argv + optind;
|
return optind;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -779,12 +856,14 @@ int main(int argc, char **argv)
|
|||||||
int ret = EXIT_SUCCESS;
|
int ret = EXIT_SUCCESS;
|
||||||
const char *progname = argv[0];
|
const char *progname = argv[0];
|
||||||
FILE *outf = stdout, *outf_save = NULL;
|
FILE *outf = stdout, *outf_save = NULL;
|
||||||
|
regex_t mode_filter;
|
||||||
|
|
||||||
if (argc > 2) {
|
if (argc > 1) {
|
||||||
dfprintf(stderr, "Error: Too many options.\n");
|
int pos = parse_args(argc, argv);
|
||||||
|
if (pos < argc) {
|
||||||
|
dfprintf(stderr, "Error: Unknown options.\n");
|
||||||
print_usage(progname, true);
|
print_usage(progname, true);
|
||||||
} else if (argc == 2) {
|
}
|
||||||
argv = parse_args(argc, argv);
|
|
||||||
} else {
|
} else {
|
||||||
verbose = 1;
|
verbose = 1;
|
||||||
/* default opt_show */
|
/* default opt_show */
|
||||||
@ -792,6 +871,12 @@ int main(int argc, char **argv)
|
|||||||
/* default opt_json */
|
/* default opt_json */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (regcomp(&mode_filter, opt_mode, REG_NOSUB) != 0) {
|
||||||
|
dfprintf(stderr, "Error: failed to compile mode filter '%s'\n",
|
||||||
|
opt_mode);
|
||||||
|
return AA_EXIT_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/* check apparmor is available and we have permissions */
|
/* check apparmor is available and we have permissions */
|
||||||
ret = open_profiles(&fp);
|
ret = open_profiles(&fp);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
@ -820,10 +905,10 @@ int main(int argc, char **argv)
|
|||||||
json_header(outf);
|
json_header(outf);
|
||||||
if (opt_show & SHOW_PROFILES) {
|
if (opt_show & SHOW_PROFILES) {
|
||||||
if (opt_count) {
|
if (opt_count) {
|
||||||
ret = simple_filtered_count(outf, opt_mode,
|
ret = simple_filtered_count(outf, &mode_filter,
|
||||||
profiles, nprofiles);
|
profiles, nprofiles);
|
||||||
} else {
|
} else {
|
||||||
ret = detailed_profiles(outf, opt_mode, opt_json,
|
ret = detailed_profiles(outf, &mode_filter, opt_json,
|
||||||
profiles, nprofiles);
|
profiles, nprofiles);
|
||||||
}
|
}
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
@ -838,10 +923,10 @@ int main(int argc, char **argv)
|
|||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dfprintf(stderr, "Failed to get processes: %d....\n", ret);
|
dfprintf(stderr, "Failed to get processes: %d....\n", ret);
|
||||||
} else if (opt_count) {
|
} else if (opt_count) {
|
||||||
ret = simple_filtered_process_count(outf, opt_mode,
|
ret = simple_filtered_process_count(outf, &mode_filter,
|
||||||
processes, nprocesses);
|
processes, nprocesses);
|
||||||
} else {
|
} else {
|
||||||
ret = detailed_processes(outf, opt_mode, opt_json,
|
ret = detailed_processes(outf, &mode_filter, opt_json,
|
||||||
processes, nprocesses);
|
processes, nprocesses);
|
||||||
}
|
}
|
||||||
free_processes(processes, nprocesses);
|
free_processes(processes, nprocesses);
|
||||||
@ -880,6 +965,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
free_profiles(profiles, nprofiles);
|
free_profiles(profiles, nprofiles);
|
||||||
|
regfree(&mode_filter);
|
||||||
|
|
||||||
exit(ret);
|
exit(ret);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user