summaryrefslogtreecommitdiffstats
path: root/libseaudit/src
diff options
context:
space:
mode:
Diffstat (limited to 'libseaudit/src')
-rw-r--r--libseaudit/src/Makefile.am52
-rw-r--r--libseaudit/src/avc_message.c630
-rw-r--r--libseaudit/src/bool_message.c153
-rw-r--r--libseaudit/src/filter-internal.c1526
-rw-r--r--libseaudit/src/filter-internal.h109
-rw-r--r--libseaudit/src/filter.c1124
-rw-r--r--libseaudit/src/libseaudit.map88
-rw-r--r--libseaudit/src/load_message.c91
-rw-r--r--libseaudit/src/log.c253
-rw-r--r--libseaudit/src/message.c204
-rw-r--r--libseaudit/src/model.c808
-rw-r--r--libseaudit/src/parse.c1513
-rw-r--r--libseaudit/src/report.c1060
-rw-r--r--libseaudit/src/seaudit_internal.h664
-rw-r--r--libseaudit/src/sort.c744
-rw-r--r--libseaudit/src/util.c32
16 files changed, 9051 insertions, 0 deletions
diff --git a/libseaudit/src/Makefile.am b/libseaudit/src/Makefile.am
new file mode 100644
index 0000000..74ccb26
--- /dev/null
+++ b/libseaudit/src/Makefile.am
@@ -0,0 +1,52 @@
+lib_LIBRARIES = libseaudit.a
+
+seauditso_DATA = libseaudit.so.@libseaudit_version@
+seauditsodir = $(libdir)
+
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ @APOL_CFLAGS@ @QPOL_CFLAGS@ @XML_CFLAGS@ -I$(srcdir)/../include -fpic
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@
+
+libseaudit_a_SOURCES = \
+ avc_message.c \
+ bool_message.c \
+ filter.c filter-internal.c filter-internal.h \
+ load_message.c \
+ log.c \
+ message.c \
+ model.c \
+ parse.c \
+ report.c \
+ sort.c \
+ util.c \
+ seaudit_internal.h
+
+libseaudit_a_DEPENDENCIES = $(top_builddir)/libapol/src/libapol.so
+
+libseaudit_so_OBJS = $(patsubst %.c,%.o,$(filter %.c,$(libseaudit_a_SOURCES)))
+LIBSEAUDIT_SONAME = @libseaudit_soname@
+
+dist_noinst_DATA = libseaudit.map
+
+$(seauditso_DATA): $(libseaudit_so_OBJS) libseaudit.map
+ $(CC) -shared -o $@ $(libseaudit_so_OBJS) $(AM_LDFLAGS) $(LDFLAGS) -Wl,-soname,$(LIBSEAUDIT_SONAME),--version-script=$(srcdir)/libseaudit.map,-z,defs $(top_builddir)/libqpol/src/libqpol.so $(top_builddir)/libapol/src/libapol.so $(XML_LIBS) -lselinux
+ $(LN_S) -f $@ @libseaudit_soname@
+ $(LN_S) -f $@ libseaudit.so
+
+libseaudit.so: $(seauditso_DATA)
+
+$(top_builddir)/libapol/src/libapol.so:
+ $(MAKE) -C $(top_builddir)/libapol/src $(notdir $@)
+
+$(top_builddir)/libqpol/src/libqpol.so:
+ $(MAKE) -C $(top_builddir)/libqpol/src $(notdir $@)
+
+install-data-hook:
+ cd $(DESTDIR)$(seauditsodir) && $(LN_S) -f $(seauditso_DATA) @libseaudit_soname@
+ cd $(DESTDIR)$(seauditsodir) && $(LN_S) -f $(seauditso_DATA) libseaudit.so
+
+mostlyclean-local:
+ -rm -rf *.gcno *.gcda *.gprof *.gcov libseaudit.so @libseaudit_soname@ $(seauditso_DATA)
+
+uninstall-local:
+ -rm -rf $(DESTDIR)$(seauditsodir)/$(seauditso_DATA) $(DESTDIR)$(seauditsodir)/@libseaudit_soname@ $(DESTDIR)$(seauditsodir)/libseaudit.so
diff --git a/libseaudit/src/avc_message.c b/libseaudit/src/avc_message.c
new file mode 100644
index 0000000..c054a72
--- /dev/null
+++ b/libseaudit/src/avc_message.c
@@ -0,0 +1,630 @@
+/**
+ * @file
+ * Implementation of a single avc log message.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "seaudit_internal.h"
+
+#include <apol/util.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+seaudit_avc_message_type_e seaudit_avc_message_get_message_type(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return SEAUDIT_AVC_UNKNOWN;
+ }
+ return avc->msg;
+}
+
+long seaudit_avc_message_get_timestamp_nano(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return avc->tm_stmp_sec;
+}
+
+const char *seaudit_avc_message_get_source_user(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->suser;
+}
+
+const char *seaudit_avc_message_get_source_role(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->srole;
+}
+
+const char *seaudit_avc_message_get_source_type(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->stype;
+}
+
+const char *seaudit_avc_message_get_source_mls_lvl(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->smls_lvl;
+}
+
+const char *seaudit_avc_message_get_source_mls_clr(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->smls_clr;
+}
+
+const char *seaudit_avc_message_get_target_user(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->tuser;
+}
+
+const char *seaudit_avc_message_get_target_role(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->trole;
+}
+
+const char *seaudit_avc_message_get_target_type(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->ttype;
+}
+
+const char *seaudit_avc_message_get_target_mls_lvl(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->tmls_lvl;
+}
+
+const char *seaudit_avc_message_get_target_mls_clr(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->tmls_clr;
+}
+
+const char *seaudit_avc_message_get_object_class(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->tclass;
+}
+
+const apol_vector_t *seaudit_avc_message_get_perm(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->perms;
+}
+
+const char *seaudit_avc_message_get_exe(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->exe;
+}
+
+const char *seaudit_avc_message_get_comm(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->comm;
+}
+
+const char *seaudit_avc_message_get_name(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->name;
+}
+
+unsigned int seaudit_avc_message_get_pid(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ if (!avc->is_pid) {
+ return 0;
+ }
+ return avc->pid;
+}
+
+unsigned long seaudit_avc_message_get_inode(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ if (!avc->is_inode) {
+ return 0;
+ }
+ return avc->inode;
+}
+
+const char *seaudit_avc_message_get_path(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->path;
+}
+
+const char *seaudit_avc_message_get_dev(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->dev;
+}
+
+const char *seaudit_avc_message_get_netif(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->netif;
+}
+
+int seaudit_avc_message_get_port(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return avc->port;
+}
+
+const char *seaudit_avc_message_get_laddr(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->laddr;
+}
+
+int seaudit_avc_message_get_lport(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return avc->lport;
+}
+
+const char *seaudit_avc_message_get_faddr(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->faddr;
+}
+
+int seaudit_avc_message_get_fport(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return avc->fport;
+}
+
+const char *seaudit_avc_message_get_saddr(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->saddr;
+}
+
+int seaudit_avc_message_get_sport(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return avc->source;
+}
+
+const char *seaudit_avc_message_get_daddr(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return avc->daddr;
+}
+
+int seaudit_avc_message_get_dport(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return avc->dest;
+}
+
+int seaudit_avc_message_get_key(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!avc->is_key) {
+ return -1;
+ }
+ return avc->key;
+}
+
+int seaudit_avc_message_get_cap(const seaudit_avc_message_t * avc)
+{
+ if (avc == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!avc->is_capability) {
+ return -1;
+ }
+ return avc->capability;
+}
+
+/******************** protected functions below ********************/
+
+seaudit_avc_message_t *avc_message_create(void)
+{
+ seaudit_avc_message_t *avc = calloc(1, sizeof(seaudit_avc_message_t));
+ if (avc == NULL) {
+ return NULL;
+ }
+ if ((avc->perms = apol_vector_create_with_capacity(1, NULL)) == NULL) {
+ int error = errno;
+ avc_message_free(avc);
+ errno = error;
+ return NULL;
+ }
+ return avc;
+}
+
+void avc_message_free(seaudit_avc_message_t * avc)
+{
+ if (avc != NULL) {
+ free(avc->exe);
+ free(avc->comm);
+ free(avc->path);
+ free(avc->dev);
+ free(avc->netif);
+ free(avc->laddr);
+ free(avc->faddr);
+ free(avc->saddr);
+ free(avc->daddr);
+ free(avc->name);
+ free(avc->ipaddr);
+ apol_vector_destroy(&avc->perms);
+ free(avc);
+ }
+}
+
+/**
+ * Build the misc string sans timestamp and serial number.
+ */
+static char *avc_message_get_misc_string(const seaudit_avc_message_t * avc)
+{
+ char *s = NULL;
+ size_t len = 0;
+ if (avc->dev && apol_str_appendf(&s, &len, "dev=%s ", avc->dev) < 0) {
+ return NULL;
+ }
+ if (avc->ipaddr && apol_str_appendf(&s, &len, "ipaddr=%s ", avc->ipaddr) < 0) {
+ return NULL;
+ }
+ if (avc->laddr && apol_str_appendf(&s, &len, "laddr=%s ", avc->laddr) < 0) {
+ return NULL;
+ }
+ if (avc->lport != 0 && apol_str_appendf(&s, &len, "lport=%d ", avc->lport) < 0) {
+ return NULL;
+ }
+ if (avc->faddr && apol_str_appendf(&s, &len, "faddr=%s ", avc->faddr) < 0) {
+ return NULL;
+ }
+ if (avc->fport != 0 && apol_str_appendf(&s, &len, "fport=%d ", avc->fport) < 0) {
+ return NULL;
+ }
+ if (avc->daddr && apol_str_appendf(&s, &len, "daddr=%s ", avc->daddr) < 0) {
+ return NULL;
+ }
+ if (avc->dest != 0 && apol_str_appendf(&s, &len, "dest=%d ", avc->dest) < 0) {
+ return NULL;
+ }
+ if (avc->port != 0 && apol_str_appendf(&s, &len, "port=%d ", avc->port) < 0) {
+ return NULL;
+ }
+ if (avc->saddr && apol_str_appendf(&s, &len, "saddr=%s ", avc->saddr) < 0) {
+ return NULL;
+ }
+ if (avc->source != 0 && apol_str_appendf(&s, &len, "source=%d ", avc->source) < 0) {
+ return NULL;
+ }
+ if (avc->netif && apol_str_appendf(&s, &len, "netif=%s ", avc->netif) < 0) {
+ return NULL;
+ }
+ if (avc->is_key && apol_str_appendf(&s, &len, "key=%d ", avc->key) < 0) {
+ return NULL;
+ }
+ if (avc->is_capability && apol_str_appendf(&s, &len, "capability=%d ", avc->capability) < 0) {
+ return NULL;
+ }
+ if (s == NULL) {
+ return strdup("");
+ }
+ return s;
+}
+
+char *avc_message_to_string(const seaudit_message_t * msg, const char *date)
+{
+ seaudit_avc_message_t *avc = msg->data.avc;
+ const char *host = msg->host;
+ const char *manager = msg->manager;
+ char *s = NULL, *misc_string = NULL, *perm;
+ size_t i, len = 0;
+ if (apol_str_appendf(&s, &len, "%s %s %s: ", date, host, manager) < 0) {
+ return NULL;
+ }
+ if (!(avc->tm_stmp_sec == 0 && avc->tm_stmp_nano == 0 && avc->serial == 0)) {
+ if (apol_str_appendf(&s, &len, "audit(%lu.%03lu:%u): ", avc->tm_stmp_sec, avc->tm_stmp_nano, avc->serial) < 0) {
+ return NULL;
+ }
+ }
+ if (apol_str_appendf(&s, &len,
+ "avc: %s ",
+ (avc->msg == SEAUDIT_AVC_DENIED ? "denied" :
+ avc->msg == SEAUDIT_AVC_GRANTED ? "granted" : "<unknown>")) < 0) {
+ return NULL;
+ }
+
+ if (apol_vector_get_size(avc->perms) > 0) {
+ if (apol_str_append(&s, &len, "{ ") < 0) {
+ return NULL;
+ }
+ for (i = 0; i < apol_vector_get_size(avc->perms); i++) {
+ perm = apol_vector_get_element(avc->perms, i);
+ if (apol_str_appendf(&s, &len, "%s ", perm) < 0) {
+ return NULL;
+ }
+ }
+ if (apol_str_append(&s, &len, "} for ") < 0) {
+ return NULL;
+ }
+ }
+ if (avc->is_pid && apol_str_appendf(&s, &len, "pid=%d ", avc->pid) < 0) {
+ return NULL;
+ }
+ if (avc->exe && apol_str_appendf(&s, &len, "exe=%s ", avc->exe) < 0) {
+ return NULL;
+ }
+ if (avc->comm && apol_str_appendf(&s, &len, "comm=%s ", avc->comm) < 0) {
+ return NULL;
+ }
+ if (avc->path && apol_str_appendf(&s, &len, "path=%s ", avc->path) < 0) {
+ return NULL;
+ }
+ if (avc->name && apol_str_appendf(&s, &len, "name=%s ", avc->name) < 0) {
+ return NULL;
+ }
+ if (avc->is_inode && apol_str_appendf(&s, &len, "ino=%lu ", avc->inode) < 0) {
+ return NULL;
+ }
+ if ((misc_string = avc_message_get_misc_string(avc)) == NULL || apol_str_append(&s, &len, misc_string) < 0) {
+ int error = errno;
+ free(misc_string);
+ errno = error;
+ return NULL;
+ }
+ free(misc_string);
+
+ if (strcmp(avc->smls_lvl, avc->smls_clr)) { /* level and clearance are not the same - show both */
+ if (avc->suser && apol_str_appendf(&s, &len, "scontext=%s:%s:%s:%s-%s ", avc->suser, avc->srole, avc->stype, avc->smls_lvl, avc->smls_clr) < 0) {
+ return NULL;
+ }
+ } else if (avc->suser && apol_str_appendf(&s, &len, "scontext=%s:%s:%s:%s ", avc->suser, avc->srole, avc->stype, avc->smls_lvl) < 0) {
+ /* level and clearance are the same - only show one */
+ return NULL;
+ }
+ if (strcmp(avc->tmls_lvl, avc->tmls_clr)) { /* level and clearance are not the same - show both */
+ if (avc->tuser && apol_str_appendf(&s, &len, "tcontext=%s:%s:%s:%s-%s ", avc->tuser, avc->trole, avc->ttype, avc->tmls_lvl, avc->tmls_clr) < 0) {
+ return NULL;
+ }
+ } else if (avc->tuser && apol_str_appendf(&s, &len, "tcontext=%s:%s:%s:%s ", avc->tuser, avc->trole, avc->ttype, avc->tmls_lvl) < 0) {
+ /* level and clearance are the same - only show one */
+ return NULL;
+ }
+ if (avc->tclass && apol_str_appendf(&s, &len, "tclass=%s ", avc->tclass) < 0) {
+ return NULL;
+ }
+ return s;
+}
+
+char *avc_message_to_string_html(const seaudit_message_t * msg, const char *date)
+{
+ seaudit_avc_message_t *avc = msg->data.avc;
+ const char *host = msg->host;
+ const char *manager = msg->manager;
+ char *s = NULL, *misc_string = NULL, *perm;
+ size_t i, len = 0;
+ if (apol_str_appendf(&s, &len,
+ "<font class=\"message_date\">%s</font> "
+ "<font class=\"host_name\">%s</font> " "%s: ", date, host, manager) < 0) {
+ return NULL;
+ }
+ if (!(avc->tm_stmp_sec == 0 && avc->tm_stmp_nano == 0 && avc->serial == 0)) {
+ if (apol_str_appendf(&s, &len,
+ "<font class=\"syscall_timestamp\">audit(%lu.%03lu:%u): </font>",
+ avc->tm_stmp_sec, avc->tm_stmp_nano, avc->serial) < 0) {
+ return NULL;
+ }
+ }
+ if (apol_str_appendf(&s, &len,
+ "avc: %s ",
+ (avc->msg == SEAUDIT_AVC_DENIED ? "<font class=\"avc_deny\">denied</font> " :
+ avc->msg == SEAUDIT_AVC_GRANTED ? "<font class=\"avc_grant\">granted</font>" : "<unknown>")) < 0) {
+ return NULL;
+ }
+
+ if (apol_vector_get_size(avc->perms) > 0) {
+ if (apol_str_append(&s, &len, "{ ") < 0) {
+ return NULL;
+ }
+ for (i = 0; i < apol_vector_get_size(avc->perms); i++) {
+ perm = apol_vector_get_element(avc->perms, i);
+ if (apol_str_appendf(&s, &len, "%s ", perm) < 0) {
+ return NULL;
+ }
+ }
+ if (apol_str_append(&s, &len, "} for ") < 0) {
+ return NULL;
+ }
+ }
+ if (avc->is_pid && apol_str_appendf(&s, &len, "pid=%d ", avc->pid) < 0) {
+ return NULL;
+ }
+ if (avc->exe && apol_str_appendf(&s, &len, "<font class=\"exe\">exe=%s</font> ", avc->exe) < 0) {
+ return NULL;
+ }
+ if (avc->comm && apol_str_appendf(&s, &len, "comm=%s ", avc->comm) < 0) {
+ return NULL;
+ }
+ if (avc->path && apol_str_appendf(&s, &len, "path=%s ", avc->path) < 0) {
+ return NULL;
+ }
+ if (avc->name && apol_str_appendf(&s, &len, "name=%s ", avc->name) < 0) {
+ return NULL;
+ }
+ if (avc->is_inode && apol_str_appendf(&s, &len, "ino=%lu ", avc->inode) < 0) {
+ return NULL;
+ }
+ if ((misc_string = avc_message_get_misc_string(avc)) == NULL || apol_str_append(&s, &len, misc_string) < 0) {
+ int error = errno;
+ free(misc_string);
+ errno = error;
+ return NULL;
+ }
+ free(misc_string);
+ if(strcmp(avc->smls_lvl, avc->smls_clr)) { /* level and clearance are not the same - show both */
+ if (avc->suser &&
+ apol_str_appendf(&s, &len, "<font class=\"src_context\">scontext=%s:%s:%s:%s-%s</font> ",
+ avc->suser, avc->srole, avc->stype, avc->smls_lvl, avc->smls_clr) < 0) {
+ return NULL;
+ }
+ } else if (avc->suser && apol_str_appendf(&s, &len, "<font class=\"src_context\">scontext=%s:%s:%s:%s</font> ",
+ avc->suser, avc->srole, avc->stype, avc->smls_lvl) < 0) {
+ /* level and clearance are the same - only show one */
+ return NULL;
+ }
+ if(strcmp(avc->tmls_lvl, avc->tmls_clr)) { /* level and clearance are not the same - show both */
+ if (avc->tuser &&
+ apol_str_appendf(&s, &len, "<font class=\"tgt_context\">tcontext=%s:%s:%s:%s-%s</font> ",
+ avc->tuser, avc->trole, avc->ttype, avc->tmls_lvl, avc->tmls_clr) < 0) {
+ return NULL;
+ }
+ } else if (avc->tuser &&
+ apol_str_appendf(&s, &len, "<font class=\"tgt_context\">tcontext=%s:%s:%s:%s</font> ",
+ avc->tuser, avc->trole, avc->ttype, avc->tmls_lvl) < 0) {
+ /* level and clearance are the same - only show one */
+ return NULL;
+ }
+ if (avc->tclass && apol_str_appendf(&s, &len, "<font class=\"obj_class\">tclass=%s</font> ", avc->tclass) < 0) {
+ return NULL;
+ }
+ if (apol_str_appendf(&s, &len, "<br>") < 0) {
+ return NULL;
+ }
+ return s;
+}
+
+char *avc_message_to_misc_string(const seaudit_avc_message_t * avc)
+{
+ char *s = avc_message_get_misc_string(avc);
+ size_t len;
+ if (s == NULL) {
+ return NULL;
+ }
+ len = strlen(s) + 1;
+ if (!(avc->tm_stmp_sec == 0 && avc->tm_stmp_nano == 0 && avc->serial == 0)) {
+ if (apol_str_appendf(&s, &len, "%stimestamp=%lu.%03lu serial=%u",
+ (len > 1 ? " " : ""), avc->tm_stmp_sec, avc->tm_stmp_nano, avc->serial) < 0) {
+ return NULL;
+ }
+ }
+ return s;
+}
diff --git a/libseaudit/src/bool_message.c b/libseaudit/src/bool_message.c
new file mode 100644
index 0000000..f105cf0
--- /dev/null
+++ b/libseaudit/src/bool_message.c
@@ -0,0 +1,153 @@
+/**
+ * @file
+ * Implementation of a single boolean change log message.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "seaudit_internal.h"
+
+#include <apol/util.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/******************** protected functions below ********************/
+
+static void seaudit_bool_change_free(void *elem)
+{
+ if (elem != NULL) {
+ seaudit_bool_message_change_t *b = elem;
+ free(b);
+ }
+}
+
+seaudit_bool_message_t *bool_message_create(void)
+{
+ seaudit_bool_message_t *boolm = calloc(1, sizeof(seaudit_bool_message_t));
+ if (boolm == NULL) {
+ return NULL;
+ }
+ if ((boolm->changes = apol_vector_create(seaudit_bool_change_free)) == NULL) {
+ bool_message_free(boolm);
+ return NULL;
+ }
+ return boolm;
+}
+
+int bool_change_append(seaudit_log_t * log, seaudit_bool_message_t * boolm, const char *name, int value)
+{
+ char *s = strdup(name);
+ seaudit_bool_message_change_t *bc = NULL;
+ int error;
+ if (s == NULL || apol_bst_insert_and_get(log->bools, (void **)&s, NULL) < 0) {
+ error = errno;
+ free(s);
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ if ((bc = calloc(1, sizeof(*bc))) == NULL || apol_vector_append(boolm->changes, bc) < 0) {
+ error = errno;
+ free(s);
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ bc->boolean = s;
+ bc->value = value;
+ return 0;
+}
+
+void bool_message_free(seaudit_bool_message_t * boolm)
+{
+ if (boolm != NULL) {
+ apol_vector_destroy(&boolm->changes);
+ free(boolm);
+ }
+}
+
+char *bool_message_to_string(const seaudit_message_t * msg, const char *date)
+{
+ seaudit_bool_message_t *boolm = msg->data.boolm;
+ const char *host = msg->host;
+ const char *manager = msg->manager;
+ char *s = NULL, *misc_string;
+ size_t len = 0;
+ char *open_brace = "", *close_brace = "";
+ if (apol_vector_get_size(boolm->changes) > 0) {
+ open_brace = "{ ";
+ close_brace = " }";
+ }
+ if (apol_str_appendf(&s, &len, "%s %s %s: security: committed booleans: %s", date, host, manager, open_brace) < 0) {
+ return NULL;
+ }
+ if ((misc_string = bool_message_to_misc_string(boolm)) == NULL ||
+ apol_str_appendf(&s, &len, misc_string) < 0 || apol_str_append(&s, &len, close_brace) < 0) {
+ free(misc_string);
+ return NULL;
+ }
+ free(misc_string);
+ return s;
+}
+
+char *bool_message_to_string_html(const seaudit_message_t * msg, const char *date)
+{
+ seaudit_bool_message_t *boolm = msg->data.boolm;
+ const char *host = msg->host;
+ const char *manager = msg->manager;
+ char *s = NULL, *misc_string;
+ size_t len = 0;
+ char *open_brace = "", *close_brace = "";
+ if (apol_vector_get_size(boolm->changes) > 0) {
+ open_brace = "{ ";
+ close_brace = " }";
+ }
+ if (apol_str_appendf(&s, &len,
+ "<font class=\"message_date\">%s</font> "
+ "<font class=\"host_name\">%s</font> "
+ "%s: security: committed booleans: %s", date, host, manager, open_brace) < 0) {
+ return NULL;
+ }
+ if ((misc_string = bool_message_to_misc_string(boolm)) == NULL ||
+ apol_str_appendf(&s, &len, misc_string) < 0 || apol_str_appendf(&s, &len, "%s%s<br>", s, close_brace) < 0) {
+ free(misc_string);
+ return NULL;
+ }
+ free(misc_string);
+ return s;
+}
+
+char *bool_message_to_misc_string(const seaudit_bool_message_t * boolm)
+{
+ char *s = NULL;
+ size_t len = 0, i;
+ for (i = 0; i < apol_vector_get_size(boolm->changes); i++) {
+ seaudit_bool_message_change_t *bc = apol_vector_get_element(boolm->changes, i);
+ if (apol_str_appendf(&s, &len, "%s%s:%d", (i == 0 ? "" : ", "), bc->boolean, bc->value) < 0) {
+ return NULL;
+ }
+ }
+ if (s == NULL) {
+ return strdup("");
+ }
+ return s;
+}
diff --git a/libseaudit/src/filter-internal.c b/libseaudit/src/filter-internal.c
new file mode 100644
index 0000000..9aa7c86
--- /dev/null
+++ b/libseaudit/src/filter-internal.c
@@ -0,0 +1,1526 @@
+/**
+ * @file
+ * Implementation of seaudit filters private functions.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "seaudit_internal.h"
+#include "filter-internal.h"
+
+#include <apol/util.h>
+
+#include <errno.h>
+#include <fnmatch.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <libxml/uri.h>
+
+/******************** support functions ********************/
+
+static int filter_string_vector_read(apol_vector_t ** v, const xmlChar * ch)
+{
+ char *s;
+ if (*v == NULL && (*v = apol_vector_create_with_capacity(1, free)) == NULL) {
+ return -1;
+ }
+ if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL || apol_vector_append(*v, s) < 0) {
+ free(s);
+ return -1;
+ }
+ return 0;
+}
+
+static int filter_string_read(char **dest, const xmlChar * ch)
+{
+ free(*dest);
+ *dest = NULL;
+ if ((*dest = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+static int filter_ulong_read(unsigned long *dest, const xmlChar * ch)
+{
+ char *s, *endptr;
+ int retval = -1;
+ if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) {
+ return -1;
+ }
+ *dest = strtoul(s, &endptr, 10);
+ if (*s != '\0' && *endptr == '\0') {
+ retval = 0;
+ }
+ free(s);
+ return retval;
+}
+
+static unsigned int filter_uint_read(unsigned int *dest, const xmlChar * ch)
+{
+ char *s, *endptr;
+ int retval = -1;
+ if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) {
+ return -1;
+ }
+ *dest = (unsigned int)(strtoul(s, &endptr, 10));
+ if (*s != '\0' && *endptr == '\0') {
+ retval = 0;
+ }
+ free(s);
+ return retval;
+}
+
+static int filter_int_read(int *dest, const xmlChar * ch)
+{
+ char *s, *endptr;
+ int retval = -1;
+ if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) {
+ return -1;
+ }
+ *dest = (int)(strtol(s, &endptr, 10));
+ if (*s != '\0' && *endptr == '\0') {
+ retval = 0;
+ }
+ free(s);
+ return retval;
+}
+
+static void filter_string_vector_print(const char *criteria_name, apol_vector_t * v, FILE * f, int tabs)
+{
+ int i;
+ size_t j;
+ if (v == NULL) {
+ return;
+ }
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "<criteria type=\"%s\">\n", criteria_name);
+ for (j = 0; j < apol_vector_get_size(v); j++) {
+ xmlChar *s = xmlCharStrdup(apol_vector_get_element(v, j));
+ xmlChar *escaped = xmlURIEscapeStr(s, NULL);
+ for (i = 0; i < tabs + 1; i++) {
+ fprintf(f, "\t");
+ }
+ fprintf(f, "<item>%s</item>\n", escaped);
+ free(escaped);
+ free(s);
+ }
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "</criteria>\n");
+}
+
+static void filter_string_print(const char *criteria_name, const char *s, FILE * f, int tabs)
+{
+ int i;
+ xmlChar *t, *escaped;
+ if (s == NULL) {
+ return;
+ }
+ t = xmlCharStrdup(s);
+ escaped = xmlURIEscapeStr(t, NULL);
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "<criteria type=\"%s\">\n", criteria_name);
+ for (i = 0; i < tabs + 1; i++) {
+ fprintf(f, "\t");
+ }
+ fprintf(f, "<item>%s</item>\n", escaped);
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "</criteria>\n");
+ free(escaped);
+ free(t);
+}
+
+static void filter_ulong_print(const char *criteria_name, const unsigned long val, FILE * f, int tabs)
+{
+ int i;
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "<criteria type=\"%s\">\n", criteria_name);
+ for (i = 0; i < tabs + 1; i++) {
+ fprintf(f, "\t");
+ }
+ fprintf(f, "<item>%lu</item>\n", val);
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "</criteria>\n");
+}
+
+static void filter_uint_print(const char *criteria_name, const unsigned int val, FILE * f, int tabs)
+{
+ int i;
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "<criteria type=\"%s\">\n", criteria_name);
+ for (i = 0; i < tabs + 1; i++) {
+ fprintf(f, "\t");
+ }
+ fprintf(f, "<item>%u</item>\n", val);
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "</criteria>\n");
+}
+
+static void filter_int_print(const char *criteria_name, const int val, FILE * f, int tabs)
+{
+ int i;
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "<criteria type=\"%s\">\n", criteria_name);
+ for (i = 0; i < tabs + 1; i++) {
+ fprintf(f, "\t");
+ }
+ fprintf(f, "<item>%d</item>\n", val);
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "</criteria>\n");
+}
+
+/******************** filter private functions ********************/
+
+static bool filter_src_user_is_set(const seaudit_filter_t * filter)
+{
+ return filter->src_users != NULL;
+}
+
+static int filter_src_user_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->suser != NULL;
+}
+
+static int filter_src_user_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ return apol_vector_get_index(filter->src_users, msg->data.avc->suser, apol_str_strcmp, NULL, &i) == 0;
+}
+
+static int filter_src_user_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_vector_read(&filter->src_users, ch);
+}
+
+static void filter_src_user_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_vector_print(name, filter->src_users, f, tabs);
+}
+
+static bool filter_src_role_is_set(const seaudit_filter_t * filter)
+{
+ return filter->src_roles != NULL;
+}
+
+static int filter_src_role_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->srole != NULL;
+}
+
+static int filter_src_role_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ return apol_vector_get_index(filter->src_roles, msg->data.avc->srole, apol_str_strcmp, NULL, &i) == 0;
+}
+
+static int filter_src_role_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_vector_read(&filter->src_roles, ch);
+}
+
+static void filter_src_role_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_vector_print(name, filter->src_roles, f, tabs);
+}
+
+static bool filter_src_type_is_set(const seaudit_filter_t * filter)
+{
+ return filter->src_types != NULL;
+}
+
+static int filter_src_type_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->stype != NULL;
+}
+
+static int filter_src_type_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_vector_read(&filter->src_types, ch);
+}
+
+static int filter_src_type_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ return apol_vector_get_index(filter->src_types, msg->data.avc->stype, apol_str_strcmp, NULL, &i) == 0;
+}
+
+static void filter_src_type_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_vector_print(name, filter->src_types, f, tabs);
+}
+
+static bool filter_src_mls_lvl_is_set(const seaudit_filter_t * filter)
+{
+ return filter->src_mls_lvl != NULL;
+}
+
+static int filter_src_mls_lvl_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->smls_lvl != NULL;
+}
+
+static int filter_src_mls_lvl_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_vector_read(&filter->src_mls_lvl, ch);
+}
+
+static int filter_src_mls_lvl_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ return apol_vector_get_index(filter->src_mls_lvl, msg->data.avc->smls_lvl, apol_str_strcmp, NULL, &i) == 0;
+}
+
+static void filter_src_mls_lvl_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_vector_print(name, filter->src_mls_lvl, f, tabs);
+}
+
+static bool filter_src_mls_clr_is_set(const seaudit_filter_t * filter)
+{
+ return filter->src_mls_clr != NULL;
+}
+
+static int filter_src_mls_clr_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->smls_clr != NULL;
+}
+
+static int filter_src_mls_clr_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_vector_read(&filter->src_mls_clr, ch);
+}
+
+static int filter_src_mls_clr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ return apol_vector_get_index(filter->src_mls_clr, msg->data.avc->smls_clr, apol_str_strcmp, NULL, &i) == 0;
+}
+
+static void filter_src_mls_clr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_vector_print(name, filter->src_mls_clr, f, tabs);
+}
+
+static bool filter_tgt_user_is_set(const seaudit_filter_t * filter)
+{
+ return filter->tgt_users != NULL;
+}
+
+static int filter_tgt_user_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tuser != NULL;
+}
+
+static int filter_tgt_user_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ return apol_vector_get_index(filter->tgt_users, msg->data.avc->tuser, apol_str_strcmp, NULL, &i) == 0;
+}
+
+static int filter_tgt_user_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_vector_read(&filter->tgt_users, ch);
+}
+
+static void filter_tgt_user_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_vector_print(name, filter->tgt_users, f, tabs);
+}
+
+static bool filter_tgt_role_is_set(const seaudit_filter_t * filter)
+{
+ return filter->tgt_roles != NULL;
+}
+
+static int filter_tgt_role_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->trole != NULL;
+}
+
+static int filter_tgt_role_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ return apol_vector_get_index(filter->tgt_roles, msg->data.avc->trole, apol_str_strcmp, NULL, &i) == 0;
+}
+
+static int filter_tgt_role_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_vector_read(&filter->tgt_roles, ch);
+}
+
+static void filter_tgt_role_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_vector_print(name, filter->tgt_roles, f, tabs);
+}
+
+static bool filter_tgt_type_is_set(const seaudit_filter_t * filter)
+{
+ return filter->tgt_types != NULL;
+}
+
+static int filter_tgt_type_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->ttype != NULL;
+}
+
+static int filter_tgt_type_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ return apol_vector_get_index(filter->tgt_types, msg->data.avc->ttype, apol_str_strcmp, NULL, &i) == 0;
+}
+
+static int filter_tgt_type_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_vector_read(&filter->tgt_types, ch);
+}
+
+static void filter_tgt_type_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_vector_print(name, filter->tgt_types, f, tabs);
+}
+
+static bool filter_tgt_mls_lvl_is_set(const seaudit_filter_t * filter)
+{
+ return filter->tgt_mls_lvl != NULL;
+}
+
+static int filter_tgt_mls_lvl_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tmls_lvl != NULL;
+}
+
+static int filter_tgt_mls_lvl_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_vector_read(&filter->tgt_mls_lvl, ch);
+}
+
+static int filter_tgt_mls_lvl_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ return apol_vector_get_index(filter->tgt_mls_lvl, msg->data.avc->tmls_lvl, apol_str_strcmp, NULL, &i) == 0;
+}
+
+static void filter_tgt_mls_lvl_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_vector_print(name, filter->tgt_mls_lvl, f, tabs);
+}
+
+static bool filter_tgt_mls_clr_is_set(const seaudit_filter_t * filter)
+{
+ return filter->tgt_mls_clr != NULL;
+}
+
+static int filter_tgt_mls_clr_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tmls_clr != NULL;
+}
+
+static int filter_tgt_mls_clr_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_vector_read(&filter->tgt_mls_clr, ch);
+}
+
+static int filter_tgt_mls_clr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ return apol_vector_get_index(filter->tgt_mls_clr, msg->data.avc->tmls_clr, apol_str_strcmp, NULL, &i) == 0;
+}
+
+static void filter_tgt_mls_clr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_vector_print(name, filter->tgt_mls_clr, f, tabs);
+}
+
+
+static bool filter_tgt_class_is_set(const seaudit_filter_t * filter)
+{
+ return filter->tgt_classes != NULL;
+}
+
+static int filter_tgt_class_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tclass != NULL;
+}
+
+static int filter_tgt_class_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ return apol_vector_get_index(filter->tgt_classes, msg->data.avc->tclass, apol_str_strcmp, NULL, &i) == 0;
+}
+
+static int filter_tgt_class_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_vector_read(&filter->tgt_classes, ch);
+}
+
+static void filter_tgt_class_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_vector_print(name, filter->tgt_classes, f, tabs);
+}
+
+static bool filter_perm_is_set(const seaudit_filter_t * filter)
+{
+ return filter->perm != NULL;
+}
+
+static int filter_perm_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->perms != NULL &&
+ apol_vector_get_size(msg->data.avc->perms) >= 1;
+}
+
+static int filter_perm_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ size_t i;
+ for (i = 0; i < apol_vector_get_size(msg->data.avc->perms); i++) {
+ const char *p = apol_vector_get_element(msg->data.avc->perms, i);
+ if (fnmatch(filter->perm, p, 0) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int filter_perm_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_read(&filter->perm, ch);
+}
+
+static void filter_perm_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_print(name, filter->perm, f, tabs);
+}
+
+static bool filter_exe_is_set(const seaudit_filter_t * filter)
+{
+ return filter->exe != NULL;
+}
+
+static int filter_exe_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->exe != NULL;
+}
+
+static int filter_exe_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return fnmatch(filter->exe, msg->data.avc->exe, 0) == 0;
+}
+
+static int filter_exe_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_read(&filter->exe, ch);
+}
+
+static void filter_exe_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_print(name, filter->exe, f, tabs);
+}
+
+static bool filter_host_is_set(const seaudit_filter_t * filter)
+{
+ return filter->host != NULL;
+}
+
+static int filter_host_support(const seaudit_message_t * msg)
+{
+ return msg->host != NULL;
+}
+
+static int filter_host_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return fnmatch(filter->host, msg->host, 0) == 0;
+}
+
+static int filter_host_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_read(&filter->host, ch);
+}
+
+static void filter_host_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_print(name, filter->host, f, tabs);
+}
+
+static bool filter_path_is_set(const seaudit_filter_t * filter)
+{
+ return filter->path != NULL;
+}
+
+static int filter_path_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->path != NULL;
+}
+
+static int filter_path_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return fnmatch(filter->path, msg->data.avc->path, 0) == 0;
+}
+
+static int filter_path_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_read(&filter->path, ch);
+}
+
+static void filter_path_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_print(name, filter->path, f, tabs);
+}
+
+static bool filter_inode_is_set(const seaudit_filter_t * filter)
+{
+ return filter->inode != 0;
+}
+
+static int filter_inode_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->is_inode;
+}
+
+static int filter_inode_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return filter->inode == msg->data.avc->inode;
+}
+
+static int filter_inode_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_ulong_read(&filter->inode, ch);
+}
+
+static void filter_inode_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_ulong_print(name, filter->inode, f, tabs);
+}
+
+static bool filter_pid_is_set(const seaudit_filter_t * filter)
+{
+ return filter->pid != 0;
+}
+
+static int filter_pid_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->is_pid;
+}
+
+static int filter_pid_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return filter->pid == msg->data.avc->pid;
+}
+
+static int filter_pid_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_uint_read(&filter->pid, ch);
+}
+
+static void filter_pid_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_uint_print(name, filter->pid, f, tabs);
+}
+
+static bool filter_comm_is_set(const seaudit_filter_t * filter)
+{
+ return filter->comm != NULL;
+}
+
+static int filter_comm_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->comm != NULL;
+}
+
+static int filter_comm_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return fnmatch(filter->comm, msg->data.avc->comm, 0) == 0;
+}
+
+static int filter_comm_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_read(&filter->comm, ch);
+}
+
+static void filter_comm_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_print(name, filter->comm, f, tabs);
+}
+
+static bool filter_anyaddr_is_set(const seaudit_filter_t * filter)
+{
+ return filter->anyaddr != NULL;
+}
+
+static int filter_anyaddr_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && (msg->data.avc->saddr != NULL
+ || msg->data.avc->daddr != NULL
+ || msg->data.avc->faddr != NULL
+ || msg->data.avc->laddr != NULL || msg->data.avc->ipaddr != NULL);
+}
+
+static int filter_anyaddr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ if (msg->data.avc->saddr && fnmatch(filter->anyaddr, msg->data.avc->saddr, 0) == 0)
+ return 1;
+ if (msg->data.avc->daddr && fnmatch(filter->anyaddr, msg->data.avc->daddr, 0) == 0)
+ return 1;
+ if (msg->data.avc->faddr && fnmatch(filter->anyaddr, msg->data.avc->faddr, 0) == 0)
+ return 1;
+ if (msg->data.avc->laddr && fnmatch(filter->anyaddr, msg->data.avc->laddr, 0) == 0)
+ return 1;
+ if (msg->data.avc->ipaddr && fnmatch(filter->anyaddr, msg->data.avc->ipaddr, 0) == 0)
+ return 1;
+ return 0;
+}
+
+static int filter_anyaddr_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_read(&filter->anyaddr, ch);
+}
+
+static void filter_anyaddr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_print(name, filter->anyaddr, f, tabs);
+}
+
+static bool filter_anyport_is_set(const seaudit_filter_t * filter)
+{
+ return filter->anyport != 0;
+}
+
+static int filter_anyport_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && (msg->data.avc->port != 0 ||
+ msg->data.avc->source != 0 ||
+ msg->data.avc->dest != 0 ||
+ msg->data.avc->fport != 0 || msg->data.avc->lport != 0);
+}
+
+static int filter_anyport_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ if (msg->data.avc->port != 0 && filter->anyport == msg->data.avc->port) {
+ return 1;
+ }
+ if (msg->data.avc->source != 0 && filter->anyport == msg->data.avc->source) {
+ return 1;
+ }
+ if (msg->data.avc->dest != 0 && filter->anyport == msg->data.avc->dest) {
+ return 1;
+ }
+ if (msg->data.avc->fport != 0 && filter->anyport == msg->data.avc->fport) {
+ return 1;
+ }
+ if (msg->data.avc->lport != 0 && filter->anyport == msg->data.avc->lport) {
+ return 1;
+ }
+ return 0;
+}
+
+static int filter_anyport_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_int_read(&filter->anyport, ch);
+}
+
+static void filter_anyport_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_int_print(name, filter->anyport, f, tabs);
+}
+
+static bool filter_laddr_is_set(const seaudit_filter_t * filter)
+{
+ return filter->laddr != NULL;
+}
+
+static int filter_laddr_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->laddr != NULL;
+}
+
+static int filter_laddr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return fnmatch(filter->laddr, msg->data.avc->laddr, 0) == 0;
+}
+
+static int filter_laddr_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_read(&filter->laddr, ch);
+}
+
+static void filter_laddr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_print(name, filter->laddr, f, tabs);
+}
+
+static bool filter_lport_is_set(const seaudit_filter_t * filter)
+{
+ return filter->lport != 0;
+}
+
+static int filter_lport_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->lport != 0;
+}
+
+static int filter_lport_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return filter->lport == msg->data.avc->lport;
+}
+
+static int filter_lport_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_int_read(&filter->lport, ch);
+}
+
+static void filter_lport_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_int_print(name, filter->lport, f, tabs);
+}
+
+static bool filter_faddr_is_set(const seaudit_filter_t * filter)
+{
+ return filter->faddr != NULL;
+}
+
+static int filter_faddr_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->faddr != NULL;
+}
+
+static int filter_faddr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return fnmatch(filter->faddr, msg->data.avc->faddr, 0) == 0;
+}
+
+static int filter_faddr_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_read(&filter->faddr, ch);
+}
+
+static void filter_faddr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_print(name, filter->faddr, f, tabs);
+}
+
+static bool filter_fport_is_set(const seaudit_filter_t * filter)
+{
+ return filter->fport != 0;
+}
+
+static int filter_fport_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->fport != 0;
+}
+
+static int filter_fport_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return filter->fport == msg->data.avc->fport;
+}
+
+static int filter_fport_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_int_read(&filter->fport, ch);
+}
+
+static void filter_fport_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_int_print(name, filter->fport, f, tabs);
+}
+
+static bool filter_saddr_is_set(const seaudit_filter_t * filter)
+{
+ return filter->saddr != NULL;
+}
+
+static int filter_saddr_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->saddr != NULL;
+}
+
+static int filter_saddr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return fnmatch(filter->saddr, msg->data.avc->saddr, 0) == 0;
+}
+
+static int filter_saddr_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_read(&filter->saddr, ch);
+}
+
+static void filter_saddr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_print(name, filter->saddr, f, tabs);
+}
+
+static bool filter_sport_is_set(const seaudit_filter_t * filter)
+{
+ return filter->sport != 0;
+}
+
+static int filter_sport_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->source != 0;
+}
+
+static int filter_sport_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return filter->sport == msg->data.avc->source;
+}
+
+static int filter_sport_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_int_read(&filter->sport, ch);
+}
+
+static void filter_sport_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_int_print(name, filter->sport, f, tabs);
+}
+
+static bool filter_daddr_is_set(const seaudit_filter_t * filter)
+{
+ return filter->daddr != NULL;
+}
+
+static int filter_daddr_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->daddr != NULL;
+}
+
+static int filter_daddr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return fnmatch(filter->daddr, msg->data.avc->daddr, 0) == 0;
+}
+
+static int filter_daddr_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_read(&filter->daddr, ch);
+}
+
+static void filter_daddr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_print(name, filter->daddr, f, tabs);
+}
+
+static bool filter_dport_is_set(const seaudit_filter_t * filter)
+{
+ return filter->dport != 0;
+}
+
+static int filter_dport_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->dest != 0;
+}
+
+static int filter_dport_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return filter->dport == msg->data.avc->dest;
+}
+
+static int filter_dport_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_int_read(&filter->dport, ch);
+}
+
+static void filter_dport_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_int_print(name, filter->dport, f, tabs);
+}
+
+static bool filter_port_is_set(const seaudit_filter_t * filter)
+{
+ return filter->port != 0;
+}
+
+static int filter_port_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->port != 0;
+}
+
+static int filter_port_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return filter->port == msg->data.avc->port;
+}
+
+static int filter_port_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_int_read(&filter->port, ch);
+}
+
+static void filter_port_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_int_print(name, filter->port, f, tabs);
+}
+
+static bool filter_netif_is_set(const seaudit_filter_t * filter)
+{
+ return filter->netif != NULL;
+}
+
+static int filter_netif_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->netif != NULL;
+}
+
+static int filter_netif_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return strcmp(filter->netif, msg->data.avc->netif) == 0;
+}
+
+static int filter_netif_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_string_read(&filter->netif, ch);
+}
+
+static void filter_netif_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_string_print(name, filter->netif, f, tabs);
+}
+
+static bool filter_key_is_set(const seaudit_filter_t * filter)
+{
+ return filter->key != 0;
+}
+
+static int filter_key_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->is_key;
+}
+
+static int filter_key_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return filter->key == msg->data.avc->key;
+}
+
+static int filter_key_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_int_read(&filter->key, ch);
+}
+
+static void filter_key_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_int_print(name, filter->key, f, tabs);
+}
+
+static bool filter_cap_is_set(const seaudit_filter_t * filter)
+{
+ return filter->cap != 0;
+}
+
+static int filter_cap_support(const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->is_capability;
+}
+
+static int filter_cap_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return filter->key == msg->data.avc->capability;
+}
+
+static int filter_cap_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ return filter_int_read(&filter->cap, ch);
+}
+
+static void filter_cap_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ filter_int_print(name, filter->cap, f, tabs);
+}
+
+static bool filter_avc_msg_type_is_set(const seaudit_filter_t * filter)
+{
+ return filter->avc_msg_type != SEAUDIT_AVC_UNKNOWN;
+}
+
+static int filter_avc_msg_type_support(const seaudit_message_t * msg __attribute__ ((unused)))
+{
+ return 1;
+}
+
+static int filter_avc_msg_type_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && filter->avc_msg_type == msg->data.avc->msg;
+}
+
+static int filter_avc_msg_type_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ char *s;
+ if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) {
+ return -1;
+ }
+ filter->avc_msg_type = atoi(s);
+ free(s);
+ return 0;
+}
+
+static void filter_avc_msg_type_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ int i;
+ if (filter->avc_msg_type == SEAUDIT_AVC_UNKNOWN) {
+ return;
+ }
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "<criteria type=\"%s\">\n", name);
+ for (i = 0; i < tabs + 1; i++) {
+ fprintf(f, "\t");
+ }
+ fprintf(f, "<item>%d</item>\n", filter->avc_msg_type);
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "</criteria>\n");
+}
+
+static bool filter_date_is_set(const seaudit_filter_t * filter)
+{
+ return filter->start != NULL;
+}
+
+static int filter_date_support(const seaudit_message_t * msg)
+{
+ return msg->date_stamp != NULL;
+}
+
+/**
+ * Given two dates compare them. If both structs have years that are
+ * not zeroes then also compare their years.
+ */
+static int filter_date_comp(const struct tm *t1, const struct tm *t2)
+{
+ /* tm has year, month, day, hour, min, sec */
+ /* check if we should compare the years */
+ int retval;
+ if (t1->tm_year != 0 && t2->tm_year != 0 && (retval = t1->tm_year - t2->tm_year) != 0) {
+ return retval;
+ }
+ if ((retval = t1->tm_mon - t2->tm_mon) != 0) {
+ return retval;
+ }
+ if ((retval = t1->tm_mday - t2->tm_mday) != 0) {
+ return retval;
+ }
+ if ((retval = t1->tm_hour - t2->tm_hour) != 0) {
+ return retval;
+ }
+ if ((retval = t1->tm_min - t2->tm_min) != 0) {
+ return retval;
+ }
+ if ((retval = t1->tm_sec - t2->tm_sec) != 0) {
+ return retval;
+ }
+ return 0;
+}
+
+static int filter_date_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ int compval = filter_date_comp(filter->start, msg->date_stamp);
+ if (filter->date_match == SEAUDIT_FILTER_DATE_MATCH_BEFORE) {
+ return compval > 0;
+ } else if (filter->date_match == SEAUDIT_FILTER_DATE_MATCH_AFTER) {
+ return compval < 0;
+ } else {
+ if (compval > 0)
+ return 0;
+ compval = filter_date_comp(msg->date_stamp, filter->end);
+ return compval < 0;
+ }
+}
+
+static int filter_date_read(seaudit_filter_t * filter, const xmlChar * ch)
+{
+ char *s;
+ if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) {
+ return -1;
+ }
+ if (filter->start == NULL) {
+ if ((filter->start = calloc(1, sizeof(*(filter->start)))) == NULL) {
+ free(s);
+ return -1;
+ }
+ strptime(s, "%a %b %d %T %Y", filter->start);
+ } else if (filter->end == NULL) {
+ if ((filter->end = calloc(1, sizeof(*(filter->end)))) == NULL) {
+ free(s);
+ return -1;
+ }
+ strptime(s, "%a %b %d %T %Y", filter->end);
+ } else {
+ filter->date_match = atoi(s);
+ }
+ free(s);
+ return 0;
+}
+
+static void filter_date_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs)
+{
+ int i;
+ xmlChar *s, *escaped;
+ if (filter->start == NULL) {
+ return;
+ }
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "<criteria type=\"%s\">\n", name);
+ s = xmlCharStrdup(asctime(filter->start));
+ escaped = xmlURIEscapeStr(s, NULL);
+ for (i = 0; i < tabs + 1; i++) {
+ fprintf(f, "\t");
+ }
+ fprintf(f, "<item>%s</item>\n", escaped);
+ free(s);
+ free(escaped);
+ s = xmlCharStrdup(asctime(filter->end));
+ escaped = xmlURIEscapeStr(s, NULL);
+ for (i = 0; i < tabs + 1; i++)
+ fprintf(f, "\t");
+ fprintf(f, "<item>%s</item>\n", escaped);
+ free(s);
+ free(escaped);
+ for (i = 0; i < tabs + 1; i++)
+ fprintf(f, "\t");
+ fprintf(f, "<item>%d</item>\n", filter->date_match);
+ for (i = 0; i < tabs; i++)
+ fprintf(f, "\t");
+ fprintf(f, "</criteria>\n");
+}
+
+typedef bool(filter_is_set_func) (const seaudit_filter_t * filter);
+typedef int (filter_support_func) (const seaudit_message_t * msg);
+typedef int (filter_accept_func) (const seaudit_filter_t * filter, const seaudit_message_t * msg);
+typedef void (filter_print_func) (const seaudit_filter_t * filter, const char *name, FILE * f, int tabs);
+
+struct filter_criteria_t
+{
+ const char *name;
+ filter_is_set_func *is_set;
+ filter_support_func *support;
+ filter_accept_func *accept;
+ filter_read_func *read;
+ filter_print_func *print;
+};
+
+/**
+ * Filter criteria are actually implemented as entries within this
+ * function pointer table. During filter_is_accepted() each element
+ * of this table is retrieved; if the support functions returns
+ * non-zero then the accept function is called. To add new filter
+ * criteria, implement their support and accept functions and then
+ * append new entries to this table.
+ */
+static const struct filter_criteria_t filter_criteria[] = {
+ {"src_user", filter_src_user_is_set, filter_src_user_support, filter_src_user_accept, filter_src_user_read,
+ filter_src_user_print},
+ {"src_role", filter_src_role_is_set, filter_src_role_support, filter_src_role_accept, filter_src_role_read,
+ filter_src_role_print},
+ {"src_type", filter_src_type_is_set, filter_src_type_support, filter_src_type_accept, filter_src_type_read,
+ filter_src_type_print},
+ {"src_mls_lvl", filter_src_mls_lvl_is_set, filter_src_mls_lvl_support, filter_src_mls_lvl_accept, filter_src_mls_lvl_read,
+ filter_src_mls_lvl_print},
+ {"src_mls_clr", filter_src_mls_clr_is_set, filter_src_mls_clr_support, filter_src_mls_clr_accept, filter_src_mls_clr_read,
+ filter_src_mls_clr_print},
+ {"tgt_user", filter_tgt_user_is_set, filter_tgt_user_support, filter_tgt_user_accept, filter_tgt_user_read,
+ filter_tgt_user_print},
+ {"tgt_role", filter_tgt_role_is_set, filter_tgt_role_support, filter_tgt_role_accept, filter_tgt_role_read,
+ filter_tgt_role_print},
+ {"tgt_type", filter_tgt_type_is_set, filter_tgt_type_support, filter_tgt_type_accept, filter_tgt_type_read,
+ filter_tgt_type_print},
+ {"tgt_mls_lvl", filter_tgt_mls_lvl_is_set, filter_tgt_mls_lvl_support, filter_tgt_mls_lvl_accept, filter_tgt_mls_lvl_read,
+ filter_src_mls_lvl_print},
+ {"tgt_mls_clr", filter_tgt_mls_clr_is_set, filter_tgt_mls_clr_support, filter_tgt_mls_clr_accept, filter_tgt_mls_clr_read,
+ filter_src_mls_clr_print},
+ {"obj_class", filter_tgt_class_is_set, filter_tgt_class_support, filter_tgt_class_accept, filter_tgt_class_read,
+ filter_tgt_class_print},
+ {"perm", filter_perm_is_set, filter_perm_support, filter_perm_accept, filter_perm_read, filter_perm_print},
+ {"exe", filter_exe_is_set, filter_exe_support, filter_exe_accept, filter_exe_read, filter_exe_print},
+ {"host", filter_host_is_set, filter_host_support, filter_host_accept, filter_host_read, filter_host_print},
+ {"path", filter_path_is_set, filter_path_support, filter_path_accept, filter_path_read, filter_path_print},
+ {"inode", filter_inode_is_set, filter_inode_support, filter_inode_accept, filter_inode_read, filter_inode_print},
+ {"pid", filter_pid_is_set, filter_pid_support, filter_pid_accept, filter_pid_read, filter_pid_print},
+ {"comm", filter_comm_is_set, filter_comm_support, filter_comm_accept, filter_comm_read, filter_comm_print},
+ {"ipaddr", filter_anyaddr_is_set, filter_anyaddr_support, filter_anyaddr_accept, filter_anyaddr_read, filter_anyaddr_print},
+ {"anyport", filter_anyport_is_set, filter_anyport_support, filter_anyport_accept, filter_anyport_read,
+ filter_anyport_print},
+ {"laddr", filter_laddr_is_set, filter_laddr_support, filter_laddr_accept, filter_laddr_read, filter_laddr_print},
+ {"lport", filter_lport_is_set, filter_lport_support, filter_lport_accept, filter_lport_read, filter_lport_print},
+ {"faddr", filter_faddr_is_set, filter_faddr_support, filter_faddr_accept, filter_faddr_read, filter_faddr_print},
+ {"fport", filter_fport_is_set, filter_fport_support, filter_fport_accept, filter_fport_read, filter_fport_print},
+ {"saddr", filter_saddr_is_set, filter_saddr_support, filter_saddr_accept, filter_saddr_read, filter_saddr_print},
+ {"sport", filter_sport_is_set, filter_sport_support, filter_sport_accept, filter_sport_read, filter_sport_print},
+ {"daddr", filter_daddr_is_set, filter_daddr_support, filter_daddr_accept, filter_daddr_read, filter_daddr_print},
+ {"dport", filter_dport_is_set, filter_dport_support, filter_dport_accept, filter_dport_read, filter_dport_print},
+ {"port", filter_port_is_set, filter_port_support, filter_port_accept, filter_port_read, filter_port_print},
+ {"netif", filter_netif_is_set, filter_netif_support, filter_netif_accept, filter_netif_read, filter_netif_print},
+ {"key", filter_key_is_set, filter_key_support, filter_key_accept, filter_key_read, filter_key_print},
+ {"cap", filter_cap_is_set, filter_cap_support, filter_cap_accept, filter_cap_read, filter_cap_print},
+ {"msg", filter_avc_msg_type_is_set, filter_avc_msg_type_support, filter_avc_msg_type_accept, filter_avc_msg_type_read,
+ filter_avc_msg_type_print},
+ {"date_time", filter_date_is_set, filter_date_support, filter_date_accept, filter_date_read, filter_date_print}
+};
+
+/******************** protected functions below ********************/
+
+int filter_is_accepted(const seaudit_filter_t * filter, const seaudit_message_t * msg)
+{
+ bool tried_criterion = false;
+ int acceptval;
+ size_t i;
+
+ for (i = 0; i < sizeof(filter_criteria) / sizeof(filter_criteria[0]); i++) {
+ if (filter_criteria[i].is_set(filter)) {
+ tried_criterion = true;
+ if (filter_criteria[i].support(msg)) {
+ acceptval = filter_criteria[i].accept(filter, msg);
+ } else if (filter->strict) {
+ /* if filter is strict, then an
+ unsupported criterion is assumed to
+ not match */
+ acceptval = 0;
+ } else {
+ /* for unstrict filters, unsupported
+ criterion is assumed to be a don't
+ care state */
+ continue;
+ }
+ if (filter->match == SEAUDIT_FILTER_MATCH_ANY && acceptval == 1) {
+ return 1;
+ }
+ if (filter->match == SEAUDIT_FILTER_MATCH_ALL && acceptval == 0) {
+ return 0;
+ }
+ }
+ }
+ if (!tried_criterion) {
+ /* if got here, then the filter had no set criterion */
+ if (filter->strict) {
+ /* a strict empty filter matches nothing */
+ return 0;
+ }
+ return 1;
+ }
+ if (filter->match == SEAUDIT_FILTER_MATCH_ANY) {
+ /* if got here, then no criterion was met */
+ return 0;
+ }
+ /* if got here, then all criteria were met */
+ return 1;
+}
+
+static bool filter_parse_is_valid_tag(const xmlChar * tag)
+{
+ static const char *parse_valid_tags[] = { "item", "criteria", "view", "filter", "desc", NULL };
+ size_t i;
+ for (i = 0; parse_valid_tags[i] != NULL; i++) {
+ if (xmlStrcmp(tag, (xmlChar *) parse_valid_tags[i]) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static filter_read_func *filter_get_read_func(const xmlChar * name)
+{
+ size_t i;
+ for (i = 0; i < sizeof(filter_criteria) / sizeof(filter_criteria[0]); i++) {
+ if (xmlStrcmp(name, (xmlChar *) filter_criteria[i].name) == 0) {
+ return filter_criteria[i].read;
+ }
+ }
+ return NULL;
+}
+
+static void filter_parse_start_element(void *user_data, const xmlChar * name, const xmlChar ** attrs)
+{
+ struct filter_parse_state *state = user_data;
+ size_t i;
+ if (!filter_parse_is_valid_tag(name)) {
+ state->warnings = 1;
+ return;
+ }
+ if (xmlStrcmp(name, (xmlChar *) "view") == 0) {
+ for (i = 0; attrs[i] != NULL && attrs[i + 1] != NULL; i += 2) {
+ if (xmlStrcmp(attrs[i], (xmlChar *) "name") == 0) {
+ free(state->view_name);
+ state->view_name = xmlURIUnescapeString((const char *)attrs[i + 1], 0, NULL);
+ } else if (xmlStrcmp(attrs[i], (xmlChar *) "match") == 0) {
+ if (xmlStrcmp(attrs[i + 1], (xmlChar *) "all") == 0) {
+ state->view_match = SEAUDIT_FILTER_MATCH_ALL;
+ } else if (xmlStrcmp(attrs[i + 1], (xmlChar *) "any") == 0) {
+ state->view_match = SEAUDIT_FILTER_MATCH_ANY;
+ }
+ } else if (xmlStrcmp(attrs[i], (xmlChar *) "show") == 0) {
+ if (xmlStrcmp(attrs[i + 1], (xmlChar *) "true") == 0) {
+ state->view_visible = SEAUDIT_FILTER_VISIBLE_SHOW;
+ } else if (xmlStrcmp(attrs[i + 1], (xmlChar *) "hide") == 0) {
+ state->view_visible = SEAUDIT_FILTER_VISIBLE_HIDE;
+ }
+ }
+ }
+ } else if (xmlStrcmp(name, (xmlChar *) "filter") == 0) {
+ /* create a new filter and set it to be the one that is currently being parsed */
+ char *filter_name = NULL;
+ seaudit_filter_match_e match = SEAUDIT_FILTER_MATCH_ALL;
+ bool strict = false;
+ for (i = 0; attrs[i] != NULL && attrs[i + 1] != NULL; i += 2) {
+ if (xmlStrcmp(attrs[i], (xmlChar *) "name") == 0) {
+ free(filter_name);
+ filter_name = xmlURIUnescapeString((const char *)attrs[i + 1], 0, NULL);
+ } else if (xmlStrcmp(attrs[i], (xmlChar *) "match") == 0) {
+ if (xmlStrcmp(attrs[i + 1], (xmlChar *) "all") == 0) {
+ match = SEAUDIT_FILTER_MATCH_ALL;
+ } else if (xmlStrcmp(attrs[i + 1], (xmlChar *) "any") == 0) {
+ match = SEAUDIT_FILTER_MATCH_ANY;
+ }
+ } else if (xmlStrcmp(attrs[i], (xmlChar *) "strict") == 0) {
+ if (xmlStrcmp(attrs[i + 1], (xmlChar *) "true") == 0) {
+ strict = true;
+ } else if (xmlStrcmp(attrs[i + 1], (xmlChar *) "false") == 0) {
+ strict = false;
+ }
+ }
+ }
+ if ((state->cur_filter = seaudit_filter_create(filter_name)) != NULL) {
+ if (apol_vector_append(state->filters, state->cur_filter) < 0) {
+ seaudit_filter_destroy(&state->cur_filter);
+ } else {
+ seaudit_filter_set_match(state->cur_filter, match);
+ seaudit_filter_set_strict(state->cur_filter, strict);
+ }
+ }
+ free(filter_name);
+ } else if (xmlStrcmp(name, (xmlChar *) "criteria") == 0) {
+ for (i = 0; attrs[i] != NULL && attrs[i + 1] != NULL; i += 2) {
+ if (xmlStrcmp(attrs[i], (xmlChar *) "type") == 0) {
+ state->cur_filter_read = filter_get_read_func(attrs[i + 1]);
+ }
+ }
+ }
+ free(state->cur_string);
+ state->cur_string = NULL;
+}
+
+static void filter_parse_end_element(void *user_data, const xmlChar * name)
+{
+ struct filter_parse_state *state = user_data;
+ char *s;
+ if (!filter_parse_is_valid_tag(name)) {
+ state->warnings = 1;
+ return;
+ }
+ if (xmlStrcmp(name, (xmlChar *) "desc") == 0) {
+ if (state->cur_filter == NULL) {
+ state->warnings = 1;
+ } else {
+ s = xmlURIUnescapeString((const char *)state->cur_string, 0, NULL);
+ seaudit_filter_set_description(state->cur_filter, s);
+ free(s);
+ }
+ } else if (xmlStrcmp(name, (xmlChar *) "item") == 0) {
+ if (state->cur_filter == NULL || state->cur_filter_read == NULL) {
+ state->warnings = 1;
+ } else {
+ state->cur_filter_read(state->cur_filter, state->cur_string);
+ }
+ } else if (xmlStrcmp(name, (xmlChar *) "filter") == 0) {
+ state->cur_filter = NULL;
+ } else if (xmlStrcmp(name, (xmlChar *) "criteria") == 0) {
+ state->cur_filter_read = NULL;
+ }
+ free(state->cur_string);
+ state->cur_string = NULL;
+}
+
+static void filter_parse_characters(void *user_data, const xmlChar * ch, int len)
+{
+ struct filter_parse_state *state = user_data;
+ free(state->cur_string);
+ state->cur_string = xmlStrndup(ch, len);
+}
+
+int filter_parse_xml(struct filter_parse_state *state, const char *filename)
+{
+ xmlSAXHandler handler;
+ int err;
+
+ memset(&handler, 0, sizeof(xmlSAXHandler));
+ handler.startElement = filter_parse_start_element;
+ handler.endElement = filter_parse_end_element;
+ handler.characters = filter_parse_characters;
+ err = xmlSAXUserParseFile(&handler, state, filename);
+ free(state->cur_string);
+ state->cur_string = NULL;
+ if (err) {
+ errno = EIO;
+ return -1;
+ }
+ if (state->warnings) {
+ return 1;
+ }
+ return 0;
+}
+
+void filter_append_to_file(const seaudit_filter_t * filter, FILE * file, int tabs)
+{
+ xmlChar *escaped;
+ xmlChar *str_xml;
+ int i;
+ size_t j;
+
+ if (filter == NULL || file == NULL) {
+ errno = EINVAL;
+ return;
+ }
+
+ if (filter->name == NULL) {
+ str_xml = xmlCharStrdup("Unnamed");
+ } else {
+ str_xml = xmlCharStrdup(filter->name);
+ }
+ escaped = xmlURIEscapeStr(str_xml, NULL);
+ for (i = 0; i < tabs; i++)
+ fprintf(file, "\t");
+ fprintf(file, "<filter name=\"%s\" match=\"%s\" strict=\"%s\">\n", escaped,
+ filter->match == SEAUDIT_FILTER_MATCH_ALL ? "all" : "any", filter->strict ? "true" : "false");
+ free(escaped);
+ free(str_xml);
+
+ if (filter->desc != NULL) {
+ str_xml = xmlCharStrdup(filter->desc);
+ escaped = xmlURIEscapeStr(str_xml, NULL);
+ for (i = 0; i < tabs + 1; i++)
+ fprintf(file, "\t");
+ fprintf(file, "<desc>%s</desc>\n", escaped);
+ free(escaped);
+ free(str_xml);
+ }
+ for (j = 0; j < sizeof(filter_criteria) / sizeof(filter_criteria[0]); j++) {
+ filter_criteria[j].print(filter, filter_criteria[j].name, file, tabs + 1);
+ }
+ for (i = 0; i < tabs; i++)
+ fprintf(file, "\t");
+ fprintf(file, "</filter>\n");
+}
diff --git a/libseaudit/src/filter-internal.h b/libseaudit/src/filter-internal.h
new file mode 100644
index 0000000..abfa908
--- /dev/null
+++ b/libseaudit/src/filter-internal.h
@@ -0,0 +1,109 @@
+/**
+ * @file
+ * Protected interface for seaudit filters.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SEAUDIT_FILTER_INTERNAL_H
+#define SEAUDIT_FILTER_INTERNAL_H
+
+#include "seaudit_internal.h"
+
+struct seaudit_filter
+{
+ seaudit_filter_match_e match;
+ char *name;
+ char *desc;
+ bool strict;
+ /** model that is watching this filter */
+ seaudit_model_t *model;
+ /** vector of strings, for source users */
+ apol_vector_t *src_users;
+ /** vector of strings, for source roles */
+ apol_vector_t *src_roles;
+ /** vector of strings, for source types */
+ apol_vector_t *src_types;
+ /** vector of strings, for source mls levels */
+ apol_vector_t *src_mls_lvl;
+ /** vector of strings, for source mls clearance */
+ apol_vector_t *src_mls_clr;
+ /** vector of strings, for target users */
+ apol_vector_t *tgt_users;
+ /** vector of strings, for target roles */
+ apol_vector_t *tgt_roles;
+ /** vector of strings, for target types */
+ apol_vector_t *tgt_types;
+ /** vector of strings, for target mls levels */
+ apol_vector_t *tgt_mls_lvl;
+ /** vector of strings, for target mls clearance */
+ apol_vector_t *tgt_mls_clr;
+ /** vector of strings, for target object classes */
+ apol_vector_t *tgt_classes;
+ /** criteria for permissions, glob expression */
+ char *perm;
+ /** criteria for executable, glob expression */
+ char *exe;
+ /** criteria for host, glob expression */
+ char *host;
+ /** criteria for path, glob expression */
+ char *path;
+ /** inode criterion, as a literal value */
+ unsigned long inode;
+ /** pid criterion, as a literal value */
+ unsigned int pid;
+ /** criterion for command, glob expression */
+ char *comm;
+ /** criterion for IP address, glob expression */
+ char *anyaddr;
+ /** criterion for local address, glob expression */
+ char *laddr;
+ /** criterion for foreign address, glob expression */
+ char *faddr;
+ /** criterion for source address, glob expression */
+ char *saddr;
+ /** criterion for destination address, glob expression */
+ char *daddr;
+ /** criterion for any of the ports, exact match */
+ int anyport;
+ /** criterion for local port, exact match */
+ int lport;
+ /** criterion for foreign port, exact match */
+ int fport;
+ /** criterion for source port, exact match */
+ int sport;
+ /** criterion for destination port, exact match */
+ int dport;
+ /** criterion for just plain port, exact match */
+ int port;
+ /** criterion for netif, exact match */
+ char *netif;
+ /** criterion for IPC key, exact match */
+ int key;
+ /** criterion for capability, exact match */
+ int cap;
+ /** criterion for AVC message type */
+ seaudit_avc_message_type_e avc_msg_type;
+ struct tm *start, *end;
+ seaudit_filter_date_match_e date_match;
+};
+
+#endif
diff --git a/libseaudit/src/filter.c b/libseaudit/src/filter.c
new file mode 100644
index 0000000..298a309
--- /dev/null
+++ b/libseaudit/src/filter.c
@@ -0,0 +1,1124 @@
+/**
+ * @file
+ * Implementation of seaudit filters.
+ *
+ * If adding new filter criteria, make sure you do the following:
+ *
+ * <ol>
+ * <li>add field(s) to seaudit_filter_t</li>
+ * <li>update filter constructor, seaudit_filter_create()</li>
+ * <li>update copy-constructor, seaudit_filter_create_from_filter()</li>
+ * <li>update destructor, seaudit_filter_destroy()</li>
+ * <li>add accessor(s) and modifier(s) as necessary</li>
+ * <li>add a record to filter_criteria table (in filter-internal.c),
+ * implementing the five necessary functions</li>
+ * </ol>
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "seaudit_internal.h"
+#include "filter-internal.h"
+
+#include <apol/util.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+seaudit_filter_t *seaudit_filter_create(const char *name)
+{
+ seaudit_filter_t *s = calloc(1, sizeof(*s));
+ if (s == NULL) {
+ return NULL;
+ }
+ if (name == NULL) {
+ name = "Untitled";
+ }
+ if ((s->name = strdup(name)) == NULL) {
+ int error = errno;
+ seaudit_filter_destroy(&s);
+ errno = error;
+ return NULL;
+ }
+ return s;
+}
+
+seaudit_filter_t *seaudit_filter_create_from_filter(const seaudit_filter_t * filter)
+{
+ seaudit_filter_t *f = NULL;
+ int error = 0;
+ if (filter == NULL) {
+ error = EINVAL;
+ goto cleanup;
+ }
+ if ((f = seaudit_filter_create(filter->name)) == NULL || (filter->desc != NULL && (f->desc = strdup(filter->desc)) == NULL)) {
+ error = errno;
+ goto cleanup;
+ }
+ f->strict = filter->strict;
+ if ((filter->src_users != NULL
+ && (f->src_users = apol_vector_create_from_vector(filter->src_users, apol_str_strdup, NULL, free)) == NULL)
+ || (filter->src_roles != NULL
+ && (f->src_roles = apol_vector_create_from_vector(filter->src_roles, apol_str_strdup, NULL, free)) == NULL)
+ || (filter->src_types != NULL
+ && (f->src_types = apol_vector_create_from_vector(filter->src_types, apol_str_strdup, NULL, free)) == NULL)
+ || (filter->src_mls_lvl != NULL
+ && (f->src_mls_lvl = apol_vector_create_from_vector(filter->src_mls_lvl, apol_str_strdup, NULL, free)) == NULL)
+ || (filter->src_mls_clr != NULL
+ && (f->src_mls_clr = apol_vector_create_from_vector(filter->src_mls_clr, apol_str_strdup, NULL, free)) == NULL)
+ || (filter->tgt_users != NULL
+ && (f->tgt_users = apol_vector_create_from_vector(filter->tgt_users, apol_str_strdup, NULL, free)) == NULL)
+ || (filter->tgt_roles != NULL
+ && (f->tgt_roles = apol_vector_create_from_vector(filter->tgt_roles, apol_str_strdup, NULL, free)) == NULL)
+ || (filter->tgt_types != NULL
+ && (f->tgt_types = apol_vector_create_from_vector(filter->tgt_types, apol_str_strdup, NULL, free)) == NULL)
+ || (filter->tgt_mls_lvl != NULL
+ && (f->tgt_mls_lvl = apol_vector_create_from_vector(filter->tgt_mls_lvl, apol_str_strdup, NULL, free)) == NULL)
+ || (filter->tgt_mls_clr != NULL
+ && (f->tgt_mls_clr = apol_vector_create_from_vector(filter->tgt_mls_clr, apol_str_strdup, NULL, free)) == NULL)
+ || (filter->tgt_classes != NULL
+ && (f->tgt_classes = apol_vector_create_from_vector(filter->tgt_classes, apol_str_strdup, NULL, free)) == NULL)) {
+ error = errno;
+ goto cleanup;
+ }
+ if ((filter->perm != NULL && (f->perm = strdup(filter->perm)) == NULL) ||
+ (filter->exe != NULL && (f->exe = strdup(filter->exe)) == NULL) ||
+ (filter->host != NULL && (f->host = strdup(filter->host)) == NULL) ||
+ (filter->path != NULL && (f->path = strdup(filter->path)) == NULL) ||
+ (filter->comm != NULL && (f->comm = strdup(filter->comm)) == NULL) ||
+ (filter->anyaddr != NULL && (f->anyaddr = strdup(filter->anyaddr)) == NULL) ||
+ (filter->netif != NULL && (f->netif = strdup(filter->netif)) == NULL)) {
+ error = errno;
+ goto cleanup;
+ }
+ if ((filter->laddr != NULL && (f->laddr = strdup(filter->laddr)) == NULL) ||
+ (filter->faddr != NULL && (f->faddr = strdup(filter->faddr)) == NULL) ||
+ (filter->saddr != NULL && (f->saddr = strdup(filter->saddr)) == NULL) ||
+ (filter->daddr != NULL && (f->daddr = strdup(filter->daddr)) == NULL)) {
+ error = errno;
+ goto cleanup;
+ }
+ f->match = filter->match;
+ f->inode = filter->inode;
+ f->pid = filter->pid;
+ f->anyport = filter->anyport;
+ f->lport = filter->lport;
+ f->fport = filter->fport;
+ f->sport = filter->sport;
+ f->dport = filter->dport;
+ f->port = filter->port;
+ f->key = filter->key;
+ f->cap = filter->cap;
+ f->avc_msg_type = filter->avc_msg_type;
+ if (filter->start != NULL) {
+ if ((f->start = calloc(1, sizeof(*f->start))) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ memcpy(f->start, filter->start, sizeof(*f->start));
+ }
+ if (filter->end != NULL) {
+ if ((f->end = calloc(1, sizeof(*f->end))) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ memcpy(f->end, filter->end, sizeof(*f->end));
+ }
+ f->date_match = filter->date_match;
+ f->model = NULL;
+ cleanup:
+ if (error != 0) {
+ seaudit_filter_destroy(&f);
+ errno = error;
+ return NULL;
+ }
+ return f;
+}
+
+/**
+ * Callback invoked when free()ing a vector of filters.
+ *
+ * @param v Filter object to free.
+ */
+static void filter_free(void *v)
+{
+ seaudit_filter_t *f = v;
+ seaudit_filter_destroy(&f);
+}
+
+apol_vector_t *seaudit_filter_create_from_file(const char *filename)
+{
+ struct filter_parse_state state;
+ int retval, error;
+ memset(&state, 0, sizeof(state));
+ if ((state.filters = apol_vector_create(filter_free)) == NULL) {
+ return NULL;
+ }
+ retval = filter_parse_xml(&state, filename);
+ error = errno;
+ free(state.view_name);
+ if (retval < 0) {
+ apol_vector_destroy(&state.filters);
+ errno = error;
+ return NULL;
+ }
+ return state.filters;
+}
+
+void seaudit_filter_destroy(seaudit_filter_t ** filter)
+{
+ if (filter != NULL && *filter != NULL) {
+ free((*filter)->name);
+ free((*filter)->desc);
+ apol_vector_destroy(&(*filter)->src_users);
+ apol_vector_destroy(&(*filter)->src_roles);
+ apol_vector_destroy(&(*filter)->src_types);
+ apol_vector_destroy(&(*filter)->src_mls_lvl);
+ apol_vector_destroy(&(*filter)->src_mls_clr);
+ apol_vector_destroy(&(*filter)->tgt_users);
+ apol_vector_destroy(&(*filter)->tgt_roles);
+ apol_vector_destroy(&(*filter)->tgt_types);
+ apol_vector_destroy(&(*filter)->tgt_mls_lvl);
+ apol_vector_destroy(&(*filter)->tgt_mls_clr);
+ apol_vector_destroy(&(*filter)->tgt_classes);
+ free((*filter)->perm);
+ free((*filter)->exe);
+ free((*filter)->host);
+ free((*filter)->path);
+ free((*filter)->comm);
+ free((*filter)->anyaddr);
+ free((*filter)->laddr);
+ free((*filter)->faddr);
+ free((*filter)->saddr);
+ free((*filter)->daddr);
+ free((*filter)->netif);
+ free((*filter)->start);
+ free((*filter)->end);
+ free(*filter);
+ *filter = NULL;
+ }
+}
+
+int seaudit_filter_set_match(seaudit_filter_t * filter, seaudit_filter_match_e match)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ filter->match = match;
+ if (filter->model != NULL) {
+ model_notify_filter_changed(filter->model, filter);
+ }
+ return 0;
+}
+
+seaudit_filter_match_e seaudit_filter_get_match(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter->match;
+}
+
+int seaudit_filter_set_name(seaudit_filter_t * filter, const char *name)
+{
+ char *new_name = NULL;
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (name != filter->name) {
+ if (name != NULL && (new_name = strdup(name)) == NULL) {
+ return -1;
+ }
+ free(filter->name);
+ filter->name = new_name;;
+ }
+ return 0;
+}
+
+const char *seaudit_filter_get_name(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->name;
+}
+
+int seaudit_filter_set_description(seaudit_filter_t * filter, const char *desc)
+{
+ char *new_desc = NULL;
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (desc != filter->desc) {
+ if (desc != NULL && (new_desc = strdup(desc)) == NULL) {
+ return -1;
+ }
+ free(filter->desc);
+ filter->desc = new_desc;
+ }
+ return 0;
+}
+
+const char *seaudit_filter_get_description(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->desc;
+}
+
+int seaudit_filter_set_strict(seaudit_filter_t * filter, bool is_strict)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (filter->strict != is_strict) {
+ filter->strict = is_strict;
+ if (filter->model != NULL) {
+ model_notify_filter_changed(filter->model, filter);
+ }
+ }
+ return 0;
+}
+
+bool seaudit_filter_get_strict(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return false;
+ }
+ return filter->strict;
+}
+
+/**
+ * Helper function to set a criterion's vector, by duping the vector
+ * and its strings. Dupe the vector before destroying the existing
+ * one, in case v is the same as tgt.
+ */
+static int filter_set_vector(seaudit_filter_t * filter, apol_vector_t ** tgt, const apol_vector_t * v)
+{
+ apol_vector_t *new_v = NULL;
+ if (v != NULL) {
+ if ((new_v = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ return -1;
+ }
+ }
+ apol_vector_destroy(tgt);
+ *tgt = new_v;
+ if (filter->model != NULL) {
+ model_notify_filter_changed(filter->model, filter);
+ }
+ return 0;
+}
+
+/**
+ * Helper function to set a criterion string, by dupping the src
+ * string. As a check, if the pointers are already the same then do
+ * nothing.
+ */
+static int filter_set_string(seaudit_filter_t * filter, char **dest, const char *src)
+{
+ if (src != *dest) {
+ char *new_s = NULL;
+ if (src != NULL && (new_s = strdup(src)) == NULL) {
+ return -1;
+ }
+ free(*dest);
+ *dest = new_s;
+ if (filter->model != NULL) {
+ model_notify_filter_changed(filter->model, filter);
+ }
+ }
+ return 0;
+}
+
+static int filter_set_ulong(seaudit_filter_t * filter, unsigned long *dest, const ulong src)
+{
+ if (src != *dest) {
+ *dest = src;
+ if (filter->model != NULL) {
+ model_notify_filter_changed(filter->model, filter);
+ }
+ }
+ return 0;
+}
+
+static int filter_set_uint(seaudit_filter_t * filter, unsigned int *dest, const ulong src)
+{
+ if (src != *dest) {
+ *dest = src;
+ if (filter->model != NULL) {
+ model_notify_filter_changed(filter->model, filter);
+ }
+ }
+ return 0;
+}
+
+static int filter_set_int(seaudit_filter_t * filter, int *dest, const int src)
+{
+ int s = src;
+ if (src <= 0) {
+ s = 0;
+ }
+ if (s != *dest) {
+ *dest = s;
+ if (filter->model != NULL) {
+ model_notify_filter_changed(filter->model, filter);
+ }
+ }
+ return 0;
+}
+
+/******************** public accessors / modifiers ********************/
+
+int seaudit_filter_set_source_user(seaudit_filter_t * filter, const apol_vector_t * v)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_vector(filter, &filter->src_users, v);
+}
+
+const apol_vector_t *seaudit_filter_get_source_user(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->src_users;
+}
+
+int seaudit_filter_set_source_role(seaudit_filter_t * filter, const apol_vector_t * v)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_vector(filter, &filter->src_roles, v);
+}
+
+const apol_vector_t *seaudit_filter_get_source_role(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->src_roles;
+}
+
+int seaudit_filter_set_source_type(seaudit_filter_t * filter, const apol_vector_t * v)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_vector(filter, &filter->src_types, v);
+}
+
+const apol_vector_t *seaudit_filter_get_source_type(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->src_types;
+}
+
+int seaudit_filter_set_source_mls_lvl(seaudit_filter_t * filter, const apol_vector_t * v)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_vector(filter, &filter->src_mls_lvl, v);
+}
+
+const apol_vector_t *seaudit_filter_get_source_mls_lvl(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->src_mls_lvl;
+}
+
+int seaudit_filter_set_source_mls_clr(seaudit_filter_t * filter, const apol_vector_t * v)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_vector(filter, &filter->src_mls_clr, v);
+}
+
+const apol_vector_t *seaudit_filter_get_source_mls_clr(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->src_mls_clr;
+}
+int seaudit_filter_set_target_user(seaudit_filter_t * filter, const apol_vector_t * v)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_vector(filter, &filter->tgt_users, v);
+}
+
+const apol_vector_t *seaudit_filter_get_target_user(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->tgt_users;
+}
+
+int seaudit_filter_set_target_role(seaudit_filter_t * filter, const apol_vector_t * v)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_vector(filter, &filter->tgt_roles, v);
+}
+
+const apol_vector_t *seaudit_filter_get_target_role(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->tgt_roles;
+}
+
+int seaudit_filter_set_target_type(seaudit_filter_t * filter, const apol_vector_t * v)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_vector(filter, &filter->tgt_types, v);
+}
+
+const apol_vector_t *seaudit_filter_get_target_type(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->tgt_types;
+}
+
+int seaudit_filter_set_target_mls_lvl(seaudit_filter_t * filter, const apol_vector_t * v)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_vector(filter, &filter->tgt_mls_lvl, v);
+}
+
+const apol_vector_t *seaudit_filter_get_target_mls_lvl(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->tgt_mls_lvl;
+}
+
+int seaudit_filter_set_target_mls_clr(seaudit_filter_t * filter, const apol_vector_t * v)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_vector(filter, &filter->tgt_mls_clr, v);
+}
+
+const apol_vector_t *seaudit_filter_get_target_mls_clr(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->tgt_mls_clr;
+}
+
+int seaudit_filter_set_target_class(seaudit_filter_t * filter, const apol_vector_t * v)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_vector(filter, &filter->tgt_classes, v);
+}
+
+const apol_vector_t *seaudit_filter_get_target_class(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->tgt_classes;
+}
+
+int seaudit_filter_set_permission(seaudit_filter_t * filter, const char *perm)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_string(filter, &filter->perm, perm);
+}
+
+const char *seaudit_filter_get_permission(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->perm;
+}
+
+int seaudit_filter_set_executable(seaudit_filter_t * filter, const char *exe)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_string(filter, &filter->exe, exe);
+}
+
+const char *seaudit_filter_get_executable(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->exe;
+}
+
+int seaudit_filter_set_host(seaudit_filter_t * filter, const char *host)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_string(filter, &filter->host, host);
+}
+
+const char *seaudit_filter_get_host(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->host;
+}
+
+int seaudit_filter_set_path(seaudit_filter_t * filter, const char *path)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_string(filter, &filter->path, path);
+}
+
+const char *seaudit_filter_get_path(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->path;
+}
+
+int seaudit_filter_set_inode(seaudit_filter_t * filter, unsigned long inode)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_ulong(filter, &filter->inode, inode);
+ return 0;
+}
+
+unsigned long seaudit_filter_get_inode(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter->inode;
+}
+
+int seaudit_filter_set_pid(seaudit_filter_t * filter, unsigned int pid)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_uint(filter, &filter->pid, pid);
+ return 0;
+}
+
+unsigned int seaudit_filter_get_pid(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter->pid;
+}
+
+int seaudit_filter_set_command(seaudit_filter_t * filter, const char *command)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_string(filter, &filter->comm, command);
+}
+
+const char *seaudit_filter_get_command(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->comm;
+}
+
+int seaudit_filter_set_anyaddr(seaudit_filter_t * filter, const char *ipaddr)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_string(filter, &filter->anyaddr, ipaddr);
+}
+
+const char *seaudit_filter_get_anyaddr(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->anyaddr;
+}
+
+int seaudit_filter_set_anyport(seaudit_filter_t * filter, const int port)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter_set_int(filter, &filter->anyport, port);
+}
+
+int seaudit_filter_get_anyport(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter->anyport;
+}
+
+int filter_set_ipaddress_vers_4_1(seaudit_filter_t * filter, const char *ipaddr)
+{
+ return seaudit_filter_set_anyaddr(filter, ipaddr);
+}
+
+const char *filter_get_ipaddress_vers_4_1(const seaudit_filter_t * filter)
+{
+ return seaudit_filter_get_anyaddr(filter);
+}
+
+int filter_set_port_vers_4_1(seaudit_filter_t * filter, const int port)
+{
+ return seaudit_filter_set_anyport(filter, port);
+}
+
+int filter_get_port_vers_4_1(const seaudit_filter_t * filter)
+{
+ return seaudit_filter_get_anyport(filter);
+}
+
+#if LINK_SHARED == 1
+__asm__(".symver filter_set_ipaddress_vers_4_1,seaudit_filter_set_ipaddress@VERS_4.1");
+__asm__(".symver filter_get_ipaddress_vers_4_1,seaudit_filter_get_ipaddress@VERS_4.1");
+__asm__(".symver filter_set_port_vers_4_1,seaudit_filter_set_port@VERS_4.1");
+__asm__(".symver filter_get_port_vers_4_1,seaudit_filter_get_port@VERS_4.1");
+#endif
+
+int seaudit_filter_set_laddr(seaudit_filter_t * filter, const char *laddr)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_string(filter, &filter->laddr, laddr);
+}
+
+const char *seaudit_filter_get_laddr(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->laddr;
+}
+
+int seaudit_filter_set_lport(seaudit_filter_t * filter, const int lport)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter_set_int(filter, &filter->lport, lport);
+}
+
+int seaudit_filter_get_lport(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter->lport;
+}
+
+int seaudit_filter_set_faddr(seaudit_filter_t * filter, const char *faddr)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_string(filter, &filter->faddr, faddr);
+}
+
+const char *seaudit_filter_get_faddr(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->faddr;
+}
+
+int seaudit_filter_set_fport(seaudit_filter_t * filter, const int fport)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter_set_int(filter, &filter->fport, fport);
+}
+
+int seaudit_filter_get_fport(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter->fport;
+}
+
+int seaudit_filter_set_saddr(seaudit_filter_t * filter, const char *saddr)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_string(filter, &filter->saddr, saddr);
+}
+
+const char *seaudit_filter_get_saddr(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->saddr;
+}
+
+int seaudit_filter_set_sport(seaudit_filter_t * filter, const int sport)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter_set_int(filter, &filter->sport, sport);
+}
+
+int seaudit_filter_get_sport(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter->sport;
+}
+
+int seaudit_filter_set_daddr(seaudit_filter_t * filter, const char *daddr)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_string(filter, &filter->daddr, daddr);
+}
+
+const char *seaudit_filter_get_daddr(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->daddr;
+}
+
+int seaudit_filter_set_dport(seaudit_filter_t * filter, const int dport)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter_set_int(filter, &filter->dport, dport);
+}
+
+int seaudit_filter_get_dport(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter->dport;
+}
+
+int filter_set_port_vers_4_2(seaudit_filter_t * filter, const int port)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter_set_int(filter, &filter->port, port);
+}
+
+int filter_get_port_vers_4_2(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter->port;
+}
+
+#if LINK_SHARED == 1
+__asm__(".symver filter_set_port_vers_4_2,seaudit_filter_set_port@@VERS_4.2");
+__asm__(".symver filter_get_port_vers_4_2,seaudit_filter_get_port@@VERS_4.2");
+#endif
+
+int seaudit_filter_set_key(seaudit_filter_t * filter, const int key)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter_set_int(filter, &filter->key, key);
+}
+
+int seaudit_filter_get_key(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter->key;
+}
+
+int seaudit_filter_set_cap(seaudit_filter_t * filter, const int cap)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter_set_int(filter, &filter->cap, cap);
+}
+
+int seaudit_filter_get_cap(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+ return filter->cap;
+}
+
+int seaudit_filter_set_netif(seaudit_filter_t * filter, const char *netif)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return filter_set_string(filter, &filter->netif, netif);
+}
+
+const char *seaudit_filter_get_netif(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return filter->netif;
+}
+
+int seaudit_filter_set_message_type(seaudit_filter_t * filter, const seaudit_avc_message_type_e message_type)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ filter->avc_msg_type = message_type;
+ if (filter->model != NULL) {
+ model_notify_filter_changed(filter->model, filter);
+ }
+ return 0;
+}
+
+seaudit_avc_message_type_e seaudit_filter_get_message_type(const seaudit_filter_t * filter)
+{
+ if (filter == NULL) {
+ errno = EINVAL;
+ return SEAUDIT_AVC_UNKNOWN;
+ }
+ return filter->avc_msg_type;
+}
+
+int seaudit_filter_set_date(seaudit_filter_t * filter, const struct tm *start, const struct tm *end,
+ seaudit_filter_date_match_e date_match)
+{
+ struct tm *new_tm = NULL;
+ if (filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ /* the following weird branching exists because start and end
+ * could be shadowing filter->start and filter->end. if
+ * filters->start and filter->end are free()d to early, then
+ * there may be a dereference of free()d memory */
+ if (filter->start != start) {
+ new_tm = NULL;
+ if (start != NULL) {
+ if ((new_tm = calloc(1, sizeof(*new_tm))) == NULL) {
+ return -1;
+ }
+ memcpy(new_tm, start, sizeof(*start));
+ }
+ free(filter->start);
+ filter->start = new_tm;
+ }
+ if (start != NULL) {
+ if (filter->end != end) {
+ new_tm = NULL;
+ if (end != NULL) {
+ if ((new_tm = calloc(1, sizeof(*new_tm))) == NULL) {
+ return -1;
+ }
+ memcpy(new_tm, end, sizeof(*end));
+ }
+ free(filter->end);
+ filter->end = new_tm;
+ }
+ } else {
+ free(filter->end);
+ filter->end = NULL;
+ }
+ filter->date_match = date_match;
+ if (filter->model != NULL) {
+ model_notify_filter_changed(filter->model, filter);
+ }
+ return 0;
+}
+
+void seaudit_filter_get_date(const seaudit_filter_t * filter, const struct tm **start, const struct tm **end,
+ seaudit_filter_date_match_e * match)
+{
+ if (start != NULL) {
+ *start = NULL;
+ }
+ if (end != NULL) {
+ *end = NULL;
+ }
+ if (match != NULL) {
+ *match = SEAUDIT_FILTER_DATE_MATCH_BEFORE;
+ }
+ if (filter == NULL || start == NULL || end == NULL || match == NULL) {
+ errno = EINVAL;
+ return;
+ }
+ *start = filter->start;
+ *end = filter->end;
+ *match = filter->date_match;
+}
+
+int seaudit_filter_save_to_file(const seaudit_filter_t * filter, const char *filename)
+{
+ FILE *file;
+ const char *XML_VER = "<?xml version=\"1.0\"?>\n";
+
+ if (filter == NULL || filename == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if ((file = fopen(filename, "w")) == NULL) {
+ return -1;
+ }
+ fprintf(file, XML_VER);
+ fprintf(file, "<view xmlns=\"http://oss.tresys.com/projects/setools/seaudit-%s/\">\n", FILTER_FILE_FORMAT_VERSION);
+ filter_append_to_file(filter, file, 1);
+ fprintf(file, "</view>\n");
+ fclose(file);
+ return 0;
+}
+
+/******************** protected functions below ********************/
+
+void filter_set_model(seaudit_filter_t * filter, seaudit_model_t * model)
+{
+ filter->model = model;
+}
diff --git a/libseaudit/src/libseaudit.map b/libseaudit/src/libseaudit.map
new file mode 100644
index 0000000..e0ad723
--- /dev/null
+++ b/libseaudit/src/libseaudit.map
@@ -0,0 +1,88 @@
+VERS_4.1{
+ global:
+ seaudit_avc_message_*;
+ seaudit_filter_*;
+ seaudit_handle_msg;
+ seaudit_log_*;
+ seaudit_message_*;
+ seaudit_model_*;
+ seaudit_report_*;
+ seaudit_sort_*;
+ libseaudit_get_version;
+ local: *;
+};
+
+VERS_4.2{
+ global:
+ seaudit_avc_message_get_port;
+ seaudit_filter_get_anyaddr;
+ seaudit_filter_set_anyaddr;
+ seaudit_filter_get_anyport;
+ seaudit_filter_set_anyport;
+ seaudit_filter_get_cap;
+ seaudit_filter_set_cap;
+ seaudit_filter_get_daddr;
+ seaudit_fliter_set_daddr;
+ seaudit_filter_get_dport;
+ seaudit_filter_set_dport;
+ seaudit_filter_get_faddr;
+ seaudit_fliter_set_faddr;
+ seaudit_filter_get_fport;
+ seaudit_filter_set_fport;
+ seaudit_filter_get_inode;
+ seaudit_filter_set_inode;
+ seaudit_filter_get_key;
+ seaudit_filter_set_key;
+ seaudit_filter_get_laddr;
+ seaudit_fliter_set_laddr;
+ seaudit_filter_get_lport;
+ seaudit_filter_set_lport;
+ seaudit_filter_get_permission;
+ seaudit_filter_set_permission;
+ seaudit_filter_get_pid;
+ seaudit_filter_set_pid;
+ seaudit_filter_get_port;
+ seaudit_filter_set_port;
+ seaudit_filter_get_saddr;
+ seaudit_fliter_set_saddr;
+ seaudit_filter_get_sport;
+ seaudit_filter_set_sport;
+ seaudit_filter_get_strict;
+ seaudit_filter_set_strict;
+ seaudit_log_clear;
+ seaudit_model_hide_message;
+ seaudit_sort_by_cap;
+ seaudit_sort_by_daddr;
+ seaudit_sort_by_dport;
+ seaudit_sort_by_faddr;
+ seaudit_sort_by_fport;
+ seaudit_sort_by_key;
+ seaudit_sort_by_laddr;
+ seaudit_sort_by_lport;
+ seaudit_sort_by_port;
+ seaudit_sort_by_saddr;
+ seaudit_sort_by_sport;
+ seaudit_sort_create_from_sort;
+} VERS_4.1;
+
+VERS_4.3{
+ global:
+ seaudit_avc_message_get_source__mls_lvl;
+ seaudit_avc_message_get_source__mls_clr;
+ seaudit_avc_message_get_target_mls_lvl;
+ seaudit_avc_message_get_target_mls_clr;
+ seaudit_filter_get_source_mls_lvl;
+ seaudit_filter_get_source_mls_clr;
+ seaudit_filter_set_source_mls_lvl;
+ seaudit_filter_set_source_mls_clr;
+ seaudit_filter_get_target_mls_lvl;
+ seaudit_filter_get_target_mls_clr;
+ seaudit_filter_set_target_mls_lvl;
+ seaudit_filter_set_target_mls_clr;
+ seaudit_log_get_mls_lvl;
+ seaudit_log_get_mls_clr;
+ seaudit_sort_by_source_mls_lvl;
+ seaudit_sort_by_source_mls_clr;
+ seaudit_sort_by_target_mls_lvl;
+ seaudit_sort_by_target_mls_clr;
+} VERS_4.2;
diff --git a/libseaudit/src/load_message.c b/libseaudit/src/load_message.c
new file mode 100644
index 0000000..7951eb2
--- /dev/null
+++ b/libseaudit/src/load_message.c
@@ -0,0 +1,91 @@
+/**
+ * @file
+ * Implementation of a single policy load log message.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "seaudit_internal.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/******************** protected functions below ********************/
+
+seaudit_load_message_t *load_message_create(void)
+{
+ return calloc(1, sizeof(seaudit_load_message_t));
+}
+
+void load_message_free(seaudit_load_message_t * msg)
+{
+ if (msg != NULL) {
+ free(msg->binary);
+ free(msg);
+ }
+}
+
+char *load_message_to_string(const seaudit_message_t * msg, const char *date)
+{
+ seaudit_load_message_t *load = msg->data.load;
+ const char *host = msg->host;
+ const char *manager = msg->manager;
+ char *s = NULL;
+ if (asprintf(&s,
+ "%s %s %s: security: %d users, %d roles, %d types, %d bools\n"
+ "%s %s %s: security: %d classes, %d rules",
+ date, host, manager, load->users, load->roles, load->types, load->bools, date, host, manager, load->classes,
+ load->rules) < 0) {
+ return NULL;
+ }
+ return s;
+}
+
+char *load_message_to_string_html(const seaudit_message_t * msg, const char *date)
+{
+ seaudit_load_message_t *load = msg->data.load;
+ const char *host = msg->host;
+ const char *manager = msg->manager;
+ char *s = NULL;
+ if (asprintf(&s,
+ "<font class=\"message_date\">%s</font> "
+ "<font class=\"host_name\">%s</font> "
+ "%s: security: %d users, %d roles, %d types, %d bools<br>\n"
+ "<font class=\"message_date\">%s</font> "
+ "<font class=\"host_name\">%s</font> "
+ "%s: security: %d classes, %d rules<br>",
+ date, host, manager, load->users, load->roles, load->types, load->bools, date, host, manager, load->classes,
+ load->rules) < 0) {
+ return NULL;
+ }
+ return s;
+}
+
+char *load_message_to_misc_string(const seaudit_load_message_t * load)
+{
+ char *s = NULL;
+ if (asprintf(&s,
+ "users=%d roles=%d types=%d bools=%d classes=%d rules=%d",
+ load->users, load->roles, load->types, load->bools, load->classes, load->rules) < 0) {
+ return NULL;
+ }
+ return s;
+}
diff --git a/libseaudit/src/log.c b/libseaudit/src/log.c
new file mode 100644
index 0000000..6665cd0
--- /dev/null
+++ b/libseaudit/src/log.c
@@ -0,0 +1,253 @@
+/**
+ * @file
+ * Implementation for the main libseaudit object, seaudit_log_t.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "seaudit_internal.h"
+
+#include <apol/util.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+seaudit_log_t *seaudit_log_create(seaudit_handle_fn_t fn, void *callback_arg)
+{
+ seaudit_log_t *log = NULL;
+ int error;
+ if ((log = calloc(1, sizeof(*log))) == NULL) {
+ return NULL;
+ }
+ log->fn = fn;
+ log->handle_arg = callback_arg;
+ if ((log->messages = apol_vector_create(message_free)) == NULL ||
+ (log->malformed_msgs = apol_vector_create(free)) == NULL ||
+ (log->models = apol_vector_create(NULL)) == NULL ||
+ (log->types = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->classes = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->roles = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->users = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->perms = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->mls_lvl = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->mls_clr = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->hosts = apol_bst_create(apol_str_strcmp, free)) == NULL
+ || (log->bools = apol_bst_create(apol_str_strcmp, free)) == NULL
+ || (log->managers = apol_bst_create(apol_str_strcmp, free)) == NULL) {
+ error = errno;
+ seaudit_log_destroy(&log);
+ errno = error;
+ return NULL;
+ }
+ return log;
+}
+
+void seaudit_log_destroy(seaudit_log_t ** log)
+{
+ size_t i;
+ if (log == NULL || *log == NULL) {
+ return;
+ }
+ for (i = 0; i < apol_vector_get_size((*log)->models); i++) {
+ seaudit_model_t *m = apol_vector_get_element((*log)->models, i);
+ model_remove_log(m, *log);
+ }
+ apol_vector_destroy(&(*log)->messages);
+ apol_vector_destroy(&(*log)->malformed_msgs);
+ apol_vector_destroy(&(*log)->models);
+ apol_bst_destroy(&(*log)->types);
+ apol_bst_destroy(&(*log)->classes);
+ apol_bst_destroy(&(*log)->roles);
+ apol_bst_destroy(&(*log)->users);
+ apol_bst_destroy(&(*log)->perms);
+ apol_bst_destroy(&(*log)->hosts);
+ apol_bst_destroy(&(*log)->bools);
+ apol_bst_destroy(&(*log)->managers);
+ apol_bst_destroy(&(*log)->mls_lvl);
+ apol_bst_destroy(&(*log)->mls_clr);
+ free(*log);
+ *log = NULL;
+}
+
+void seaudit_log_clear(seaudit_log_t * log)
+{
+ if (log == NULL) {
+ errno = EINVAL;
+ return;
+ }
+ apol_vector_destroy(&log->messages);
+ apol_vector_destroy(&log->malformed_msgs);
+ apol_bst_destroy(&log->types);
+ apol_bst_destroy(&log->classes);
+ apol_bst_destroy(&log->roles);
+ apol_bst_destroy(&log->users);
+ apol_bst_destroy(&log->perms);
+ apol_bst_destroy(&log->hosts);
+ apol_bst_destroy(&log->bools);
+ apol_bst_destroy(&log->managers);
+ apol_bst_destroy(&log->mls_lvl);
+ apol_bst_destroy(&log->mls_clr);
+ if ((log->messages = apol_vector_create(message_free)) == NULL ||
+ (log->malformed_msgs = apol_vector_create(free)) == NULL ||
+ (log->types = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->classes = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->roles = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->users = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->perms = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->mls_lvl = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->mls_clr = apol_bst_create(apol_str_strcmp, free)) == NULL ||
+ (log->hosts = apol_bst_create(apol_str_strcmp, free)) == NULL
+ || (log->bools = apol_bst_create(apol_str_strcmp, free)) == NULL
+ || (log->managers = apol_bst_create(apol_str_strcmp, free)) == NULL) {
+ /* hopefully will never get here... */
+ return;
+ }
+ for (size_t i = 0; i < apol_vector_get_size(log->models); i++) {
+ seaudit_model_t *m = apol_vector_get_element(log->models, i);
+ model_notify_log_changed(m, log);
+ }
+}
+
+apol_vector_t *seaudit_log_get_users(const seaudit_log_t * log)
+{
+ if (log == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return apol_bst_get_vector(log->users, 0);
+}
+
+apol_vector_t *seaudit_log_get_roles(const seaudit_log_t * log)
+{
+ if (log == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return apol_bst_get_vector(log->roles, 0);
+}
+
+apol_vector_t *seaudit_log_get_types(const seaudit_log_t * log)
+{
+ if (log == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return apol_bst_get_vector(log->types, 0);
+}
+
+apol_vector_t *seaudit_log_get_mls_lvl(const seaudit_log_t * log)
+{
+ if (log == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return apol_bst_get_vector(log->mls_lvl, 0);
+}
+
+apol_vector_t *seaudit_log_get_mls_clr(const seaudit_log_t * log)
+{
+ if (log == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return apol_bst_get_vector(log->mls_clr, 0);
+}
+
+apol_vector_t *seaudit_log_get_classes(const seaudit_log_t * log)
+{
+ if (log == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return apol_bst_get_vector(log->classes, 0);
+}
+
+/******************** protected functions below ********************/
+
+int log_append_model(seaudit_log_t * log, seaudit_model_t * model)
+{
+ if (apol_vector_append(log->models, model) < 0) {
+ int error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+void log_remove_model(seaudit_log_t * log, seaudit_model_t * model)
+{
+ size_t i;
+ if (apol_vector_get_index(log->models, model, NULL, NULL, &i) == 0) {
+ apol_vector_remove(log->models, i);
+ }
+}
+
+const apol_vector_t *log_get_messages(const seaudit_log_t * log)
+{
+ return log->messages;
+}
+
+const apol_vector_t *log_get_malformed_messages(const seaudit_log_t * log)
+{
+ return log->malformed_msgs;
+}
+
+static void seaudit_handle_default_callback(void *arg __attribute__ ((unused)),
+ const seaudit_log_t * log __attribute__ ((unused)),
+ int level, const char *fmt, va_list va_args)
+{
+ switch (level) {
+ case SEAUDIT_MSG_INFO:
+ {
+ /* by default do not display these messages */
+ return;
+ }
+ case SEAUDIT_MSG_WARN:
+ {
+ fprintf(stderr, "WARNING: ");
+ break;
+ }
+ case SEAUDIT_MSG_ERR:
+ default:
+ {
+ fprintf(stderr, "ERROR: ");
+ break;
+ }
+ }
+ vfprintf(stderr, fmt, va_args);
+ fprintf(stderr, "\n");
+}
+
+void seaudit_handle_msg(const seaudit_log_t * log, int level, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ if (log == NULL || log->fn == NULL) {
+ seaudit_handle_default_callback(NULL, NULL, level, fmt, ap);
+ } else {
+ log->fn(log->handle_arg, log, level, fmt, ap);
+ }
+ va_end(ap);
+}
diff --git a/libseaudit/src/message.c b/libseaudit/src/message.c
new file mode 100644
index 0000000..4e767d0
--- /dev/null
+++ b/libseaudit/src/message.c
@@ -0,0 +1,204 @@
+/**
+ * @file
+ * Implementation of a single seaudit log message. Because C does
+ * not have RTTI, fake it below.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "seaudit_internal.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+void *seaudit_message_get_data(const seaudit_message_t * msg, seaudit_message_type_e * type)
+{
+ if (type != NULL) {
+ *type = SEAUDIT_MESSAGE_TYPE_INVALID;
+ }
+ if (msg == NULL || type == NULL || msg->type == SEAUDIT_MESSAGE_TYPE_INVALID) {
+ errno = EINVAL;
+ return NULL;
+ }
+ switch ((*type = msg->type)) {
+ case SEAUDIT_MESSAGE_TYPE_AVC:
+ return msg->data.avc;
+ case SEAUDIT_MESSAGE_TYPE_BOOL:
+ return msg->data.boolm;
+ case SEAUDIT_MESSAGE_TYPE_LOAD:
+ return msg->data.load;
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+}
+
+const struct tm *seaudit_message_get_time(const seaudit_message_t * msg)
+{
+ if (!msg) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return msg->date_stamp;
+}
+
+const char *seaudit_message_get_host(const seaudit_message_t * msg)
+{
+ if (!msg) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return msg->host;
+}
+
+#define DATE_STR_SIZE 256
+
+char *seaudit_message_to_string(const seaudit_message_t * msg)
+{
+ char date[DATE_STR_SIZE];
+ if (msg == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ strftime(date, DATE_STR_SIZE, "%b %d %H:%M:%S", msg->date_stamp);
+ switch (msg->type) {
+ case SEAUDIT_MESSAGE_TYPE_AVC:
+ return avc_message_to_string(msg, date);
+ case SEAUDIT_MESSAGE_TYPE_BOOL:
+ return bool_message_to_string(msg, date);
+ case SEAUDIT_MESSAGE_TYPE_LOAD:
+ return load_message_to_string(msg, date);
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+}
+
+char *seaudit_message_to_string_html(const seaudit_message_t * msg)
+{
+ char date[DATE_STR_SIZE];
+ if (msg == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ strftime(date, DATE_STR_SIZE, "%b %d %H:%M:%S", msg->date_stamp);
+ switch (msg->type) {
+ case SEAUDIT_MESSAGE_TYPE_AVC:
+ return avc_message_to_string_html(msg, date);
+ case SEAUDIT_MESSAGE_TYPE_BOOL:
+ return bool_message_to_string_html(msg, date);
+ case SEAUDIT_MESSAGE_TYPE_LOAD:
+ return load_message_to_string_html(msg, date);
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+}
+
+char *seaudit_message_to_misc_string(const seaudit_message_t * msg)
+{
+ if (msg == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ switch (msg->type) {
+ case SEAUDIT_MESSAGE_TYPE_AVC:
+ return avc_message_to_misc_string(msg->data.avc);
+ case SEAUDIT_MESSAGE_TYPE_BOOL:
+ return bool_message_to_misc_string(msg->data.boolm);
+ case SEAUDIT_MESSAGE_TYPE_LOAD:
+ return load_message_to_misc_string(msg->data.load);
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+}
+
+/******************** protected functions below ********************/
+
+seaudit_message_t *message_create(seaudit_log_t * log, seaudit_message_type_e type)
+{
+ seaudit_message_t *m;
+ int error, rt = 0;
+ if (type == SEAUDIT_MESSAGE_TYPE_INVALID) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return NULL;
+ }
+ if ((m = calloc(1, sizeof(*m))) == NULL || apol_vector_append(log->messages, m) < 0) {
+ error = errno;
+ message_free(m);
+ ERR(log, "%s", strerror(error));
+ errno = errno;
+ return NULL;
+ }
+ m->type = type;
+ switch (m->type) {
+ case SEAUDIT_MESSAGE_TYPE_AVC:
+ if ((m->data.avc = avc_message_create()) == NULL) {
+ rt = -1;
+ }
+ break;
+ case SEAUDIT_MESSAGE_TYPE_BOOL:
+ if ((m->data.boolm = bool_message_create()) == NULL) {
+ rt = -1;
+ }
+ break;
+ case SEAUDIT_MESSAGE_TYPE_LOAD:
+ if ((m->data.load = load_message_create()) == NULL) {
+ rt = -1;
+ }
+ break;
+ default: /* shouldn't get here */
+ assert(0);
+ }
+ if (rt < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = errno;
+ return NULL;
+ }
+ return m;
+}
+
+void message_free(void *msg)
+{
+ if (msg != NULL) {
+ seaudit_message_t *m = (seaudit_message_t *) msg;
+ free(m->date_stamp);
+ switch (m->type) {
+ case SEAUDIT_MESSAGE_TYPE_AVC:
+ avc_message_free(m->data.avc);
+ break;
+ case SEAUDIT_MESSAGE_TYPE_BOOL:
+ bool_message_free(m->data.boolm);
+ break;
+ case SEAUDIT_MESSAGE_TYPE_LOAD:
+ load_message_free(m->data.load);
+ break;
+ default:
+ break;
+ }
+ free(m);
+ }
+}
diff --git a/libseaudit/src/model.c b/libseaudit/src/model.c
new file mode 100644
index 0000000..1bc4a23
--- /dev/null
+++ b/libseaudit/src/model.c
@@ -0,0 +1,808 @@
+/**
+ * @file
+ * Implementation of seaudit_model_t.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "seaudit_internal.h"
+
+#include <apol/bst.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libxml/uri.h>
+
+#define DEFAULT_MODEL_NAME "Untitled"
+
+struct seaudit_model
+{
+ char *name;
+ /** vector of seaudit_log_t pointers; this model will get
+ * messages from these logs */
+ apol_vector_t *logs;
+ /** vector of seaudit_message_t pointers; these point into
+ * messages from the watched logs (only valid if dirty == 0) */
+ apol_vector_t *messages;
+ /** vector of char * pointers; these point into malformed
+ * messages from the watched logs (only valid if dirty == 0) */
+ apol_vector_t *malformed_messages;
+ /** list of messages to hide */
+ apol_bst_t *hidden_messages;
+ /** vector of seaudit_filter_t */
+ apol_vector_t *filters;
+ /** if more than one filter is being applied, then accept
+ * messages if any match or if all match */
+ seaudit_filter_match_e match;
+ /** if a filter is being applied, then either show/hide
+ * messages selected by filter */
+ seaudit_filter_visible_e visible;
+ /** vector of seaudit_sort_t, order from highest priority to lowest */
+ apol_vector_t *sorts;
+ /** number of allow messages in the model (only valid if dirty == 0) */
+ size_t num_allows;
+ /** number of deny messages in the model (only valid if dirty == 0) */
+ size_t num_denies;
+ /** number of boolean changes in the model (only valid if dirty == 0) */
+ size_t num_bools;
+ /** number of policy loads in the model (only valid if dirty == 0) */
+ size_t num_loads;
+ /** non-zero whenever this model needs to be recalculated */
+ int dirty;
+};
+
+/**
+ * Apply all of the model's filters to the message.
+ *
+ * @param model Model containing filters to apply.
+ * @param m Message to check.
+ *
+ * @return Non-zero if the message is accepted by the filters, 0 if not.
+ */
+static int model_filter_message(seaudit_model_t * model, const seaudit_message_t * m)
+{
+ size_t i;
+ int compval, filters_passed = 0;
+ if (apol_vector_get_size(model->filters) == 0) {
+ return 1;
+ }
+ for (i = 0; i < apol_vector_get_size(model->filters); i++) {
+ seaudit_filter_t *f = apol_vector_get_element(model->filters, i);
+ compval = filter_is_accepted(f, m);
+ if (compval) {
+ if (model->match == SEAUDIT_FILTER_MATCH_ANY) {
+ return 1;
+ }
+ filters_passed++;
+ } else {
+ if (model->match == SEAUDIT_FILTER_MATCH_ALL) {
+ return 0;
+ }
+ }
+ }
+ if (model->match == SEAUDIT_FILTER_MATCH_ANY) {
+ /* if got here, then no filters were met */
+ return 0;
+ }
+ /* if got here, then all criteria were met */
+ if (filters_passed) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Callback for sorting the model's messages vector.
+ *
+ * @param a First message to compare.
+ * @param b Second message to compare.
+ * @param data Pointer to the model being sorted.
+ *
+ * @return 0 if the messages are equivalent, < 0 if a is first, > 0 if
+ * b is first.
+ */
+static int message_comp(const void *a, const void *b, void *data)
+{
+ const seaudit_message_t *m1 = a;
+ const seaudit_message_t *m2 = b;
+ seaudit_model_t *model = data;
+ size_t i;
+ seaudit_sort_t *s;
+ int compval, s1, s2;
+ for (i = 0; i < apol_vector_get_size(model->sorts); i++) {
+ s = apol_vector_get_element(model->sorts, i);
+ s1 = sort_is_supported(s, m1);
+ s2 = sort_is_supported(s, m2);
+ if (!s1 && !s2) {
+ continue;
+ }
+ if (!s2) {
+ return -1;
+ }
+ if (!s1) {
+ return 1;
+ }
+ if ((compval = sort_comp(s, m1, m2)) != 0) {
+ return compval;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Sort the model's messages. Create two temporary vectors. The
+ * first holds messages that are sortable, according to the list of
+ * sort objects. Sort them in their priority order. The second
+ * vector holds messages that are not sortable; append those messages
+ * to the end of the first (now sorted) vector.
+ *
+ * @param log Error handling log.
+ * @param model Model to sort.
+ *
+ * @return 0 on successful sort, < 0 on error.
+ */
+static int model_sort(const seaudit_log_t * log, seaudit_model_t * model)
+{
+ size_t i, j, num_messages = apol_vector_get_size(model->messages);
+ apol_vector_t *sup = NULL, *unsup = NULL;
+ seaudit_message_t *m;
+ seaudit_sort_t *s;
+ int supported = 0, retval = -1, error = 0;
+ if (apol_vector_get_size(model->sorts) == 0) {
+ retval = 0;
+ goto cleanup;
+ }
+
+ if ((sup = apol_vector_create_with_capacity(num_messages, NULL)) == NULL ||
+ (unsup = apol_vector_create_with_capacity(num_messages, NULL)) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ for (i = 0; i < num_messages; i++) {
+ m = apol_vector_get_element(model->messages, i);
+ supported = 0;
+ for (j = 0; j < apol_vector_get_size(model->sorts); j++) {
+ s = apol_vector_get_element(model->sorts, j);
+ if ((supported = sort_is_supported(s, m)) != 0) {
+ break;
+ }
+ }
+ if ((supported && apol_vector_append(sup, m) < 0) || (!supported && apol_vector_append(unsup, m) < 0)) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ }
+ apol_vector_sort(sup, message_comp, model);
+ if (apol_vector_cat(sup, unsup) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ apol_vector_destroy(&model->messages);
+ model->messages = sup;
+ sup = NULL;
+ retval = 0;
+ cleanup:
+ apol_vector_destroy(&sup);
+ apol_vector_destroy(&unsup);
+ if (retval != 0) {
+ errno = error;
+ }
+ return retval;
+}
+
+/**
+ * Iterate through the model's messages and recalculate the number of
+ * each type of message is stored within.
+ *
+ * @param model Model to recalculate.
+ */
+static void model_recalc_stats(seaudit_model_t * model)
+{
+ size_t i;
+ seaudit_message_t *msg;
+ seaudit_message_type_e type;
+ void *v;
+ seaudit_avc_message_t *avc;
+ model->num_allows = model->num_denies = model->num_bools = model->num_loads = 0;
+ for (i = 0; i < apol_vector_get_size(model->messages); i++) {
+ msg = apol_vector_get_element(model->messages, i);
+ v = seaudit_message_get_data(msg, &type);
+ if (type == SEAUDIT_MESSAGE_TYPE_AVC) {
+ avc = (seaudit_avc_message_t *) v;
+ if (avc->msg == SEAUDIT_AVC_DENIED) {
+ model->num_denies++;
+ } else if (avc->msg == SEAUDIT_AVC_GRANTED) {
+ model->num_allows++;
+ }
+ } else if (type == SEAUDIT_MESSAGE_TYPE_BOOL) {
+ model->num_bools++;
+ } else if (type == SEAUDIT_MESSAGE_TYPE_LOAD) {
+ model->num_loads++;
+ }
+ }
+}
+
+/**
+ * Recalculate all of the messages associated with a particular model,
+ * based upon that model's criteria. If the model is marked as not
+ * dirty then do nothing and return success.
+ *
+ * @param log Log to which report error messages.
+ * @param model Model whose messages list to refresh.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int model_refresh(const seaudit_log_t * log, seaudit_model_t * model)
+{
+ size_t i, j;
+ seaudit_log_t *l;
+ const apol_vector_t *v;
+ seaudit_message_t *message;
+ void *result;
+ int error, filter_match;
+
+ if (!model->dirty) {
+ return 0;
+ }
+ apol_vector_destroy(&model->messages);
+ apol_vector_destroy(&model->malformed_messages);
+ if ((model->messages = apol_vector_create(NULL)) == NULL || (model->malformed_messages = apol_vector_create(NULL)) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ for (i = 0; i < apol_vector_get_size(model->logs); i++) {
+ l = apol_vector_get_element(model->logs, i);
+ v = log_get_messages(l);
+ for (j = 0; j < apol_vector_get_size(v); j++) {
+ message = apol_vector_get_element(v, j);
+ if (apol_bst_get_element(model->hidden_messages, message, NULL, &result) == 0) {
+ continue;
+ }
+ filter_match = model_filter_message(model, message);
+ if (((filter_match && model->visible == SEAUDIT_FILTER_VISIBLE_SHOW) ||
+ (!filter_match && model->visible == SEAUDIT_FILTER_VISIBLE_HIDE)) &&
+ apol_vector_append(model->messages, message) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ }
+ v = log_get_malformed_messages(l);
+ if (apol_vector_cat(model->malformed_messages, v) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ }
+ if (model_sort(log, model) < 0) {
+ return -1;
+ }
+ model_recalc_stats(model);
+ model->dirty = 0;
+ return 0;
+}
+
+/**
+ * Callback invoked when free()ing a vector of filters.
+ *
+ * @param v Filter object to free.
+ */
+static void filter_free(void *v)
+{
+ seaudit_filter_t *f = v;
+ seaudit_filter_destroy(&f);
+}
+
+/**
+ * Callback invoked when free()ing a vector of sort objects.
+ *
+ * @param v Sort object to free.
+ */
+static void sort_free(void *v)
+{
+ seaudit_sort_t *sort = v;
+ seaudit_sort_destroy(&sort);
+}
+
+seaudit_model_t *seaudit_model_create(const char *name, seaudit_log_t * log)
+{
+ seaudit_model_t *m = NULL;
+ int error;
+ if ((m = calloc(1, sizeof(*m))) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return NULL;
+ }
+ if (name == NULL) {
+ name = DEFAULT_MODEL_NAME;
+ }
+ if ((m->name = strdup(name)) == NULL ||
+ (m->logs = apol_vector_create_with_capacity(1, NULL)) == NULL ||
+ (m->hidden_messages = apol_bst_create(NULL, NULL)) == NULL ||
+ (m->filters = apol_vector_create_with_capacity(1, filter_free)) == NULL ||
+ (m->sorts = apol_vector_create_with_capacity(1, sort_free)) == NULL) {
+ error = errno;
+ seaudit_model_destroy(&m);
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return NULL;
+ }
+ if (log != NULL) {
+ if (apol_vector_append(m->logs, log) < 0 || log_append_model(log, m)) {
+ error = errno;
+ seaudit_model_destroy(&m);
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return NULL;
+ }
+ }
+ m->dirty = 1;
+ return m;
+}
+
+static void *model_filter_dup(const void *elem, void *data)
+{
+ const seaudit_filter_t *filter = elem;
+ seaudit_model_t *model = data;
+ seaudit_filter_t *f;
+ if ((f = seaudit_filter_create_from_filter(filter)) == NULL) {
+ return NULL;
+ }
+ filter_set_model(f, model);
+ return f;
+}
+
+static void *model_sort_dup(const void *elem, void *data __attribute__ ((unused)))
+{
+ const seaudit_sort_t *sort = elem;
+ seaudit_model_t *model = data;
+ seaudit_sort_t *s;
+ if ((s = sort_create_from_sort(sort)) == NULL) {
+ return NULL;
+ }
+ if (seaudit_model_append_sort(model, s) < 0) {
+ seaudit_sort_destroy(&s);
+ return NULL;
+ }
+ return s;
+}
+
+seaudit_model_t *seaudit_model_create_from_model(const seaudit_model_t * model)
+{
+ seaudit_model_t *m = NULL;
+ int error = 0;
+ size_t i;
+ const char *name;
+
+ if (model == NULL) {
+ error = EINVAL;
+ goto cleanup;
+ }
+ if ((m = calloc(1, sizeof(*m))) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ if ((name = model->name) == NULL) {
+ name = "Untitled";
+ }
+ if ((m->name = strdup(name)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ m->dirty = 1;
+ if ((m->logs = apol_vector_create_from_vector(model->logs, NULL, NULL, NULL)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ if ((m->filters = apol_vector_create_from_vector(model->filters, model_filter_dup, (void *)m, filter_free)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ if ((m->sorts = apol_vector_create_from_vector(model->sorts, model_sort_dup, (void *)m, sort_free)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ m->match = model->match;
+ m->visible = model->visible;
+ /* link this new model to the old model's logs */
+ for (i = 0; i < apol_vector_get_size(m->logs); i++) {
+ seaudit_log_t *log = apol_vector_get_element(m->logs, i);
+ if (log_append_model(log, m) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ }
+ cleanup:
+ if (error != 0) {
+ seaudit_model_destroy(&m);
+ errno = error;
+ return NULL;
+ }
+ return m;
+}
+
+seaudit_model_t *seaudit_model_create_from_file(const char *filename)
+{
+ struct filter_parse_state state;
+ int retval, error;
+ seaudit_model_t *m;
+ memset(&state, 0, sizeof(state));
+ if ((state.filters = apol_vector_create(filter_free)) == NULL) {
+ return NULL;
+ }
+ retval = filter_parse_xml(&state, filename);
+ if (retval < 0) {
+ error = errno;
+ free(state.view_name);
+ apol_vector_destroy(&state.filters);
+ errno = errno;
+ return NULL;
+ }
+ if ((m = seaudit_model_create(state.view_name, NULL)) == NULL) {
+ error = errno;
+ free(state.view_name);
+ apol_vector_destroy(&state.filters);
+ errno = error;
+ return NULL;
+ }
+ free(state.view_name);
+ apol_vector_destroy(&m->filters);
+ m->filters = state.filters;
+ state.filters = NULL;
+ seaudit_model_set_filter_match(m, state.view_match);
+ seaudit_model_set_filter_visible(m, state.view_visible);
+ return m;
+}
+
+void seaudit_model_destroy(seaudit_model_t ** model)
+{
+ size_t i;
+ if (model == NULL || *model == NULL) {
+ return;
+ }
+ for (i = 0; i < apol_vector_get_size((*model)->logs); i++) {
+ seaudit_log_t *l = apol_vector_get_element((*model)->logs, i);
+ log_remove_model(l, *model);
+ }
+ free((*model)->name);
+ apol_vector_destroy(&(*model)->logs);
+ apol_vector_destroy(&(*model)->filters);
+ apol_vector_destroy(&(*model)->sorts);
+ apol_vector_destroy(&(*model)->messages);
+ apol_vector_destroy(&(*model)->malformed_messages);
+ apol_bst_destroy(&(*model)->hidden_messages);
+ free(*model);
+ *model = NULL;
+}
+
+int seaudit_model_save_to_file(const seaudit_model_t * model, const char *filename)
+{
+ FILE *file;
+ const char *XML_VER = "<?xml version=\"1.0\"?>\n";
+ seaudit_filter_t *filter;
+ size_t i;
+
+ if (model == NULL || filename == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if ((file = fopen(filename, "w")) == NULL) {
+ return -1;
+ }
+ fprintf(file, XML_VER);
+ fprintf(file, "<view xmlns=\"http://oss.tresys.com/projects/setools/seaudit-%s/\" name=\"%s\" match=\"%s\" show=\"%s\">\n",
+ FILTER_FILE_FORMAT_VERSION, model->name,
+ model->match == SEAUDIT_FILTER_MATCH_ALL ? "all" : "any",
+ model->visible == SEAUDIT_FILTER_VISIBLE_SHOW ? "true" : "false");
+ for (i = 0; i < apol_vector_get_size(model->filters); i++) {
+ filter = apol_vector_get_element(model->filters, i);
+ filter_append_to_file(filter, file, 1);
+ }
+ fprintf(file, "</view>\n");
+ fclose(file);
+ return 0;
+}
+
+const char *seaudit_model_get_name(const seaudit_model_t * model)
+{
+ if (model == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return model->name;
+}
+
+int seaudit_model_set_name(seaudit_model_t * model, const char *name)
+{
+ char *s;
+ if (model == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (name == NULL) {
+ name = DEFAULT_MODEL_NAME;
+ }
+ if ((s = strdup(name)) == NULL) {
+ return -1;
+ }
+ free(model->name);
+ model->name = s;
+ return 0;
+}
+
+int seaudit_model_append_log(seaudit_model_t * model, seaudit_log_t * log)
+{
+ if (model == NULL || log == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ if (apol_vector_append(model->logs, log) < 0 || log_append_model(log, model) < 0) {
+ int error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ model->dirty = 1;
+ return 0;
+}
+
+int seaudit_model_append_filter(seaudit_model_t * model, seaudit_filter_t * filter)
+{
+ if (model == NULL || filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (apol_vector_append(model->filters, filter) < 0) {
+ return -1;
+ }
+ filter_set_model(filter, model);
+ model->dirty = 1;
+ return 0;
+}
+
+const apol_vector_t *seaudit_model_get_filters(const seaudit_model_t * model)
+{
+ if (model == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return model->filters;
+}
+
+int seaudit_model_remove_filter(seaudit_model_t * model, seaudit_filter_t * filter)
+{
+ size_t i;
+ if (model == NULL || filter == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (apol_vector_get_index(model->filters, filter, NULL, NULL, &i) < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ seaudit_filter_destroy(&filter);
+ apol_vector_remove(model->filters, i);
+ model->dirty = 1;
+ return 0;
+}
+
+int seaudit_model_set_filter_match(seaudit_model_t * model, seaudit_filter_match_e match)
+{
+ if (model == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ model->match = match;
+ model->dirty = 1;
+ return 0;
+}
+
+seaudit_filter_match_e seaudit_model_get_filter_match(const seaudit_model_t * model)
+{
+ if (model == NULL) {
+ errno = EINVAL;
+ return SEAUDIT_FILTER_MATCH_ALL;
+ }
+ return model->match;
+}
+
+int seaudit_model_set_filter_visible(seaudit_model_t * model, seaudit_filter_visible_e visible)
+{
+ if (model == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ model->visible = visible;
+ model->dirty = 1;
+ return 0;
+}
+
+seaudit_filter_visible_e seaudit_model_get_filter_visible(const seaudit_model_t * model)
+{
+ if (model == NULL) {
+ errno = EINVAL;
+ return SEAUDIT_FILTER_VISIBLE_SHOW;
+ }
+ return model->visible;
+}
+
+int seaudit_model_append_sort(seaudit_model_t * model, seaudit_sort_t * sort)
+{
+ if (model == NULL || sort == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (apol_vector_append(model->sorts, sort) < 0) {
+ return -1;
+ }
+ model->dirty = 1;
+ return 0;
+}
+
+int seaudit_model_clear_sorts(seaudit_model_t * model)
+{
+ if (model == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ apol_vector_destroy(&model->sorts);
+ if ((model->sorts = apol_vector_create_with_capacity(1, sort_free)) == NULL) {
+ return -1;
+ }
+ model->dirty = 1;
+ return 0;
+}
+
+int seaudit_model_is_changed(const seaudit_model_t * model)
+{
+ if (model == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return model->dirty;
+}
+
+apol_vector_t *seaudit_model_get_messages(const seaudit_log_t * log, seaudit_model_t * model)
+{
+ if (log == NULL || model == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return NULL;
+ }
+ if (model_refresh(log, model) < 0) {
+ return NULL;
+ }
+ return apol_vector_create_from_vector(model->messages, NULL, NULL, NULL);
+}
+
+apol_vector_t *seaudit_model_get_malformed_messages(const seaudit_log_t * log, seaudit_model_t * model)
+{
+ if (log == NULL || model == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return NULL;
+ }
+ if (model_refresh(log, model) < 0) {
+ return NULL;
+ }
+ return apol_vector_create_from_vector(model->malformed_messages, NULL, NULL, NULL);
+}
+
+void seaudit_model_hide_message(seaudit_model_t * model, const seaudit_message_t * message)
+{
+ if (model == NULL) {
+ errno = EINVAL;
+ return;
+ }
+ if (message == NULL) {
+ return;
+ }
+ if (apol_bst_insert(model->hidden_messages, (seaudit_message_t *) message, NULL) == 0) {
+ model->dirty = 1;
+ }
+}
+
+size_t seaudit_model_get_num_allows(const seaudit_log_t * log, seaudit_model_t * model)
+{
+ if (log == NULL || model == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return 0;
+ }
+ if (model_refresh(log, model) < 0) {
+ return 0;
+ }
+ return model->num_allows;
+}
+
+size_t seaudit_model_get_num_denies(const seaudit_log_t * log, seaudit_model_t * model)
+{
+ if (log == NULL || model == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return 0;
+ }
+ if (model_refresh(log, model) < 0) {
+ return 0;
+ }
+ return model->num_denies;
+}
+
+size_t seaudit_model_get_num_bools(const seaudit_log_t * log, seaudit_model_t * model)
+{
+ if (log == NULL || model == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return 0;
+ }
+ if (model_refresh(log, model) < 0) {
+ return 0;
+ }
+ return model->num_bools;
+}
+
+size_t seaudit_model_get_num_loads(const seaudit_log_t * log, seaudit_model_t * model)
+{
+ if (log == NULL || model == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return 0;
+ }
+ if (model_refresh(log, model) < 0) {
+ return 0;
+ }
+ return model->num_loads;
+}
+
+/******************** protected functions below ********************/
+
+void model_remove_log(seaudit_model_t * model, seaudit_log_t * log)
+{
+ size_t i;
+ if (apol_vector_get_index(model->logs, log, NULL, NULL, &i) == 0) {
+ apol_vector_remove(model->logs, i);
+ model->dirty = 1;
+ }
+}
+
+void model_notify_log_changed(seaudit_model_t * model, seaudit_log_t * log)
+{
+ size_t i;
+ if (apol_vector_get_index(model->logs, log, NULL, NULL, &i) == 0) {
+ model->dirty = 1;
+ }
+}
+
+void model_notify_filter_changed(seaudit_model_t * model, seaudit_filter_t * filter)
+{
+ size_t i;
+ if (apol_vector_get_index(model->filters, filter, NULL, NULL, &i) == 0) {
+ model->dirty = 1;
+ }
+}
diff --git a/libseaudit/src/parse.c b/libseaudit/src/parse.c
new file mode 100644
index 0000000..f1d44ba
--- /dev/null
+++ b/libseaudit/src/parse.c
@@ -0,0 +1,1513 @@
+/**
+ * @file
+ * Implementation for the audit log parser.
+ *
+ * @author Meggan Whalen mwhalen@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "seaudit_internal.h"
+#include <seaudit/parse.h>
+#include <apol/util.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <selinux/context.h>
+
+#define ALT_SYSCALL_STRING "msg=audit(" /* should contain SYSCALL_STRING */
+#define AUDITD_MSG "type="
+#define AVCMSG " avc: "
+#define BOOLMSG "committed booleans"
+#define LOADMSG " security: "
+#define NUM_TIME_COMPONENTS 3
+#define OLD_LOAD_POLICY_STRING "loadingpolicyconfigurationfrom"
+#define PARSE_NUM_SYSCALL_FIELDS 3
+#define SYSCALL_STRING "audit("
+
+/**
+ * Given a line from an audit log, create and return a vector of
+ * tokens from that line. The caller is responsible for calling
+ * apol_vector_destroy() upon that vector. Note that this function
+ * will modify the passed in line.
+ */
+static int get_tokens(seaudit_log_t * log, char *line, apol_vector_t ** tokens)
+{
+ char *line_ptr, *next;
+ *tokens = NULL;
+ int error = 0;
+
+ if ((*tokens = apol_vector_create(NULL)) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ line_ptr = line;
+ /* Tokenize line while ignoring any adjacent whitespace chars. */
+ while ((next = strsep(&line_ptr, " ")) != NULL) {
+ if (strcmp(next, "") && !apol_str_is_only_white_space(next)) {
+ if (apol_vector_append(*tokens, next) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ }
+ }
+ cleanup:
+ if (error != 0) {
+ apol_vector_destroy(tokens);
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Given a line, determine what type of audit message it is.
+ */
+static seaudit_message_type_e is_selinux(const char *line)
+{
+ if (strstr(line, BOOLMSG) && (strstr(line, "kernel") || strstr(line, AUDITD_MSG)))
+ return SEAUDIT_MESSAGE_TYPE_BOOL;
+ else if (strstr(line, LOADMSG) && (strstr(line, "kernel") || strstr(line, AUDITD_MSG)))
+ return SEAUDIT_MESSAGE_TYPE_LOAD;
+ else if (strstr(line, AVCMSG) && (strstr(line, "kernel") || strstr(line, AUDITD_MSG)))
+ return SEAUDIT_MESSAGE_TYPE_AVC;
+ else
+ return SEAUDIT_MESSAGE_TYPE_INVALID;
+}
+
+extern int daylight;
+
+ /**
+ * Fill in the date_stamp field of a message. If the stamp was not
+ * already allocated space then do it here.
+ *
+ * @return 0 on success, > 0 on warning, < 0 on error.
+ */
+static int insert_time(const seaudit_log_t * log, const apol_vector_t * tokens, size_t * position, seaudit_message_t * msg)
+{
+ char *t = NULL;
+ size_t i, length = 0;
+ int error;
+
+ if (*position + NUM_TIME_COMPONENTS >= apol_vector_get_size(tokens)) {
+ WARN(log, "%s", "Not enough tokens for time.");
+ return 1;
+ }
+ for (i = 0; i < NUM_TIME_COMPONENTS; i++) {
+ length += strlen((char *)apol_vector_get_element(tokens, i + *position));
+ }
+
+ /* Increase size for terminating string char and whitespace within. */
+ length += NUM_TIME_COMPONENTS;
+ if ((t = (char *)calloc(1, length)) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+
+ for (i = 0; i < NUM_TIME_COMPONENTS; i++) {
+ if (i > 0) {
+ strcat(t, " ");
+ }
+ strcat(t, (char *)apol_vector_get_element(tokens, *position));
+ (*position)++;
+ }
+
+ if (!msg->date_stamp) {
+ if ((msg->date_stamp = (struct tm *)calloc(1, sizeof(struct tm))) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ free(t);
+ errno = error;
+ return -1;
+ }
+ }
+
+ if (strptime(t, "%b %d %T", msg->date_stamp) != NULL) {
+ /* set year to 1900 since we know no valid logs were
+ * generated. this will tell us that the msg does not
+ * really have a year */
+ msg->date_stamp->tm_isdst = 0;
+ msg->date_stamp->tm_year = 0;
+ }
+ free(t);
+ return 0;
+}
+
+/**
+ * Fill in the host field of a message.
+ *
+ * @return 0 on success, > 0 on warning, < 0 on error.
+ */
+static int insert_hostname(const seaudit_log_t * log, const apol_vector_t * tokens, size_t * position, seaudit_message_t * msg)
+{
+ char *s, *host;
+ if (*position >= apol_vector_get_size(tokens)) {
+ WARN(log, "%s", "Not enough tokens for hostname.");
+ return 1;
+ }
+ s = apol_vector_get_element(tokens, *position);
+ /* Make sure this is not the kernel string identifier, which
+ * may indicate that the hostname is empty. */
+ if (strstr(s, "kernel")) {
+ msg->host = NULL;
+ return 1;
+ }
+ (*position)++;
+ if ((host = strdup(s)) == NULL || apol_bst_insert_and_get(log->hosts, (void **)&host, NULL) < 0) {
+ int error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ msg->host = host;
+ return 0;
+}
+
+static int insert_standard_msg_header(const seaudit_log_t * log, const apol_vector_t * tokens, size_t * position,
+ seaudit_message_t * msg)
+{
+ int ret = 0;
+ if ((ret = insert_time(log, tokens, position, msg)) != 0) {
+ return ret;
+ }
+ if ((ret = insert_hostname(log, tokens, position, msg)) != 0) {
+ return ret;
+ }
+ return ret;
+}
+
+/**
+ * Parse the object manager that generated this audit message.
+ */
+static int insert_manager(const seaudit_log_t * log, seaudit_message_t * msg, const char *manager)
+{
+ char *m;
+ if ((m = strdup(manager)) == NULL || apol_bst_insert_and_get(log->managers, (void **)&m, NULL) < 0) {
+ int error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ msg->manager = m;
+ return 0;
+}
+
+/**
+ * Parse a context (user:role:type). For each of the pieces, add them
+ * to the log's BSTs. Set reference pointers to those strings.
+ */
+static int parse_context(seaudit_log_t * log, char *token, char **user, char **role, char **type, char **mls_lvl, char **mls_clr)
+{
+ char *s, *range;
+ int error, ret = 0;
+ context_t con = context_new(token);
+ *user = *role = *type = *mls_lvl = *mls_clr = NULL;
+
+ if (con == NULL) {
+ WARN(log, "%s", "Error parsing context.");
+ ret = 1;
+ goto out;
+ }
+
+ if ((s = strdup(context_user_get(con))) == NULL || apol_bst_insert_and_get(log->users, (void **)&s, NULL) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ ret = -1;
+ goto out;
+ }
+ *user = s;
+
+ if ((s = strdup(context_role_get(con))) == NULL || apol_bst_insert_and_get(log->roles, (void **)&s, NULL) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ ret = -1;
+ goto out;
+ }
+ *role = s;
+
+ if ((s = strdup(context_type_get(con))) == NULL || apol_bst_insert_and_get(log->types, (void **)&s, NULL) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ ret = -1;
+ goto out;
+ }
+ *type = s;
+
+ if (range = context_range_get(con)) {
+ char *lvl, *clr;
+ lvl = strsep(&range, "-");
+ clr = strsep(&range, "-");
+ if (clr == NULL)
+ /* level and clearance are the same */
+ clr = lvl;
+
+ if ((s = strdup(lvl)) == NULL || apol_bst_insert_and_get(log->mls_lvl, (void **)&s, NULL) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ ret = -1;
+ goto out;
+ }
+ *mls_lvl = s;
+
+ if ((s = strdup(clr)) == NULL || apol_bst_insert_and_get(log->mls_clr, (void **)&s, NULL) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ ret = -1;
+ goto out;
+ }
+ *mls_clr = s;
+ }
+
+out:
+ context_free(con);
+ return ret;
+}
+
+/******************** AVC message parsing ********************/
+
+/**
+ * Given a token, determine if it is the new AVC header or not.
+ */
+static int avc_msg_is_token_new_audit_header(const char *token)
+{
+ return (strstr(token, SYSCALL_STRING) ? 1 : 0);
+}
+
+/**
+ * If the given token begins with prefix, then set reference pointer
+ * result to everything following prefix and return 1. Otherwise
+ * return 0.
+ */
+static int avc_msg_is_prefix(char *token, char *prefix, char **result)
+{
+ size_t i = 0, length;
+
+ length = strlen(prefix);
+ if (strlen(token) < length)
+ return 0;
+
+ for (i = 0; i < length; i++) {
+ if (token[i] != prefix[i]) {
+ return 0;
+ }
+ }
+
+ *result = token + length;
+ return 1;
+}
+
+/**
+ * Beginning with element *position, fill in the given avc message
+ * with all permissions found. Afterwards update *position to point
+ * to the next unprocessed token. Permissions should start and end
+ * with braces and if not, then this is invalid.
+ *
+ * @return 0 on success, > 0 on warning, < 0 on error.
+ */
+static int avc_msg_insert_perms(const seaudit_log_t * log, apol_vector_t * tokens, size_t * position, seaudit_avc_message_t * avc)
+{
+ char *s, *perm;
+ int error;
+ if ((s = apol_vector_get_element(tokens, *position)) == NULL || strcmp(s, "{") != 0) {
+ WARN(log, "%s", "Expected an opening brace while parsing permissions.");
+ return 1;
+ }
+ (*position)++;
+
+ while (*position < apol_vector_get_size(tokens)) {
+ s = apol_vector_get_element(tokens, *position);
+ assert(s != NULL);
+ (*position)++;
+ if (strcmp(s, "}") == 0) {
+ return 0;
+ }
+
+ if ((perm = strdup(s)) == NULL ||
+ apol_bst_insert_and_get(log->perms, (void **)&perm, NULL) < 0 || apol_vector_append(avc->perms, perm) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ }
+
+ /* if got here, then message is too short */
+ WARN(log, "%s", "Expected a closing brace while parsing permissions.");
+ return 1;
+}
+
+static int avc_msg_insert_syscall_info(const seaudit_log_t * log, char *token, seaudit_message_t * msg, seaudit_avc_message_t * avc)
+{
+ size_t length, header_len = 0, i = 0;
+ char *fields[PARSE_NUM_SYSCALL_FIELDS];
+ char *time_str = NULL;
+ time_t temp;
+
+ length = strlen(token);
+
+ /* Chop off the ':' at the end of the syscall info token */
+ if (token[length - 1] == ':') {
+ token[length - 1] = '\0';
+ length--;
+ }
+ /* Chop off the ')' at the end of the syscall info token */
+ if (token[length - 1] == ')') {
+ token[length - 1] = '\0';
+ length--;
+ }
+ header_len = strlen(SYSCALL_STRING);
+
+ /* Check to see if variations on syscall header exist */
+ if (strstr(token, ALT_SYSCALL_STRING)) {
+ header_len = strlen(ALT_SYSCALL_STRING);
+ }
+
+ time_str = token + header_len;
+ /* Parse seconds.nanoseconds:serial */
+ while (i < PARSE_NUM_SYSCALL_FIELDS && (fields[i] = strsep(&time_str, ".:")) != NULL) {
+ i++;
+ }
+
+ if (i != PARSE_NUM_SYSCALL_FIELDS) {
+ WARN(log, "%s", "Not enough fields for syscall info.");
+ return 1;
+ }
+
+ temp = (time_t) atol(fields[0]);
+ avc->tm_stmp_sec = temp;
+ avc->tm_stmp_nano = atoi(fields[1]);
+ avc->serial = atoi(fields[2]);
+
+ if (msg->date_stamp == NULL) {
+ if ((msg->date_stamp = (struct tm *)malloc(sizeof(struct tm))) == NULL) {
+ int error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ }
+ localtime_r(&temp, msg->date_stamp);
+ return 0;
+}
+
+static int avc_msg_insert_access_type(const seaudit_log_t * log, const char *token, seaudit_avc_message_t * avc)
+{
+ if (strcmp(token, "granted") == 0) {
+ avc->msg = SEAUDIT_AVC_GRANTED;
+ return 0;
+ } else if (strcmp(token, "denied") == 0) {
+ avc->msg = SEAUDIT_AVC_DENIED;
+ return 0;
+ }
+ WARN(log, "%s", "No AVC message type found, assuming it was a denial.");
+ avc->msg = SEAUDIT_AVC_DENIED;
+ return 1;
+}
+
+static int avc_msg_insert_scon(seaudit_log_t * log, seaudit_avc_message_t * avc, char *tmp)
+{
+ char *user, *role, *type, *mls_lvl, *mls_clr;
+ int retval;
+ if (tmp == NULL) {
+ WARN(log, "%s", "Invalid source context.");
+ return 1;
+ }
+ retval = parse_context(log, tmp, &user, &role, &type, &mls_lvl, &mls_clr);
+ if (retval != 0) {
+ return retval;
+ }
+ avc->suser = user;
+ avc->srole = role;
+ avc->stype = type;
+ avc->smls_lvl = mls_lvl;
+ avc->smls_clr = mls_clr;
+ return 0;
+}
+
+static int avc_msg_insert_tcon(seaudit_log_t * log, seaudit_avc_message_t * avc, char *tmp)
+{
+ char *user, *role, *type, *mls_lvl, *mls_clr;
+ int retval;
+ if (tmp == NULL) {
+ WARN(log, "%s", "Invalid target context.");
+ return 1;
+ }
+ retval = parse_context(log, tmp, &user, &role, &type, &mls_lvl, &mls_clr);
+ if (retval != 0) {
+ return retval;
+ }
+ avc->tuser = user;
+ avc->trole = role;
+ avc->ttype = type;
+ avc->tmls_lvl = mls_lvl;
+ avc->tmls_clr = mls_clr;
+ return 0;
+}
+
+static int avc_msg_insert_tclass(seaudit_log_t * log, seaudit_avc_message_t * avc, const char *tmp)
+{
+ char *tclass;
+ if ((tclass = strdup(tmp)) == NULL || apol_bst_insert_and_get(log->classes, (void **)&tclass, NULL) < 0) {
+ int error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ avc->tclass = tclass;
+ return 0;
+}
+
+static int avc_msg_insert_string(const seaudit_log_t * log, char *src, char **dest)
+{
+ if ((*dest = strdup(src)) == NULL) {
+ int error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Removes quotes from a string, this is currently to remove quotes
+ * from the command argument.
+ */
+static int avc_msg_remove_quotes_insert_string(const seaudit_log_t * log, char *src, char **dest)
+{
+ size_t i, j, l;
+
+ l = strlen(src);
+ /* see if there are any quotes to begin with if there aren't
+ * just run insert string */
+ if (src[0] == '\"' && l > 0 && src[l - 1] == '\"') {
+ if ((*dest = calloc(1, l + 1)) == NULL) {
+ int error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ for (i = 0, j = 0; i < l; i++) {
+ if (src[i] != '\"') {
+ (*dest)[j] = src[i];
+ j++;
+ }
+ }
+ return 0;
+ } else
+ return avc_msg_insert_string(log, src, dest);
+}
+
+/**
+ * If there is exactly one equal sign in orig_token then return 1.
+ * Otherwise return 0.
+ */
+static int avc_msg_is_valid_additional_field(const char *orig_token)
+{
+ char *first_eq = strchr(orig_token, '=');
+
+ if (first_eq == NULL) {
+ return 0;
+ }
+ if (strchr(first_eq + 1, '=') != NULL) {
+ return 0;
+ }
+ return 1;
+}
+
+static int avc_msg_reformat_path(const seaudit_log_t * log, seaudit_avc_message_t * avc, const char *token)
+{
+ int error;
+ if (avc->path == NULL) {
+ if ((avc->path = strdup(token)) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ } else {
+ size_t len = strlen(avc->path) + strlen(token) + 2;
+ char *s = realloc(avc->path, len);
+ if (s == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ avc->path = s;
+ strcat(avc->path, " ");
+ strcat(avc->path, token);
+ }
+ return 0;
+}
+
+/**
+ * Parse the remaining tokens of an AVC message, filling as much
+ * information as possible.
+ *
+ * @return 0 on success, > 0 if warnings, < 0 on error
+ */
+static int avc_msg_insert_additional_field_data(seaudit_log_t * log, apol_vector_t * tokens, seaudit_avc_message_t * avc,
+ size_t * position)
+{
+ char *token, *v;
+ int retval, has_warnings = 0;
+
+ avc->avc_type = SEAUDIT_AVC_DATA_FS;
+ for (; (*position) < apol_vector_get_size(tokens); (*position)++) {
+ token = apol_vector_get_element(tokens, (*position));
+ v = NULL;
+ if (strcmp(token, "") == 0) {
+ break;
+ }
+
+ if (!avc->is_pid && avc_msg_is_prefix(token, "pid=", &v)) {
+ avc->pid = atoi(v);
+ avc->is_pid = 1;
+ continue;
+ }
+
+ if (!avc->exe && avc_msg_is_prefix(token, "exe=", &v)) {
+ if (avc_msg_insert_string(log, v, &avc->exe) < 0) {
+ return -1;
+ }
+ continue;
+ }
+
+ if (!avc->comm && avc_msg_is_prefix(token, "comm=", &v)) {
+ if (avc_msg_remove_quotes_insert_string(log, v, &avc->comm) < 0) {
+ return -1;
+ }
+ continue;
+ }
+
+ /* Gather all tokens located after the path=XXXX token
+ * until we encounter a valid additional field. This
+ * is because a path name file name may be seperated
+ * by whitespace. Look ahead at the next token, but we
+ * make sure not to access memory beyond the total
+ * number of tokens. */
+ if (!avc->path && avc_msg_is_prefix(token, "path=", &v)) {
+ if (avc_msg_reformat_path(log, avc, v) < 0) {
+ return -1;
+ }
+ while (*position + 1 < apol_vector_get_size(tokens)) {
+ token = apol_vector_get_element(tokens, *position + 1);
+ if (avc_msg_is_valid_additional_field(token)) {
+ break;
+ }
+ (*position)++;
+ if (avc_msg_reformat_path(log, avc, token) < 0) {
+ return -1;
+ }
+ }
+ continue;
+ }
+
+ if (!avc->name && avc_msg_is_prefix(token, "name=", &v)) {
+ if (avc_msg_remove_quotes_insert_string(log, v, &avc->name) < 0) {
+ return -1;
+ }
+ continue;
+ }
+
+ if (!avc->dev && avc_msg_is_prefix(token, "dev=", &v)) {
+ if (avc_msg_insert_string(log, v, &avc->dev) < 0) {
+ return -1;
+ }
+ continue;
+ }
+
+ if (!avc->saddr && avc_msg_is_prefix(token, "saddr=", &v)) {
+ if (avc_msg_insert_string(log, v, &avc->saddr) < 0) {
+ return -1;
+ }
+ continue;
+ }
+
+ if (!avc->source && (avc_msg_is_prefix(token, "source=", &v) || avc_msg_is_prefix(token, "src=", &v))) {
+ avc->source = atoi(v);
+ continue;
+ }
+
+ if (!avc->daddr && avc_msg_is_prefix(token, "daddr=", &v)) {
+ if (avc_msg_insert_string(log, v, &avc->daddr)) {
+ return -1;
+ }
+ continue;
+ }
+
+ if (!avc->dest && avc_msg_is_prefix(token, "dest=", &v)) {
+ avc->dest = atoi(v);
+ continue;
+ }
+
+ if (!avc->netif && avc_msg_is_prefix(token, "netif=", &v)) {
+ if (avc_msg_insert_string(log, v, &avc->netif)) {
+ return -1;
+ }
+ avc->avc_type = SEAUDIT_AVC_DATA_NET;
+ continue;
+ }
+
+ if (!avc->laddr && avc_msg_is_prefix(token, "laddr=", &v)) {
+ if (avc_msg_insert_string(log, v, &avc->laddr)) {
+ return -1;
+ }
+ continue;
+ }
+
+ if (!avc->lport && avc_msg_is_prefix(token, "lport=", &v)) {
+ avc->lport = atoi(v);
+ avc->avc_type = SEAUDIT_AVC_DATA_NET;
+ continue;
+ }
+
+ if (!avc->faddr && avc_msg_is_prefix(token, "faddr=", &v)) {
+ if (avc_msg_insert_string(log, v, &avc->faddr)) {
+ return -1;
+ }
+ continue;
+ }
+
+ if (!avc->fport && avc_msg_is_prefix(token, "fport=", &v)) {
+ avc->fport = atoi(v);
+ continue;
+ }
+
+ if (!avc->port && avc_msg_is_prefix(token, "port=", &v)) {
+ avc->port = atoi(v);
+ avc->avc_type = SEAUDIT_AVC_DATA_NET;
+ continue;
+ }
+
+ if (!avc->is_src_sid && avc_msg_is_prefix(token, "ssid=", &v)) {
+ avc->src_sid = (unsigned int)strtoul(v, NULL, 10);
+ avc->is_src_sid = 1;
+ continue;
+ }
+
+ if (!avc->is_tgt_sid && avc_msg_is_prefix(token, "tsid=", &v)) {
+ avc->tgt_sid = (unsigned int)strtoul(v, NULL, 10);
+ avc->is_tgt_sid = 1;
+ continue;
+ }
+
+ if (!avc->is_capability && avc_msg_is_prefix(token, "capability=", &v)) {
+ avc->capability = atoi(v);
+ avc->is_capability = 1;
+ avc->avc_type = SEAUDIT_AVC_DATA_CAP;
+ continue;
+ }
+
+ if (!avc->is_key && avc_msg_is_prefix(token, "key=", &v)) {
+ avc->key = atoi(v);
+ avc->is_key = 1;
+ avc->avc_type = SEAUDIT_AVC_DATA_IPC;
+ continue;
+ }
+
+ if (!avc->is_inode && avc_msg_is_prefix(token, "ino=", &v)) {
+ avc->inode = strtoul(v, NULL, 10);
+ avc->is_inode = 1;
+ continue;
+ }
+
+ if (!avc->ipaddr && avc_msg_is_prefix(token, "ipaddr=", &v)) {
+ if (avc_msg_insert_string(log, v, &avc->ipaddr)) {
+ return -1;
+ }
+ continue;
+ }
+
+ if (!avc->suser && avc_msg_is_prefix(token, "scontext=", &v)) {
+ retval = avc_msg_insert_scon(log, avc, v);
+ if (retval < 0) {
+ return retval;
+ } else if (retval > 0) {
+ has_warnings = 1;
+ }
+ continue;
+ }
+
+ if (!avc->tuser && avc_msg_is_prefix(token, "tcontext=", &v)) {
+ retval = avc_msg_insert_tcon(log, avc, v);
+ if (retval < 0) {
+ return retval;
+ } else if (retval > 0) {
+ has_warnings = 1;
+ }
+ continue;
+ }
+
+ if (!avc->tclass && avc_msg_is_prefix(token, "tclass=", &v)) {
+ if (avc_msg_insert_tclass(log, avc, v) < 0) {
+ return -1;
+ }
+ continue;
+ }
+ /* found a field that this parser did not understand,
+ * so flag the entire message as a warning */
+ has_warnings = 1;
+ }
+
+ /* can't have both a sid and a context */
+ if ((avc->is_src_sid && avc->suser) || (avc->is_tgt_sid && avc->tuser)) {
+ has_warnings = 1;
+ }
+
+ if (!avc->tclass) {
+ has_warnings = 1;
+ }
+
+ if (has_warnings) {
+ avc->avc_type = SEAUDIT_AVC_DATA_MALFORMED;
+ }
+
+ return has_warnings;
+}
+
+static int avc_parse(seaudit_log_t * log, apol_vector_t * tokens)
+{
+ seaudit_message_t *msg;
+ seaudit_avc_message_t *avc;
+ seaudit_message_type_e type;
+ int ret, has_warnings = 0;
+ size_t position = 0, num_tokens = apol_vector_get_size(tokens);
+ char *token, *t;
+
+ if ((msg = message_create(log, SEAUDIT_MESSAGE_TYPE_AVC)) == NULL) {
+ return -1;
+ }
+ avc = seaudit_message_get_data(msg, &type);
+
+ token = apol_vector_get_element(tokens, position);
+
+ /* Check for new auditd log format */
+ if (strstr(token, AUDITD_MSG)) {
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for audit header.");
+ return 1;
+ }
+ log->logtype = SEAUDIT_LOG_TYPE_AUDITD;
+ token = apol_vector_get_element(tokens, position);
+ }
+
+ /* Insert the audit header if it exists */
+ if (avc_msg_is_token_new_audit_header(token)) {
+ ret = avc_msg_insert_syscall_info(log, token, msg, avc);
+ if (ret < 0) {
+ return ret;
+ } else if (ret > 0) {
+ has_warnings = 1;
+ } else {
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for new audit header.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+ } else {
+ ret = insert_standard_msg_header(log, tokens, &position, msg);
+ if (ret < 0) {
+ return ret;
+ } else if (ret > 0) {
+ has_warnings = 1;
+ }
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for new audit header.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+
+ /* for now, only let avc messages set their object
+ * manager */
+ if ((t = strrchr(token, ':')) == NULL) {
+ WARN(log, "%s", "Expected to find an object manager here.");
+ has_warnings = 1;
+ /* Hold the position */
+ } else {
+ *t = '\0';
+ if ((ret = insert_manager(log, msg, token)) < 0) {
+ return ret;
+ }
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for new audit header.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+
+ /* new style audit messages can show up in syslog
+ * files starting with FC5. This means that both the
+ * old kernel: header and the new audit header might
+ * be present. So, here we check again for the audit
+ * message.
+ */
+ if (avc_msg_is_token_new_audit_header(token)) {
+ ret = avc_msg_insert_syscall_info(log, token, msg, avc);
+ if (ret < 0) {
+ return ret;
+ } else if (ret > 0) {
+ has_warnings = 1;
+ } else {
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for new audit header.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+ }
+ }
+
+ /* Make sure the following token is the string "avc:" */
+ if (strcmp(token, "avc:") != 0) {
+ /* Hold the position */
+ has_warnings = 1;
+ WARN(log, "%s", "Expected an avc: token here.");
+ } else {
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for new audit header.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+
+ /* Insert denied or granted */
+ if (avc_msg_insert_access_type(log, token, avc)) {
+ has_warnings = 1;
+ } else {
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for new audit header.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+
+ /* Insert perm(s) */
+ ret = avc_msg_insert_perms(log, tokens, &position, avc);
+ if (ret < 0) {
+ return ret;
+ } else if (ret > 0) {
+ has_warnings = 1;
+ }
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Message appears to be truncated.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+
+ if (strcmp(token, "for") != 0) {
+ /* Hold the position */
+ has_warnings = 1;
+ WARN(log, "%s", "Expected a 'for' token here.");
+ } else {
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for new audit header.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+
+ /* At this point we have a valid message, for we have gathered
+ * all of the standard fields so insert anything else. If
+ * nothing else is left, the message is still considered
+ * valid. */
+ ret = avc_msg_insert_additional_field_data(log, tokens, avc, &position);
+ if (ret < 0) {
+ return ret;
+ } else if (ret > 0) {
+ has_warnings = 1;
+ }
+
+ return has_warnings;
+}
+
+/******************** boolean parsing ********************/
+
+static int boolean_msg_insert_bool(seaudit_log_t * log, seaudit_bool_message_t * boolm, char *token)
+{
+ size_t len = strlen(token);
+ int value;
+
+ /* Strip off ending comma */
+ if (token[len - 1] == ',') {
+ token[len - 1] = '\0';
+ len--;
+ }
+
+ if (token[len - 2] != ':') {
+ WARN(log, "%s", "Boolean change was not in correct format.");
+ return 1;
+ }
+
+ if (token[len - 1] == '0')
+ value = 0;
+ else if (token[len - 1] == '1')
+ value = 1;
+ else {
+ WARN(log, "%s", "Invalid new boolean value.");
+ return 1;
+ }
+
+ token[len - 2] = '\0';
+
+ return bool_change_append(log, boolm, token, value);
+}
+
+static int bool_parse(seaudit_log_t * log, apol_vector_t * tokens)
+{
+ seaudit_message_t *msg;
+ seaudit_bool_message_t *boolm;
+ seaudit_message_type_e type;
+ int ret, has_warnings = 0, next_line = log->next_line;
+ size_t position = 0, num_tokens = apol_vector_get_size(tokens);
+ char *token;
+
+ if (log->next_line) {
+ /* still processing a boolean change message, so don't
+ * create a new one */
+ size_t num_messages = apol_vector_get_size(log->messages);
+ assert(num_messages > 0);
+ msg = apol_vector_get_element(log->messages, num_messages - 1);
+ log->next_line = 0;
+ } else {
+ if ((msg = message_create(log, SEAUDIT_MESSAGE_TYPE_BOOL)) == NULL) {
+ return -1;
+ }
+ }
+ boolm = seaudit_message_get_data(msg, &type);
+
+ ret = insert_standard_msg_header(log, tokens, &position, msg);
+ if (ret < 0) {
+ return ret;
+ } else if (ret > 0) {
+ has_warnings = 1;
+ }
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for boolean change.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+
+ /* Make sure the following token is the string "kernel:" */
+ if (!strstr(token, "kernel:")) {
+ WARN(log, "%s", "Expected to see kernel here.");
+ has_warnings = 1;
+ /* Hold the position */
+ } else {
+ if ((ret = insert_manager(log, msg, "kernel")) < 0) {
+ return ret;
+ }
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for boolean change.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+
+ if (!next_line) {
+ if (!strstr(token, "security:")) {
+ WARN(log, "%s", "Expected to see security here.");
+ has_warnings = 1;
+ /* Hold the position */
+ } else {
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for boolean change.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+
+ if (!strstr(token, "committed")) {
+ WARN(log, "%s", "Expected to see committed here.");
+ has_warnings = 1;
+ /* Hold the position */
+ } else {
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for boolean change.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+
+ if (!strstr(token, "booleans")) {
+ WARN(log, "%s", "Expected to see booleans here.");
+ has_warnings = 1;
+ /* Hold the position */
+ } else {
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for boolean change.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+
+ if (!strstr(token, "{")) {
+ WARN(log, "%s", "Expected to see '{' here.");
+ has_warnings = 1;
+ /* Hold the position */
+ } else {
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for boolean change.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+ }
+
+ /* keep parsing until a closing brace is found. if end of
+ * tokens is reached, then keep parsing the next line */
+ while (position < num_tokens) {
+ token = apol_vector_get_element(tokens, position);
+ position++;
+
+ if (!strcmp(token, "}")) {
+ if (position < num_tokens) {
+ WARN(log, "%s", "Excess tokens after closing brace");
+ has_warnings = 1;
+ }
+ return has_warnings;
+ }
+
+ ret = boolean_msg_insert_bool(log, boolm, token);
+ if (ret < 0) {
+ return ret;
+ } else if (ret > 0) {
+ has_warnings = 1;
+ }
+ }
+
+ /* did not find a closing brace yet */
+ log->next_line = 1;
+ return has_warnings;
+}
+
+/******************** policy load parsing ********************/
+
+/**
+ * Determine if a series of tokens represents the older style of a
+ * policy load.
+ *
+ * @return 0 if not older style, 1 if it is the older style, < 0 on
+ * error. If it is the older style, then increment reference pointer
+ * position to point to the next unprocessed token.
+ */
+static int load_policy_msg_is_old_load_policy_string(const seaudit_log_t * log, const apol_vector_t * tokens, size_t * position)
+{
+ size_t i, length = 0;
+ int rt;
+ char *tmp = NULL;
+ if (*position + 4 >= apol_vector_get_size(tokens)) {
+ return 0;
+ }
+
+ for (i = 0; i < 4; i++) {
+ length += strlen((char *)apol_vector_get_element(tokens, i + *position));
+ }
+
+ if ((tmp = (char *)calloc(length + 1, sizeof(char))) == NULL) {
+ int error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+
+ for (i = 0; i < 4; i++) {
+ strcat(tmp, (char *)apol_vector_get_element(tokens, i + *position));
+ }
+
+ rt = strcmp(tmp, OLD_LOAD_POLICY_STRING);
+ free(tmp);
+
+ if (rt == 0) {
+ *position += 4;
+ return 1;
+ } else
+ return 0;
+}
+
+static void load_policy_msg_get_policy_components(seaudit_load_message_t * load, const apol_vector_t * tokens, size_t * position)
+{
+ char *arg = apol_vector_get_element(tokens, *position);
+ char *endptr;
+ unsigned int val = (unsigned int)strtoul(arg, &endptr, 10);
+ if (*endptr != '\0') {
+ /* found a key-value pair where the key is not a
+ * number, so skip this */
+ (*position)++;
+ return;
+ }
+ char *id = apol_vector_get_element(tokens, *position + 1);
+ assert(id != NULL && arg != NULL);
+ if (load->classes == 0 && strstr(id, "classes")) {
+ load->classes = val;
+ } else if (load->rules == 0 && strstr(id, "rules")) {
+ load->rules = val;
+ } else if (load->users == 0 && strstr(id, "users")) {
+ load->users = val;
+ } else if (load->roles == 0 && strstr(id, "roles")) {
+ load->roles = val;
+ } else if (load->types == 0 && strstr(id, "types")) {
+ load->types = val;
+ } else if (load->bools == 0 && strstr(id, "bools")) {
+ load->bools = val;
+ }
+ *position += 2;
+}
+
+static int load_parse(seaudit_log_t * log, const apol_vector_t * tokens)
+{
+ seaudit_message_t *msg;
+ seaudit_load_message_t *load;
+ seaudit_message_type_e type;
+ int ret, error, has_warnings = 0;
+ size_t position = 0, num_tokens = apol_vector_get_size(tokens);
+ char *token;
+
+ if (log->next_line) {
+ /* still processing a load message, so don't create a
+ * new one */
+ size_t num_messages = apol_vector_get_size(log->messages);
+ assert(num_messages > 0);
+ msg = apol_vector_get_element(log->messages, num_messages - 1);
+ log->next_line = 0;
+ } else {
+ if ((msg = message_create(log, SEAUDIT_MESSAGE_TYPE_LOAD)) == NULL) {
+ return -1;
+ }
+ }
+ load = seaudit_message_get_data(msg, &type);
+
+ ret = insert_standard_msg_header(log, tokens, &position, msg);
+ if (ret < 0) {
+ return ret;
+ } else if (ret > 0) {
+ has_warnings = 1;
+ }
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for policy load.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+
+ if (strcmp(token, "invalidating") == 0) {
+ WARN(log, "%s", "Got an unexpected invalidating message.");
+ return 1;
+ }
+
+ if (position + 1 >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for policy load.");
+ return 1;
+ }
+ if (strcmp((char *)apol_vector_get_element(tokens, position + 1), "bools") == 0) {
+ WARN(log, "%s", "Got an unexpected bools message.");
+ return 1;
+ }
+
+ /* Check the following token for the string "kernel:" */
+ if (!strstr(token, "kernel:")) {
+ WARN(log, "%s", "Expected to see kernel here.");
+ has_warnings = 1;
+ /* Hold the position */
+ } else {
+ if ((ret = insert_manager(log, msg, "kernel")) < 0) {
+ return ret;
+ }
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for policy load.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+
+ if (strcmp(token, "security:")) {
+ WARN(log, "%s", "Expected to see security here.");
+ has_warnings = 1;
+ /* Hold the position */
+ } else {
+ position++;
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for policy load.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ }
+
+ ret = load_policy_msg_is_old_load_policy_string(log, tokens, &position);
+ if (ret < 0) {
+ return ret;
+ } else if (ret > 0) {
+ if (position >= num_tokens) {
+ WARN(log, "%s", "Not enough tokens for policy load.");
+ return 1;
+ }
+ token = apol_vector_get_element(tokens, position);
+ if ((load->binary = strdup(token)) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ log->next_line = 1;
+ } else {
+ while (position < num_tokens) {
+ load_policy_msg_get_policy_components(load, tokens, &position);
+ }
+ /* Check to see if we have gathered ALL policy
+ * components. If not, we need to load the next
+ * line. */
+ if (load->classes == 0 || load->rules == 0 || load->users == 0 || load->roles == 0 || load->types == 0) {
+ log->next_line = 1;
+ }
+ }
+ return has_warnings;
+}
+
+/**
+ * Parse a single nul-terminated line from an selinux audit log.
+ */
+static int seaudit_log_parse_line(seaudit_log_t * log, char *line)
+{
+ char *orig_line = NULL;
+ seaudit_message_t *prev_message;
+ seaudit_message_type_e is_sel, prev_message_type;
+ apol_vector_t *tokens = NULL;
+ int retval = -1, retval2, has_warnings = 0, error = 0;
+
+ is_sel = is_selinux(line);
+ if (log->next_line) {
+ prev_message = apol_vector_get_element(log->messages, apol_vector_get_size(log->messages) - 1);
+ seaudit_message_get_data(prev_message, &prev_message_type);
+ if (!(is_sel == SEAUDIT_MESSAGE_TYPE_INVALID && prev_message_type == SEAUDIT_MESSAGE_TYPE_BOOL) &&
+ !(is_sel == SEAUDIT_MESSAGE_TYPE_LOAD && prev_message_type == SEAUDIT_MESSAGE_TYPE_LOAD)) {
+ WARN(log, "%s", "Parser was in the middle of a line, but next message was not the correct format.");
+ has_warnings = 1;
+ log->next_line = 0;
+ } else {
+ is_sel = prev_message_type;
+ }
+ }
+ if (is_sel == SEAUDIT_MESSAGE_TYPE_INVALID) {
+ /* unknown line, so ignore it */
+ return 0;
+ }
+
+ if ((orig_line = strdup(line)) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ if (get_tokens(log, line, &tokens) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+
+ switch (is_sel) {
+ case SEAUDIT_MESSAGE_TYPE_AVC:
+ retval2 = avc_parse(log, tokens);
+ break;
+ case SEAUDIT_MESSAGE_TYPE_BOOL:
+ retval2 = bool_parse(log, tokens);
+ break;
+ case SEAUDIT_MESSAGE_TYPE_LOAD:
+ retval2 = load_parse(log, tokens);
+ break;
+ default:
+ /* should never get here */
+ assert(0);
+ errno = EINVAL;
+ retval2 = -1;
+ }
+ if (retval2 < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ } else if (retval2 > 0) {
+ if (apol_vector_append(log->malformed_msgs, orig_line) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ orig_line = NULL;
+ has_warnings = 1;
+ }
+
+ retval = 0;
+ cleanup:
+ free(orig_line);
+ apol_vector_destroy(&tokens);
+ if (retval < 0) {
+ errno = error;
+ return -1;
+ }
+ return has_warnings;
+}
+
+/******************** public functions below ********************/
+
+int seaudit_log_parse(seaudit_log_t * log, FILE * syslog)
+{
+ FILE *audit_file = syslog;
+ char *line = NULL;
+ int retval = -1, retval2, has_warnings = 0, error = 0;
+ size_t line_size = 0, i;
+
+ if (log == NULL || syslog == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ error = EINVAL;
+ goto cleanup;
+ }
+
+ if (!log->tz_initialized) {
+ tzset();
+ log->tz_initialized = 1;
+ }
+
+ clearerr(audit_file);
+
+ while (1) {
+ if (getline(&line, &line_size, audit_file) < 0) {
+ error = errno;
+ if (!feof(audit_file)) {
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ break;
+ }
+ apol_str_trim(line);
+ retval2 = seaudit_log_parse_line(log, line);
+ if (retval2 < 0) {
+ error = errno;
+ goto cleanup;
+ } else if (retval2 > 0) {
+ has_warnings = 1;
+ }
+ }
+
+ retval = 0;
+ cleanup:
+ free(line);
+ for (i = 0; i < apol_vector_get_size(log->models); i++) {
+ seaudit_model_t *m = apol_vector_get_element(log->models, i);
+ model_notify_log_changed(m, log);
+ }
+ if (retval < 0) {
+ errno = error;
+ return -1;
+ }
+ if (has_warnings) {
+ WARN(log, "%s", "Audit log was parsed, but there were one or more invalid message found within it.");
+ }
+ return has_warnings;
+}
+
+int seaudit_log_parse_buffer(seaudit_log_t * log, const char *buffer, const size_t bufsize)
+{
+ const char *s;
+ char *line = NULL, *l;
+ int retval = -1, retval2, has_warnings = 0, error = 0;
+ size_t offset = 0, line_size, i;
+
+ if (log == NULL || buffer == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ error = EINVAL;
+ goto cleanup;
+ }
+
+ if (!log->tz_initialized) {
+ tzset();
+ log->tz_initialized = 1;
+ }
+
+ while (offset < bufsize) {
+ /* create a new string up to the first newline or end of
+ * buffer, whichever comes first */
+ for (s = buffer + offset; s < buffer + bufsize && *s != '\n'; s++) ;
+ line_size = s - (buffer + offset);
+ assert(line_size > 0);
+ if ((l = realloc(line, line_size + 1)) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ line = l;
+ memcpy(line, buffer + offset, line_size);
+ line[line_size] = '\0';
+ offset += line_size;
+ if (s < buffer + bufsize) {
+ /* this branch can only be true if not at end of file */
+ assert(*s == '\n');
+ offset++;
+ }
+ apol_str_trim(line);
+ retval2 = seaudit_log_parse_line(log, line);
+ if (retval2 < 0) {
+ error = errno;
+ goto cleanup;
+ } else if (retval2 > 0) {
+ has_warnings = 1;
+ }
+ }
+
+ retval = 0;
+ cleanup:
+ free(line);
+ for (i = 0; i < apol_vector_get_size(log->models); i++) {
+ seaudit_model_t *m = apol_vector_get_element(log->models, i);
+ model_notify_log_changed(m, log);
+ }
+ if (retval < 0) {
+ errno = error;
+ return -1;
+ }
+ if (has_warnings) {
+ WARN(log, "%s", "Audit log was parsed, but there were one or more invalid message found within it.");
+ }
+ return has_warnings;
+}
diff --git a/libseaudit/src/report.c b/libseaudit/src/report.c
new file mode 100644
index 0000000..9b198c5
--- /dev/null
+++ b/libseaudit/src/report.c
@@ -0,0 +1,1060 @@
+/**
+ * @file
+ * Implementation of seaudit report generator.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "seaudit_internal.h"
+
+#include <seaudit/report.h>
+
+#include <apol/util.h>
+#include <libxml/xmlreader.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define CONFIG_FILE "seaudit-report.conf"
+#define STYLESHEET_FILE "seaudit-report.css"
+#define LINE_MAX 1024
+
+struct seaudit_report
+{
+ /** output format for the report */
+ seaudit_report_format_e format;
+ /** path to configuration file, or NULL to use system configuration */
+ char *config;
+ /** path to HTML stylesheet, or NULL to use system stylesheet */
+ char *stylesheet;
+ /** if non-zero, then use a stylesheet when generating HTML reports */
+ int use_stylesheet;
+ /** if non-zero, then print malformed messages */
+ int malformed;
+ /** model from which messages will be obtained */
+ seaudit_model_t *model;
+};
+
+static const char *seaudit_report_node_names[] = {
+ "seaudit-report",
+ "standard-section",
+ "custom-section",
+ "view",
+ NULL
+};
+
+static const char *seaudit_standard_section_names[] = {
+ "PolicyLoads",
+ "EnforcementToggles",
+ "PolicyBooleans",
+ "Statistics",
+ "AllowListing",
+ "DenyListing",
+ NULL
+};
+
+seaudit_report_t *seaudit_report_create(seaudit_model_t * model)
+{
+ seaudit_report_t *r = calloc(1, sizeof(*r));
+ if (r == NULL) {
+ return NULL;
+ }
+ r->model = model;
+ return r;
+}
+
+void seaudit_report_destroy(seaudit_report_t ** report)
+{
+ if (report == NULL || *report == NULL) {
+ return;
+ }
+ free((*report)->config);
+ free((*report)->stylesheet);
+ free(*report);
+ *report = NULL;
+}
+
+int seaudit_report_set_format(const seaudit_log_t * log, seaudit_report_t * report, seaudit_report_format_e format)
+{
+ if (report == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ report->format = format;
+ return 0;
+}
+
+/**
+ * Set the report's configuration file to the default system file.
+ */
+static int report_set_default_configuration(const seaudit_log_t * log, seaudit_report_t * report)
+{
+ char *config_dir = apol_file_find(CONFIG_FILE);
+ int error;
+
+ if (config_dir == NULL) {
+ error = errno;
+ ERR(log, "%s", "Could not find default configuration file.");
+ errno = error;
+ return -1;
+ }
+ if (asprintf(&report->config, "%s/%s", config_dir, CONFIG_FILE) < 0) {
+ error = errno;
+ report->config = NULL;
+ free(config_dir);
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ free(config_dir);
+
+ /* check if can read the file */
+ if (access(report->config, R_OK) != 0) {
+ error = errno;
+ ERR(log, "Could not read default config file %s.", report->config);
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+int seaudit_report_set_configuration(const seaudit_log_t * log, seaudit_report_t * report, const char *file)
+{
+ if (report == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ free(report->config);
+ report->config = NULL;
+ if (file == NULL) {
+ return report_set_default_configuration(log, report);
+ } else {
+ if ((report->config = strdup(file)) == NULL) {
+ int error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ return 0;
+ }
+}
+
+/**
+ * Set the report's stylesheet to the default system stylesheet.
+ */
+static int report_set_default_stylesheet(const seaudit_log_t * log, seaudit_report_t * report)
+{
+ char *dir = apol_file_find(STYLESHEET_FILE);
+ int error;
+ if (dir == NULL) {
+ error = errno;
+ ERR(log, "%s", "Could not find default stylesheet.");
+ errno = error;
+ return -1;
+ }
+
+ if (asprintf(&report->stylesheet, "%s/%s", dir, STYLESHEET_FILE) < 0) {
+ error = errno;
+ report->stylesheet = NULL;
+ free(dir);
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ free(dir);
+
+ return 0;
+}
+
+int seaudit_report_set_stylesheet(const seaudit_log_t * log, seaudit_report_t * report, const char *file, const int use_stylesheet)
+{
+ if (report == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ free(report->stylesheet);
+ report->stylesheet = NULL;
+ report->use_stylesheet = use_stylesheet;
+ if (file == NULL) {
+ return report_set_default_stylesheet(log, report);
+ } else {
+ if ((report->stylesheet = strdup(file)) == NULL) {
+ return -1;
+ int error = errno;
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ return 0;
+ }
+}
+
+int seaudit_report_set_malformed(const seaudit_log_t * log, seaudit_report_t * report, const int do_malformed)
+{
+ if (report == NULL) {
+ ERR(log, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+ report->malformed = do_malformed;
+ return 0;
+}
+
+/**
+ * Insert the contents of the stylesheet into the output file. If it
+ * is not readable then generate a warning. This is not an error
+ * because the stylesheet is not strictly necessary.
+ */
+static int report_import_html_stylesheet(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
+{
+ char line[LINE_MAX], *line_ptr = NULL;
+ FILE *fp;
+
+ if (report->use_stylesheet) {
+ fp = fopen(report->stylesheet, "r");
+ if (fp == NULL) {
+ WARN(log, "Cannot open stylesheet file %s.", report->stylesheet);
+ return 1;
+ }
+ fprintf(outfile, "<style type=\"text/css\">\n");
+
+ while (fgets(line, LINE_MAX, fp) != NULL) {
+ free(line_ptr);
+ line_ptr = NULL;
+ if ((line_ptr = strdup(line)) == NULL) {
+ int error = errno;
+ free(line_ptr);
+ fclose(fp);
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ apol_str_trim(line_ptr);
+ if (line_ptr[0] == '#' || apol_str_is_only_white_space(line_ptr))
+ continue;
+ fprintf(outfile, "%s\n", line_ptr);
+ }
+ fprintf(outfile, "</style>\n");
+ fclose(fp);
+ free(line_ptr);
+ }
+ return 0;
+}
+
+static int report_print_header(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
+{
+ time_t ltime;
+
+ time(&ltime);
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ fprintf(outfile, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n");
+ fprintf(outfile, "<html>\n<head>\n");
+ if (report_import_html_stylesheet(log, report, outfile) < 0) {
+ return -1;
+ }
+ fprintf(outfile, "<title>seaudit-report</title>\n</head>\n");
+ fprintf(outfile, "<body>\n");
+ fprintf(outfile, "<b class=\"report_date\"># Report generated by seaudit-report on %s</b><br>\n", ctime(&ltime));
+ } else {
+ fprintf(outfile, "# Begin\n\n");
+ fprintf(outfile, "# Report generated by seaudit-report on %s\n", ctime(&ltime));
+ }
+ return 0;
+}
+
+static int report_print_footer(const seaudit_report_t * report, FILE * outfile)
+{
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ fprintf(outfile, "</body>\n</html>\n");
+ } else {
+ fprintf(outfile, "# End\n");
+ }
+ return 0;
+}
+
+static int report_is_valid_node_name(const char *name)
+{
+ size_t i;
+ for (i = 0; seaudit_report_node_names[i] != NULL; i++)
+ if (strcmp(seaudit_report_node_names[i], name) == 0)
+ return 1;
+ return 0;
+}
+
+static int report_is_valid_section_name(const char *name)
+{
+ size_t i;
+ for (i = 0; seaudit_standard_section_names[i] != NULL; i++)
+ if (strcmp(seaudit_standard_section_names[i], name) == 0)
+ return 1;
+ return 0;
+}
+
+static int report_parse_seaudit_report(const seaudit_log_t * log, const seaudit_report_t * report __attribute__ ((unused)),
+ xmlTextReaderPtr reader, xmlChar ** id_value
+ __attribute__ ((unused)), xmlChar ** title_value)
+{
+ int rt, error;
+ xmlChar *name = NULL;
+
+ if (xmlTextReaderNodeType(reader) == 1 && xmlTextReaderAttributeCount(reader) > 0) {
+ /* Parse attributes */
+ rt = xmlTextReaderMoveToNextAttribute(reader);
+ while (rt > 0) {
+ name = xmlTextReaderName(reader);
+ if (name == NULL) {
+ error = errno;
+ ERR(log, "%s", "Attribute name unavailable.");
+ errno = error;
+ return -1;
+ }
+ if (strcmp((char *)name, "title") == 0) {
+ *title_value = xmlTextReaderValue(reader);
+ }
+
+ xmlFree(name);
+ rt = xmlTextReaderMoveToNextAttribute(reader);
+ }
+ if (rt < 0) {
+ error = errno;
+ ERR(log, "%s", "Error parsing attribute for seaudit-report node.");
+ errno = error;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int report_parse_standard_attribs(const seaudit_log_t * log, const seaudit_report_t * report __attribute__ ((unused)),
+ xmlTextReaderPtr reader, xmlChar ** id_value, xmlChar ** title_value)
+{
+ int rt, error;
+ xmlChar *name = NULL;
+
+ if (xmlTextReaderNodeType(reader) == 1 && xmlTextReaderAttributeCount(reader) > 0) {
+ /* Parse attributes */
+ rt = xmlTextReaderMoveToNextAttribute(reader);
+ while (rt > 0) {
+ name = xmlTextReaderName(reader);
+ if (name == NULL) {
+ error = errno;
+ ERR(log, "%s", "Attribute name unavailable.");
+ errno = error;
+ return -1;
+ }
+ if (strcmp((char *)name, "id") == 0) {
+ *id_value = xmlTextReaderValue(reader);
+ } else if (strcmp((char *)name, "title") == 0) {
+ *title_value = xmlTextReaderValue(reader);
+ }
+ xmlFree(name);
+ rt = xmlTextReaderMoveToNextAttribute(reader);
+ }
+ if (rt < 0) {
+ error = errno;
+ ERR(log, "%s", "Error parsing attribute for standard-section node.");
+ errno = error;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int report_parse_custom_attribs(const seaudit_log_t * log, const seaudit_report_t * report __attribute__ ((unused)),
+ xmlTextReaderPtr reader, xmlChar ** title_value)
+{
+ int rt, error;
+ xmlChar *name = NULL;
+
+ if (xmlTextReaderNodeType(reader) == 1 && xmlTextReaderAttributeCount(reader) > 0) {
+ /* Parse attributes */
+ rt = xmlTextReaderMoveToNextAttribute(reader);
+ while (rt > 0) {
+ name = xmlTextReaderName(reader);
+ if (name == NULL) {
+ error = errno;
+ ERR(log, "%s", "Attribute name unavailable.");
+ errno = error;
+ return -1;
+ }
+ if (strcmp((char *)name, "title") == 0) {
+ *title_value = xmlTextReaderValue(reader);
+ }
+
+ xmlFree(name);
+ rt = xmlTextReaderMoveToNextAttribute(reader);
+ }
+ if (rt < 0) {
+ error = errno;
+ ERR(log, "%s", "Error parsing attribute for custom-section node.");
+ errno = error;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Allocate and return a filter for setenforce toggles. (Actually, it
+ * can't filter on permissions.)
+ */
+static seaudit_filter_t *report_enforce_toggle_filter_create(const seaudit_log_t * log, const seaudit_report_t * report
+ __attribute__ ((unused)))
+{
+ seaudit_filter_t *filter = NULL;
+ apol_vector_t *type_v = NULL, *class_v;
+ int retval = -1, error = 0;
+ char *tgt_type = "security_t";
+ char *obj_class = "security";
+
+ if ((filter = seaudit_filter_create(NULL)) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ if ((type_v = apol_vector_create_with_capacity(1, NULL)) == NULL ||
+ apol_vector_append(type_v, tgt_type) < 0 || seaudit_filter_set_target_type(filter, type_v) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ if ((class_v = apol_vector_create_with_capacity(1, NULL)) == NULL ||
+ apol_vector_append(class_v, obj_class) < 0 || seaudit_filter_set_target_class(filter, class_v) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ retval = 0;
+ cleanup:
+ apol_vector_destroy(&type_v);
+ apol_vector_destroy(&class_v);
+ if (retval != 0) {
+ seaudit_filter_destroy(&filter);
+ errno = error;
+ return NULL;
+ }
+ return filter;
+}
+
+static int report_print_enforce_toggles(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
+{
+ seaudit_filter_t *filter = NULL;
+ seaudit_model_t *dup_model = NULL;
+ size_t i, j, num_setenforce = 0;
+ apol_vector_t *v = NULL;
+ seaudit_message_t *msg;
+ seaudit_avc_message_t *avc;
+ seaudit_message_type_e type;
+ char *s;
+ char *perm = "setenforce";
+ int retval = -1, error = 0;
+
+ if ((filter = report_enforce_toggle_filter_create(log, report)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ if ((dup_model = seaudit_model_create_from_model(report->model)) == NULL ||
+ seaudit_model_append_filter(dup_model, filter) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ filter = NULL;
+ /* Loop through and get the number of avc allow messages with
+ * the setenforce permission. */
+ v = seaudit_model_get_messages(log, dup_model);
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ msg = apol_vector_get_element(v, i);
+ avc = seaudit_message_get_data(msg, &type);
+ if (type != SEAUDIT_MESSAGE_TYPE_AVC || avc->msg == SEAUDIT_AVC_DENIED)
+ continue;
+ if (apol_vector_get_index(avc->perms, perm, apol_str_strcmp, NULL, &j) == 0) {
+ /* Increment number of setenforce messages */
+ num_setenforce++;
+ }
+ }
+
+ /* Since we cannot filter by setenforce permission within the
+ * view, we do so manually within the following for loop. */
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
+ fprintf(outfile,
+ "<font class=\"message_count_label\">Number of messages:</font> <b class=\"message_count\">%zd</b><br>\n<br>\n",
+ num_setenforce);
+ else
+ fprintf(outfile, "Number of messages: %zd\n\n", num_setenforce);
+
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ msg = apol_vector_get_element(v, i);
+ avc = seaudit_message_get_data(msg, &type);
+ if (type != SEAUDIT_MESSAGE_TYPE_AVC ||
+ avc->msg == SEAUDIT_AVC_DENIED || apol_vector_get_index(avc->perms, perm, apol_str_strcmp, NULL, &j) < 0) {
+ continue;
+ }
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ s = seaudit_message_to_string_html(msg);
+ } else {
+ s = seaudit_message_to_string(msg);
+ }
+ if (s == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ fputs(s, outfile);
+ fputc('\n', outfile);
+ free(s);
+ }
+ retval = 0;
+ cleanup:
+ apol_vector_destroy(&v);
+ seaudit_filter_destroy(&filter);
+ seaudit_model_destroy(&dup_model);
+ if (error != 0) {
+ errno = error;
+ }
+ return retval;
+}
+
+static int report_print_policy_booleans(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
+{
+ size_t i, num = seaudit_model_get_num_bools(log, report->model);
+ apol_vector_t *v = seaudit_model_get_messages(log, report->model);
+ seaudit_message_t *m;
+ seaudit_message_type_e type;
+ char *s;
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
+ fprintf(outfile,
+ "<font class=\"message_count_label\">Number of messages:</font> <b class=\"message_count\">%zd</b><br>\n<br>\n",
+ num);
+ else
+ fprintf(outfile, "Number of messages: %zd\n\n", num);
+
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ m = apol_vector_get_element(v, i);
+ seaudit_message_get_data(m, &type);
+ if (type == SEAUDIT_MESSAGE_TYPE_BOOL) {
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ s = seaudit_message_to_string_html(m);
+ } else {
+ s = seaudit_message_to_string(m);
+ }
+ if (s == NULL) {
+ int error = errno;
+ apol_vector_destroy(&v);
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ fputs(s, outfile);
+ fputc('\n', outfile);
+ free(s);
+ }
+ }
+ apol_vector_destroy(&v);
+ return 0;
+}
+
+static int report_print_policy_loads(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
+{
+ size_t i, num = seaudit_model_get_num_loads(log, report->model);
+ apol_vector_t *v = seaudit_model_get_messages(log, report->model);
+ seaudit_message_t *m;
+ seaudit_message_type_e type;
+ char *s;
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
+ fprintf(outfile,
+ "<font class=\"message_count_label\">Number of messages:</font> <b class=\"message_count\">%zd</b><br>\n<br>\n",
+ num);
+ else
+ fprintf(outfile, "Number of messages: %zd\n\n", num);
+
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ m = apol_vector_get_element(v, i);
+ seaudit_message_get_data(m, &type);
+ if (type == SEAUDIT_MESSAGE_TYPE_LOAD) {
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ s = seaudit_message_to_string_html(m);
+ } else {
+ s = seaudit_message_to_string(m);
+ }
+ if (s == NULL) {
+ int error = errno;
+ apol_vector_destroy(&v);
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ fputs(s, outfile);
+ fputc('\n', outfile);
+ free(s);
+ }
+ }
+ apol_vector_destroy(&v);
+ return 0;
+}
+
+static int report_print_avc_listing(const seaudit_log_t * log, const seaudit_report_t * report, seaudit_avc_message_type_e avc_type,
+ FILE * outfile)
+{
+ size_t i, num;
+ apol_vector_t *v = seaudit_model_get_messages(log, report->model);
+ seaudit_message_t *m;
+ seaudit_avc_message_t *avc;
+ seaudit_message_type_e type;
+ char *s;
+ if (avc_type == SEAUDIT_AVC_GRANTED) {
+ num = seaudit_model_get_num_allows(log, report->model);
+ } else {
+ num = seaudit_model_get_num_denies(log, report->model);
+ }
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
+ fprintf(outfile,
+ "<font class=\"message_count_label\">Number of messages:</font> <b class=\"message_count\">%zd</b><br>\n<br>\n",
+ num);
+ else
+ fprintf(outfile, "Number of messages: %zd\n\n", num);
+
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ m = apol_vector_get_element(v, i);
+ avc = seaudit_message_get_data(m, &type);
+ if (type == SEAUDIT_MESSAGE_TYPE_AVC && avc->msg == avc_type) {
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ s = seaudit_message_to_string_html(m);
+ } else {
+ s = seaudit_message_to_string(m);
+ }
+ if (s == NULL) {
+ int error = errno;
+ apol_vector_destroy(&v);
+ ERR(log, "%s", strerror(error));
+ errno = error;
+ return -1;
+ }
+ fputs(s, outfile);
+ fputc('\n', outfile);
+ free(s);
+ }
+ }
+ apol_vector_destroy(&v);
+ return 0;
+}
+
+static int report_print_stats(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
+{
+ apol_vector_t *v = seaudit_model_get_messages(log, report->model);
+ size_t num_messages = apol_vector_get_size(v);
+ apol_vector_destroy(&v);
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ fprintf(outfile,
+ "<font class=\"stats_label\">Number of total messages:</font> <b class=\"stats_count\">%zd</b><br>\n",
+ num_messages);
+ fprintf(outfile,
+ "<font class=\"stats_label\">Number of policy load messages:</font> <b class=\"stats_count\">%zd</b><br>\n",
+ seaudit_model_get_num_loads(log, report->model));
+ fprintf(outfile,
+ "<font class=\"stats_label\">Number of policy boolean messages:</font> <b class=\"stats_count\">%zd</b><br>\n",
+ seaudit_model_get_num_bools(log, report->model));
+ fprintf(outfile,
+ "<font class=\"stats_label\">Number of allow messages:</font> <b class=\"stats_count\">%zd</b><br>\n",
+ seaudit_model_get_num_allows(log, report->model));
+ fprintf(outfile,
+ "<font class=\"stats_label\">Number of denied messages:</font> <b class=\"stats_count\">%zd</b><br>\n",
+ seaudit_model_get_num_denies(log, report->model));
+ } else {
+ fprintf(outfile, "Number of total messages: %zd\n", num_messages);
+ fprintf(outfile, "Number of policy load messages: %zd\n", seaudit_model_get_num_loads(log, report->model));
+ fprintf(outfile, "Number of policy boolean messages: %zd\n", seaudit_model_get_num_bools(log, report->model));
+ fprintf(outfile, "Number of allow messages: %zd\n", seaudit_model_get_num_allows(log, report->model));
+ fprintf(outfile, "Number of denied messages: %zd\n", seaudit_model_get_num_denies(log, report->model));
+ }
+ return 0;
+}
+
+static int report_print_standard_section(const seaudit_log_t * log, const seaudit_report_t * report,
+ xmlChar * id, xmlChar * title, FILE * outfile)
+{
+ size_t sz, len, i;
+ int rt = 0;
+
+ if (!report_is_valid_section_name((char *)id)) {
+ ERR(log, "%s", "Invalid standard section ID.");
+ errno = EINVAL;
+ return -1;
+ }
+ sz = strlen((char *)id);
+ if (title != NULL) {
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ fprintf(outfile, "<h2 class=\"standard_section_title\"><u>%s</h2></u>\n", title);
+ } else {
+ fprintf(outfile, "%s\n", title);
+ len = strlen((char *)title);
+ for (i = 0; i < len; i++) {
+ fprintf(outfile, "-");
+ }
+ fprintf(outfile, "\n");
+ }
+ }
+ if (strncasecmp((char *)id, "PolicyLoads", sz) == 0) {
+ rt = report_print_policy_loads(log, report, outfile);
+ } else if (strncasecmp((char *)id, "EnforcementToggles", sz) == 0) {
+ rt = report_print_enforce_toggles(log, report, outfile);
+ } else if (strncasecmp((char *)id, "PolicyBooleans", sz) == 0) {
+ rt = report_print_policy_booleans(log, report, outfile);
+ } else if (strncasecmp((char *)id, "AllowListing", sz) == 0) {
+ rt = report_print_avc_listing(log, report, SEAUDIT_AVC_GRANTED, outfile);
+ } else if (strncasecmp((char *)id, "DenyListing", sz) == 0) {
+ rt = report_print_avc_listing(log, report, SEAUDIT_AVC_DENIED, outfile);
+ } else if (strncasecmp((char *)id, "Statistics", sz) == 0) {
+ rt = report_print_stats(log, report, outfile);
+ }
+ if (rt < 0) {
+ return rt;
+ }
+
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
+ fprintf(outfile, "<br>\n");
+ else
+ fprintf(outfile, "\n");
+
+ return 0;
+}
+
+static int report_print_loaded_view(const seaudit_log_t * log, const seaudit_report_t * report, xmlChar * view_filePath,
+ FILE * outfile)
+{
+ size_t i, filters_added = 0;
+ apol_vector_t *loaded_filters = NULL;
+ seaudit_model_t *dup_model = NULL;
+ seaudit_filter_t *filter;
+ seaudit_message_t *msg;
+ char *s;
+ apol_vector_t *v = NULL;
+ int retval = -1, error = 0;
+
+ if ((loaded_filters = seaudit_filter_create_from_file((char *)view_filePath)) == NULL) {
+ error = errno;
+ ERR(log, "Error parsing file %s.", view_filePath);
+ goto cleanup;
+ }
+ if ((dup_model = seaudit_model_create_from_model(report->model)) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ for (i = 0; i < apol_vector_get_size(loaded_filters); i++, filters_added++) {
+ filter = apol_vector_get_element(loaded_filters, i);
+ if (seaudit_model_append_filter(dup_model, filter) < 0) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ }
+ if ((v = seaudit_model_get_messages(log, dup_model)) == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ fprintf(outfile, "View file: %s<br>\n", view_filePath);
+ fprintf(outfile,
+ "<font class=\"message_count_label\">Number of messages:</font> <b class=\"message_count\">%zd</b><br>\n<br>\n",
+ apol_vector_get_size(v));
+ } else {
+ fprintf(outfile, "View file: %s\n", view_filePath);
+ fprintf(outfile, "Number of messages: %zd\n\n", apol_vector_get_size(v));
+ }
+
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ msg = apol_vector_get_element(v, i);
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ s = seaudit_message_to_string_html(msg);
+ } else {
+ s = seaudit_message_to_string(msg);
+ }
+ if (s == NULL) {
+ error = errno;
+ ERR(log, "%s", strerror(error));
+ goto cleanup;
+ }
+ fputs(s, outfile);
+ fputc('\n', outfile);
+ free(s);
+ }
+ retval = 0;
+ cleanup:
+ /* only destroy filters that were not added to the model
+ * (recall that model takes ownership of filters) */
+ if (loaded_filters != NULL) {
+ for (i = filters_added; i < apol_vector_get_size(loaded_filters); i++) {
+ filter = apol_vector_get_element(loaded_filters, i);
+ seaudit_filter_destroy(&filter);
+ }
+ apol_vector_destroy(&loaded_filters);
+ }
+ seaudit_model_destroy(&dup_model);
+ apol_vector_destroy(&v);
+ if (error != 0) {
+ errno = error;
+ }
+ return retval;
+}
+
+static int report_print_custom_section(const seaudit_log_t * log, const seaudit_report_t * report,
+ xmlTextReaderPtr reader, xmlChar * title, FILE * outfile)
+{
+ size_t len, i;
+ int rt, error = 0, retval = -1, end_of_element = 0;
+ xmlChar *view_filePath = NULL, *name = NULL;
+
+ if (title != NULL) {
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ fprintf(outfile, "<h2 class=\"custom_section_title\"><u>%s</h2></u>\n", title);
+ } else {
+ fprintf(outfile, "%s\n", title);
+ len = strlen((char *)title);
+ for (i = 0; i < len; i++) {
+ fprintf(outfile, "-");
+ }
+ fprintf(outfile, "\n");
+ }
+ }
+
+ /* Moves the position of the current instance to the next node
+ * in the stream, which should be a view node */
+ rt = xmlTextReaderRead(reader);
+ while (rt == 1) {
+ /* Read inner child view node(s) */
+ name = xmlTextReaderName(reader);
+ if (name == NULL) {
+ error = errno;
+ ERR(log, "%s", "Unavailable node name within.");
+ goto cleanup;
+ }
+ /* We have reached the end-of-element for the
+ * custom-section node (indicated by 15) */
+ if (strcmp((char *)name, "custom-section") == 0 && xmlTextReaderNodeType(reader) == 15) {
+ xmlFree(name);
+ end_of_element = 1;
+ break;
+ }
+ if (strcmp((char *)name, "view") == 0 && xmlTextReaderNodeType(reader) == 1 && xmlTextReaderHasAttributes(reader)) {
+ view_filePath = xmlTextReaderGetAttribute(reader, (const xmlChar *)"file");
+ if (view_filePath == NULL) {
+ error = errno;
+ ERR(log, "%s", "Error getting file attribute for view node.");
+ goto cleanup;
+ }
+ if (report_print_loaded_view(log, report, view_filePath, outfile) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ xmlFree(view_filePath);
+ }
+ xmlFree(name);
+ rt = xmlTextReaderRead(reader);
+ }
+ if (!end_of_element && rt != 0) {
+ error = EIO;
+ ERR(log, "Error parsing config file %s. (rt:%d)", report->config, rt);
+ goto cleanup;
+ }
+
+ if (!end_of_element) {
+ error = EIO;
+ ERR(log, "%s", "Encountered end of file before finding end of element for custom-section node.");
+ goto cleanup;;
+ }
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
+ fprintf(outfile, "<br>\n");
+ else
+ fprintf(outfile, "\n");
+
+ return 0;
+ cleanup:
+ if (view_filePath)
+ xmlFree(view_filePath);
+ if (name)
+ xmlFree(name);
+ if (error != 0) {
+ errno = error;
+ }
+ return retval;
+}
+
+static int report_process_xmlNode(const seaudit_log_t * log, const seaudit_report_t * report, xmlTextReaderPtr reader,
+ FILE * outfile)
+{
+ xmlChar *name = NULL, *id_attr = NULL, *title_attr = NULL;
+ int retval = -1, error = 0;
+
+ if ((name = xmlTextReaderName(reader)) == NULL) {
+ error = errno;
+ ERR(log, "%s", "Unavailable node name.");
+ goto cleanup;
+ }
+
+ if (!report_is_valid_node_name((char *)name)) {
+ retval = 0;
+ goto cleanup;
+ }
+
+ if (strcmp((char *)name, "seaudit-report") == 0 && xmlTextReaderNodeType(reader) == 1) {
+ if (report_parse_seaudit_report(log, report, reader, &id_attr, &title_attr) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ fprintf(outfile, "<h1 class=\"report_title\">Title: %s</h1>\n", title_attr);
+ } else {
+ fprintf(outfile, "Title: %s\n", title_attr);
+ }
+ } else if (strcmp((char *)name, "standard-section") == 0 && xmlTextReaderNodeType(reader) == 1) {
+ if (report_parse_standard_attribs(log, report, reader, &id_attr, &title_attr) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if (id_attr == NULL) {
+ ERR(log, "%s", "Missing required id attribute for standard section node.");
+ error = EIO;
+ goto cleanup;
+ }
+ /* NOTE: If a title wasn't provided, we still continue. */
+ if (report_print_standard_section(log, report, id_attr, title_attr, outfile) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ } else if (strcmp((char *)name, "custom-section") == 0 && xmlTextReaderNodeType(reader) == 1) {
+ if (report_parse_custom_attribs(log, report, reader, &title_attr) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ /* NOTE: If a title wasn't provided, we still continue. */
+ if (report_print_custom_section(log, report, reader, title_attr, outfile) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ }
+
+ retval = 0;
+ cleanup:
+ xmlFree(name);
+ xmlFree(id_attr);
+ xmlFree(title_attr);
+ if (retval < 0) {
+ errno = error;
+ }
+ return retval;
+}
+
+static int report_print_malformed(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
+{
+ size_t i, len;
+ apol_vector_t *v = seaudit_model_get_malformed_messages(log, report->model);
+ if (v == NULL) {
+ return -1;
+ }
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
+ fprintf(outfile, "<b><u>Malformed messages</b></u>\n");
+ fprintf(outfile, "<br>\n<br>\n");
+ } else {
+ fprintf(outfile, "Malformed messages\n");
+ len = strlen("Malformed messages\n");
+ for (i = 0; i < len; i++) {
+ fprintf(outfile, "-");
+ }
+ fprintf(outfile, "\n");
+ }
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ char *malformed_msg;
+ malformed_msg = apol_vector_get_element(v, i);
+ if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
+ fprintf(outfile, "%s<br>\n", malformed_msg);
+ else
+ fprintf(outfile, "%s\n", malformed_msg);
+ }
+ fprintf(outfile, "\n");
+ apol_vector_destroy(&v);
+ return 0;
+}
+
+int seaudit_report_write(const seaudit_log_t * log, const seaudit_report_t * report, const char *out_file)
+{
+ xmlTextReaderPtr reader;
+ FILE *outfile = NULL;
+ int rt, retval = -1, error = 0;
+
+ /* Set/Open the output stream */
+ if (out_file == NULL) {
+ outfile = stdout;
+ } else {
+ if ((outfile = fopen(out_file, "w+")) == NULL) {
+ error = errno;
+ ERR(log, "Could not open %s for writing.", out_file);
+ goto cleanup;
+ }
+ }
+
+ /* Print report header */
+ if (report_print_header(log, report, outfile) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+
+ /* Parse the xml config file and output report */
+ reader = xmlNewTextReaderFilename(report->config);
+ if (reader == NULL) {
+ error = errno;
+ ERR(log, "Unable to open config file (%s).", report->config);
+ goto cleanup;
+ }
+ rt = xmlTextReaderRead(reader);
+ while (rt == 1) {
+ report_process_xmlNode(log, report, reader, outfile);
+ rt = xmlTextReaderRead(reader);
+ }
+ error = errno;
+ xmlFreeTextReader(reader);
+ if (rt != 0) {
+ ERR(log, "Failed to parse config file %s.", report->config);
+ goto cleanup;
+ }
+ if (report->malformed && report_print_malformed(log, report, outfile) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ report_print_footer(report, outfile);
+
+ retval = 0;
+ cleanup:
+ if (outfile != NULL) {
+ fclose(outfile);
+ }
+ if (retval < 0) {
+ errno = error;
+ }
+ return retval;
+}
diff --git a/libseaudit/src/seaudit_internal.h b/libseaudit/src/seaudit_internal.h
new file mode 100644
index 0000000..272dfbd
--- /dev/null
+++ b/libseaudit/src/seaudit_internal.h
@@ -0,0 +1,664 @@
+/**
+ * @file
+ * Protected interface seaudit library.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SEAUDIT_SEAUDIT_INTERNAL_H
+#define SEAUDIT_SEAUDIT_INTERNAL_H
+
+#include <config.h>
+
+#include <seaudit/avc_message.h>
+#include <seaudit/bool_message.h>
+#include <seaudit/filter.h>
+#include <seaudit/load_message.h>
+#include <seaudit/log.h>
+#include <seaudit/message.h>
+#include <seaudit/model.h>
+#include <seaudit/sort.h>
+
+#include <apol/bst.h>
+#include <apol/vector.h>
+
+#include <libxml/uri.h>
+
+#define FILTER_FILE_FORMAT_VERSION "1.3"
+
+/*************** master seaudit log object (defined in log.c) ***************/
+
+struct seaudit_log
+{
+ /** vector of seaudit_message_t pointers */
+ apol_vector_t *messages;
+ /** vector of strings, corresponding to log messages that did
+ * not parse cleanly */
+ apol_vector_t *malformed_msgs;
+ /** vector of seaudit_model_t that are watching this log */
+ apol_vector_t *models;
+ apol_bst_t *types, *classes, *roles, *users;
+ apol_bst_t *perms, *hosts, *bools, *managers;
+ apol_bst_t *mls_lvl, *mls_clr;
+ seaudit_log_type_e logtype;
+ seaudit_handle_fn_t fn;
+ void *handle_arg;
+ /** non-zero if tzset() has been called */
+ int tz_initialized;
+ /** non-zero if the parser is in the middle of a line */
+ int next_line;
+};
+
+/**
+ * Notify a log that model is now watching it.
+ *
+ * @param log Log to append model.
+ * @param model Model that is watching.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+int log_append_model(seaudit_log_t * log, seaudit_model_t * model);
+
+/**
+ * Notify a log that model is no longer watching it.
+ *
+ * @param log Log to append model.
+ * @param model Model that stopped watching.
+ */
+void log_remove_model(seaudit_log_t * log, seaudit_model_t * model);
+
+/**
+ * Get a vector of all messages from this seaudit log object.
+ *
+ * @param log Log object containing messages.
+ *
+ * @return Vector of seaudit_message_t pointers. Do not free() or
+ * otherwise modify this vector or its contents.
+ */
+const apol_vector_t *log_get_messages(const seaudit_log_t * log);
+
+/**
+ * Get a vector of all malformed messages from this seaudit log
+ * object. These are SELinux messages that did not parse cleanly for
+ * some reason. They will be returned in the same order in which they
+ * were read from the log file.
+ *
+ * @param log Log object containing malformed messages.
+ *
+ * @return Vector of strings. Do not free() or otherwise modify this
+ * vector or its contents.
+ */
+const apol_vector_t *log_get_malformed_messages(const seaudit_log_t * log);
+
+/*************** messages (defined in message.c) ***************/
+
+struct seaudit_message
+{
+ /** when this message was generated */
+ struct tm *date_stamp;
+ /** pointer into log->hosts for the hostname that generated
+ * this message, or NULL if none found */
+ char *host;
+ /** pointer intor log->managers for the object manager that
+ * generated this message, or NULL if none found */
+ char *manager;
+ /** type of message this really is */
+ seaudit_message_type_e type;
+ /** fake polymorphism by having a union of possible subclasses */
+ union
+ {
+ seaudit_avc_message_t *avc;
+ seaudit_bool_message_t *boolm;
+ seaudit_load_message_t *load;
+ } data;
+};
+
+/**
+ * Allocate a new seaudit message, append the message to the log, and
+ * return the message.
+ *
+ * @param log Log to which append the message.
+ * @param type Message type for the newly constructed message.
+ *
+ * @return A newly allocated message. The caller must not free the
+ * value.
+ */
+seaudit_message_t *message_create(seaudit_log_t * log, seaudit_message_type_e type);
+
+/**
+ * Deallocate all space associated with a message, recursing into the
+ * message's data field.
+ *
+ * @param msg If not NULL, message to free.
+ */
+void message_free(void *msg);
+
+/*************** avc messages (defined in avc_message.c) ***************/
+
+typedef enum seaudit_avc_message_class
+{
+ SEAUDIT_AVC_DATA_INVALID = 0,
+ SEAUDIT_AVC_DATA_MALFORMED,
+ SEAUDIT_AVC_DATA_IPC,
+ SEAUDIT_AVC_DATA_CAP, /* capability */
+ SEAUDIT_AVC_DATA_FS,
+ SEAUDIT_AVC_DATA_NET,
+} seaudit_avc_message_class_e;
+
+/**
+ * Definition of an avc message. Note that unless stated otherwise,
+ * character pointers are into the message's log's respective BST.
+ */
+struct seaudit_avc_message
+{
+ seaudit_avc_message_type_e msg;
+ /** type of avc message this is, either a deny or a granted
+ * (i.e., auditallow) */
+ seaudit_avc_message_class_e avc_type;
+ /** executable and path - free() this */
+ char *exe;
+ /** command - free() this */
+ char *comm;
+ /** path of the OBJECT - free() this */
+ char *path;
+ /** device for the object - free() this */
+ char *dev;
+ /** network interface - free() this */
+ char *netif;
+ /** local address - free() this */
+ char *laddr;
+ /** foreign address - free() this */
+ char *faddr;
+ /** source address - free() this */
+ char *saddr;
+ /** destination address - free() this */
+ char *daddr;
+ /** free() this */
+ char *name;
+ /** free() this */
+ char *ipaddr;
+ /** source context's user */
+ char *suser;
+ /** source context's role */
+ char *srole;
+ /** source context's type */
+ char *stype;
+ /** source context's mls level */
+ char *smls_lvl;
+ /** source context's mls clearance */
+ char *smls_clr;
+ /** target context's user */
+ char *tuser;
+ /** target context's role */
+ char *trole;
+ /** target context's type */
+ char *ttype;
+ /** target context's mls level */
+ char *tmls_lvl;
+ /** target context's mls clearance */
+ char *tmls_clr;
+ /** target class */
+ char *tclass;
+ /** audit header timestamp (seconds) */
+ time_t tm_stmp_sec;
+ /** audit header timestamp (nanoseconds) */
+ long tm_stmp_nano;
+ /** audit header serial number */
+ unsigned int serial;
+ /** pointers into log->perms BST (hence char *) */
+ apol_vector_t *perms;
+ /** key for an IPC call */
+ int key;
+ int is_key;
+ /** process capability (corresponds with class 'capability') */
+ int capability;
+ int is_capability;
+ /** inode of the object */
+ unsigned long inode;
+ int is_inode;
+ /** source port */
+ int source;
+ /** destination port */
+ int dest;
+ /** local port */
+ int lport;
+ /** foreign port */
+ int fport;
+ int port;
+ /** source sid */
+ unsigned int src_sid;
+ int is_src_sid;
+ /** target sid */
+ unsigned int tgt_sid;
+ int is_tgt_sid;
+ /** process ID of the subject */
+ unsigned int pid;
+ int is_pid;
+};
+
+/**
+ * Allocate and return a new seaudit AVC message.
+ *
+ * @return A newly allocated AVC message. The caller must not call
+ * avc_message_free() upon the returned value afterwards.
+ */
+seaudit_avc_message_t *avc_message_create(void);
+
+/**
+ * Deallocate all space associated with an AVC message.
+ *
+ * @param msg If not NULL, message to free.
+ */
+void avc_message_free(seaudit_avc_message_t * avc);
+
+/**
+ * Given an avc message, allocate and return a string that
+ * approximates the message as it had appeared within the log file.
+ *
+ * @param msg Message whose string representation to get.
+ * @param date Date and time when message was generated.
+ *
+ * @return String representation for message, or NULL upon error. The
+ * caller is responsible for free()ing the string afterwards.
+ */
+char *avc_message_to_string(const seaudit_message_t * msg, const char *date);
+
+/**
+ * Given an avc change message, allocate and return a string,
+ * formatted in HTML, that approximates the message as it had appeared
+ * within the log file.
+ *
+ * @param msg Message whose string representation to get.
+ * @param date Date and time when message was generated.
+ *
+ * @return String representation for message, or NULL upon error. The
+ * caller is responsible for free()ing the string afterwards.
+ */
+char *avc_message_to_string_html(const seaudit_message_t * msg, const char *date);
+
+/**
+ * Given an avc change message, allocate and return a string that
+ * gives miscellaneous info (e.g., ports, IP addresses).
+ *
+ * @param avc Message from which to get miscellaneous information.
+ *
+ * @return Miscellaneous message string representation, or NULL upon
+ * error. The caller is responsible for free()ing the string
+ * afterwards.
+ */
+char *avc_message_to_misc_string(const seaudit_avc_message_t * avc);
+
+/*************** bool messages (defined in bool_message.c) ***************/
+
+typedef struct seaudit_bool_message_change
+{
+ /** pointer into log's bools BST */
+ char *boolean;
+ /** new value for the boolean */
+ int value;
+} seaudit_bool_message_change_t;
+
+struct seaudit_bool_message
+{
+ /** vector of seaudit_bool_change_t pointers; vector owns objects. */
+ apol_vector_t *changes;
+};
+
+/**
+ * Allocate and return a new seaudit boolean change message.
+ *
+ * @return A newly allocated boolean change message. The caller must
+ * not call bool_message_free() upon the returned value afterwards.
+ */
+seaudit_bool_message_t *bool_message_create(void);
+
+/**
+ * Append a boolean change to a particular boolean message. This will
+ * add the boolean name to the log's BST as needed.
+ *
+ * @param log Log containing boolean name BST.
+ * @param bool Boolean message to change.
+ * @param name Name of the boolean that was changed. This function
+ * will dup the incoming name.
+ * @param value New value for the boolean.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+int bool_change_append(seaudit_log_t * log, seaudit_bool_message_t * boolm, const char *name, int value);
+
+/**
+ * Deallocate all space associated with a boolean change message.
+ *
+ * @param msg If not NULL, message to free.
+ */
+void bool_message_free(seaudit_bool_message_t * boolm);
+
+/**
+ * Given a boolean change message, allocate and return a string that
+ * approximates the message as it had appeared within the log file.
+ *
+ * @param msg Message whose string representation to get.
+ * @param date Date and time when message was generated.
+ *
+ * @return String representation for message, or NULL upon error. The
+ * caller is responsible for free()ing the string afterwards.
+ */
+char *bool_message_to_string(const seaudit_message_t * msg, const char *date);
+
+/**
+ * Given a boolean change message, allocate and return a string,
+ * formatted in HTML, that approximates the message as it had appeared
+ * within the log file.
+ *
+ * @param msg Message whose string representation to get.
+ * @param date Date and time when message was generated.
+ *
+ * @return String representation for message, or NULL upon error. The
+ * caller is responsible for free()ing the string afterwards.
+ */
+char *bool_message_to_string_html(const seaudit_message_t * msg, const char *date);
+
+/**
+ * Given a boolean change message, allocate and return a string that
+ * gives miscellaneous info (i.e., list of boolean names and their new
+ * values.)
+ *
+ * @param bool Message from which to get miscellaneous information.
+ *
+ * @return Miscellaneous message string representation, or NULL upon
+ * error. The caller is responsible for free()ing the string
+ * afterwards.
+ */
+char *bool_message_to_misc_string(const seaudit_bool_message_t * boolm);
+
+/*************** load messages (defined in load_message.c) ***************/
+
+struct seaudit_load_message
+{
+ unsigned int users; /* number of users */
+ unsigned int roles; /* number of roles */
+ unsigned int types; /* number of types */
+ unsigned int classes; /* number of classes */
+ unsigned int rules; /* number of rules */
+ unsigned int bools; /* number of bools */
+ char *binary; /* path for binary that was loaded */
+};
+
+/**
+ * Allocate and return a new seaudit policy load message.
+ *
+ * @return A newly allocated policy load message. The caller must
+ * not call load_message_free() upon the returned value afterwards.
+ */
+seaudit_load_message_t *load_message_create(void);
+
+/**
+ * Deallocate all space associated with a policy load message.
+ *
+ * @param msg If not NULL, message to free.
+ */
+void load_message_free(seaudit_load_message_t * msg);
+
+/**
+ * Given a load message, allocate and return a string that
+ * approximates the message as it had appeared within the log file.
+ *
+ * @param msg Message whose string representation to get.
+ * @param date Date and time when message was generated.
+ *
+ * @return String representation for message, or NULL upon error. The
+ * caller is responsible for free()ing the string afterwards.
+ */
+char *load_message_to_string(const seaudit_message_t * msg, const char *date);
+
+/**
+ * Given a load message, allocate and return a string, formatted in
+ * HTML, that approximates the message as it had appeared within the
+ * log file.
+ *
+ * @param msg Message whose string representation to get.
+ * @param date Date and time when message was generated.
+ *
+ * @return String representation for message, or NULL upon error. The
+ * caller is responsible for free()ing the string afterwards.
+ */
+char *load_message_to_string_html(const seaudit_message_t * msg, const char *date);
+
+/**
+ * Given a load message, allocate and return a string that gives
+ * miscellaneous info (e.g., number of types in the new policy).
+ *
+ * @param load Message from which to get miscellaneous information.
+ *
+ * @return Miscellaneous message string representation, or NULL upon
+ * error. The caller is responsible for free()ing the string
+ * afterwards.
+ */
+char *load_message_to_misc_string(const seaudit_load_message_t * load);
+
+/*************** model functions (defined in model.h) ***************/
+
+/**
+ * Notify a model to stop watching a log.
+ *
+ * @param model Model to notify.
+ * @param log Log to stop watching.
+ */
+void model_remove_log(seaudit_model_t * model, seaudit_log_t * log);
+
+/**
+ * Notify a model that a log has been changed; the model will need to
+ * recalculate its messages.
+ *
+ * @param model Model to notify.
+ * @param log Log that has been changed.
+ */
+void model_notify_log_changed(seaudit_model_t * model, seaudit_log_t * log);
+
+/**
+ * Notify a model that a filter has been changed; the model will need
+ * to recalculate its messages.
+ *
+ * @param model Model to notify.
+ * @param filter Filter that has been changed.
+ */
+void model_notify_filter_changed(seaudit_model_t * model, seaudit_filter_t * filter);
+
+/*************** filter functions (defined in filter.c) ***************/
+
+/**
+ * Link a model to a filter. Whenever the filter changes, it should
+ * call model_notify_filter_changed(); that way the model will
+ * recalculate itself.
+ *
+ * @param filter Filter to be watched.
+ * @param model Model that is watching.
+ */
+void filter_set_model(seaudit_filter_t * filter, seaudit_model_t * model);
+
+/********** more filter functions (defined in filter-internal.c) **********/
+
+typedef int (filter_read_func) (seaudit_filter_t * filter, const xmlChar * ch);
+
+struct filter_parse_state
+{
+ /** vector of filters created, appended to by <filter> tags;
+ caller must destroy this */
+ apol_vector_t *filters;
+ /** string from name attribute in a <view> tag; caller must free()
+ this */
+ char *view_name;
+ /** value from match attribute in a <view> tag */
+ seaudit_filter_match_e view_match;
+ /** value form show attribute in a <view> tag */
+ seaudit_filter_visible_e view_visible;
+
+ /****
+ The following are to be considered private data and may only
+ be used by filter-internal.c.
+ ****/
+ /** the most recently read string that was not part of a tag */
+ xmlChar *cur_string;
+ int warnings;
+ /** filter currently being parsed, set by most recent <filter> tag */
+ seaudit_filter_t *cur_filter;
+ /** pointer to a filter parsing function, set by <criteria> tag */
+ filter_read_func *cur_filter_read;
+};
+
+/**
+ * Given a filter and a message, return non-zero if the msg is
+ * accepted by the filter according to the filter's criteria. If the
+ * filter does not have enough information to decide (because the
+ * message is incomplete) then this should return 0.
+ *
+ * @param filter Filter to apply.
+ * @param msg Message to check.
+ *
+ * @return Non-zero if message is accepted, 0 if not.
+ */
+int filter_is_accepted(const seaudit_filter_t * filter, const seaudit_message_t * msg);
+
+/**
+ * Parse the given XML file and fill in the passed in struct. The
+ * caller must create the struct and the vector within. Upon return,
+ * the caller must destroy the vector and free view_name.
+ *
+ * @param state An initialized state struct for parsing.
+ * @param filename Name of XML file to parse.
+ *
+ * @return 0 on success, > 0 if parse warnings, < 0 on error.
+ */
+int filter_parse_xml(struct filter_parse_state *state, const char *filename);
+
+/**
+ * Append the given filter's values, in XML format, to a file handler.
+ * This includes the filter's name and criteria.
+ *
+ * @param filter Filter to save.
+ * @param file File to which write.
+ *
+ * @see seaudit_filter_create_from_file()
+ */
+void filter_append_to_file(const seaudit_filter_t * filter, FILE * file, int tabs);
+
+/*************** sort functions (defined in sort.c) ***************/
+
+/**
+ * Create and return a new sort object, initialized with the data from
+ * an existing sort object. The new sort object will not be attached
+ * to any models.
+ *
+ * @param sort Sort object to clone.
+ *
+ * @return A cloned sort object, or NULL upon error. The caller is
+ * responsible for calling seaudit_sort_destroy() afterwards.
+ */
+seaudit_sort_t *sort_create_from_sort(const seaudit_sort_t * sort);
+
+/**
+ * Create and return a new sort object based upon the name of the sort
+ * (as returned by sort_get_name()). The new sort object will not be
+ * attached to any models.
+ *
+ * @param name Name of the type of sort to create.
+ * @param direction Direction to sort, non-negative for ascending,
+ * negative for descending.
+ *
+ * @return A new sort object, or NULL upon error. The caller is
+ * responsible for calling seaudit_sort_destroy() afterwards.
+ */
+seaudit_sort_t *sort_create_from_name(const char *name, int direction);
+
+/**
+ * Given a sort object and a message, return non-zero if this sort
+ * object could operate on the message, 0 if not. (Messages may have
+ * incomplete information due to parser warnings.)
+ *
+ * @param sort Sort object to query.
+ * @param msg Message to check.
+ *
+ * @return Non-zero if sort supports the message, 0 if not.
+ */
+int sort_is_supported(const seaudit_sort_t * sort, const seaudit_message_t * msg);
+
+/**
+ * Invoke a sort object's comparison function.
+ *
+ * @param sort Sort object that contains a comparator.
+ * @param m1 First message to compare.
+ * @param m2 Second message to compare.
+ *
+ * @return 0 if the messages are equivalent, < 0 if a is first, > 0 if
+ * b is first.
+ */
+int sort_comp(const seaudit_sort_t * sort, const seaudit_message_t * a, const seaudit_message_t * b);
+
+/**
+ * Return the type of sort this sort object is. The name is valid for
+ * sort_create_from_name()'s first parameter.
+ *
+ * @param sort Sort object to query.
+ *
+ * @return Type of sort this object is.
+ */
+const char *sort_get_name(const seaudit_sort_t * sort);
+
+/**
+ * Return the sort direction for a sort object.
+ *
+ * @param sort Sort object to query.
+ *
+ * @return Non-negative for ascending, negative for descending.
+ */
+int sort_get_direction(const seaudit_sort_t * sort);
+
+/*************** error handling code (defined in log.c) ***************/
+
+#define SEAUDIT_MSG_ERR 1
+#define SEAUDIT_MSG_WARN 2
+#define SEAUDIT_MSG_INFO 3
+
+/**
+ * Write a message to the callback stored within a seaudit_log_t
+ * handler. If the msg_callback field is empty then suppress the
+ * message.
+ *
+ * @param log Error reporting handler. If NULL then write message to
+ * stderr.
+ * @param level Severity of message, one of SEAUDIT_MSG_ERR,
+ * SEAUDIT_MSG_WARN, or SEAUDIT_MSG_INFO.
+ * @param fmt Format string to print, using syntax of printf(3).
+ */
+extern void seaudit_handle_msg(const seaudit_log_t * log, int level, const char *fmt, ...);
+
+__attribute__ ((format(printf, 3, 4)))
+extern void seaudit_handle_msg(const seaudit_log_t * log, int level, const char *fmt, ...);
+
+#undef ERR
+#undef WARN
+#undef INFO
+
+#define ERR(handle, format, ...) seaudit_handle_msg(handle, SEAUDIT_MSG_ERR, format, __VA_ARGS__)
+#define WARN(handle, format, ...) seaudit_handle_msg(handle, SEAUDIT_MSG_WARN, format, __VA_ARGS__)
+#define INFO(handle, format, ...) seaudit_handle_msg(handle, SEAUDIT_MSG_INFO, format, __VA_ARGS__)
+
+#endif
diff --git a/libseaudit/src/sort.c b/libseaudit/src/sort.c
new file mode 100644
index 0000000..2d119b9
--- /dev/null
+++ b/libseaudit/src/sort.c
@@ -0,0 +1,744 @@
+/**
+ * @file
+ * Implementation of seaudit sort routines.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "seaudit_internal.h"
+
+#include <apol/util.h>
+
+#include <errno.h>
+#include <string.h>
+
+/**
+ * Callback that compares two messages.
+ */
+typedef int (sort_comp_func) (const seaudit_sort_t * sort, const seaudit_message_t * a, const seaudit_message_t * b);
+
+/**
+ * Callback that returns non-zero if the sort routine can handle the
+ * given message, 0 if not supported.
+ */
+typedef int (sort_supported_func) (const seaudit_sort_t * sort, const seaudit_message_t * m);
+
+struct seaudit_sort
+{
+ const char *name;
+ sort_comp_func *comp;
+ sort_supported_func *support;
+ int direction;
+};
+
+seaudit_sort_t *seaudit_sort_create_from_sort(const seaudit_sort_t * sort)
+{
+ seaudit_sort_t *s;
+ if (sort == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if ((s = calloc(1, sizeof(*s))) == NULL) {
+ return NULL;
+ }
+ s->name = sort->name;
+ s->comp = sort->comp;
+ s->support = sort->support;
+ s->direction = sort->direction;
+ return s;
+}
+
+void seaudit_sort_destroy(seaudit_sort_t ** sort)
+{
+ if (sort != NULL && *sort != NULL) {
+ free(*sort);
+ *sort = NULL;
+ }
+}
+
+static seaudit_sort_t *sort_create(const char *name, sort_comp_func * comp, sort_supported_func support, const int direction)
+{
+ seaudit_sort_t *s = calloc(1, sizeof(*s));
+ if (s == NULL) {
+ return NULL;
+ }
+ s->name = name;
+ s->comp = comp;
+ s->support = support;
+ s->direction = direction;
+ return s;
+}
+
+seaudit_sort_t *sort_create_from_sort(const seaudit_sort_t * sort)
+{
+ if (sort == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return sort_create(sort->name, sort->comp, sort->support, sort->direction);
+}
+
+static int sort_message_type_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ if (a->type != b->type) {
+ return a->type - b->type;
+ }
+ if (a->type == SEAUDIT_MESSAGE_TYPE_AVC) {
+ return a->data.avc->msg - b->data.avc->msg;
+ }
+ return 0;
+}
+
+static int sort_message_type_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type != SEAUDIT_MESSAGE_TYPE_INVALID;
+}
+
+seaudit_sort_t *seaudit_sort_by_message_type(const int direction)
+{
+ return sort_create("message_type", sort_message_type_comp, sort_message_type_support, direction);
+}
+
+/**
+ * Given two dates compare them, checking to see if the dates passed
+ * in have valid years and correcting if not before comparing.
+ */
+static int sort_date_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ /* tm has year, month, day, hour, min, sec */
+ /* if we should compare the years */
+ struct tm *t1 = a->date_stamp;
+ struct tm *t2 = b->date_stamp;
+ int retval;
+ if (t1->tm_year != 0 && t2->tm_year != 0 && (retval = t1->tm_year - t2->tm_year) != 0) {
+ return retval;
+ }
+ if ((retval = t1->tm_mon - t2->tm_mon) != 0) {
+ return retval;
+ }
+ if ((retval = t1->tm_mday - t2->tm_mday) != 0) {
+ return retval;
+ }
+ if ((retval = t1->tm_hour - t2->tm_hour) != 0) {
+ return retval;
+ }
+ if ((retval = t1->tm_min - t2->tm_min) != 0) {
+ return retval;
+ }
+ if ((retval = t1->tm_sec - t2->tm_sec) != 0) {
+ return retval;
+ }
+ return 0;
+}
+
+static int sort_date_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->date_stamp != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_date(const int direction)
+{
+ return sort_create("date", sort_date_comp, sort_date_support, direction);
+}
+
+static int sort_host_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->host, b->host);
+}
+
+static int sort_host_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->host != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_host(const int direction)
+{
+ return sort_create("host", sort_host_comp, sort_host_support, direction);
+}
+
+static int sort_perm_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ size_t i;
+ return apol_vector_compare(a->data.avc->perms, b->data.avc->perms, apol_str_strcmp, NULL, &i);
+}
+
+static int sort_perm_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC &&
+ msg->data.avc->perms != NULL && apol_vector_get_size(msg->data.avc->perms) >= 1;
+}
+
+seaudit_sort_t *seaudit_sort_by_permission(const int direction)
+{
+ return sort_create("permission", sort_perm_comp, sort_perm_support, direction);
+}
+
+static int sort_source_user_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->suser, b->data.avc->suser);
+}
+
+static int sort_source_user_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->suser != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_source_user(const int direction)
+{
+ return sort_create("source_user", sort_source_user_comp, sort_source_user_support, direction);
+}
+
+static int sort_source_role_comp(const seaudit_sort_t * sort __attribute((unused)), const seaudit_message_t * a,
+ const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->srole, b->data.avc->srole);
+}
+
+static int sort_source_role_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->srole != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_source_role(const int direction)
+{
+ return sort_create("source_role", sort_source_role_comp, sort_source_role_support, direction);
+}
+
+static int sort_source_type_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->stype, b->data.avc->stype);
+}
+
+static int sort_source_type_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->stype != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_source_type(const int direction)
+{
+ return sort_create("source_type", sort_source_type_comp, sort_source_type_support, direction);
+}
+
+static int sort_source_mls_lvl_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->smls_lvl, b->data.avc->smls_lvl);
+}
+
+static int sort_source_mls_lvl_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->smls_lvl != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_source_mls_lvl(const int direction)
+{
+ return sort_create("source_mls_lvl", sort_source_mls_lvl_comp, sort_source_mls_lvl_support, direction);
+}
+
+static int sort_source_mls_clr_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->smls_clr, b->data.avc->smls_clr);
+}
+
+static int sort_source_mls_clr_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->smls_clr != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_source_mls_clr(const int direction)
+{
+ return sort_create("source_mls_clr", sort_source_mls_clr_comp, sort_source_mls_clr_support, direction);
+}
+
+static int sort_target_user_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->tuser, b->data.avc->tuser);
+}
+
+static int sort_target_user_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tuser != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_target_user(const int direction)
+{
+ return sort_create("target_user", sort_target_user_comp, sort_target_user_support, direction);
+}
+
+static int sort_target_role_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->trole, b->data.avc->trole);
+}
+
+static int sort_target_role_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->trole != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_target_role(const int direction)
+{
+ return sort_create("target_role", sort_target_role_comp, sort_target_role_support, direction);
+}
+
+static int sort_target_type_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->ttype, b->data.avc->ttype);
+}
+
+static int sort_target_type_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->ttype != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_target_type(const int direction)
+{
+ return sort_create("target_type", sort_target_type_comp, sort_target_type_support, direction);
+}
+
+static int sort_target_mls_lvl_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->tmls_lvl, b->data.avc->tmls_lvl);
+}
+
+static int sort_target_mls_lvl_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tmls_lvl != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_target_mls_lvl(const int direction)
+{
+ return sort_create("target_mls_lvl", sort_target_mls_lvl_comp, sort_target_mls_lvl_support, direction);
+}
+
+static int sort_target_mls_clr_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->tmls_clr, b->data.avc->tmls_clr);
+}
+
+static int sort_target_mls_clr_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tmls_clr != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_target_mls_clr(const int direction)
+{
+ return sort_create("target_mls_clr", sort_target_mls_clr_comp, sort_target_mls_clr_support, direction);
+}
+
+static int sort_object_class_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->tclass, b->data.avc->tclass);
+}
+
+static int sort_object_class_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tclass != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_object_class(const int direction)
+{
+ return sort_create("object_class", sort_object_class_comp, sort_object_class_support, direction);
+}
+
+static int sort_executable_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->exe, b->data.avc->exe);
+}
+
+static int sort_executable_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->exe != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_executable(const int direction)
+{
+ return sort_create("executable", sort_executable_comp, sort_executable_support, direction);
+}
+
+static int sort_command_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->comm, b->data.avc->comm);
+}
+
+static int sort_command_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->comm != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_command(const int direction)
+{
+ return sort_create("command", sort_command_comp, sort_command_support, direction);
+}
+
+static int sort_name_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->name, b->data.avc->name);
+}
+
+static int sort_name_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->name != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_name(const int direction)
+{
+ return sort_create("name", sort_name_comp, sort_name_support, direction);
+}
+
+static int sort_path_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->path, b->data.avc->path);
+}
+
+static int sort_path_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->path != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_path(const int direction)
+{
+ return sort_create("path", sort_path_comp, sort_path_support, direction);
+}
+
+static int sort_device_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->dev, b->data.avc->dev);
+}
+
+static int sort_device_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->dev != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_device(const int direction)
+{
+ return sort_create("device", sort_device_comp, sort_device_support, direction);
+}
+
+static int sort_inode_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ /* need this logic because inodes are unsigned, so subtraction
+ * could overflow */
+ if (a->data.avc->inode < b->data.avc->inode) {
+ return -1;
+ }
+ return a->data.avc->inode - b->data.avc->inode;
+}
+
+static int sort_inode_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->inode > 0;
+}
+
+seaudit_sort_t *seaudit_sort_by_inode(const int direction)
+{
+ return sort_create("inode", sort_inode_comp, sort_inode_support, direction);
+}
+
+static int sort_pid_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ /* need this logic because pids are unsigned, so subtraction
+ * could overflow */
+ if (a->data.avc->pid < b->data.avc->pid) {
+ return -1;
+ }
+ return a->data.avc->pid - b->data.avc->pid;
+}
+
+static int sort_pid_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->pid > 0;
+}
+
+seaudit_sort_t *seaudit_sort_by_pid(const int direction)
+{
+ return sort_create("pid", sort_pid_comp, sort_pid_support, direction);
+}
+
+static int sort_port_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return a->data.avc->port - b->data.avc->port;
+}
+
+static int sort_port_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->port > 0;
+}
+
+seaudit_sort_t *seaudit_sort_by_port(const int direction)
+{
+ return sort_create("port", sort_port_comp, sort_port_support, direction);
+}
+
+static int sort_laddr_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->laddr, b->data.avc->laddr);
+}
+
+static int sort_laddr_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->laddr != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_laddr(const int direction)
+{
+ return sort_create("laddr", sort_laddr_comp, sort_laddr_support, direction);
+}
+
+static int sort_lport_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return a->data.avc->lport - b->data.avc->lport;
+}
+
+static int sort_lport_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->lport > 0;
+}
+
+seaudit_sort_t *seaudit_sort_by_lport(const int direction)
+{
+ return sort_create("lport", sort_lport_comp, sort_lport_support, direction);
+}
+
+static int sort_faddr_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->faddr, b->data.avc->faddr);
+}
+
+static int sort_faddr_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->faddr != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_faddr(const int direction)
+{
+ return sort_create("faddr", sort_faddr_comp, sort_faddr_support, direction);
+}
+
+static int sort_fport_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return a->data.avc->fport - b->data.avc->fport;
+}
+
+static int sort_fport_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->fport > 0;
+}
+
+seaudit_sort_t *seaudit_sort_by_fport(const int direction)
+{
+ return sort_create("fport", sort_fport_comp, sort_fport_support, direction);
+}
+
+static int sort_saddr_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->saddr, b->data.avc->saddr);
+}
+
+static int sort_saddr_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->saddr != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_saddr(const int direction)
+{
+ return sort_create("saddr", sort_saddr_comp, sort_saddr_support, direction);
+}
+
+static int sort_sport_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return a->data.avc->source - b->data.avc->source;
+}
+
+static int sort_sport_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->source > 0;
+}
+
+seaudit_sort_t *seaudit_sort_by_sport(const int direction)
+{
+ return sort_create("sport", sort_sport_comp, sort_sport_support, direction);
+}
+
+static int sort_daddr_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return strcmp(a->data.avc->daddr, b->data.avc->daddr);
+}
+
+static int sort_daddr_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->daddr != NULL;
+}
+
+seaudit_sort_t *seaudit_sort_by_daddr(const int direction)
+{
+ return sort_create("daddr", sort_daddr_comp, sort_daddr_support, direction);
+}
+
+static int sort_dport_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return a->data.avc->dest - b->data.avc->dest;
+}
+
+static int sort_dport_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->dest > 0;
+}
+
+seaudit_sort_t *seaudit_sort_by_dport(const int direction)
+{
+ return sort_create("dport", sort_dport_comp, sort_dport_support, direction);
+}
+
+static int sort_key_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return a->data.avc->key - b->data.avc->key;
+}
+
+static int sort_key_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->is_key;
+}
+
+seaudit_sort_t *seaudit_sort_by_key(const int direction)
+{
+ return sort_create("key", sort_key_comp, sort_key_support, direction);
+}
+
+static int sort_cap_comp(const seaudit_sort_t * sort
+ __attribute__ ((unused)), const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ return a->data.avc->capability - b->data.avc->capability;
+}
+
+static int sort_cap_support(const seaudit_sort_t * sort __attribute__ ((unused)), const seaudit_message_t * msg)
+{
+ return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->is_capability;
+}
+
+seaudit_sort_t *seaudit_sort_by_cap(const int direction)
+{
+ return sort_create("cap", sort_cap_comp, sort_cap_support, direction);
+}
+
+/******************** protected functions below ********************/
+
+struct sort_name_map
+{
+ const char *name;
+ seaudit_sort_t *(*create_fn) (int);
+};
+
+static const struct sort_name_map create_map[] = {
+ {"message_type", seaudit_sort_by_message_type},
+ {"date", seaudit_sort_by_date},
+ {"host", seaudit_sort_by_host},
+ {"permission", seaudit_sort_by_permission},
+ {"source_user", seaudit_sort_by_source_user},
+ {"source_role", seaudit_sort_by_source_role},
+ {"source_type", seaudit_sort_by_source_type},
+ {"target_user", seaudit_sort_by_target_user},
+ {"target_role", seaudit_sort_by_target_role},
+ {"target_type", seaudit_sort_by_target_type},
+ {"object_class", seaudit_sort_by_object_class},
+ {"executable", seaudit_sort_by_executable},
+ {"name", seaudit_sort_by_name},
+ {"command", seaudit_sort_by_command},
+ {"path", seaudit_sort_by_path},
+ {"device", seaudit_sort_by_device},
+ {"inode", seaudit_sort_by_inode},
+ {"pid", seaudit_sort_by_pid},
+ {"port", seaudit_sort_by_port},
+ {"laddr", seaudit_sort_by_laddr},
+ {"lport", seaudit_sort_by_lport},
+ {"faddr", seaudit_sort_by_faddr},
+ {"fport", seaudit_sort_by_fport},
+ {"saddr", seaudit_sort_by_saddr},
+ {"sport", seaudit_sort_by_sport},
+ {"daddr", seaudit_sort_by_daddr},
+ {"dport", seaudit_sort_by_dport},
+ {"key", seaudit_sort_by_key},
+ {"cap", seaudit_sort_by_cap},
+ {NULL, NULL}
+};
+
+seaudit_sort_t *sort_create_from_name(const char *name, int direction)
+{
+ size_t i;
+ for (i = 0; create_map[i].name != NULL; i++) {
+ if (strcmp(create_map[i].name, name) == 0) {
+ return create_map[i].create_fn(direction);
+ }
+ }
+ errno = EINVAL;
+ return NULL;
+}
+
+int sort_is_supported(const seaudit_sort_t * sort, const seaudit_message_t * msg)
+{
+ return sort->support(sort, msg);
+}
+
+int sort_comp(const seaudit_sort_t * sort, const seaudit_message_t * a, const seaudit_message_t * b)
+{
+ int retval = sort->comp(sort, a, b);
+ return (sort->direction >= 0 ? retval : -1 * retval);
+}
+
+const char *sort_get_name(const seaudit_sort_t * sort)
+{
+ return sort->name;
+}
+
+int sort_get_direction(const seaudit_sort_t * sort)
+{
+ return sort->direction;
+}
diff --git a/libseaudit/src/util.c b/libseaudit/src/util.c
new file mode 100644
index 0000000..4df653c
--- /dev/null
+++ b/libseaudit/src/util.c
@@ -0,0 +1,32 @@
+/**
+ * @file
+ *
+ * Implementation of utility functions.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <seaudit/util.h>
+
+const char *libseaudit_get_version(void)
+{
+ return LIBSEAUDIT_VERSION_STRING;
+}