Signed-off-by: Tyler Hicks <tyhi...@canonical.com> --- libraries/libapparmor/include/sys/apparmor.h | 13 + libraries/libapparmor/src/Makefile.am | 2 +- libraries/libapparmor/src/features.c | 448 +++++++++++++++++++++++++++ libraries/libapparmor/src/libapparmor.map | 23 ++ libraries/libapparmor/src/private.h | 1 + parser/Makefile | 9 +- parser/features.c | 448 --------------------------- parser/features.h | 34 -- parser/kernel_interface.h | 2 + 9 files changed, 491 insertions(+), 489 deletions(-) create mode 100644 libraries/libapparmor/src/features.c delete mode 100644 parser/features.c delete mode 100644 parser/features.h
diff --git a/libraries/libapparmor/include/sys/apparmor.h b/libraries/libapparmor/include/sys/apparmor.h index 361cde8..34507e4 100644 --- a/libraries/libapparmor/include/sys/apparmor.h +++ b/libraries/libapparmor/include/sys/apparmor.h @@ -18,6 +18,7 @@ #ifndef _SYS_APPARMOR_H #define _SYS_APPARMOR_H 1 +#include <stdbool.h> #include <stdint.h> #include <sys/types.h> @@ -103,6 +104,18 @@ extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow, #define aa_change_hat_vargs(T, X...) \ (aa_change_hat_vargs)(T, __macroarg_counter(X), X) +typedef struct aa_features aa_features; +int aa_features_new(aa_features **features, const char *path); +int aa_features_new_from_string(aa_features **features, + const char *string, size_t size); +int aa_features_new_from_kernel(aa_features **features); +aa_features *aa_features_ref(aa_features *features); +void aa_features_unref(aa_features *features); + +int aa_features_write_to_file(aa_features *features, const char *path); +bool aa_features_is_equal(aa_features *features1, aa_features *features2); +bool aa_features_supports(aa_features *features, char *str); + __END_DECLS #endif /* sys/apparmor.h */ diff --git a/libraries/libapparmor/src/Makefile.am b/libraries/libapparmor/src/Makefile.am index 42934d0..ac93bf5 100644 --- a/libraries/libapparmor/src/Makefile.am +++ b/libraries/libapparmor/src/Makefile.am @@ -48,7 +48,7 @@ af_protos.h: /usr/include/netinet/in.h lib_LTLIBRARIES = libapparmor.la noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h -libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel_interface.c scanner.c private.c +libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel_interface.c scanner.c private.c features.c libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -dynamic -pthread \ -Wl,--version-script=$(top_srcdir)/src/libapparmor.map diff --git a/libraries/libapparmor/src/features.c b/libraries/libapparmor/src/features.c new file mode 100644 index 0000000..cf2389c --- /dev/null +++ b/libraries/libapparmor/src/features.c @@ -0,0 +1,448 @@ +/* + * 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 <errno.h> +#include <ctype.h> +#include <dirent.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/apparmor.h> + +#include "private.h" + +#define FEATURES_FILE "/sys/kernel/security/apparmor/features" + +#define STRING_SIZE 8192 + +struct aa_features { + unsigned int ref_count; + char string[STRING_SIZE]; +}; + +struct features_struct { + char *buffer; + int size; + char *pos; +}; + +static int features_snprintf(struct features_struct *fst, const char *fmt, ...) +{ + va_list args; + int i, remaining = fst->size - (fst->pos - fst->buffer); + + if (remaining < 0) { + errno = EINVAL; + PERROR("Invalid features buffer offset\n"); + return -1; + } + + va_start(args, fmt); + i = vsnprintf(fst->pos, remaining, fmt, args); + va_end(args); + + if (i < 0) { + errno = EIO; + PERROR("Failed to write to features buffer\n"); + return -1; + } else if (i >= remaining) { + errno = ENOBUFS; + PERROR("Feature buffer full."); + return -1; + } + + fst->pos += i; + return 0; +} + +static int features_dir_cb(DIR *dir, const char *name, struct stat *st, + void *data) +{ + struct features_struct *fst = (struct features_struct *) data; + + /* skip dot files and files with no name */ + if (*name == '.' || !strlen(name)) + return 0; + + if (features_snprintf(fst, "%s {", name) == -1) + return -1; + + if (S_ISREG(st->st_mode)) { + autoclose int file = -1; + int len; + int remaining = fst->size - (fst->pos - fst->buffer); + + file = openat(dirfd(dir), name, O_RDONLY); + if (file == -1) { + PDEBUG("Could not open '%s'", name); + return -1; + } + PDEBUG("Opened features \"%s\"\n", name); + if (st->st_size > remaining) { + PDEBUG("Feature buffer full."); + errno = ENOBUFS; + return -1; + } + + do { + len = read(file, fst->pos, remaining); + if (len > 0) { + remaining -= len; + fst->pos += len; + *fst->pos = 0; + } + } while (len > 0); + if (len < 0) { + PDEBUG("Error reading feature file '%s'\n", name); + return -1; + } + } else if (S_ISDIR(st->st_mode)) { + if (_aa_dirat_for_each(dir, name, fst, features_dir_cb)) + return -1; + } + + if (features_snprintf(fst, "}\n") == -1) + return -1; + + return 0; +} + +static int handle_features_dir(const char *filename, char *buffer, int size, + char *pos) +{ + struct features_struct fst = { buffer, size, pos }; + + if (_aa_dirat_for_each(NULL, filename, &fst, features_dir_cb)) { + PDEBUG("Failed evaluating %s\n", filename); + return -1; + } + + return 0; +} + +static int load_features_file(const char *name, char *buffer, size_t size) +{ + autofclose FILE *f = NULL; + size_t end; + + f = fopen(name, "r"); + if (!f) + return -1; + + errno = 0; + end = fread(buffer, 1, size - 1, f); + if (ferror(f)) { + if (!errno) + errno = EIO; + return -1; + } + buffer[end] = 0; + + return 0; +} + +static bool walk_one(const char **str, const char *component, bool is_top_level) +{ + const char *cur = *str; + uint32_t bracket_count = 0; + int i = 0; + + /* Empty strings are not accepted */ + if (!*cur || !component[0]) + return false; + + /** + * If @component is not top-level, the first character in the string to + * search MUST be '{' + */ + if (!is_top_level) { + if (*cur != '{') + return false; + + cur++; + } + + /** + * This loop tries to find the @component in *@str. When this loops + * completes, cur will either point one character past the end of the + * matched @component or to the NUL terminator of *@str. + */ + while(*cur && component[i]) { + if (!isascii(*cur)) { + /* Only ASCII is expected */ + return false; + } else if (*cur == '{') { + /* There's a limit to the number of opening brackets */ + if (bracket_count == UINT32_MAX) + return false; + + bracket_count++; + } else if (*cur == '}') { + /* Check for unexpected closing brackets */ + if (bracket_count == 0) + return false; + + bracket_count--; + } + + /** + * Move to the next character in @component if we have a match + * and either @component is not top-level or, if @component is + * top-level, we're not inside of brackets + */ + if (*cur == component[i] && + (!is_top_level || bracket_count == 0)) + i++; + else + i = 0; + + cur++; + } + + /* A full match was not found if component[i] is non-NUL */ + if (component[i]) + return false; + + /** + * This loop eats up valid (ASCII) characters until a non-bracket or + * non-space character is found so that *@str is properly set to call + * back into this function, if necessary + */ + while (*cur) { + if (!isascii(*cur)) + return false; + else if (*cur == '{' || *cur == '}' || !isspace(*cur)) + break; + + cur++; + } + + *str = cur; + return true; +} + +/** + * aa_features_new - create a new features based on a path + * @features: will point to the address of an allocated and initialized + * aa_features object upon success + * @path: path to a features file or directory + * + * Returns: 0 on success, -1 on error with errno set and *@features pointing to + * NULL + */ +int aa_features_new(aa_features **features, const char *path) +{ + struct stat stat_file; + aa_features *f; + int retval; + + *features = NULL; + + if (stat(path, &stat_file) == -1) + return -1; + + f = (aa_features *) calloc(1, sizeof(*f)); + if (!f) { + errno = ENOMEM; + return -1; + } + aa_features_ref(f); + + retval = S_ISDIR(stat_file.st_mode) ? + handle_features_dir(path, f->string, STRING_SIZE, f->string) : + load_features_file(path, f->string, STRING_SIZE); + if (retval) { + int save = errno; + + aa_features_unref(f); + errno = save; + return -1; + } + + *features = f; + + return 0; +} + +/** + * aa_features_new_from_string - create a new features based on a string + * @features: will point to the address of an allocated and initialized + * aa_features object upon success + * @string: a NUL-terminated string representation of features + * @size: the size of @string, not counting the NUL-terminator + * + * Returns: 0 on success, -1 on error with errno set and *@features pointing to + * NULL + */ +int aa_features_new_from_string(aa_features **features, + const char *string, size_t size) +{ + aa_features *f; + + *features = NULL; + + /* Require size to be less than STRING_SIZE so there's room for a NUL */ + if (size >= STRING_SIZE) + return ENOBUFS; + + f = (aa_features *) calloc(1, sizeof(*f)); + if (!f) { + errno = ENOMEM; + return -1; + } + aa_features_ref(f); + + memcpy(f->string, string, size); + f->string[size] = '\0'; + *features = f; + + return 0; +} + +/** + * aa_features_new_from_kernel - create a new features based on the current kernel + * @features: will point to the address of an allocated and initialized + * aa_features object upon success + * + * Returns: 0 on success, -1 on error with errno set and *@features pointing to + * NULL + */ +int aa_features_new_from_kernel(aa_features **features) +{ + return aa_features_new(features, FEATURES_FILE); +} + +/** + * aa_features_ref - increments the ref count of a features + * @features: the features + * + * Returns: the features + */ +aa_features *aa_features_ref(aa_features *features) +{ + atomic_inc(&features->ref_count); + return features; +} + +/** + * aa_features_unref - decrements the ref count and frees the features when 0 + * @features: the features (can be NULL) + */ +void aa_features_unref(aa_features *features) +{ + if (features && atomic_dec_and_test(&features->ref_count)) + free(features); +} + +/** + * aa_features_write_to_file - write a string representation to a file + * @features: the features + * @path: the path to write to + * + * Returns: 0 on success, -1 on error with errno set + */ +int aa_features_write_to_file(aa_features *features, const char *path) +{ + autoclose int fd = -1; + size_t size; + ssize_t retval; + char *string; + + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_CLOEXEC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd == -1) + return -1; + + string = features->string; + size = strlen(string); + do { + retval = write(fd, string, size); + if (retval == -1) + return -1; + + size -= retval; + string += retval; + } while (size); + + return 0; +} + +/** + * aa_features_is_equal - equality test for two features + * @features1: the first features (can be NULL) + * @features2: the second features (can be NULL) + * + * Returns: true if they're equal, false if they're not or either are NULL + */ +bool aa_features_is_equal(aa_features *features1, aa_features *features2) +{ + return features1 && features2 && + strcmp(features1->string, features2->string) == 0; +} + +/** + * aa_features_supports - provides features support status + * @features: the features + * @str: the string representation of a feature to check + * + * Example @str values are "dbus/mask/send", "caps/mask/audit_read", and + * "policy/versions/v7". + * + * Returns: a bool specifying the support status of @str feature + */ +bool aa_features_supports(aa_features *features, char *str) +{ + const char *features_string = features->string; + char *components[32]; + char *saveptr = NULL; + size_t i; + + /* Empty strings are not accepted. Neither are leading '/' chars. */ + if (!str || str[0] == '/') + return false; + + /** + * Break @str into an array of components. For example, + * "mount/mask/mount" would turn into "mount" as the first component, + * "mask" as the second, and "mount" as the third + */ + for (i = 0; i < sizeof(components); i++) { + components[i] = strtok_r(str, "/", &saveptr); + if (!components[i]) + break; + + str = NULL; + } + + /* At least one valid token is required */ + if (!components[0]) + return false; + + /* Ensure that all components are valid and found */ + for (i = 0; i < sizeof(components) && components[i]; i++) { + if (!walk_one(&features_string, components[i], i == 0)) + return false; + } + + return true; +} diff --git a/libraries/libapparmor/src/libapparmor.map b/libraries/libapparmor/src/libapparmor.map index 1ea221f..d0020c7 100644 --- a/libraries/libapparmor/src/libapparmor.map +++ b/libraries/libapparmor/src/libapparmor.map @@ -52,6 +52,29 @@ APPARMOR_2.9 { *; } APPARMOR_1.1; +APPARMOR_2.10 { + global: + aa_features_new; + aa_features_new_from_string; + aa_features_new_from_kernel; + aa_features_ref; + aa_features_unref; + aa_features_write_to_file; + aa_features_is_equal; + aa_features_supports_max_abi; + aa_features_supports_policydb; + aa_features_supports_set_load; + aa_features_supports_network; + aa_features_supports_af_unix; + aa_features_supports_mount; + aa_features_supports_dbus; + aa_features_supports_signal; + aa_features_supports_ptrace; + aa_features_supports_diff_encode; + local: + *; +} APPARMOR_2.9; + PRIVATE { global: _aa_is_blacklisted; diff --git a/libraries/libapparmor/src/private.h b/libraries/libapparmor/src/private.h index 3a8beac..83813c4 100644 --- a/libraries/libapparmor/src/private.h +++ b/libraries/libapparmor/src/private.h @@ -18,6 +18,7 @@ #define _AA_PRIVATE_H 1 #include <stdbool.h> +#include <sys/apparmor_private.h> #define autofree __attribute((cleanup(_aa_autofree))) #define autoclose __attribute((cleanup(_aa_autoclose))) diff --git a/parser/Makefile b/parser/Makefile index 372136d..120672f 100644 --- a/parser/Makefile +++ b/parser/Makefile @@ -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_alias.c common_optarg.c lib.c network.c \ mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \ - af_rule.cc af_unix.cc features.c policy_cache.c kernel_interface.c + af_rule.cc af_unix.cc policy_cache.c kernel_interface.c 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 \ - features.h policy_cache.h kernel_interface.h + policy_cache.h kernel_interface.h TOOLS = apparmor_parser OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o)) @@ -237,10 +237,7 @@ mount.o: mount.cc mount.h parser.h immunix.h rule.h common_optarg.o: common_optarg.c common_optarg.h parser.h libapparmor_re/apparmor_re.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< -features.o: features.c features.h parser.h libapparmor_re/apparmor_re.h - $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< - -policy_cache.o: policy_cache.c policy_cache.h parser.h features.h +policy_cache.o: policy_cache.c policy_cache.h parser.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< kernel_interface.o: kernel_interface.c kernel_interface.h diff --git a/parser/features.c b/parser/features.c deleted file mode 100644 index 8b9844f..0000000 --- a/parser/features.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - * 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 <errno.h> -#include <ctype.h> -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -#include "features.h" -#include "lib.h" -#include "parser.h" - -#define FEATURES_FILE "/sys/kernel/security/" MODULE_NAME "/features" - -#define STRING_SIZE 8192 - -struct aa_features { - unsigned int ref_count; - char string[STRING_SIZE]; -}; - -struct features_struct { - char *buffer; - int size; - char *pos; -}; - -static int features_snprintf(struct features_struct *fst, const char *fmt, ...) -{ - va_list args; - int i, remaining = fst->size - (fst->pos - fst->buffer); - - if (remaining < 0) { - errno = EINVAL; - PERROR("Invalid features buffer offset\n"); - return -1; - } - - va_start(args, fmt); - i = vsnprintf(fst->pos, remaining, fmt, args); - va_end(args); - - if (i < 0) { - errno = EIO; - PERROR("Failed to write to features buffer\n"); - return -1; - } else if (i >= remaining) { - errno = ENOBUFS; - PERROR("Feature buffer full."); - return -1; - } - - fst->pos += i; - return 0; -} - -static int features_dir_cb(DIR *dir, const char *name, struct stat *st, - void *data) -{ - struct features_struct *fst = (struct features_struct *) data; - - /* skip dot files and files with no name */ - if (*name == '.' || !strlen(name)) - return 0; - - if (features_snprintf(fst, "%s {", name) == -1) - return -1; - - if (S_ISREG(st->st_mode)) { - autoclose int file = -1; - int len; - int remaining = fst->size - (fst->pos - fst->buffer); - - file = openat(dirfd(dir), name, O_RDONLY); - if (file == -1) { - PDEBUG("Could not open '%s'", name); - return -1; - } - PDEBUG("Opened features \"%s\"\n", name); - if (st->st_size > remaining) { - PDEBUG("Feature buffer full."); - errno = ENOBUFS; - return -1; - } - - do { - len = read(file, fst->pos, remaining); - if (len > 0) { - remaining -= len; - fst->pos += len; - *fst->pos = 0; - } - } while (len > 0); - if (len < 0) { - PDEBUG("Error reading feature file '%s'\n", name); - return -1; - } - } else if (S_ISDIR(st->st_mode)) { - if (dirat_for_each(dir, name, fst, features_dir_cb)) - return -1; - } - - if (features_snprintf(fst, "}\n") == -1) - return -1; - - return 0; -} - -static int handle_features_dir(const char *filename, char *buffer, int size, - char *pos) -{ - struct features_struct fst = { buffer, size, pos }; - - if (dirat_for_each(NULL, filename, &fst, features_dir_cb)) { - PDEBUG("Failed evaluating %s\n", filename); - return -1; - } - - return 0; -} - -static int load_features_file(const char *name, char *buffer, size_t size) -{ - autofclose FILE *f = NULL; - size_t end; - - f = fopen(name, "r"); - if (!f) - return -1; - - errno = 0; - end = fread(buffer, 1, size - 1, f); - if (ferror(f)) { - if (!errno) - errno = EIO; - return -1; - } - buffer[end] = 0; - - return 0; -} - -static bool walk_one(const char **str, const char *component, bool is_top_level) -{ - const char *cur = *str; - uint32_t bracket_count = 0; - int i = 0; - - /* Empty strings are not accepted */ - if (!*cur || !component[0]) - return false; - - /** - * If @component is not top-level, the first character in the string to - * search MUST be '{' - */ - if (!is_top_level) { - if (*cur != '{') - return false; - - cur++; - } - - /** - * This loop tries to find the @component in *@str. When this loops - * completes, cur will either point one character past the end of the - * matched @component or to the NUL terminator of *@str. - */ - while(*cur && component[i]) { - if (!isascii(*cur)) { - /* Only ASCII is expected */ - return false; - } else if (*cur == '{') { - /* There's a limit to the number of opening brackets */ - if (bracket_count == UINT32_MAX) - return false; - - bracket_count++; - } else if (*cur == '}') { - /* Check for unexpected closing brackets */ - if (bracket_count == 0) - return false; - - bracket_count--; - } - - /** - * Move to the next character in @component if we have a match - * and either @component is not top-level or, if @component is - * top-level, we're not inside of brackets - */ - if (*cur == component[i] && - (!is_top_level || bracket_count == 0)) - i++; - else - i = 0; - - cur++; - } - - /* A full match was not found if component[i] is non-NUL */ - if (component[i]) - return false; - - /** - * This loop eats up valid (ASCII) characters until a non-bracket or - * non-space character is found so that *@str is properly set to call - * back into this function, if necessary - */ - while (*cur) { - if (!isascii(*cur)) - return false; - else if (*cur == '{' || *cur == '}' || !isspace(*cur)) - break; - - cur++; - } - - *str = cur; - return true; -} - -/** - * aa_features_new - create a new features based on a path - * @features: will point to the address of an allocated and initialized - * aa_features object upon success - * @path: path to a features file or directory - * - * Returns: 0 on success, -1 on error with errno set and *@features pointing to - * NULL - */ -int aa_features_new(aa_features **features, const char *path) -{ - struct stat stat_file; - aa_features *f; - int retval; - - *features = NULL; - - if (stat(path, &stat_file) == -1) - return -1; - - f = (aa_features *) calloc(1, sizeof(*f)); - if (!f) { - errno = ENOMEM; - return -1; - } - aa_features_ref(f); - - retval = S_ISDIR(stat_file.st_mode) ? - handle_features_dir(path, f->string, STRING_SIZE, f->string) : - load_features_file(path, f->string, STRING_SIZE); - if (retval) { - int save = errno; - - aa_features_unref(f); - errno = save; - return -1; - } - - *features = f; - - return 0; -} - -/** - * aa_features_new_from_string - create a new features based on a string - * @features: will point to the address of an allocated and initialized - * aa_features object upon success - * @string: a NUL-terminated string representation of features - * @size: the size of @string, not counting the NUL-terminator - * - * Returns: 0 on success, -1 on error with errno set and *@features pointing to - * NULL - */ -int aa_features_new_from_string(aa_features **features, - const char *string, size_t size) -{ - aa_features *f; - - *features = NULL; - - /* Require size to be less than STRING_SIZE so there's room for a NUL */ - if (size >= STRING_SIZE) - return ENOBUFS; - - f = (aa_features *) calloc(1, sizeof(*f)); - if (!f) { - errno = ENOMEM; - return -1; - } - aa_features_ref(f); - - memcpy(f->string, string, size); - f->string[size] = '\0'; - *features = f; - - return 0; -} - -/** - * aa_features_new_from_kernel - create a new features based on the current kernel - * @features: will point to the address of an allocated and initialized - * aa_features object upon success - * - * Returns: 0 on success, -1 on error with errno set and *@features pointing to - * NULL - */ -int aa_features_new_from_kernel(aa_features **features) -{ - return aa_features_new(features, FEATURES_FILE); -} - -/** - * aa_features_ref - increments the ref count of a features - * @features: the features - * - * Returns: the features - */ -aa_features *aa_features_ref(aa_features *features) -{ - atomic_inc(&features->ref_count); - return features; -} - -/** - * aa_features_unref - decrements the ref count and frees the features when 0 - * @features: the features (can be NULL) - */ -void aa_features_unref(aa_features *features) -{ - if (features && atomic_dec_and_test(&features->ref_count)) - free(features); -} - -/** - * aa_features_write_to_file - write a string representation to a file - * @features: the features - * @path: the path to write to - * - * Returns: 0 on success, -1 on error with errno set - */ -int aa_features_write_to_file(aa_features *features, const char *path) -{ - autoclose int fd = -1; - size_t size; - ssize_t retval; - char *string; - - fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_CLOEXEC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (fd == -1) - return -1; - - string = features->string; - size = strlen(string); - do { - retval = write(fd, string, size); - if (retval == -1) - return -1; - - size -= retval; - string += retval; - } while (size); - - return 0; -} - -/** - * aa_features_is_equal - equality test for two features - * @features1: the first features (can be NULL) - * @features2: the second features (can be NULL) - * - * Returns: true if they're equal, false if they're not or either are NULL - */ -bool aa_features_is_equal(aa_features *features1, aa_features *features2) -{ - return features1 && features2 && - strcmp(features1->string, features2->string) == 0; -} - -/** - * aa_features_supports - provides features support status - * @features: the features - * @str: the string representation of a feature to check - * - * Example @str values are "dbus/mask/send", "caps/mask/audit_read", and - * "policy/versions/v7". - * - * Returns: a bool specifying the support status of @str feature - */ -bool aa_features_supports(aa_features *features, char *str) -{ - const char *features_string = features->string; - char *components[32]; - char *saveptr = NULL; - size_t i; - - /* Empty strings are not accepted. Neither are leading '/' chars. */ - if (!str || str[0] == '/') - return false; - - /** - * Break @str into an array of components. For example, - * "mount/mask/mount" would turn into "mount" as the first component, - * "mask" as the second, and "mount" as the third - */ - for (i = 0; i < sizeof(components); i++) { - components[i] = strtok_r(str, "/", &saveptr); - if (!components[i]) - break; - - str = NULL; - } - - /* At least one valid token is required */ - if (!components[0]) - return false; - - /* Ensure that all components are valid and found */ - for (i = 0; i < sizeof(components) && components[i]; i++) { - if (!walk_one(&features_string, components[i], i == 0)) - return false; - } - - return true; -} diff --git a/parser/features.h b/parser/features.h deleted file mode 100644 index 1d3cf3f..0000000 --- a/parser/features.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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_FEATURES_H -#define __AA_FEATURES_H - -typedef struct aa_features aa_features; - -int aa_features_new(aa_features **features, const char *path); -int aa_features_new_from_string(aa_features **features, - const char *string, size_t size); -int aa_features_new_from_kernel(aa_features **features); -aa_features *aa_features_ref(aa_features *features); -void aa_features_unref(aa_features *features); -int aa_features_write_to_file(aa_features *features, const char *path); -bool aa_features_is_equal(aa_features *features1, aa_features *features2); -bool aa_features_supports(aa_features *features, char *str); - -#endif /* __AA_FEATURES_H */ diff --git a/parser/kernel_interface.h b/parser/kernel_interface.h index 6dcd3ca..8e210d1 100644 --- a/parser/kernel_interface.h +++ b/parser/kernel_interface.h @@ -19,6 +19,8 @@ #ifndef __AA_KERNEL_INTERFACE_H #define __AA_KERNEL_INTERFACE_H +#include <sys/apparmor.h> + #include "features.h" typedef struct aa_kernel_interface aa_kernel_interface; -- 2.1.4 -- AppArmor mailing list AppArmor@lists.ubuntu.com Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor