mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-22 10:07:12 +00:00
split the policy cache handling fns into their own file
Signed-off-by: John Johansen <john.johansen@canonical.com> [tyhicks: Don't move globals in favor of lifting those out later] Signed-off-by: Tyler Hicks <tyhicks@canonical.com> Acked-by: Seth Arnold <seth.arnold@canonical.com>
This commit is contained in:
parent
4959e2e2a8
commit
2dd3fa9383
@ -75,10 +75,10 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
|||||||
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
||||||
parser_alias.c common_optarg.c lib.c network.c \
|
parser_alias.c common_optarg.c lib.c network.c \
|
||||||
mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
|
mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
|
||||||
af_rule.cc af_unix.cc features.c
|
af_rule.cc af_unix.cc features.c policy_cache.c
|
||||||
HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h \
|
HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h \
|
||||||
rule.h common_optarg.h signal.h ptrace.h network.h af_rule.h af_unix.h \
|
rule.h common_optarg.h signal.h ptrace.h network.h af_rule.h af_unix.h \
|
||||||
features.h
|
features.h policy_cache.h
|
||||||
TOOLS = apparmor_parser
|
TOOLS = apparmor_parser
|
||||||
|
|
||||||
OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o))
|
OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o))
|
||||||
@ -115,7 +115,8 @@ TEST_OBJECTS = $(filter-out \
|
|||||||
parser_lex.o \
|
parser_lex.o \
|
||||||
parser_yacc.o \
|
parser_yacc.o \
|
||||||
common_optarg.o \
|
common_optarg.o \
|
||||||
parser_main.o, ${OBJECTS}) \
|
parser_main.o \
|
||||||
|
policy_cache.o, ${OBJECTS}) \
|
||||||
$(AAREOBJECTS)
|
$(AAREOBJECTS)
|
||||||
TEST_LDFLAGS = $(AARE_LDFLAGS)
|
TEST_LDFLAGS = $(AARE_LDFLAGS)
|
||||||
|
|
||||||
@ -187,7 +188,7 @@ apparmor_parser: $(OBJECTS) $(AAREOBJECTS) $(LIBAPPARMOR_A)
|
|||||||
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h
|
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h
|
||||||
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
|
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
|
||||||
|
|
||||||
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h
|
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h
|
||||||
$(LEX) ${LEXFLAGS} -o$@ $<
|
$(LEX) ${LEXFLAGS} -o$@ $<
|
||||||
|
|
||||||
parser_lex.o: parser_lex.c parser.h parser_yacc.h
|
parser_lex.o: parser_lex.c parser.h parser_yacc.h
|
||||||
@ -199,7 +200,7 @@ parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h cap_names.h $(APPA
|
|||||||
parser_yacc.o: parser_yacc.c parser_yacc.h $(APPARMOR_H)
|
parser_yacc.o: parser_yacc.c parser_yacc.h $(APPARMOR_H)
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_main.o: parser_main.c parser.h parser_version.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
|
parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h
|
parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h
|
||||||
@ -238,6 +239,9 @@ common_optarg.o: common_optarg.c common_optarg.h parser.h libapparmor_re/apparmo
|
|||||||
features.o: features.c features.h parser.h libapparmor_re/apparmor_re.h
|
features.o: features.c features.h parser.h libapparmor_re/apparmor_re.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
policy_cache.o: policy_cache.c policy_cache.h parser.h lib.h
|
||||||
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
lib.o: lib.c lib.h parser.h
|
lib.o: lib.c lib.h parser.h
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
@ -318,9 +318,21 @@ extern void pwarn(const char *fmt, ...) __attribute__((__format__(__printf__, 1,
|
|||||||
|
|
||||||
/* from parser_main (cannot be used in tst builds) */
|
/* from parser_main (cannot be used in tst builds) */
|
||||||
extern int force_complain;
|
extern int force_complain;
|
||||||
extern struct timespec mru_tstamp;
|
|
||||||
extern void update_mru_tstamp(FILE *file, const char *path);
|
|
||||||
extern void display_version(void);
|
extern void display_version(void);
|
||||||
|
extern int show_cache;
|
||||||
|
extern int skip_cache;
|
||||||
|
extern int skip_read_cache;
|
||||||
|
extern int write_cache;
|
||||||
|
extern int cond_clear_cache;
|
||||||
|
extern int force_clear_cache;
|
||||||
|
extern int create_cache_dir;
|
||||||
|
extern int preprocess_only;
|
||||||
|
extern int skip_mode_force;
|
||||||
|
extern int abort_on_error;
|
||||||
|
extern int skip_bad_cache_rebuild;
|
||||||
|
extern int mru_skip_cache;
|
||||||
|
extern int debug_cache;
|
||||||
|
extern struct timespec mru_tstamp;
|
||||||
|
|
||||||
/* provided by parser_lex.l (cannot be used in tst builds) */
|
/* provided by parser_lex.l (cannot be used in tst builds) */
|
||||||
extern FILE *yyin;
|
extern FILE *yyin;
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "parser_include.h"
|
#include "parser_include.h"
|
||||||
#include "parser_yacc.h"
|
#include "parser_yacc.h"
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
|
#include "policy_cache.h"
|
||||||
|
|
||||||
#ifdef PDEBUG
|
#ifdef PDEBUG
|
||||||
#undef PDEBUG
|
#undef PDEBUG
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include "parser_version.h"
|
#include "parser_version.h"
|
||||||
#include "parser_include.h"
|
#include "parser_include.h"
|
||||||
#include "common_optarg.h"
|
#include "common_optarg.h"
|
||||||
|
#include "policy_cache.h"
|
||||||
#include "libapparmor_re/apparmor_re.h"
|
#include "libapparmor_re/apparmor_re.h"
|
||||||
|
|
||||||
#define OLD_MODULE_NAME "subdomain"
|
#define OLD_MODULE_NAME "subdomain"
|
||||||
@ -708,69 +709,6 @@ int test_for_dir_mode(const char *basename, const char *linkdir)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define le16_to_cpu(x) ((uint16_t)(le16toh (*(uint16_t *) x)))
|
|
||||||
|
|
||||||
const char header_string[] = "\004\010\000version\000\002";
|
|
||||||
#define HEADER_STRING_SIZE 12
|
|
||||||
static bool valid_cached_file_version(const char *cachename)
|
|
||||||
{
|
|
||||||
char buffer[16];
|
|
||||||
FILE *f;
|
|
||||||
if (!(f = fopen(cachename, "r"))) {
|
|
||||||
PERROR(_("Error: Could not read cache file '%s', skipping...\n"), cachename);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
size_t res = fread(buffer, 1, 16, f);
|
|
||||||
fclose(f);
|
|
||||||
if (res < 16) {
|
|
||||||
if (debug_cache)
|
|
||||||
pwarn("%s: cache file '%s' invalid size\n", progname, cachename);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 12 byte header that is always the same and then 4 byte version # */
|
|
||||||
if (memcmp(buffer, header_string, HEADER_STRING_SIZE) != 0) {
|
|
||||||
if (debug_cache)
|
|
||||||
pwarn("%s: cache file '%s' has wrong header\n", progname, cachename);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t version = cpu_to_le32(ENCODE_VERSION(force_complain,
|
|
||||||
policy_version,
|
|
||||||
parser_abi_version,
|
|
||||||
kernel_abi_version));
|
|
||||||
if (memcmp(buffer + 12, &version, 4) != 0) {
|
|
||||||
if (debug_cache)
|
|
||||||
pwarn("%s: cache file '%s' has wrong version\n", progname, cachename);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* returns true if time is more recent than mru_tstamp */
|
|
||||||
#define mru_t_cmp(a) \
|
|
||||||
(((a).tv_sec == (mru_tstamp).tv_sec) ? \
|
|
||||||
(a).tv_nsec > (mru_tstamp).tv_nsec : (a).tv_sec > (mru_tstamp).tv_sec)
|
|
||||||
|
|
||||||
void set_mru_tstamp(struct timespec t)
|
|
||||||
{
|
|
||||||
mru_skip_cache = 0;
|
|
||||||
mru_tstamp = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_mru_tstamp(FILE *file, const char *name)
|
|
||||||
{
|
|
||||||
struct stat stat_file;
|
|
||||||
if (fstat(fileno(file), &stat_file) || (mru_tstamp.tv_sec == 0 && mru_tstamp.tv_nsec == 0))
|
|
||||||
return;
|
|
||||||
if (mru_t_cmp(stat_file.st_mtim)) {
|
|
||||||
if (debug_cache)
|
|
||||||
pwarn("%s: file '%s' is newer than cache file\n", progname, name);
|
|
||||||
mru_skip_cache = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int process_profile(int option, const char *profilename)
|
int process_profile(int option, const char *profilename)
|
||||||
{
|
{
|
||||||
struct stat stat_bin;
|
struct stat stat_bin;
|
||||||
@ -982,65 +920,6 @@ static int binary_dir_cb(DIR *dir unused, const char *name, struct stat *st,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int clear_cache_cb(DIR *dir, const char *path, struct stat *st,
|
|
||||||
void *data unused)
|
|
||||||
{
|
|
||||||
/* remove regular files */
|
|
||||||
if (S_ISREG(st->st_mode))
|
|
||||||
return unlinkat(dirfd(dir), path, 0);
|
|
||||||
|
|
||||||
/* do nothing with other file types */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int clear_cache_files(const char *path)
|
|
||||||
{
|
|
||||||
return dirat_for_each(NULL, path, NULL, clear_cache_cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int create_cache(const char *cachedir, const char *path,
|
|
||||||
const char *features)
|
|
||||||
{
|
|
||||||
struct stat stat_file;
|
|
||||||
FILE * f = NULL;
|
|
||||||
|
|
||||||
if (clear_cache_files(cacheloc) != 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
create_file:
|
|
||||||
f = fopen(path, "w");
|
|
||||||
if (f) {
|
|
||||||
if (fwrite(features, strlen(features), 1, f) != 1 )
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
error:
|
|
||||||
/* does the dir exist? */
|
|
||||||
if (stat(cachedir, &stat_file) == -1 && create_cache_dir) {
|
|
||||||
if (mkdir(cachedir, 0700) == 0)
|
|
||||||
goto create_file;
|
|
||||||
if (show_cache)
|
|
||||||
PERROR(_("Can't create cache directory: %s\n"), cachedir);
|
|
||||||
} else if (!S_ISDIR(stat_file.st_mode)) {
|
|
||||||
if (show_cache)
|
|
||||||
PERROR(_("File in cache directory location: %s\n"), cachedir);
|
|
||||||
} else {
|
|
||||||
if (show_cache)
|
|
||||||
PERROR(_("Can't update cache directory: %s\n"), cachedir);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (show_cache)
|
|
||||||
PERROR("Cache write disabled: cannot create %s\n", path);
|
|
||||||
write_cache = 0;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_flags(void)
|
static void setup_flags(void)
|
||||||
{
|
{
|
||||||
char *cache_features_path = NULL;
|
char *cache_features_path = NULL;
|
||||||
|
151
parser/policy_cache.c
Normal file
151
parser/policy_cache.c
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014
|
||||||
|
* Canonical, Ltd. (All rights reserved)
|
||||||
|
*
|
||||||
|
* 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. or Canonical
|
||||||
|
* Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <libintl.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#define _(s) gettext(s)
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "parser.h"
|
||||||
|
#include "policy_cache.h"
|
||||||
|
|
||||||
|
#define le16_to_cpu(x) ((uint16_t)(le16toh (*(uint16_t *) x)))
|
||||||
|
|
||||||
|
const char header_string[] = "\004\010\000version\000\002";
|
||||||
|
#define HEADER_STRING_SIZE 12
|
||||||
|
bool valid_cached_file_version(const char *cachename)
|
||||||
|
{
|
||||||
|
char buffer[16];
|
||||||
|
FILE *f;
|
||||||
|
if (!(f = fopen(cachename, "r"))) {
|
||||||
|
PERROR(_("Error: Could not read cache file '%s', skipping...\n"), cachename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t res = fread(buffer, 1, 16, f);
|
||||||
|
fclose(f);
|
||||||
|
if (res < 16) {
|
||||||
|
if (debug_cache)
|
||||||
|
pwarn("%s: cache file '%s' invalid size\n", progname, cachename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 12 byte header that is always the same and then 4 byte version # */
|
||||||
|
if (memcmp(buffer, header_string, HEADER_STRING_SIZE) != 0) {
|
||||||
|
if (debug_cache)
|
||||||
|
pwarn("%s: cache file '%s' has wrong header\n", progname, cachename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t version = cpu_to_le32(ENCODE_VERSION(force_complain,
|
||||||
|
policy_version,
|
||||||
|
parser_abi_version,
|
||||||
|
kernel_abi_version));
|
||||||
|
if (memcmp(buffer + 12, &version, 4) != 0) {
|
||||||
|
if (debug_cache)
|
||||||
|
pwarn("%s: cache file '%s' has wrong version\n", progname, cachename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void set_mru_tstamp(struct timespec t)
|
||||||
|
{
|
||||||
|
mru_skip_cache = 0;
|
||||||
|
mru_tstamp = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_mru_tstamp(FILE *file, const char *name)
|
||||||
|
{
|
||||||
|
struct stat stat_file;
|
||||||
|
if (fstat(fileno(file), &stat_file) || (mru_tstamp.tv_sec == 0 && mru_tstamp.tv_nsec == 0))
|
||||||
|
return;
|
||||||
|
if (mru_t_cmp(stat_file.st_mtim)) {
|
||||||
|
if (debug_cache)
|
||||||
|
pwarn("%s: file '%s' is newer than cache file\n", progname, name);
|
||||||
|
mru_skip_cache = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clear_cache_cb(DIR *dir, const char *path, struct stat *st,
|
||||||
|
void *data unused)
|
||||||
|
{
|
||||||
|
/* remove regular files */
|
||||||
|
if (S_ISREG(st->st_mode))
|
||||||
|
return unlinkat(dirfd(dir), path, 0);
|
||||||
|
|
||||||
|
/* do nothing with other file types */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int clear_cache_files(const char *path)
|
||||||
|
{
|
||||||
|
return dirat_for_each(NULL, path, NULL, clear_cache_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_cache(const char *cachedir, const char *path, const char *features)
|
||||||
|
{
|
||||||
|
struct stat stat_file;
|
||||||
|
FILE * f = NULL;
|
||||||
|
|
||||||
|
if (clear_cache_files(cachedir) != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
create_file:
|
||||||
|
f = fopen(path, "w");
|
||||||
|
if (f) {
|
||||||
|
if (fwrite(features, strlen(features), 1, f) != 1 )
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
|
/* does the dir exist? */
|
||||||
|
if (stat(cachedir, &stat_file) == -1 && create_cache_dir) {
|
||||||
|
if (mkdir(cachedir, 0700) == 0)
|
||||||
|
goto create_file;
|
||||||
|
if (show_cache)
|
||||||
|
PERROR(_("Can't create cache directory: %s\n"), cachedir);
|
||||||
|
} else if (!S_ISDIR(stat_file.st_mode)) {
|
||||||
|
if (show_cache)
|
||||||
|
PERROR(_("File in cache directory location: %s\n"), cachedir);
|
||||||
|
} else {
|
||||||
|
if (show_cache)
|
||||||
|
PERROR(_("Can't update cache directory: %s\n"), cachedir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_cache)
|
||||||
|
PERROR("Cache write disabled: cannot create %s\n", path);
|
||||||
|
write_cache = 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
45
parser/policy_cache.h
Normal file
45
parser/policy_cache.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014
|
||||||
|
* Canonical, Ltd. (All rights reserved)
|
||||||
|
*
|
||||||
|
* 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. or Canonical
|
||||||
|
* Ltd.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __AA_POLICY_CACHE_H
|
||||||
|
#define __AA_POLICY_CACHE_H
|
||||||
|
|
||||||
|
extern struct timespec mru_tstamp;
|
||||||
|
|
||||||
|
/* returns true if time is more recent than mru_tstamp */
|
||||||
|
#define mru_t_cmp(a) \
|
||||||
|
(((a).tv_sec == (mru_tstamp).tv_sec) ? \
|
||||||
|
(a).tv_nsec > (mru_tstamp).tv_nsec : (a).tv_sec > (mru_tstamp).tv_sec)
|
||||||
|
|
||||||
|
extern int show_cache;
|
||||||
|
extern int skip_cache;
|
||||||
|
extern int skip_read_cache;
|
||||||
|
extern int write_cache;
|
||||||
|
extern int cond_clear_cache; /* only applies if write is set */
|
||||||
|
extern int force_clear_cache; /* force clearing regargless of state */
|
||||||
|
extern int create_cache_dir; /* create the cache dir if missing? */
|
||||||
|
extern int mru_skip_cache;
|
||||||
|
extern int debug_cache;
|
||||||
|
|
||||||
|
void set_mru_tstamp(struct timespec t);
|
||||||
|
void update_mru_tstamp(FILE *file, const char *path);
|
||||||
|
bool valid_cached_file_version(const char *cachename);
|
||||||
|
int clear_cache_files(const char *path);
|
||||||
|
int create_cache(const char *cachedir, const char *path, const char *features);
|
||||||
|
|
||||||
|
#endif /* __AA_POLICY_CACHE_H */
|
Loading…
x
Reference in New Issue
Block a user