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

Reply via email to