summaryrefslogtreecommitdiffstats
path: root/libseaudit
diff options
context:
space:
mode:
Diffstat (limited to 'libseaudit')
-rw-r--r--libseaudit/Makefile.am8
-rw-r--r--libseaudit/include/Makefile.am1
-rw-r--r--libseaudit/include/seaudit/Makefile.am14
-rw-r--r--libseaudit/include/seaudit/avc_message.h374
-rw-r--r--libseaudit/include/seaudit/bool_message.h43
-rw-r--r--libseaudit/include/seaudit/filter.h1025
-rw-r--r--libseaudit/include/seaudit/load_message.h41
-rw-r--r--libseaudit/include/seaudit/log.h162
-rw-r--r--libseaudit/include/seaudit/message.h133
-rw-r--r--libseaudit/include/seaudit/model.h362
-rw-r--r--libseaudit/include/seaudit/parse.h72
-rw-r--r--libseaudit/include/seaudit/report.h140
-rw-r--r--libseaudit/include/seaudit/sort.h491
-rw-r--r--libseaudit/include/seaudit/util.h44
-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
-rw-r--r--libseaudit/swig/Makefile.am15
-rw-r--r--libseaudit/swig/java/MANIFEST.MF.in14
-rw-r--r--libseaudit/swig/java/Makefile.am90
-rw-r--r--libseaudit/swig/python/Makefile.am39
-rw-r--r--libseaudit/swig/seaudit.i1373
-rw-r--r--libseaudit/swig/tcl/Makefile.am37
-rw-r--r--libseaudit/tests/Makefile.am16
-rw-r--r--libseaudit/tests/filters.c114
-rw-r--r--libseaudit/tests/filters.h35
-rw-r--r--libseaudit/tests/libseaudit-tests.c54
-rw-r--r--libseaudit/tests/parse_file.c113
-rw-r--r--libseaudit/tests/parse_file.h35
42 files changed, 13896 insertions, 0 deletions
diff --git a/libseaudit/Makefile.am b/libseaudit/Makefile.am
new file mode 100644
index 0000000..b1a8149
--- /dev/null
+++ b/libseaudit/Makefile.am
@@ -0,0 +1,8 @@
+if DO_SWIGIFY
+ MAYBE_SWIG = swig
+endif
+
+SUBDIRS = src include tests $(MAYBE_SWIG)
+
+libseaudit.a libseaudit.so:
+ $(MAKE) -C src $@
diff --git a/libseaudit/include/Makefile.am b/libseaudit/include/Makefile.am
new file mode 100644
index 0000000..e922703
--- /dev/null
+++ b/libseaudit/include/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = seaudit \ No newline at end of file
diff --git a/libseaudit/include/seaudit/Makefile.am b/libseaudit/include/seaudit/Makefile.am
new file mode 100644
index 0000000..7f11f38
--- /dev/null
+++ b/libseaudit/include/seaudit/Makefile.am
@@ -0,0 +1,14 @@
+seauditdir = $(includedir)/seaudit
+
+seaudit_HEADERS = \
+ avc_message.h \
+ bool_message.h \
+ filter.h \
+ load_message.h \
+ log.h \
+ message.h \
+ model.h \
+ parse.h \
+ report.h \
+ sort.h \
+ util.h
diff --git a/libseaudit/include/seaudit/avc_message.h b/libseaudit/include/seaudit/avc_message.h
new file mode 100644
index 0000000..b7263ea
--- /dev/null
+++ b/libseaudit/include/seaudit/avc_message.h
@@ -0,0 +1,374 @@
+/**
+ * @file
+ * Public interface for a single AVC log message. This is a subclass
+ * of seaudit_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
+ */
+
+#ifndef SEAUDIT_AVC_MESSAGE_H
+#define SEAUDIT_AVC_MESSAGE_H
+
+#include <apol/vector.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ typedef struct seaudit_avc_message seaudit_avc_message_t;
+
+/**
+ * AVC messages may be either a granted (i.e., an allow) or a denied.
+ */
+ typedef enum seaudit_avc_message_type
+ {
+ SEAUDIT_AVC_UNKNOWN = 0,
+ SEAUDIT_AVC_DENIED,
+ SEAUDIT_AVC_GRANTED
+ } seaudit_avc_message_type_e;
+
+/**
+ * Return the type of avc message this is, either a granted (i.e., an
+ * allow) or a denied.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return One of SEAUDIT_AVC_DENIED or SEAUDIT_AVC_GRANTED, or
+ * SEAUDIT_AVC_UNKNOWN upon error or if unknown.
+ */
+ extern seaudit_avc_message_type_e seaudit_avc_message_get_message_type(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the avc message's timestamp, measured in nanoseconds.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Timestamp, in nanoseconds, or 0 upon error or if unknown.
+ */
+ extern long seaudit_avc_message_get_timestamp_nano(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the source context's user of an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Source user, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_source_user(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the source context's role of an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Source role, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_source_role(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the source context's type of an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Source target, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_source_type(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the source context's mls level of an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Source target, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_source_mls_lvl(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the source context's mls clearance of an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Source target, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_source_mls_clr(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the target context's user of an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Target user, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_target_user(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the target context's role of an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Target role, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_target_role(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the target context's type of an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Target type, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_target_type(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the target context's mls level of an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Target type, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_target_mls_lvl(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the target context's mls clearance of an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Target type, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_target_mls_clr(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the object class from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Object class, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_object_class(const seaudit_avc_message_t * avc);
+
+/**
+ * Return a vector of permissions (type char *) from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Vector of permission strings, or NULL upon error or if
+ * unknown. Do not modify the vector in any way.
+ */
+ extern const apol_vector_t *seaudit_avc_message_get_perm(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the executable and path from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Executable string, or NULL upon error or if unknown. Do
+ * not free() this string.
+ */
+ extern const char *seaudit_avc_message_get_exe(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the command from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Command, or NULL upon error or if unknown. Do not free()
+ * this string.
+ */
+ extern const char *seaudit_avc_message_get_comm(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the name from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Name, or NULL upon error or if unknown. Do not free() this
+ * string.
+ */
+ extern const char *seaudit_avc_message_get_name(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the process ID from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Process's PID, or 0 upon error or if unknown.
+ */
+ extern unsigned int seaudit_avc_message_get_pid(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the inode from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Process's PID, or 0 upon error or if unknown.
+ */
+ extern unsigned long seaudit_avc_message_get_inode(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the path of the object from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Object's path, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_path(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the device for the object from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Object's device, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_dev(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the network interface for the object from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Network interface, or NULL upon error or if unknown. Do
+ * not free() this string.
+ */
+ extern const char *seaudit_avc_message_get_netif(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the port number from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Port, or 0 upon error or if unknown.
+ */
+ extern int seaudit_avc_message_get_port(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the local address from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Local address, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_laddr(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the local port from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Local port, or 0 upon error or if unknown.
+ */
+ extern int seaudit_avc_message_get_lport(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the foreign address from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Foreign address, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_faddr(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the foreign port from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Foreign port, or 0 upon error or if unknown.
+ */
+ extern int seaudit_avc_message_get_fport(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the source address from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Source address, or NULL upon error or if unknown. Do not
+ * free() this string.
+ */
+ extern const char *seaudit_avc_message_get_saddr(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the source port from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Source port, or 0 upon error or if unknown.
+ */
+ extern int seaudit_avc_message_get_sport(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the destination address from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Destination address, or NULL upon error or if unknown. Do
+ * not free() this string.
+ */
+ extern const char *seaudit_avc_message_get_daddr(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the destination port from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Destination port, or 0 upon error or if unknown.
+ */
+ extern int seaudit_avc_message_get_dport(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the IPC key from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Key, or -1 upon error or if unknown.
+ */
+ extern int seaudit_avc_message_get_key(const seaudit_avc_message_t * avc);
+
+/**
+ * Return the process capability from an avc message.
+ *
+ * @param avc AVC message to check.
+ *
+ * @return Capability, or -1 upon error or if unknown.
+ */
+ extern int seaudit_avc_message_get_cap(const seaudit_avc_message_t * avc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libseaudit/include/seaudit/bool_message.h b/libseaudit/include/seaudit/bool_message.h
new file mode 100644
index 0000000..4ff9df3
--- /dev/null
+++ b/libseaudit/include/seaudit/bool_message.h
@@ -0,0 +1,43 @@
+/**
+ * @file
+ * Public interface for a single boolean change log message. This is
+ * a subclass of seaudit_message; it has no publicly accessible
+ * 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
+ */
+
+#ifndef SEAUDIT_BOOL_MESSAGE_H
+#define SEAUDIT_BOOL_MESSAGE_H
+
+#include <apol/vector.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ typedef struct seaudit_bool_message seaudit_bool_message_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libseaudit/include/seaudit/filter.h b/libseaudit/include/seaudit/filter.h
new file mode 100644
index 0000000..ce40b5e
--- /dev/null
+++ b/libseaudit/include/seaudit/filter.h
@@ -0,0 +1,1025 @@
+/**
+ * @file
+ *
+ * Public interface to a seaudit_filter. A filter is used to modify
+ * the list of messages returned from a seaudit_model.
+ *
+ * @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
+ */
+
+#ifndef SEAUDIT_FILTER_H
+#define SEAUDIT_FILTER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <seaudit/avc_message.h>
+
+#include <apol/vector.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <time.h>
+
+ typedef struct seaudit_filter seaudit_filter_t;
+
+/**
+ * By default, all criteria of a filter must be met for a message to
+ * be accepted. This behavior can be changed such that a message is
+ * accepted if any of the criteria pass.
+ */
+ typedef enum seaudit_filter_match
+ {
+ SEAUDIT_FILTER_MATCH_ALL = 0,
+ SEAUDIT_FILTER_MATCH_ANY
+ } seaudit_filter_match_e;
+
+/**
+ * By default, only messages accepted by filters will be shown by the
+ * model. This behavior can be changed such that filters are used to
+ * select messages to hide.
+ */
+ typedef enum seaudit_filter_visible
+ {
+ SEAUDIT_FILTER_VISIBLE_SHOW = 0,
+ SEAUDIT_FILTER_VISIBLE_HIDE
+ } seaudit_filter_visible_e;
+
+/**
+ * When specifying a date/time for the filter, one must also give how
+ * to match the date and time.
+ */
+ typedef enum seaudit_filter_date_match
+ {
+ SEAUDIT_FILTER_DATE_MATCH_BEFORE = 0,
+ SEAUDIT_FILTER_DATE_MATCH_AFTER,
+ SEAUDIT_FILTER_DATE_MATCH_BETWEEN
+ } seaudit_filter_date_match_e;
+
+/**
+ * Create a new filter object. The default matching behavior is to
+ * accept all messages.
+ *
+ * @param name Name for the filter; the string will be duplicated. If
+ * NULL then the filter will be assigned a default name.
+ *
+ * @return A newly allocated filter. The caller is responsible for
+ * calling seaudit_filter_destroy() afterwards.
+ */
+ extern seaudit_filter_t *seaudit_filter_create(const char *name);
+
+/**
+ * Create a new filter object, initialized with the data from an
+ * existing filter. This will do a deep copy of the original filter.
+ * The new filter will not be attached to any model.
+ *
+ * @param filter Filter to clone.
+ *
+ * @return A cloned filter, or NULL upon error. The caller is
+ * responsible for calling seaudit_filter_destroy() afterwards.
+ */
+ extern seaudit_filter_t *seaudit_filter_create_from_filter(const seaudit_filter_t * filter);
+
+/**
+ * Create and return a vector of filters (type seaudit_filter),
+ * initialized from the contents of a XML configuration file.
+ *
+ * @param filename File containing one or more filter data.
+ *
+ * @return Vector of filters created from that file, or NULL upon
+ * error. The caller is responsible for apol_vector_destroy().
+ *
+ * @see seaudit_filter_save_to_file()
+ */
+ extern apol_vector_t *seaudit_filter_create_from_file(const char *filename);
+
+/**
+ * Destroy the referenced seaudit_filter object.
+ *
+ * @param filter Filter object to destroy. The pointer will be set to
+ * NULL afterwards. (If pointer is already NULL then do nothing.)
+ */
+ extern void seaudit_filter_destroy(seaudit_filter_t ** filter);
+
+/**
+ * Save to disk, in XML format, the given filter's values. This
+ * includes the filter's criteria.
+ *
+ * @param filter Filter to save.
+ * @param filename Name of the file to write. If the file already
+ * exists it will be overwritten.
+ *
+ * @return 0 on success, < 0 on error.
+ *
+ * @see seaudit_filter_create_from_file()
+ */
+ extern int seaudit_filter_save_to_file(const seaudit_filter_t * filter, const char *filename);
+
+/**
+ * Set a filter to accept a message if all criteria are met (default
+ * behavior) or if any criterion is met.
+ *
+ * @param filter Filter to modify.
+ * @param match Matching behavior if filter has multiple criteria.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_match(seaudit_filter_t * filter, seaudit_filter_match_e match);
+
+/**
+ * Get the current match value for a filter.
+ *
+ * @param filter Filter containing match value.
+ *
+ * @return One of SEAUDIT_FILTER_MATCH_ALL or SEAUDIT_FILTER_MATCH_ANY.
+ */
+ extern seaudit_filter_match_e seaudit_filter_get_match(const seaudit_filter_t * filter);
+
+/**
+ * Set the name of this filter, overwriting any previous name.
+ *
+ * @param filter Filter to modify.
+ * @param name New name for this filter. This function will duplicate
+ * the string. If this is NULL then clear the existing name.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_name(seaudit_filter_t * filter, const char *name);
+
+/**
+ * Get the name of this filter.
+ *
+ * @param filter Filter from which to get name.
+ *
+ * @return Name of the filter, or NULL if no name has been set. Do
+ * not free() or otherwise modify this string.
+ */
+ extern const char *seaudit_filter_get_name(const seaudit_filter_t * filter);
+
+/**
+ * Set the description of this filter, overwriting any previous
+ * description.
+ *
+ * @param filter Filter to modify.
+ * @param desc New description for this filter. This function will
+ * duplicate the string. If this is NULL then clear the existing
+ * description.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_description(seaudit_filter_t * filter, const char *desc);
+
+/**
+ * Get the description of this filter.
+ *
+ * @param filter Filter from which to get description.
+ *
+ * @return Description of the filter, or NULL if no description has
+ * been set. Do not free() or otherwise modify this string.
+ */
+ extern const char *seaudit_filter_get_description(const seaudit_filter_t * filter);
+
+/**
+ * Set the strictness of this filter. By default, the filter's
+ * criteria are not "strict", meaning if a message does not have a
+ * field then the criterion will match it. For example, an AVC denied
+ * message might not have an 'laddr' field in it. If a filter was
+ * created with seaudit_filter_set_laddr(), the filter would still
+ * accept the message.
+ *
+ * If instead a filter is set as strict, then messages that do not
+ * have the field in question will be rejected. For the example
+ * above, a strict filter would eliminate that AVC message. In
+ * addition, an empty filter (i.e., one without any criterion set)
+ * does not match any messages if it is set to strict.
+ *
+ * @param filter Filter to modify.
+ * @param strict If true, enable strict matching.
+ *
+ * @return Always 0.
+ */
+ extern int seaudit_filter_set_strict(seaudit_filter_t * filter, bool is_strict);
+
+/**
+ * Get the strictness of this filter.
+ *
+ * @param filter Filter from which to get strictness.
+ *
+ * @return True if the filter will reject messages that do not contain
+ * fields being filtered, false if they are accepted.
+ */
+ extern bool seaudit_filter_get_strict(const seaudit_filter_t * filter);
+
+/**
+ * Set the list of source users. A message is accepted if its source
+ * user is within this list. The filter will duplicate the vector and
+ * the strings within.
+ *
+ * @param filter Filter to modify.
+ * @param v Vector of strings, or NULL to clear current settings.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_source_user(seaudit_filter_t * filter, const apol_vector_t * v);
+
+/**
+ * Return the current list of source users for a filter. This will be
+ * a vector of strings. Treat the vector and its contents as const.
+ *
+ * @param filter Filter to get values.
+ *
+ * @return Vector of strings, or NULL if no value has been set.
+ */
+ extern const apol_vector_t *seaudit_filter_get_source_user(const seaudit_filter_t * filter);
+
+/**
+ * Set the list of source roles. A message is accepted if its source
+ * role is within this list. The filter will duplicate the vector and
+ * the strings within.
+ *
+ * @param filter Filter to modify.
+ * @param v Vector of strings, or NULL to clear current settings.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_source_role(seaudit_filter_t * filter, const apol_vector_t * v);
+
+/**
+ * Return the current list of source roles for a filter. This will be
+ * a vector of strings. Treat the vector and its contents as const.
+ *
+ * @param filter Filter to get values.
+ *
+ * @return Vector of strings, or NULL if no value has been set.
+ */
+ extern const apol_vector_t *seaudit_filter_get_source_role(const seaudit_filter_t * filter);
+
+/**
+ * Set the list of source types. A message is accepted if its source
+ * type is within this list. The filter will duplicate the vector and
+ * the strings within.
+ *
+ * @param filter Filter to modify.
+ * @param v Vector of strings, or NULL to clear current settings.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_source_type(seaudit_filter_t * filter, const apol_vector_t * v);
+
+/**
+ * Return the current list of source types for a filter. This will be
+ * a vector of strings. Treat the vector and its contents as const.
+ *
+ * @param filter Filter to get values.
+ *
+ * @return Vector of strings, or NULL if no value has been set.
+ */
+ extern const apol_vector_t *seaudit_filter_get_source_type(const seaudit_filter_t * filter);
+
+/**
+ * Set the list of source mls levels. A message is accepted if its source
+ * mls level is within this list. The filter will duplicate the vector and
+ * the strings within.
+ *
+ * @param filter Filter to modify.
+ * @param v Vector of strings, or NULL to clear current settings.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_source_mls_lvl(seaudit_filter_t * filter, const apol_vector_t * v);
+
+/**
+ * Return the current list of source mls levels for a filter. This will be
+ * a vector of strings. Treat the vector and its contents as const.
+ *
+ * @param filter Filter to get values.
+ *
+ * @return Vector of strings, or NULL if no value has been set.
+ */
+ extern const apol_vector_t *seaudit_filter_get_source_mls_lvl(const seaudit_filter_t * filter);
+
+/**
+ * Set the list of source mls clearance. A message is accepted if its source
+ * mls clearance is within this list. The filter will duplicate the vector and
+ * the strings within.
+ *
+ * @param filter Filter to modify.
+ * @param v Vector of strings, or NULL to clear current settings.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_source_mls_clr(seaudit_filter_t * filter, const apol_vector_t * v);
+
+/**
+ * Return the current list of source mls clearance for a filter. This will be
+ * a vector of strings. Treat the vector and its contents as const.
+ *
+ * @param filter Filter to get values.
+ *
+ * @return Vector of strings, or NULL if no value has been set.
+ */
+ extern const apol_vector_t *seaudit_filter_get_source_mls_clr(const seaudit_filter_t * filter);
+
+/**
+ * Set the list of target users. A message is accepted if its target
+ * user is within this list. The filter will duplicate the vector and
+ * the strings within.
+ *
+ * @param filter Filter to modify.
+ * @param v Vector of strings, or NULL to clear current settings.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_target_user(seaudit_filter_t * filter, const apol_vector_t * v);
+
+/**
+ * Return the current list of target users for a filter. This will be
+ * a vector of strings. Treat the vector and its contents as const.
+ *
+ * @param filter Filter to get values.
+ *
+ * @return Vector of strings, or NULL if no value has been set.
+ */
+ extern const apol_vector_t *seaudit_filter_get_target_user(const seaudit_filter_t * filter);
+
+/**
+ * Set the list of target roles. A message is accepted if its target
+ * role is within this list. The filter will duplicate the vector and
+ * the strings within.
+ *
+ * @param filter Filter to modify.
+ * @param v Vector of strings, or NULL to clear current settings.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_target_role(seaudit_filter_t * filter, const apol_vector_t * v);
+
+/**
+ * Return the current list of target roles for a filter. This will be
+ * a vector of strings. Treat the vector and its contents as const.
+ *
+ * @param filter Filter to get values.
+ *
+ * @return Vector of strings, or NULL if no value has been set.
+ */
+ extern const apol_vector_t *seaudit_filter_get_target_role(const seaudit_filter_t * filter);
+
+/**
+ * Set the list of target types. A message is accepted if its target
+ * type is within this list. The filter will duplicate the vector and
+ * the strings within.
+ *
+ * @param filter Filter to modify.
+ * @param v Vector of strings, or NULL to clear current settings.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_target_type(seaudit_filter_t * filter, const apol_vector_t * v);
+
+/**
+ * Return the current list of target types for a filter. This will be
+ * a vector of strings. Treat the vector and its contents as const.
+ *
+ * @param filter Filter to get values.
+ *
+ * @return Vector of strings, or NULL if no value has been set.
+ */
+ extern const apol_vector_t *seaudit_filter_get_target_type(const seaudit_filter_t * filter);
+
+/**
+ * Set the list of target mls levels. A message is accepted if its target
+ * mls level is within this list. The filter will duplicate the vector and
+ * the strings within.
+ *
+ * @param filter Filter to modify.
+ * @param v Vector of strings, or NULL to clear current settings.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_target_mls_lvl(seaudit_filter_t * filter, const apol_vector_t * v);
+
+/**
+ * Return the current list of target mls levels for a filter. This will be
+ * a vector of strings. Treat the vector and its contents as const.
+ *
+ * @param filter Filter to get values.
+ *
+ * @return Vector of strings, or NULL if no value has been set.
+ */
+ extern const apol_vector_t *seaudit_filter_get_target_mls_lvl(const seaudit_filter_t * filter);
+
+ /**
+ * Set the list of target mls clearance. A message is accepted if its target
+ * mls clearance is within this list. The filter will duplicate the vector and
+ * the strings within.
+ *
+ * @param filter Filter to modify.
+ * @param v Vector of strings, or NULL to clear current settings.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_target_mls_clr(seaudit_filter_t * filter, const apol_vector_t * v);
+
+/**
+ * Return the current list of target mls clearance for a filter. This will be
+ * a vector of strings. Treat the vector and its contents as const.
+ *
+ * @param filter Filter to get values.
+ *
+ * @return Vector of strings, or NULL if no value has been set.
+ */
+ extern const apol_vector_t *seaudit_filter_get_target_mls_clr(const seaudit_filter_t * filter);
+
+/**
+ * Set the list of target object classes. A message is accepted if
+ * its target class is within this list. The filter will duplicate
+ * the vector and the strings within.
+ *
+ * @param filter Filter to modify.
+ * @param v Vector of strings, or NULL to clear current settings.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_target_class(seaudit_filter_t * filter, const apol_vector_t * v);
+
+/**
+ * Return the current list of target object classes for a filter.
+ * This will be a vector of strings. Treat the vector and its
+ * contents as const.
+ *
+ * @param filter Filter to get values.
+ *
+ * @return Vector of strings, or NULL if no value has been set.
+ */
+ extern const apol_vector_t *seaudit_filter_get_target_class(const seaudit_filter_t * filter);
+
+/**
+ * Set the permission criterion, as a glob expression. A message is
+ * accepted if at least one of its AVC permissions match the
+ * criterion.
+ *
+ * @param filter Filter to modify.
+ * @param perm Glob expression for permission. This function will
+ * duplicate the string. If this is NULL then clear the existing
+ * permission.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_permission(seaudit_filter_t * filter, const char *perm);
+
+/**
+ * Return the current permission for a filter. Treat this string as
+ * const.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Glob expression for permission, or NULL if none set.
+ */
+ extern const char *seaudit_filter_get_permission(const seaudit_filter_t * filter);
+
+/**
+ * Set the executable criterion, as a glob expression. A message is
+ * accepted if its executable matches this expression.
+ *
+ * @param filter Filter to modify.
+ * @param exe Glob expression for executable. This function will
+ * duplicate the string. If this is NULL then clear the existing
+ * executable.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_executable(seaudit_filter_t * filter, const char *exe);
+
+/**
+ * Return the current executable for a filter. Treat this string as
+ * const.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Glob expression for executable, or NULL if none set.
+ */
+ extern const char *seaudit_filter_get_executable(const seaudit_filter_t * filter);
+
+/**
+ * Set the host criterion, as a glob expression. A message is
+ * accepted if its host matches this expression.
+ *
+ * @param filter Filter to modify.
+ * @param host Glob expression for host. This function will duplicate
+ * the string. If this is NULL then clear the existing host.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_host(seaudit_filter_t * filter, const char *host);
+
+/**
+ * Return the current host for a filter. Treat this string as const.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Glob expression for host, or NULL if none set.
+ */
+ extern const char *seaudit_filter_get_host(const seaudit_filter_t * filter);
+
+/**
+ * Set the path criterion, as a glob expression. A message is
+ * accepted if its path matches this expression.
+ *
+ * @param filter Filter to modify.
+ * @param path Glob expression for path. This function will duplicate
+ * the string. If this is NULL then clear the existing path.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_path(seaudit_filter_t * filter, const char *path);
+
+/**
+ * Return the current path for a filter. Treat this string as const.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Glob expression for path, or NULL if none set.
+ */
+ extern const char *seaudit_filter_get_path(const seaudit_filter_t * filter);
+
+/**
+ * Set the inode criterion. A message is accepted if its inode
+ * exactly matches this inode value.
+ *
+ * @param filter Filter to modify.
+ * @param inode inode value to match. If this is 0 then clear the
+ * existing inode.
+ *
+ * @return Always 0.
+ */
+ extern int seaudit_filter_set_inode(seaudit_filter_t * filter, unsigned long inode);
+
+/**
+ * Return the current inode for a filter.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Current inode value, or 0 if none set.
+ */
+ extern unsigned long seaudit_filter_get_inode(const seaudit_filter_t * filter);
+
+/**
+ * Set the pid criterion. A message is accepted if its pid value
+ * exactly matches this pid value.
+ *
+ * @param filter Filter to modify.
+ * @param pid value to match. If this is 0 then clear the existing pid.
+ *
+ * @return Always 0.
+ */
+ extern int seaudit_filter_set_pid(seaudit_filter_t * filter, unsigned int pid);
+
+/**
+ * Return the current pid for a filter.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Current pid value, or 0 if none set.
+ */
+ extern unsigned int seaudit_filter_get_pid(const seaudit_filter_t * filter);
+
+/**
+ * Set the command criterion, as a glob expression. A message is
+ * accepted if its command matches this expression.
+ *
+ * @param filter Filter to modify.
+ * @param command Glob expression for command. This function will
+ * duplicate the string. If this is NULL then clear the existing
+ * command.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_command(seaudit_filter_t * filter, const char *command);
+
+/**
+ * Return the current command for a filter. Treat this string as const.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Glob expression for command, or NULL if none set.
+ */
+ extern const char *seaudit_filter_get_command(const seaudit_filter_t * filter);
+
+/**
+ * Set the IP address criterion, as a glob expression. A message is
+ * accepted if any of its IP addresses (ipaddr, saddr, daddr, faddr,
+ * or laddr) matches this expression.
+ *
+ * @param filter Filter to modify.
+ * @param ipaddr Glob expression for IP address. This function will
+ * duplicate the string. If this is NULL then clear the existing
+ * address.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_anyaddr(seaudit_filter_t * filter, const char *ipaddr);
+
+/**
+ * Return the current IP address for a filter. Treat this string as
+ * const.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Glob expression for address, or NULL if none set.
+ */
+ extern const char *seaudit_filter_get_anyaddr(const seaudit_filter_t * filter);
+
+/**
+ * Set the port criterion. A message is accepted if any of its ports
+ * (port, source, dest, fport, or lport) matches this port.
+ *
+ * @param filter Filter to modify.
+ * @param port Port criterion. If this is zero or negative then clear
+ * the existing port.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_anyport(seaudit_filter_t * filter, const int port);
+
+/**
+ * Return the current port for a filter.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Current port criterion, or 0 if none set.
+ */
+ extern int seaudit_filter_get_anyport(const seaudit_filter_t * filter);
+
+/**
+ * Set the local address criterion, as a glob expression. A message
+ * is accepted if its local address (laddr) matches this expression.
+ * Note that if seaudit_filter_set_anyaddr() is also set, then the
+ * message must match both ipaddr and laddr for it to be accepted
+ * (assuming that the match is set to SEAUDIT_FILTER_MATCH_ALL).
+ *
+ * @param filter Filter to modify.
+ * @param laddr Glob expression for local address. This function will
+ * duplicate the string. If this is NULL then clear the existing
+ * address.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_laddr(seaudit_filter_t * filter, const char *laddr);
+
+/**
+ * Return the current local address for a filter. Treat this string
+ * as const.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Glob expression for address, or NULL if none set.
+ */
+ extern const char *seaudit_filter_get_laddr(const seaudit_filter_t * filter);
+
+/**
+ * Set the local port criterion. A message is accepted if its local
+ * port (lport) matches this port. Note that if
+ * seaudit_filter_set_anyport() is also set, then the message must
+ * match both anyport and lport for it to be accepted (assuming that
+ * the match is set to SEAUDIT_FILTER_MATCH_ALL).
+ *
+ * @param filter Filter to modify.
+ * @param lport Local port criterion. If this is zero or negative
+ * then clear the existing port.
+ *
+ * @return Always 0.
+ */
+ extern int seaudit_filter_set_lport(seaudit_filter_t * filter, const int lport);
+
+/**
+ * Return the current local port for a filter.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Current port criterion, or 0 if none set.
+ */
+ extern int seaudit_filter_get_lport(const seaudit_filter_t * filter);
+
+/**
+ * Set the foreign address criterion, as a glob expression. A message
+ * is accepted if its foreign address (faddr) matches this expression.
+ * Note that if seaudit_filter_set_anyaddr() is also set, then the
+ * message must match both ipaddr and faddr for it to be accepted
+ * (assuming that the match is set to SEAUDIT_FILTER_MATCH_ALL).
+ *
+ * @param filter Filter to modify.
+ * @param faddr Glob expression for foreign address. This function
+ * will duplicate the string. If this is NULL then clear the existing
+ * address.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_faddr(seaudit_filter_t * filter, const char *faddr);
+
+/**
+ * Return the current foreign address for a filter. Treat this string
+ * as const.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Glob expression for address, or NULL if none set.
+ */
+ extern const char *seaudit_filter_get_faddr(const seaudit_filter_t * filter);
+
+/**
+ * Set the foreign port criterion. A message is accepted if its
+ * foreign port (fport) matches this port. Note that if
+ * seaudit_filter_set_anyport() is also set, then the message must
+ * match both anyport and fport for it to be accepted (assuming that
+ * the match is set to SEAUDIT_FILTER_MATCH_ALL).
+ *
+ * @param filter Filter to modify.
+ * @param fport Foreign port criterion. If this is zero or negative
+ * then clear the existing port.
+ *
+ * @return Always 0.
+ */
+ extern int seaudit_filter_set_fport(seaudit_filter_t * filter, const int fport);
+
+/**
+ * Return the current foreign port for a filter.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Current port criterion, or 0 if none set.
+ */
+ extern int seaudit_filter_get_fport(const seaudit_filter_t * filter);
+
+/**
+ * Set the source address criterion, as a glob expression. A message
+ * is accepted if its source address (saddr) matches this expression.
+ * Note that if seaudit_filter_set_anyaddr() is also set, then the
+ * message must match both ipaddr and saddr for it to be accepted
+ * (assuming that the match is set to SEAUDIT_FILTER_MATCH_ALL).
+ *
+ * @param filter Filter to modify.
+ * @param saddr Glob expression for source address. This function
+ * will duplicate the string. If this is NULL then clear the existing
+ * address.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_saddr(seaudit_filter_t * filter, const char *saddr);
+
+/**
+ * Return the current source address for a filter. Treat this string
+ * as const.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Glob expression for address, or NULL if none set.
+ */
+ extern const char *seaudit_filter_get_saddr(const seaudit_filter_t * filter);
+
+/**
+ * Set the source port criterion. A message is accepted if its source
+ * port (sport) matches this port. Note that if
+ * seaudit_filter_set_anyport() is also set, then the message must
+ * match both anyport and sport for it to be accepted (assuming that
+ * the match is set to SEAUDIT_FILTER_MATCH_ALL).
+ *
+ * @param filter Filter to modify.
+ * @param sport Source port criterion. If this is zero or negative
+ * then clear the existing port.
+ *
+ * @return Always 0.
+ */
+ extern int seaudit_filter_set_sport(seaudit_filter_t * filter, const int sport);
+
+/**
+ * Return the current source port for a filter.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Current port criterion, or 0 if none set.
+ */
+ extern int seaudit_filter_get_sport(const seaudit_filter_t * filter);
+
+/**
+ * Set the destination address criterion, as a glob expression. A
+ * message is accepted if its destination address (daddr) matches this
+ * expression. Note that if seaudit_filter_set_anyaddr() is also set,
+ * then the message must match both ipaddr and daddr for it to be
+ * accepted (assuming that the match is set to
+ * SEAUDIT_FILTER_MATCH_ALL).
+ *
+ * @param filter Filter to modify.
+ * @param daddr Glob expression for destination address. This
+ * function will duplicate the string. If this is NULL then clear the
+ * existing address.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_daddr(seaudit_filter_t * filter, const char *daddr);
+
+/**
+ * Return the current destination address for a filter. Treat this
+ * string as const.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Glob expression for address, or NULL if none set.
+ */
+ extern const char *seaudit_filter_get_daddr(const seaudit_filter_t * filter);
+
+/**
+ * Set the destination port criterion. A message is accepted if its
+ * destination port (dport) matches this port. Note that if
+ * seaudit_filter_set_anyport() is also set, then the message must
+ * match both anyport and dport for it to be accepted (assuming that
+ * the match is set to SEAUDIT_FILTER_MATCH_ALL).
+ *
+ * @param filter Filter to modify.
+ * @param dport Destination port criterion. If this is zero or
+ * negative then clear the existing port.
+ *
+ * @return Always 0.
+ */
+ extern int seaudit_filter_set_dport(seaudit_filter_t * filter, const int dport);
+
+/**
+ * Return the current destination port for a filter.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Current port criterion, or 0 if none set.
+ */
+ extern int seaudit_filter_get_dport(const seaudit_filter_t * filter);
+
+/**
+ * Set the port criterion. A message is accepted if its port matches
+ * this port value exactly. Note that if seaudit_filter_set_anyport()
+ * is also set, then the message must match both anyport and port for
+ * it to be accepted (assuming that the match is set to
+ * SEAUDIT_FILTER_MATCH_ALL).
+ *
+ * @param filter Filter to modify.
+ * @param port Port criterion. If this is zero or negative then clear
+ * the existing port.
+ *
+ * @return Always 0.
+ */
+ extern int seaudit_filter_set_port(seaudit_filter_t * filter, const int port);
+
+/**
+ * Return the current port for a filter.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Current port criterion, or 0 if none set.
+ */
+ extern int seaudit_filter_get_port(const seaudit_filter_t * filter);
+
+/**
+ * Set the network interface criterion. A message is accepted if its
+ * interface matches exactly with this string.
+ *
+ * @param filter Filter to modify.
+ * @param netif Network interface criterion. This function will
+ * duplicate the string. If this is NULL then clear the existing
+ * criterion.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_netif(seaudit_filter_t * filter, const char *netif);
+
+/**
+ * Return the current network interface for a filter. Treat this
+ * string as const.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return String for netif, or NULL if none set.
+ */
+ extern const char *seaudit_filter_get_netif(const seaudit_filter_t * filter);
+
+/**
+ * Set the key criterion. A message is accepted if its IPC key
+ * matches exactly with this value.
+ *
+ * @param filter Filter to modify.
+ * @param key Key criterion. If this is zero or negative then clear
+ * the existing key.
+ *
+ * @return Always 0.
+ */
+ extern int seaudit_filter_set_key(seaudit_filter_t * filter, const int key);
+
+/**
+ * Return the current key for a filter.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Current key criterion, or 0 if none set.
+ */
+ extern int seaudit_filter_get_key(const seaudit_filter_t * filter);
+
+/**
+ * Set the capability criterion. A message is accepted if its
+ * capability matches exactly with this value.
+ *
+ * @param filter Filter to modify.
+ * @param cap Capability criterion. If this is zero or negative then
+ * clear the existing capability.
+ *
+ * @return Always 0.
+ */
+ extern int seaudit_filter_set_cap(seaudit_filter_t * filter, const int cap);
+
+/**
+ * Return the current capability for a filter.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Current capability criterion, or 0 if none set.
+ */
+ extern int seaudit_filter_get_cap(const seaudit_filter_t * filter);
+
+/**
+ * Set the type of AVC criterion. A message is accepted if it matches
+ * this value exactly. If the message type is not SEAUDIT_AVC_UNKNOWN
+ * and the message is not an AVC then it will be rejected.
+ *
+ * @param filter Filter to modify.
+ * @param message_type One of SEAUDIT_AVC_DENIED, SEAUDIT_AVC_GRANTED,
+ * SEAUDIT_AVC_UNKNOWN. If SEAUDIT_AVC_UNKNOWN then unset this
+ * criterion.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_message_type(seaudit_filter_t * filter, const seaudit_avc_message_type_e message_type);
+
+/**
+ * Return the current message type for a filter.
+ *
+ * @param filter Filter to get value.
+ *
+ * @return Type of AVC message to filter, or SEAUDIT_AVC_UNKNOWN if
+ * none set.
+ */
+ extern seaudit_avc_message_type_e seaudit_filter_get_message_type(const seaudit_filter_t * filter);
+
+/**
+ * Set the date/time criterion. A message is accepted if its
+ * date/time falls within the allowable range.
+ *
+ * @param filter Filter to modify.
+ * @param start Starting time. This structure will be duplicated. If
+ * NULL, then do not filter by dates.
+ * @param end Ending time. This structure will be duplicated. It
+ * will be ignored (and hence may be NULL) if date_match is not
+ * SEAUDIT_FILTER_DATE_MATCH_BETWEEN.
+ * @param date_match How to match dates, either ones falling before
+ * start, ones falling after start, or ones between start and end.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_filter_set_date(seaudit_filter_t * filter, const struct tm *start, const struct tm *end,
+ seaudit_filter_date_match_e match);
+
+/**
+ * Return the current date/time for a filter. Note that if no
+ * date/time has been set then both reference pointers will be set to
+ * NULL (match will be set to an invalid value).
+ *
+ * @param filter Filter to get value.
+ * @param start Pointer to location to store starting time. Do not
+ * free() or otherwise modify this pointer.
+ * @param end Pointer to location to store ending time. Do not free()
+ * or otherwise modify this pointer. If match is not
+ * SEAUDIT_FILTER_DATE_MATCH_BETWEEN then the contents of this
+ * structure are invalid.
+ * @param date_match Pointer to location to set date matching option.
+ */
+ extern void seaudit_filter_get_date(const seaudit_filter_t * filter, const struct tm **start, const struct tm **end,
+ seaudit_filter_date_match_e * match);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libseaudit/include/seaudit/load_message.h b/libseaudit/include/seaudit/load_message.h
new file mode 100644
index 0000000..52cedd6
--- /dev/null
+++ b/libseaudit/include/seaudit/load_message.h
@@ -0,0 +1,41 @@
+/**
+ * @file
+ * Public interface for a single loaded policy log message. This is
+ * a subclass of seaudit_message; it has no publicly accessible
+ * 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
+ */
+
+#ifndef SEAUDIT_LOAD_MESSAGE_H
+#define SEAUDIT_LOAD_MESSAGE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ typedef struct seaudit_load_message seaudit_load_message_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libseaudit/include/seaudit/log.h b/libseaudit/include/seaudit/log.h
new file mode 100644
index 0000000..b94a2a1
--- /dev/null
+++ b/libseaudit/include/seaudit/log.h
@@ -0,0 +1,162 @@
+/**
+ * @file
+ *
+ * Public interface for the main libseaudit object, seaudit_log.
+ * Note that there is no public way to get at the messages stored
+ * within a model. For that, the caller must create a seaudit_model
+ * and then access messages through the model.
+ *
+ * @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
+ */
+
+#ifndef SEAUDIT_LOG_H
+#define SEAUDIT_LOG_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdarg.h>
+#include <apol/vector.h>
+
+ typedef struct seaudit_log seaudit_log_t;
+ typedef void (*seaudit_handle_fn_t) (void *arg, const seaudit_log_t * log, int level, const char *fmt, va_list va_args);
+
+/**
+ * Define the types of logs that this library can parse.
+ */
+ typedef enum seaudit_log_type
+ {
+ SEAUDIT_LOG_TYPE_INVALID = 0,
+ SEAUDIT_LOG_TYPE_SYSLOG,
+ SEAUDIT_LOG_TYPE_AUDITD
+ } seaudit_log_type_e;
+
+/**
+ * Allocate and initialize a new seaudit log structure. This
+ * structure holds log messages from one or more files; call
+ * seaudit_log_parse() to actually add messages to this log.
+ *
+ * @param fn Function to be called by the error handler. If NULL
+ * then write messages to standard error.
+ * @param callback_arg Argument for the callback.
+ *
+ * @return A newly allocated and initialized seaudit log structure or
+ * NULL on error; if the call fails, errno will be set. The caller is
+ * responsible for calling seaudit_log_destroy() to free memory used
+ * by this structure.
+ */
+ extern seaudit_log_t *seaudit_log_create(seaudit_handle_fn_t fn, void *callback_arg);
+
+/**
+ * Free all memory used by an seaudit log structure and set it to
+ * NULL.
+ *
+ * @param log Reference pointer to the log structure to destroy. This
+ * pointer will be set to NULL. (If already NULL, function is a
+ * no-op.)
+ */
+ extern void seaudit_log_destroy(seaudit_log_t ** log);
+
+/**
+ * Remove all messages from the log. The next time the model(s) that
+ * are watching this log are accessed, they will be refreshed. Note
+ * that any existing pointers to messages within this log will become
+ * invalid. (This function does not actually delete the log file from
+ * disk; it just removes them from memory.)
+ *
+ * @param log Log to clear.
+ */
+ extern void seaudit_log_clear(seaudit_log_t * log);
+
+/**
+ * Return a vector of strings corresponding to all users found within
+ * the log file. The vector will be sorted alphabetically.
+ *
+ * @param log Log file to access.
+ *
+ * @return Vector of sorted users, or NULL upon error. The caller
+ * must call apol_vector_destroy() upon the return value.
+ */
+ apol_vector_t *seaudit_log_get_users(const seaudit_log_t * log);
+
+/**
+ * Return a vector of strings corresponding to all roles found within
+ * the log file. The vector will be sorted alphabetically.
+ *
+ * @param log Log file to access.
+ *
+ * @return Vector of sorted roles, or NULL upon error. The caller
+ * must call apol_vector_destroy() upon the return value.
+ */
+ apol_vector_t *seaudit_log_get_roles(const seaudit_log_t * log);
+
+/**
+ * Return a vector of strings corresponding to all types found within
+ * the log file. The vector will be sorted alphabetically.
+ *
+ * @param log Log file to access.
+ *
+ * @return Vector of sorted types, or NULL upon error. The caller
+ * must call apol_vector_destroy() upon the return value.
+ */
+ apol_vector_t *seaudit_log_get_types(const seaudit_log_t * log);
+
+/**
+ * Return a vector of strings corresponding to all mls levels found within
+ * the log file. The vector will be sorted alphabetically.
+ *
+ * @param log Log file to access.
+ *
+ * @return Vector of sorted types, or NULL upon error. The caller
+ * must call apol_vector_destroy() upon the return value.
+ */
+ apol_vector_t *seaudit_log_get_mls_lvl(const seaudit_log_t * log);
+
+/**
+ * Return a vector of strings corresponding to all mls clearance found within
+ * the log file. The vector will be sorted alphabetically.
+ *
+ * @param log Log file to access.
+ *
+ * @return Vector of sorted types, or NULL upon error. The caller
+ * must call apol_vector_destroy() upon the return value.
+ */
+ apol_vector_t *seaudit_log_get_mls_clr(const seaudit_log_t * log);
+
+/**
+ * Return a vector of strings corresponding to all object classes
+ * found within the log file. The vector will be sorted
+ * alphabetically.
+ *
+ * @param log Log file to access.
+ *
+ * @return Vector of sorted classes, or NULL upon error. The caller
+ * must call apol_vector_destroy() upon the return value.
+ */
+ apol_vector_t *seaudit_log_get_classes(const seaudit_log_t * log);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libseaudit/include/seaudit/message.h b/libseaudit/include/seaudit/message.h
new file mode 100644
index 0000000..2266ee8
--- /dev/null
+++ b/libseaudit/include/seaudit/message.h
@@ -0,0 +1,133 @@
+/**
+ * @file
+ * Public interface for a single seaudit log message. Note that this
+ * is an abstract class.
+ *
+ * @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
+ */
+
+#ifndef SEAUDIT_MESSAGE_H
+#define SEAUDIT_MESSAGE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <time.h>
+
+ typedef struct seaudit_message seaudit_message_t;
+
+/**
+ * This enum defines the different types of audit messages this
+ * library will handle. Message types are put in alphabetical order
+ * to make msg_field_compare() in sort.c easier.
+ */
+ typedef enum seaudit_message_type
+ {
+ SEAUDIT_MESSAGE_TYPE_INVALID = 0,
+ /** BOOL is the message that results when changing
+ booleans in a conditional policy. */
+ SEAUDIT_MESSAGE_TYPE_BOOL,
+ /** AVC is a standard 'allowed' or 'denied' type
+ message. */
+ SEAUDIT_MESSAGE_TYPE_AVC,
+ /** LOAD is the message that results when a policy is
+ loaded into the system. */
+ SEAUDIT_MESSAGE_TYPE_LOAD
+ } seaudit_message_type_e;
+
+/**
+ * Get a pointer to a message's specific data. This returns a void
+ * pointer; the caller must cast it to one of seaudit_avc_message_t,
+ * seaudit_bool_message_t, or seaudit_load_message_t. Use the
+ * returned value from the second parameter to determine which type
+ * this message really is.
+ *
+ * @param msg Message from which to get data.
+ * @param type Reference to the message specific type.
+ *
+ * @return Pointer to message's specific type, or NULL upon error.
+ */
+ extern void *seaudit_message_get_data(const seaudit_message_t * msg, seaudit_message_type_e * type);
+
+/**
+ * Return the time that this audit message was generated.
+ *
+ * @param msg Message from which to get its time.
+ *
+ * @return Time of the message. Treat the contents of this struct as
+ * const.
+ *
+ * @see localtime(3)
+ */
+ extern const struct tm *seaudit_message_get_time(const seaudit_message_t * msg);
+
+/**
+ * Return the name of the host that generated this audit message.
+ *
+ * @param msg Message from which to get its time.
+ *
+ * @return Host of the message. Do not modify this string.
+ */
+ extern const char *seaudit_message_get_host(const seaudit_message_t * msg);
+
+/**
+ * Given a message, allocate and return a string that approximates the
+ * message as it had appeared within the original log file.
+ *
+ * @param msg Message to convert.
+ *
+ * @return String representation for message, or NULL upon error. The
+ * caller is responsible for free()ing the string afterwards.
+ */
+ extern char *seaudit_message_to_string(const seaudit_message_t * msg);
+
+/**
+ * Given a message, allocate and return a string, formatted in HTML,
+ * that approximates the message as it had appeared within the
+ * original log file.
+ *
+ * @param msg Message to convert.
+ *
+ * @return HTML String representation for message, or NULL upon error.
+ * The caller is responsible for free()ing the string afterwards.
+ */
+ extern char *seaudit_message_to_string_html(const seaudit_message_t * msg);
+
+/**
+ * Given a message, allocate and return a string that gives
+ * miscellaneous (i.e., uncategorized) information about the message.
+ * To get the more important values you will need to use more specific
+ * accessor methods.
+ *
+ * @param msg 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.
+ */
+ extern char *seaudit_message_to_misc_string(const seaudit_message_t * msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libseaudit/include/seaudit/model.h b/libseaudit/include/seaudit/model.h
new file mode 100644
index 0000000..e5daacf
--- /dev/null
+++ b/libseaudit/include/seaudit/model.h
@@ -0,0 +1,362 @@
+/**
+ * @file
+ *
+ * Public interface to a seaudit_model. This represents a subset of
+ * log messages from one or more seaudit_log, where the subset is
+ * defined by a finite set of seaudit_filter and sorted by some
+ * criterion or criteria.
+ *
+ * @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
+ */
+
+#ifndef SEAUDIT_MODEL_H
+#define SEAUDIT_MODEL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "filter.h"
+#include "log.h"
+#include "message.h"
+#include "sort.h"
+
+#include <stdlib.h>
+
+ typedef struct seaudit_model seaudit_model_t;
+
+/**
+ * Create a seaudit_model based upon the messages from some particular
+ * seaudit_log. The model will be initialized with the default filter
+ * (i.e., accept all of the messages from the log).
+ *
+ * @param name Name for the model; the string will be duplicated. If
+ * NULL then the model will be assigned a non-unique default name.
+ * @param log Initial log for this model to watch. If NULL then do
+ * not watch any log files.
+ *
+ * @return An initialized model, or NULL upon error. The caller must
+ * call seaudit_model_destroy() afterwards.
+ */
+ extern seaudit_model_t *seaudit_model_create(const char *name, seaudit_log_t * log);
+
+/**
+ * Create a new seaudit_model object, initialized with the data from
+ * an existing model. This will do a deep copy of the original model.
+ * The new model will be watch the same logs that the original model
+ * was watching.
+ *
+ * @param model Model to clone.
+ *
+ * @return A cloned model, or NULL upon error. The caller must call
+ * seaudit_model_destroy() afterwards.
+ */
+ extern seaudit_model_t *seaudit_model_create_from_model(const seaudit_model_t * model);
+
+/**
+ * Create and return a model initialized from the contents of a XML
+ * configuration file. This will also load filters into the model.
+ * The model will not be associated with any logs; for that call
+ * seaudit_model_append_log().
+ *
+ * @param filename File containing model data.
+ *
+ * @return An initialized model, or NULL upon error. The caller must
+ * call seaudit_model_destroy() afterwards.
+ *
+ * @see seaudit_model_save_to_file()
+ */
+ extern seaudit_model_t *seaudit_model_create_from_file(const char *filename);
+
+/**
+ * Destroy the referenced seadit_model object.
+ *
+ * @param model Model to destroy. The pointer will be set to NULL
+ * afterwards. (If pointer is already NULL then do nothing.)
+ */
+ extern void seaudit_model_destroy(seaudit_model_t ** model);
+
+/**
+ * Save to disk, in XML format, the given model's values. This
+ * includes the filters contained within the model as well. Note that
+ * this does not save the messages within the model nor the associated
+ * logs.
+ *
+ * @param model Model to save.
+ * @param filename Name of the file to write. If the file already
+ * exists it will be overwritten.
+ *
+ * @return 0 on success, < 0 on error.
+ *
+ * @see seaudit_model_create_from_file()
+ */
+ extern int seaudit_model_save_to_file(const seaudit_model_t * model, const char *filename);
+
+/**
+ * Get the name of this model.
+ *
+ * @param model Model whose name to get.
+ *
+ * @return Name of the model, or NULL upon error. Do not modify this
+ * string.
+ */
+ extern const char *seaudit_model_get_name(const seaudit_model_t * model);
+
+/**
+ * Set the name of this model, overwriting any previous name.
+ *
+ * @param model Model whose name to set.
+ * @param name New name for the model; the string will be duplicated.
+ * If NULL then the model will be assigned a non-unique default name.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_model_set_name(seaudit_model_t * model, const char *name);
+
+/**
+ * Have the given model start watching the given log file, in addition
+ * to any other log files the model was watching.
+ *
+ * @param model Model to modify.
+ * @param log Additional log file to watch.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_model_append_log(seaudit_model_t * model, seaudit_log_t * log);
+
+/**
+ * Append a filter to a model. The next time the model's messages are
+ * retrieved only those messages that match this filter will be
+ * returned. Multiple filters may be applied to a model. Upon
+ * success, the model takes ownership of the filter.
+ *
+ * @param model Model to modify.
+ * @param filter Additional filter to be applied.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_model_append_filter(seaudit_model_t * model, seaudit_filter_t * filter);
+
+/**
+ * Get the list of filters for a model. Whenever a filter is modified
+ * the model will be recomputed. Note: to remove a filter from the
+ * model use seaudit_model_remove_filter().
+ *
+ * @param model Model containing filters.
+ *
+ * @return Vector of seaudit_filter objects, or NULL upon error. Note
+ * that the vector my be empty. Do not destroy or otherwise modify
+ * this vector. (It is safe to manipulate the elements within the
+ * vector.)
+ */
+ extern const apol_vector_t *seaudit_model_get_filters(const seaudit_model_t * model);
+
+/**
+ * Remove a filter from a model. The given parameter must match one
+ * of the filters stored within the model; call
+ * seaudit_model_get_filters() to get a list of the model's filters.
+ *
+ * @param model Model to modify.
+ * @param filter Filter to remove. Upon success the pointer becomes
+ * invalid.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_model_remove_filter(seaudit_model_t * model, seaudit_filter_t * filter);
+
+/**
+ * Set a model to accept a message if all filters are met (default
+ * behavior) or if any filter is met. Note that is independent from
+ * the setting given to seaudit_model_set_filter_visible().
+ *
+ * @param model Model to modify.
+ * @param match Matching behavior if model has multiple filters.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_model_set_filter_match(seaudit_model_t * model, seaudit_filter_match_e match);
+
+/**
+ * Get the current filter match value for a model.
+ *
+ * @param model Model containing filter match value.
+ *
+ * @return One of SEAUDIT_FILTER_MATCH_ALL or SEAUDIT_FILTER_MATCH_ANY.
+ */
+ extern seaudit_filter_match_e seaudit_model_get_filter_match(const seaudit_model_t * model);
+
+/**
+ * Set a model to either show (default behavior) or hide messages
+ * accepted by the filters. Note that is independent from the setting
+ * given to seaudit_model_set_filter_match().
+ *
+ * @param model Model to modify.
+ * @param visible Messages to show if model has any filters.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_model_set_filter_visible(seaudit_model_t * model, seaudit_filter_visible_e visible);
+
+/**
+ * Get the current filter visibility value for a model.
+ *
+ * @param model Model containing filter visibility value.
+ *
+ * @return One of SEAUDIT_FILTER_VISIBLE_SHOW or
+ * SEAUDIT_FILTER_VISIBLE_HIDE.
+ */
+ extern seaudit_filter_visible_e seaudit_model_get_filter_visible(const seaudit_model_t * model);
+
+/**
+ * Append a sort criterion to a model. The next time the model's
+ * messages are retrieved they will be sorted by this criterion. If
+ * the model already has sort criteria, they will have a higher
+ * priority than this new criterion. Upon success, the model takes
+ * ownership of the sort object
+ *
+ * @param model Model to modify.
+ * @param sort Additional sort criterion.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_model_append_sort(seaudit_model_t * model, seaudit_sort_t * sort);
+
+/**
+ * Remove all sort criteria from this model. The next time the
+ * model's messages are retrieved they will be in the same order as
+ * provided by the model's log(s).
+ *
+ * @param model Model to modify.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_model_clear_sorts(seaudit_model_t * model);
+
+/**
+ * Return a value indicating if this model has changed since the last
+ * time seaudit_model_get_messages() was called. Note that upon a
+ * non-zero return value, the vector returned by
+ * seaudit_model_get_messages() might contain the same messages. For
+ * example, the user could have removed all sorts but then re-inserted
+ * them in the same order.
+ *
+ * @param model Model to check.
+ *
+ * @return 0 if the model is unchanged, non-zero if it may have
+ * changed.
+ */
+ extern int seaudit_model_is_changed(const seaudit_model_t * model);
+
+/**
+ * Return a sorted list of messages associated with this model. This
+ * will cause the model to recalculate, as necessary, all messages
+ * according to its filters and then sort them.
+ *
+ * @param log Log to which report error messages.
+ * @param model Model containing messages.
+ *
+ * @return A newly allocated vector of seaudit_message_t, pre-filtered
+ * and pre-sorted, or NULL upon error. The caller is responsible for
+ * calling apol_vector_destroy() upon this value.
+ */
+ extern apol_vector_t *seaudit_model_get_messages(const seaudit_log_t * log, seaudit_model_t * model);
+
+/**
+ * Return a sorted list of malformed messages associated with this
+ * model. This is the union of all malformed messages from the
+ * model's logs. This will cause the model to recalculate, as
+ * necessary, all messages according to its filters.
+ *
+ * @param log Log to which report error messages.
+ * @param model Model containing malformed messages.
+ *
+ * @return A newly allocated vector of strings, or NULL upon error.
+ * Treat the contents of the vector as const char *. The caller is
+ * responsible for calling apol_vector_destroy() upon this value.
+ */
+ extern apol_vector_t *seaudit_model_get_malformed_messages(const seaudit_log_t * log, seaudit_model_t * model);
+
+/**
+ * Hide a message from a model such that the next time
+ * seaudit_model_get_messages() is called, the given message will not
+ * be returned within the vector.
+ *
+ * @param model Model containing message to hide.
+ * @param message Message to be marked hidden. If NULL, then do
+ * nothing. It is safe to make duplicate calls to this function with
+ * the same message.
+ */
+ extern void seaudit_model_hide_message(seaudit_model_t * model, const seaudit_message_t * message);
+
+/**
+ * Return the number of avc allow messages currently within the model.
+ * This will cause the model to recalculate, as necessary, all
+ * messages according to its filters.
+ *
+ * @param log Log to which report error messages.
+ * @param model Model to get statistics.
+ *
+ * @return Number of allow messages in the model. This could be zero.
+ */
+ extern size_t seaudit_model_get_num_allows(const seaudit_log_t * log, seaudit_model_t * model);
+
+/**
+ * Return the number of avc deny messages currently within the model.
+ * This will cause the model to recalculate, as necessary, all
+ * messages according to its filters.
+ *
+ * @param log Log to which report error messages.
+ * @param model Model to get statistics.
+ *
+ * @return Number of deny messages in the model. This could be zero.
+ */
+ extern size_t seaudit_model_get_num_denies(const seaudit_log_t * log, seaudit_model_t * model);
+
+/**
+ * Return the number of boolean change messages currently within the
+ * model. This will cause the model to recalculate, as necessary, all
+ * messages according to its filters.
+ *
+ * @param log Log to which report error messages.
+ * @param model Model to get statistics.
+ *
+ * @return Number of boolean messages in the model. This could be
+ * zero.
+ */
+ extern size_t seaudit_model_get_num_bools(const seaudit_log_t * log, seaudit_model_t * model);
+
+/**
+ * Return the number of load messages currently within the model.
+ * This will cause the model to recalculate, as necessary, all
+ * messages according to its filters.
+ *
+ * @param log Log to which report error messages.
+ * @param model Model to get statistics.
+ *
+ * @return Number of load messages in the model. This could be zero.
+ */
+ extern size_t seaudit_model_get_num_loads(const seaudit_log_t * log, seaudit_model_t * model);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libseaudit/include/seaudit/parse.h b/libseaudit/include/seaudit/parse.h
new file mode 100644
index 0000000..385f855
--- /dev/null
+++ b/libseaudit/include/seaudit/parse.h
@@ -0,0 +1,72 @@
+/**
+ * @file
+ * Public interface for parsing an audit log.
+ *
+ * @author Meggan Whalen mwhalen@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@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
+ */
+
+#ifndef SEAUDIT_PARSE_H
+#define SEAUDIT_PARSE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "log.h"
+#include <stdio.h>
+
+/**
+ * Parse the file specified by syslog and put all selinux audit
+ * messages into the log. It is assumed that log will be created
+ * before this function. If the log already has messages, new
+ * messages will be appended to it. Afterwards all models watching
+ * this log will be notified of the changes.
+ *
+ * @param log Audit log to which append messages.
+ * @param syslog Handler to an opened file containing audit messages.
+ *
+ * @return 0 on success, > 0 on warnings, < 0 on error and errno will
+ * be set.
+ */
+ extern int seaudit_log_parse(seaudit_log_t * log, FILE * syslog);
+
+/**
+ * Parse a string buffer representing a syslog (or just lines from it)
+ * and put all selinux audit messages into the log. It is assumed
+ * that log will be created before this function. If the log already
+ * has messages, new messages will be appended to it. Afterwards all
+ * models watching this log will be notified of the changes.
+ *
+ * @param log Audit log to which append messages.
+ * @param buffer Buffer containing SELinux audit messages.
+ * @param bufsize Number of bytes in the buffer.
+ *
+ * @return 0 on success, > 0 on warnings, < 0 on error and errno will
+ * be set.
+ */
+ extern int seaudit_log_parse_buffer(seaudit_log_t * log, const char *buffer, const size_t bufsize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libseaudit/include/seaudit/report.h b/libseaudit/include/seaudit/report.h
new file mode 100644
index 0000000..3df4b43
--- /dev/null
+++ b/libseaudit/include/seaudit/report.h
@@ -0,0 +1,140 @@
+/**
+ * @file
+ *
+ * This is the interface for processing SELinux audit logs and/or
+ * seaudit views to generate concise reports containing standard
+ * information as well as customized information using seaudit views.
+ * Reports are rendered in either HTML or plain text. Future support
+ * will provide rendering into XML. The HTML report can be formatted
+ * by providing an alternate stylesheet file or by configuring the
+ * default stylesheet.
+ *
+ * @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
+ */
+
+#ifndef SEAUDIT_REPORT_H
+#define SEAUDIT_REPORT_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "model.h"
+
+ typedef struct seaudit_report seaudit_report_t;
+
+ typedef enum seaudit_report_format
+ {
+ SEAUDIT_REPORT_FORMAT_TEXT, SEAUDIT_REPORT_FORMAT_HTML
+ } seaudit_report_format_e;
+
+/**
+ * Allocate and return a new seaudit_report_t for a particular model.
+ * This will not actually write the report to disk; for that call
+ * seaudit_report_write().
+ *
+ * @param model Model containing messages that will be written.
+ *
+ * @return A newly allocated report, or NULL upon error. The caller
+ * must call seaudit_report_destroy() afterwards.
+ */
+ extern seaudit_report_t *seaudit_report_create(seaudit_model_t * model);
+
+/**
+ * Destroy the referenced seaudit_report_t object.
+ *
+ * @param report Report to destroy. The pointer will be set to NULL
+ * afterwards. (If pointer is already NULL then do nothing.)
+ */
+ extern void seaudit_report_destroy(seaudit_report_t ** report);
+
+/**
+ * Write the report with the messages currently stored in the report's
+ * model.
+ *
+ * @param log Error handler.
+ * @param report Report to write.
+ * @param out_file File name for the report. If this is NULL then
+ * write to standard output.
+ *
+ * @return 0 on successful write, < 0 on error.
+ */
+ extern int seaudit_report_write(const seaudit_log_t * log, const seaudit_report_t * report, const char *out_file);
+
+/**
+ * Set the output format of the report. The default format is plain
+ * text.
+ *
+ * @param log Error handler.
+ * @param report Report whose format to set.
+ * @param format Output formate.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_report_set_format(const seaudit_log_t * log, seaudit_report_t * report, seaudit_report_format_e format);
+
+/**
+ * Set the report to use a particular report configuration file.
+ *
+ * @param log Error handler.
+ * @param report Report whose configuration to set.
+ * @param file Name of the configuration report. If NULL then use the
+ * default installed file. (The name will be duplicated by this
+ * function.)
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_report_set_configuration(const seaudit_log_t * log, seaudit_report_t * report, const char *file);
+
+/**
+ * Set the report to use a particular HTML stylesheet file. Note that
+ * this option is ignored if not generating an HTML report.
+ *
+ * @param log Error handler.
+ * @param report Report whose stylesheet to set.
+ * @param file Name of the stylesheet. If NULL then use the default
+ * installed file. (The name will be duplicated by this function.)
+ * @param use_stylesheet If non-zero, then use the stylesheet given by
+ * the parameter 'file'. Otherwise completely disable stylesheets.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_report_set_stylesheet(const seaudit_log_t * log, seaudit_report_t * report, const char *file,
+ const int use_stylesheet);
+
+/**
+ * Set the report to print messages that did not parse cleanly (i.e.,
+ * "malformed messages").
+ *
+ * @param log Error handler.
+ * @param report Report whose malformed messagse to print.
+ * @param do_malformed If non-zero then print malformed messages.
+ * Otherwise do not print them.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+ extern int seaudit_report_set_malformed(const seaudit_log_t * log, seaudit_report_t * report, const int do_malformed);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libseaudit/include/seaudit/sort.h b/libseaudit/include/seaudit/sort.h
new file mode 100644
index 0000000..505ff60
--- /dev/null
+++ b/libseaudit/include/seaudit/sort.h
@@ -0,0 +1,491 @@
+/**
+ * @file
+ *
+ * Public interface to a seaudit_sort. This represents an abstract
+ * object that specifies how to sort messages within a particular
+ * seaudit_model. The caller obtains a specific sort object and
+ * appends it to a model via seaudit_model_append_sort(); the caller
+ * cannot get a "generic" sort object.
+ *
+ * @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
+ */
+
+#ifndef SEAUDIT_SORT_H
+#define SEAUDIT_SORT_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ typedef struct seaudit_sort seaudit_sort_t;
+
+/**
+ * Create a new sort object, initialized with the data from an
+ * existing sort. The new sort will not be attached to any model.
+ *
+ * @param sort Sort to clone.
+ *
+ * @return A cloned sort object, or NULL upon error. The caller is
+ * responsible for calling seaudit_sort_destroy() afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_create_from_sort(const seaudit_sort_t * sort);
+
+/**
+ * Destroy the referenced seaudit_sort object.
+ *
+ * @param sort Sort object to destroy. The pointer will be set to
+ * NULL afterwards. (If pointer is already NULL then do nothing.)
+ */
+ extern void seaudit_sort_destroy(seaudit_sort_t ** sort);
+
+/**
+ * Instruct a model to sort messages by message type: boolean changes,
+ * then avc denies, then avc allows, then policy load messages.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_message_type(const int direction);
+
+/**
+ * Instruct a model to sort messages by chronological order.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_date(const int direction);
+
+/**
+ * Instruct a model to sort messages by host name, alphabetically.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_host(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by permissions,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_permission(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by source context's user,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_source_user(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by source context's role,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_source_role(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by source context's type,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_source_type(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by source context's mls level.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_source_mls_lvl(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by source context's mls clearance.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_source_mls_clr(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by target context's user,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_target_user(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by target context's role,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_target_role(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by target context's type,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_target_type(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by target context's mls level.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_target_mls_lvl(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by target context's mls clearance.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_target_mls_clr(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by object class,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_object_class(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the executable,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_executable(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the command,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_command(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the name, alphabetically.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_name(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the path, alphabetically.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_path(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the device, alphabetically.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_device(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the object's inode.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_inode(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the process ID. Non-AVC
+ * messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_pid(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the port number. Non-AVC
+ * messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_port(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by local address,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_laddr(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the local port number.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_lport(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by foreign address,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_faddr(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the foreign port number.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_fport(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by source address,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_saddr(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the source port number.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_sport(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by destination address,
+ * alphabetically. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_daddr(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the destination port
+ * number. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_dport(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the IPC call's key.
+ * Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_key(const int direction);
+
+/**
+ * Instruct a model to sort AVC messages by the process capability
+ * value. Non-AVC messages will be placed below AVC ones.
+ *
+ * @param direction Direction to sort. Non-negative for ascending,
+ * negative for descending.
+ *
+ * @return Sort object for this criterion, or NULL upon error. The
+ * caller is responsible for calling seaudit_sort_destroy()
+ * afterwards.
+ */
+ extern seaudit_sort_t *seaudit_sort_by_cap(const int direction);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libseaudit/include/seaudit/util.h b/libseaudit/include/seaudit/util.h
new file mode 100644
index 0000000..dd0c031
--- /dev/null
+++ b/libseaudit/include/seaudit/util.h
@@ -0,0 +1,44 @@
+/**
+ * @file
+ * Miscellaneous, uncategorized functions for libseaudit.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@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
+ */
+
+#ifndef SEAUDIT_UTIL_H
+#define SEAUDIT_UTIL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Return an immutable string describing this library's version.
+ *
+ * @return String describing this library.
+ */
+ extern const char *libseaudit_get_version(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
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;
+}
diff --git a/libseaudit/swig/Makefile.am b/libseaudit/swig/Makefile.am
new file mode 100644
index 0000000..8eb23d4
--- /dev/null
+++ b/libseaudit/swig/Makefile.am
@@ -0,0 +1,15 @@
+if DO_SWIGIFY_PYTHON
+ MAYBE_PYSWIG = python
+endif
+
+if DO_SWIGIFY_JAVA
+ MAYBE_JSWIG = java
+endif
+
+if DO_SWIGIFY_TCL
+ MAYBE_TCLSWIG = tcl
+endif
+
+SUBDIRS = $(MAYBE_PYSWIG) $(MAYBE_JSWIG) $(MAYBE_TCLSWIG)
+
+dist_noinst_DATA = seaudit.i
diff --git a/libseaudit/swig/java/MANIFEST.MF.in b/libseaudit/swig/java/MANIFEST.MF.in
new file mode 100644
index 0000000..070cc28
--- /dev/null
+++ b/libseaudit/swig/java/MANIFEST.MF.in
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+
+Name: com/tresys/setools/
+Specification-Title: "SETools Java Libraries"
+Specification-Version: "@VERSION@"
+Specification-Vendor: "Tresys Technology"
+Implementation-Title: "com.tresys.setools.seaudit"
+Implementation-Version: "@libseaudit_version@"
+Implementation-Vendor: "Tresys Technology"
+Extension-List: qpol apol
+qpol-Extension-Name: com.tresys.setools.qpol
+qpol-Implementation-Version: @libqpol_version@
+apol-Extension-Name: com.tresys.setools.apol
+apol-Implementation-Version: @libapol_version@
diff --git a/libseaudit/swig/java/Makefile.am b/libseaudit/swig/java/Makefile.am
new file mode 100644
index 0000000..f843204
--- /dev/null
+++ b/libseaudit/swig/java/Makefile.am
@@ -0,0 +1,90 @@
+wrappedso_DATA = libjseaudit.so.@libseaudit_version@
+wrappedso_SONAME = @libseaudit_jswig_soname@
+short_name = libjseaudit.so
+wrappedsodir = $(libdir)
+
+package_name = com.tresys.setools.seaudit
+package_dir = $(dir $(subst .,/,$(package_name)))seaudit
+
+wrappedjar_DATA = seaudit.jar
+wrappedjardir = $(setoolsdir)
+
+dist_noinst_DATA = $(srcdir)/../seaudit.i
+BUILT_SOURCES = seaudit_wrap.c \
+ seaudit_avc_message_t.java \
+ seaudit_avc_message_type_e.java \
+ seaudit_bool_message_t.java \
+ seaudit_filter_date_match_e.java \
+ seaudit_filter_match_e.java \
+ seaudit_filter_t.java \
+ seaudit_filter_visible_e.java \
+ seaudit.java \
+ seauditJNI.java \
+ seaudit_load_message_t.java \
+ seaudit_log_t.java \
+ seaudit_log_type_e.java \
+ seaudit_message_t.java \
+ seaudit_message_type_e.java \
+ seaudit_model_t.java \
+ seaudit_report_format_e.java \
+ seaudit_report_t.java \
+ seaudit_sort_t.java \
+ tm_t.java \
+ SWIGTYPE_p_void.java
+
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ @QPOL_CFLAGS@ -I$(top_builddir) -fpic \
+ -I$(top_srcdir)/libapol/include -I$(top_srcdir)/libseaudit/include
+AM_JFLAGS = @DEBUGJFLAGS@ @WARNJFLAGS@ \
+ -classpath $(top_builddir)/libqpol/swig/java/qpol.jar:$(top_builddir)/libapol/swig/java/apol.jar
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@ \
+ @APOL_LIB_FLAG@ @QPOL_LIB_FLAG@ @SEAUDIT_LIB_FLAG@ @XML_LIBS@
+DEPENDENCIES = $(top_builddir)/libqpol/src/libqpol.so \
+ $(top_builddir)/libapol/src/libapol.so \
+ $(top_builddir)/libseaudit/src/libseaudit.so
+
+$(firstword $(BUILT_SOURCES)): $(dist_noinst_DATA) $(DEPENDENCIES)
+ $(SWIG) $(SWIG_JAVA_OPT) -package $(package_name) -o $@ \
+ -I$(top_srcdir)/libseaudit/include -I$(top_srcdir)/libapol/include -I$(top_srcdir)/libqpol/include \
+ -I$(top_srcdir)/libqpol/swig -I$(top_srcdir)/libapol/swig $<
+
+$(wordlist 2,$(words $(BUILT_SOURCES)), $(BUILT_SOURCES)): $(firstword $(BUILT_SOURCES))
+
+$(wrappedso_DATA): $(filter %.c, $(BUILT_SOURCES))
+ $(CC) -shared -o $@ $^ $(AM_CFLAGS) $(CFLAGS) $(SWIG_JAVA_CFLAGS) -DSWIGJAVA=1 $(AM_LDFLAGS) $(LDFLAGS) -Wl,-soname,$(wrappedso_SONAME)
+ $(LN_S) -f $@ $(wrappedso_SONAME)
+ $(LN_S) -f $@ $(short_name)
+
+# Intentionally do not include SWIGTYPE_p_void.java below so that the
+# Java compiler uses the one created in package
+# com.tresys.setools.qpol instead of the one from package
+# com.tresys.setools.seaudit.
+java_files = $(filter-out SWIGTYPE_p_void.java, $(filter %.java, $(BUILT_SOURCES)))
+
+classes = $(patsubst %.java, $(package_dir)/%.class, $(java_files))
+
+# Because the Java compiler can generate multiple class files from the
+# same source .java file, putting all of the classes below will result
+# in repeated invocations of javac. Therefore, an alternative is to
+# just depend upon the first class file, and let the Java compiler
+# create the rest of them.
+$(firstword $(classes)): $(java_files)
+ $(JAVAC) $(AM_JFLAGS) $(JAVAFLAGS) -d . $^
+
+$(wordlist 2,$(words $(classes)),$(classes)): $(firstword $(classes))
+
+$(wrappedjar_DATA): MANIFEST.MF
+
+$(wrappedjar_DATA): $(classes)
+ $(JAR) cfm $@ MANIFEST.MF $^
+
+install-data-hook:
+ cd $(DESTDIR)$(wrappedsodir) && $(LN_S) -f $(wrappedso_DATA) $(wrappedso_SONAME)
+ cd $(DESTDIR)$(wrappedsodir) && $(LN_S) -f $(wrappedso_DATA) $(short_name)
+ $(mkdir_p) $(DESTDIR)$(javadir) && cd $(DESTDIR)$(javadir) && $(LN_S) -f $(wrappedjardir)/$(wrappedjar_DATA)
+
+uninstall-local:
+ -rm -rf $(DESTDIR)$(wrappedsodir)/$(wrappedso_SONAME) $(DESTDIR)$(wrappedsodir)/$(short_name)
+ -rm -f $(DESTDIR)$(javadir)/$(wrappedjar_DATA)
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) $(classes) $(wrappedso_DATA) $(wrappedjar_DATA) $(wrappedso_SONAME) $(short_name)
diff --git a/libseaudit/swig/python/Makefile.am b/libseaudit/swig/python/Makefile.am
new file mode 100644
index 0000000..ddf9e42
--- /dev/null
+++ b/libseaudit/swig/python/Makefile.am
@@ -0,0 +1,39 @@
+wrappedso_DATA = _seaudit.so.@libseaudit_version@
+wrappedso_SONAME = @libseaudit_pyswig_soname@
+wrappedsodir = $(pkgpyexecdir)
+
+wrappedpy_DATA = seaudit.py
+wrappedpydir = $(pkgpyexecdir)
+
+dist_noinst_DATA = $(srcdir)/../seaudit.i
+BUILT_SOURCES = seaudit_wrap.c
+
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ @QPOL_CFLAGS@ @APOL_CFLAGS@ -I$(top_builddir) -fpic \
+ -I$(top_srcdir)/libseaudit/include
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@ \
+ @APOL_LIB_FLAG@ @QPOL_LIB_FLAG@ @SEAUDIT_LIB_FLAG@ @XML_LIBS@
+DEPENDENCIES = $(top_builddir)/libqpol/src/libqpol.so \
+ $(top_builddir)/libapol/src/libapol.so \
+ $(top_builddir)/libseaudit/src/libseaudit.so
+
+$(BUILT_SOURCES): $(dist_noinst_DATA) $(DEPENDENCIES)
+ $(SWIG) $(SWIG_PYTHON_OPT) -o $@ \
+ -I$(top_srcdir)/libseaudit/include -I$(top_srcdir)/libapol/include -I$(top_srcdir)/libqpol/include \
+ -I$(top_srcdir)/libqpol/swig -I$(top_srcdir)/libapol/swig $<
+
+$(wrappedso_DATA): $(BUILT_SOURCES)
+ $(CC) -shared -o $@ $^ $(AM_CFLAGS) $(CFLAGS) $(SWIG_PYTHON_CPPFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -Wl,-soname,$(wrappedso_SONAME)
+ $(LN_S) -f $@ $(wrappedso_SONAME)
+ $(LN_S) -f $@ _seaudit.so
+
+$(wrappedpy_DATA): $(BUILT_SOURCES)
+
+install-data-hook:
+ cd $(DESTDIR)$(wrappedsodir) && $(LN_S) -f $(wrappedso_DATA) $(wrappedso_SONAME)
+ cd $(DESTDIR)$(wrappedsodir) && $(LN_S) -f $(wrappedso_DATA) _seaudit.so
+
+uninstall-local:
+ -rm -rf $(DESTDIR)$(wrappedsodir)/$(wrappedso_SONAME) $(DESTDIR)$(wrappedsodir)/_seaudit.so
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) $(wrappedso_DATA) $(wrappedpy_DATA) $(wrappedso_SONAME) _seaudit.so seaudit.pyc
diff --git a/libseaudit/swig/seaudit.i b/libseaudit/swig/seaudit.i
new file mode 100644
index 0000000..8c96d89
--- /dev/null
+++ b/libseaudit/swig/seaudit.i
@@ -0,0 +1,1373 @@
+/**
+ * @file
+ * SWIG declarations for libseaudit.
+ *
+ * @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
+ */
+
+%module seaudit
+
+%{
+#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/parse.h>
+#include <seaudit/report.h>
+#include <seaudit/sort.h>
+#include <seaudit/util.h>
+#include <time.h>
+
+/* Provide hooks so that language-specific modules can define the
+ * callback function, used by the handler in seaudit_log_create().
+ */
+SWIGEXPORT seaudit_handle_fn_t seaudit_swig_message_callback = NULL;
+SWIGEXPORT void * seaudit_swig_message_callback_arg = NULL;
+
+%}
+
+#ifdef SWIGJAVA
+%javaconst(1);
+/* get the java environment so we can throw exceptions */
+%{
+ static JNIEnv *seaudit_global_jenv;
+ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
+ (*vm)->AttachCurrentThread(vm, (void **)&seaudit_global_jenv, NULL);
+ return JNI_VERSION_1_2;
+ }
+%}
+#endif
+
+%include exception.i
+%include stdint.i
+%import apol.i
+
+%{
+#undef BEGIN_EXCEPTION
+#undef END_EXCEPTION
+%}
+
+#ifdef SWIGJAVA
+
+%exception {
+ seaudit_global_jenv = jenv;
+ $action
+}
+
+%{
+#define BEGIN_EXCEPTION JNIEnv *local_jenv = seaudit_global_jenv; {
+#define END_EXCEPTION }
+%}
+
+/* handle size_t correctly in java as architecture independent */
+%typemap(jni) size_t "jlong"
+%typemap(jtype) size_t "long"
+%typemap(jstype) size_t "long"
+%typemap("javaimports") SWIGTYPE, FILE* %{
+import com.tresys.setools.qpol.*;
+import com.tresys.setools.apol.*;
+%}
+%typemap(javabody) SWIGTYPE %{
+ private long swigCPtr;
+ protected boolean swigCMemOwn;
+
+ public $javaclassname(long cPtr, boolean cMemoryOwn) {
+ swigCMemOwn = cMemoryOwn;
+ swigCPtr = cPtr;
+ }
+
+ public static long getCPtr($javaclassname obj) {
+ return (obj == null) ? 0 : obj.swigCPtr;
+ }
+%}
+/* the following handles the dependencies on qpol and apol */
+%pragma(java) jniclassimports=%{
+import com.tresys.setools.qpol.*;
+import com.tresys.setools.apol.*;
+%}
+%pragma(java) jniclasscode=%{
+ static {
+ try
+ {
+ libseaudit_get_version ();
+ }
+ catch (UnsatisfiedLinkError ule)
+ {
+ System.loadLibrary("jseaudit");
+ }
+ }
+%}
+%pragma(java) moduleimports=%{
+import com.tresys.setools.qpol.*;
+import com.tresys.setools.apol.*;
+%}
+#else
+/* not in java so handle size_t as architecture dependent */
+#ifdef SWIGWORDSIZE64
+typedef uint64_t size_t;
+#else
+typedef uint32_t size_t;
+#endif
+%{
+#define BEGIN_EXCEPTION
+#define END_EXCEPTION
+%}
+#endif
+
+#ifdef SWIGJAVA
+/* if java, pass the new exception macro to C not just SWIG */
+#undef SWIG_exception
+#define SWIG_exception(code, msg) {SWIG_JavaException(local_jenv, code, msg); goto fail;}
+%inline %{
+#undef SWIG_exception
+#define SWIG_exception(code, msg) {SWIG_JavaException(local_jenv, code, msg); goto fail;}
+%}
+#endif
+
+#ifdef SWIGTCL
+/* implement a custom non thread-safe error handler */
+%{
+static char *message = NULL;
+static void tcl_clear_error(void)
+{
+ free(message);
+ message = NULL;
+}
+static void tcl_throw_error(const char *s)
+{
+ free(message);
+ message = strdup(s);
+}
+static char *tcl_get_error(void)
+{
+ return message;
+}
+#undef SWIG_exception
+#define SWIG_exception(code, msg) {tcl_throw_error(msg); goto fail;}
+%}
+
+%wrapper %{
+/* Tcl module's initialization routine is expected to be named
+ * Seaudit_Init(), but the output file will be called libtseaudit.so instead
+ * of libseaudit.so. Therefore add an alias from Tseaudit_Init() to the
+ * real Seaudit_Init().
+ */
+SWIGEXPORT int Tseaudit_Init(Tcl_Interp *interp) {
+ return SWIG_init(interp);
+}
+%}
+
+%exception {
+ char *err;
+ tcl_clear_error();
+ $action
+ if ((err = tcl_get_error()) != NULL) {
+ Tcl_Obj *obj = Tcl_NewStringObj(message, -1);
+ Tcl_ResetResult(interp);
+ Tcl_SetObjResult(interp, obj);
+ goto fail;
+ }
+}
+#undef SWIG_exception
+#define SWIG_exception(code, msg) {tcl_throw_error(msg); goto fail;}
+#endif
+
+%inline %{
+ typedef struct apol_string_vector apol_string_vector_t;
+%}
+
+
+#ifdef SWIGPYTHON
+/* map python file to C FILE struct pointer */
+%typemap(in) FILE * {
+ if (!PyFile_Check($input)) {
+ PyErr_SetString(PyExc_TypeError, "Need a file!");
+ return NULL;
+ }
+ $1 = PyFile_AsFile($input);
+}
+/* map string into C-style memory buffer */
+%typemap(in) (const char *buffer, const size_t bufsize) {
+ $1 = PyString_AsString($input);
+ $2 = (size_t) PyString_Size($input);
+}
+#endif
+#ifdef SWIGJAVA
+/* map string into C-style memory buffer */
+%typemap(in, noblock=1) (const char *buffer, const size_t bufsize) {
+ $1 = 0;
+ $2 = 0;
+ if ($input) {
+ $1 = ($1_ltype)JCALL2(GetStringUTFChars, jenv, $input, 0);
+ if (!$1) return $null;
+ $2 = strlen($1);
+ }
+}
+%typemap(freearg, noblock=1) (const char *buffer, const size_t bufsize) {
+ if ($1) JCALL2(ReleaseStringUTFChars, jenv, $input, $1);
+}
+#endif
+#ifdef SWIGTCL
+%typemap(in) FILE * {
+ ClientData c;
+ if (Tcl_GetOpenFile(interp, Tcl_GetString($input), 0, 1, &c) == TCL_ERROR)
+ SWIG_exception(SWIG_RuntimeError, Tcl_GetStringResult(interp));
+ $1 = (FILE*)c;
+}
+#endif
+
+/* from <time.h> */
+%{
+ typedef struct tm tm_t;
+%}
+typedef struct tm {
+ int tm_sec; /* seconds */
+ int tm_min; /* minutes */
+ int tm_hour; /* hours */
+ int tm_mday; /* day of the month */
+ int tm_mon; /* month */
+ int tm_year; /* year */
+ int tm_wday; /* day of the week */
+ int tm_yday; /* day in the year */
+ int tm_isdst; /* daylight saving time */
+} tm_t;
+%extend tm_t {
+ tm_t() {
+ struct tm *t;
+ BEGIN_EXCEPTION
+ t = calloc(1, sizeof(struct tm));
+ if (!t) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return t;
+ };
+ ~tm_t() {
+ free(self);
+ }
+ /* use default accessor style for the rest */
+};
+
+const char *libseaudit_get_version(void);
+
+/* seaudit log */
+typedef enum seaudit_log_type
+{
+ SEAUDIT_LOG_TYPE_INVALID = 0,
+ SEAUDIT_LOG_TYPE_SYSLOG,
+ SEAUDIT_LOG_TYPE_AUDITD
+} seaudit_log_type_e;
+typedef struct seaudit_log {} seaudit_log_t;
+%extend seaudit_log_t {
+ seaudit_log_t() {
+ seaudit_log_t *slog;
+ BEGIN_EXCEPTION
+ slog = seaudit_log_create(seaudit_swig_message_callback, seaudit_swig_message_callback_arg);
+ if (!slog) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return slog;
+ };
+ ~seaudit_log_t() {
+ seaudit_log_destroy(&self);
+ };
+ void clear () {
+ seaudit_log_clear(self);
+ };
+ %newobject get_users();
+ apol_string_vector_t *get_users() {
+ apol_vector_t *v;
+ BEGIN_EXCEPTION
+ v = seaudit_log_get_users(self);
+ if (!v) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return (apol_string_vector_t*)v;
+ };
+ %newobject get_roles();
+ apol_string_vector_t *get_roles() {
+ apol_vector_t *v;
+ BEGIN_EXCEPTION
+ v = seaudit_log_get_roles(self);
+ if (!v) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return (apol_string_vector_t*)v;
+ };
+ %newobject get_types();
+ apol_string_vector_t *get_types() {
+ apol_vector_t *v;
+ BEGIN_EXCEPTION
+ v = seaudit_log_get_types(self);
+ if (!v) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return (apol_string_vector_t*)v;
+ };
+ %newobject get_classes();
+ apol_string_vector_t *get_classes() {
+ apol_vector_t *v;
+ BEGIN_EXCEPTION
+ v = seaudit_log_get_classes(self);
+ if (!v) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return (apol_string_vector_t*)v;
+ };
+};
+
+/* seaudit message */
+typedef enum seaudit_message_type
+{
+ SEAUDIT_MESSAGE_TYPE_INVALID = 0,
+ SEAUDIT_MESSAGE_TYPE_BOOL,
+ SEAUDIT_MESSAGE_TYPE_AVC,
+ SEAUDIT_MESSAGE_TYPE_LOAD
+} seaudit_message_type_e;
+typedef struct seaudit_message {} seaudit_message_t;
+%extend seaudit_message_t {
+ seaudit_message_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Canot directly create seaudit_message_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~seaudit_message_t() {
+ /* no op */
+ return;
+ };
+ seaudit_message_type_e get_type() {
+ seaudit_message_type_e te;
+ (void)seaudit_message_get_data(self, &te);
+ return te;
+ };
+ void *get_data() {
+ seaudit_message_type_e te;
+ return seaudit_message_get_data(self, &te);
+ };
+ const char *get_host() {
+ return seaudit_message_get_host(self);
+ };
+ const tm_t *get_time() {
+ return seaudit_message_get_time(self);
+ }
+ %newobject to_string();
+ char *to_string() {
+ char *str;
+ BEGIN_EXCEPTION
+ str = seaudit_message_to_string(self);
+ if (!str) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return str;
+ };
+ %newobject to_string_html();
+ char *to_string_html() {
+ char *str;
+ BEGIN_EXCEPTION
+ str = seaudit_message_to_string_html(self);
+ if (!str) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return str;
+ };
+ %newobject to_misc_string();
+ char *to_misc_string() {
+ char *str;
+ BEGIN_EXCEPTION
+ str = seaudit_message_to_misc_string(self);
+ if (!str) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return str;
+ };
+};
+%inline %{
+ seaudit_message_t *seaudit_message_from_void(void *x) {
+ return (seaudit_message_t*)x;
+ };
+%}
+
+/* seaudit load message */
+typedef struct seaudit_load_message {} seaudit_load_message_t;
+%extend seaudit_load_message_t {
+ seaudit_load_message_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create seaudit_load_message_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~seaudit_load_message_t() {
+ /* no op */
+ return;
+ };
+};
+%inline %{
+ seaudit_load_message_t *seaudit_load_message_from_void(void *msg) {
+ return (seaudit_load_message_t*)msg;
+ };
+%}
+
+/* seaudit bool message */
+typedef struct seaudit_bool_message {} seaudit_bool_message_t;
+%extend seaudit_bool_message_t {
+ seaudit_bool_message_t(void *msg) {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create seaudit_bool_message_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~seaudit_bool_message_t() {
+ /* no op */
+ return;
+ };
+};
+%inline %{
+ seaudit_bool_message_t *seaudit_bool_message_from_void(void *msg) {
+ return (seaudit_bool_message_t*)msg;
+ };
+%}
+
+/* seaudit avc message */
+typedef enum seaudit_avc_message_type
+{
+ SEAUDIT_AVC_UNKNOWN = 0,
+ SEAUDIT_AVC_DENIED,
+ SEAUDIT_AVC_GRANTED
+} seaudit_avc_message_type_e;
+typedef struct seaudit_avc_message {} seaudit_avc_message_t;
+%extend seaudit_avc_message_t {
+ seaudit_avc_message_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create seaudit_avc_message_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ ~seaudit_avc_message_t() {
+ /* no op */
+ return;
+ };
+ seaudit_avc_message_type_e get_message_type() {
+ return seaudit_avc_message_get_message_type(self);
+ };
+ long get_timestamp_nano() {
+ return seaudit_avc_message_get_timestamp_nano(self);
+ };
+ const char *get_source_user() {
+ return seaudit_avc_message_get_source_user(self);
+ };
+ const char *get_source_role() {
+ return seaudit_avc_message_get_source_role(self);
+ };
+ const char *get_source_type() {
+ return seaudit_avc_message_get_source_type(self);
+ };
+ const char *get_target_user() {
+ return seaudit_avc_message_get_target_user(self);
+ };
+ const char *get_target_role() {
+ return seaudit_avc_message_get_target_role(self);
+ };
+ const char *get_target_type() {
+ return seaudit_avc_message_get_target_type(self);
+ };
+ const char *get_object_class() {
+ return seaudit_avc_message_get_object_class(self);
+ };
+ const apol_string_vector_t *get_perm() {
+ return (apol_string_vector_t*)seaudit_avc_message_get_perm(self);
+ };
+ const char *get_exe() {
+ return seaudit_avc_message_get_exe(self);
+ };
+ const char *get_comm() {
+ return seaudit_avc_message_get_comm(self);
+ };
+ const char *get_name() {
+ return seaudit_avc_message_get_name(self);
+ };
+ int get_pid() {
+ return (int)seaudit_avc_message_get_pid(self);
+ };
+ long get_inode() {
+ return (long)seaudit_avc_message_get_inode(self);
+ };
+ const char *get_path() {
+ return seaudit_avc_message_get_path(self);
+ };
+ const char *get_dev() {
+ return seaudit_avc_message_get_dev(self);
+ };
+ const char *get_netif() {
+ return seaudit_avc_message_get_netif(self);
+ };
+ int get_port() {
+ return seaudit_avc_message_get_port(self);
+ };
+ const char *get_laddr() {
+ return seaudit_avc_message_get_laddr(self);
+ };
+ int get_lport() {
+ return seaudit_avc_message_get_lport(self);
+ };
+ const char *get_faddr() {
+ return seaudit_avc_message_get_faddr(self);
+ };
+ int get_fport() {
+ return seaudit_avc_message_get_fport(self);
+ };
+ const char *get_saddr() {
+ return seaudit_avc_message_get_saddr(self);
+ };
+ int get_sport() {
+ return seaudit_avc_message_get_sport(self);
+ };
+ const char *get_daddr() {
+ return seaudit_avc_message_get_daddr(self);
+ };
+ int get_dport() {
+ return seaudit_avc_message_get_dport(self);
+ };
+ int get_key() {
+ return seaudit_avc_message_get_key(self);
+ };
+ int get_cap() {
+ return seaudit_avc_message_get_cap(self);
+ };
+};
+%inline %{
+ seaudit_avc_message_t *seaudit_avc_message_from_void(void *msg) {
+ return (seaudit_avc_message_t*)msg;
+ };
+%}
+
+/* Java does not permit parsing directly from a file; parsing may only
+ be done through a memory buffer. */
+#ifndef SWIGJAVA
+int seaudit_log_parse(seaudit_log_t * log, FILE * syslog);
+#endif
+int seaudit_log_parse_buffer(seaudit_log_t * log, const char *buffer, const size_t bufsize);
+
+/* seaudit filter */
+typedef enum seaudit_filter_match
+{
+ SEAUDIT_FILTER_MATCH_ALL = 0,
+ SEAUDIT_FILTER_MATCH_ANY
+} seaudit_filter_match_e;
+typedef enum seaudit_filter_visible
+{
+ SEAUDIT_FILTER_VISIBLE_SHOW = 0,
+ SEAUDIT_FILTER_VISIBLE_HIDE
+} seaudit_filter_visible_e;
+typedef enum seaudit_filter_date_match
+{
+ SEAUDIT_FILTER_DATE_MATCH_BEFORE = 0,
+ SEAUDIT_FILTER_DATE_MATCH_AFTER,
+ SEAUDIT_FILTER_DATE_MATCH_BETWEEN
+} seaudit_filter_date_match_e;
+typedef struct seaudit_filter {} seaudit_filter_t;
+%extend seaudit_filter_t {
+ seaudit_filter_t(char *name = NULL) {
+ seaudit_filter_t *sf = NULL;
+ BEGIN_EXCEPTION
+ sf = seaudit_filter_create(name);
+ if (!sf) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return sf;
+ };
+ seaudit_filter_t(seaudit_filter_t *in) {
+ seaudit_filter_t *sf = NULL;
+ BEGIN_EXCEPTION
+ sf = seaudit_filter_create_from_filter(in);
+ if (!sf) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return sf;
+ };
+ ~seaudit_filter_t() {
+ seaudit_filter_destroy(&self);
+ };
+ void save(char *path) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_save_to_file(self, path)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not save filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void set_match(seaudit_filter_match_e match) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_match(self, match)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set filter matching method");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ }
+ seaudit_filter_match_e get_match() {
+ return seaudit_filter_get_match(self);
+ };
+ void set_name(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_name(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set filter name");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_name() {
+ return seaudit_filter_get_name(self);
+ };
+ void set_description(char *description) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_description(self, description)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set filter description");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_description() {
+ return seaudit_filter_get_description(self);
+ };
+ void set_strict(bool is_strict) {
+ seaudit_filter_set_strict(self, is_strict);
+ };
+ bool get_strict() {
+ return seaudit_filter_get_strict(self);
+ };
+ void set_source_user(apol_string_vector_t *v) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_source_user(self, (apol_vector_t*)v)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set source user list for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const apol_string_vector_t *get_source_user() {
+ return (apol_string_vector_t*)seaudit_filter_get_source_user(self);
+ };
+ void set_source_role(apol_string_vector_t *v) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_source_role(self, (apol_vector_t*)v)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set source role list for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const apol_string_vector_t *get_source_role() {
+ return (apol_string_vector_t*)seaudit_filter_get_source_role(self);
+ };
+ void set_source_type(apol_string_vector_t *v) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_source_type(self, (apol_vector_t*)v)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set source type list for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const apol_string_vector_t *get_source_type() {
+ return (apol_string_vector_t*)seaudit_filter_get_source_type(self);
+ };
+ void set_target_user(apol_string_vector_t *v) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_target_user(self, (apol_vector_t*)v)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set target user list for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const apol_string_vector_t *get_target_user() {
+ return (apol_string_vector_t*)seaudit_filter_get_target_user(self);
+ };
+ void set_target_role(apol_string_vector_t *v) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_target_role(self, (apol_vector_t*)v)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set target role list for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const apol_string_vector_t *get_target_role() {
+ return (apol_string_vector_t*)seaudit_filter_get_target_role(self);
+ };
+ void set_target_type(apol_string_vector_t *v) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_target_type(self, (apol_vector_t*)v)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set target type list for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const apol_string_vector_t *get_target_type() {
+ return (apol_string_vector_t*)seaudit_filter_get_target_type(self);
+ };
+ void set_target_class(apol_string_vector_t *v) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_target_class(self, (apol_vector_t*)v)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set target class list for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const apol_string_vector_t *get_target_class() {
+ return (apol_string_vector_t*)seaudit_filter_get_target_class(self);
+ };
+ void set_permission(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_permission(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set permission for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_permission() {
+ return seaudit_filter_get_permission(self);
+ };
+ void set_executable(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_executable(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set executable for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_executable() {
+ return seaudit_filter_get_executable(self);
+ };
+ void set_host(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_host(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set host for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_host() {
+ return seaudit_filter_get_host(self);
+ };
+ void set_path(char *path) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_path(self, path)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set path for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_path() {
+ return seaudit_filter_get_path(self);
+ };
+ void set_command(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_command(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set command for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void set_inode(long inode) {
+ seaudit_filter_set_inode(self, (long) inode);
+ };
+ long get_inode() {
+ return (long) seaudit_filter_get_inode(self);
+ };
+ void set_pid(long pid) {
+ seaudit_filter_set_pid(self, (unsigned int) pid);
+ };
+ long get_pid() {
+ return (long) seaudit_filter_get_pid(self);
+ };
+ const char *get_command() {
+ return seaudit_filter_get_command(self);
+ };
+ void set_anyaddr(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_anyaddr(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set ip address for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_anyaddr() {
+ return seaudit_filter_get_anyaddr(self);
+ };
+ void set_anyport(int port) {
+ seaudit_filter_set_anyport(self, port);
+ };
+ int get_anyport() {
+ return seaudit_filter_get_anyport(self);
+ };
+ void set_laddr(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_laddr(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set local address for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_laddr() {
+ return seaudit_filter_get_laddr(self);
+ };
+ void set_lport(int port) {
+ seaudit_filter_set_lport(self, port);
+ };
+ int get_lport() {
+ return seaudit_filter_get_lport(self);
+ };
+ void set_faddr(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_faddr(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set foreign address for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_faddr() {
+ return seaudit_filter_get_faddr(self);
+ };
+ void set_fport(int port) {
+ seaudit_filter_set_fport(self, port);
+ };
+ int get_fport() {
+ return seaudit_filter_get_fport(self);
+ };
+ void set_saddr(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_saddr(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set source address for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_saddr() {
+ return seaudit_filter_get_saddr(self);
+ };
+ void set_sport(int port) {
+ seaudit_filter_set_sport(self, port);
+ };
+ int get_sport() {
+ return seaudit_filter_get_sport(self);
+ };
+ void set_daddr(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_daddr(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set destination address for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_daddr() {
+ return seaudit_filter_get_daddr(self);
+ };
+ void set_dport(int port) {
+ seaudit_filter_set_dport(self, port);
+ };
+ int get_dport() {
+ return seaudit_filter_get_dport(self);
+ };
+ void set_port(int port) {
+ seaudit_filter_set_port(self, port);
+ };
+ int get_port() {
+ return seaudit_filter_get_port(self);
+ };
+ void set_netif(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_netif(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set network interface for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const char *get_netif() {
+ return seaudit_filter_get_netif(self);
+ };
+ void set_key(int key) {
+ seaudit_filter_set_key(self, key);
+ };
+ int get_key() {
+ return seaudit_filter_get_key(self);
+ };
+ void set_cap(int cap) {
+ seaudit_filter_set_cap(self, cap);
+ };
+ int get_cap() {
+ return seaudit_filter_get_cap(self);
+ };
+ void set_message_type(seaudit_avc_message_type_e mtype) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_message_type(self, mtype)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set message type for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ seaudit_message_type_e get_message_type() {
+ return seaudit_filter_get_message_type(self);
+ };
+ void set_date(struct tm *start, struct tm *end, seaudit_filter_date_match_e match) {
+ BEGIN_EXCEPTION
+ if (seaudit_filter_set_date(self, start, end, match)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set date for filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const struct tm *get_start_date() {
+ const struct tm *s;
+ const struct tm *e;
+ seaudit_filter_date_match_e m;
+ seaudit_filter_get_date(self, &s, &e, &m);
+ return s;
+ };
+ const struct tm *get_end_date() {
+ const struct tm *s;
+ const struct tm *e;
+ seaudit_filter_date_match_e m;
+ seaudit_filter_get_date(self, &s, &e, &m);
+ return e;
+ };
+ seaudit_filter_date_match_e get_date_match() {
+ const struct tm *s;
+ const struct tm *e;
+ seaudit_filter_date_match_e m;
+ seaudit_filter_get_date(self, &s, &e, &m);
+ return m;
+ };
+};
+%newobject seaudit_filter_create_from_file(const char*);
+apol_vector_t *seaudit_filter_create_from_file(const char *filename);
+%inline %{
+ seaudit_filter_t *seaudit_filter_from_void(void *x) {
+ return (seaudit_filter_t*)x;
+ };
+%}
+
+/* seaudit sort */
+typedef struct seaudit_sort {} seaudit_sort_t;
+%extend seaudit_sort_t {
+ seaudit_sort_t() {
+ BEGIN_EXCEPTION
+ SWIG_exception(SWIG_RuntimeError, "Cannot directly create seaudit_sort_t objects");
+ END_EXCEPTION
+ fail:
+ return NULL;
+ };
+ seaudit_sort_t(seaudit_sort_t *in) {
+ seaudit_sort_t *ss = NULL;
+ BEGIN_EXCEPTION
+ ss = seaudit_sort_create_from_sort(in);
+ if (!ss) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return ss;
+ };
+ ~seaudit_sort_t() {
+ seaudit_sort_destroy(&self);
+ };
+};
+%newobject seaudit_sort_by_message_type(const int);
+seaudit_sort_t *seaudit_sort_by_message_type(const int direction);
+%newobject seaudit_sort_by_date(const int);
+seaudit_sort_t *seaudit_sort_by_date(const int direction);
+%newobject seaudit_sort_by_host(const int);
+seaudit_sort_t *seaudit_sort_by_host(const int direction);
+%newobject seaudit_sort_by_permission(const int);
+seaudit_sort_t *seaudit_sort_by_permission(const int direction);
+%newobject seaudit_sort_by_source_user(const int);
+seaudit_sort_t *seaudit_sort_by_source_user(const int direction);
+%newobject seaudit_sort_by_source_role(const int);
+seaudit_sort_t *seaudit_sort_by_source_role(const int direction);
+%newobject seaudit_sort_by_source_type(const int);
+seaudit_sort_t *seaudit_sort_by_source_type(const int direction);
+%newobject seaudit_sort_by_target_user(const int);
+seaudit_sort_t *seaudit_sort_by_target_user(const int direction);
+%newobject seaudit_sort_by_target_role(const int);
+seaudit_sort_t *seaudit_sort_by_target_role(const int direction);
+%newobject seaudit_sort_by_target_type(const int);
+seaudit_sort_t *seaudit_sort_by_target_type(const int direction);
+%newobject seaudit_sort_by_object_class(const int);
+seaudit_sort_t *seaudit_sort_by_object_class(const int direction);
+%newobject seaudit_sort_by_executable(const int);
+seaudit_sort_t *seaudit_sort_by_executable(const int direction);
+%newobject seaudit_sort_by_command(const int);
+seaudit_sort_t *seaudit_sort_by_command(const int direction);
+%newobject seaudit_sort_by_name(const int);
+seaudit_sort_t *seaudit_sort_by_name(const int direction);
+%newobject seaudit_sort_by_path(const int);
+seaudit_sort_t *seaudit_sort_by_path(const int direction);
+%newobject seaudit_sort_by_device(const int);
+seaudit_sort_t *seaudit_sort_by_device(const int direction);
+%newobject seaudit_sort_by_inode(const int);
+seaudit_sort_t *seaudit_sort_by_inode(const int direction);
+%newobject seaudit_sort_by_pid(const int);
+seaudit_sort_t *seaudit_sort_by_pid(const int direction);
+%newobject seaudit_sort_by_port(const int);
+extern seaudit_sort_t *seaudit_sort_by_port(const int direction);
+%newobject seaudit_sort_by_laddr(const int);
+extern seaudit_sort_t *seaudit_sort_by_laddr(const int direction);
+%newobject seaudit_sort_by_lport(const int);
+extern seaudit_sort_t *seaudit_sort_by_lport(const int direction);
+%newobject seaudit_sort_by_faddr(const int);
+extern seaudit_sort_t *seaudit_sort_by_faddr(const int direction);
+%newobject seaudit_sort_by_fport(const int);
+extern seaudit_sort_t *seaudit_sort_by_fport(const int direction);
+%newobject seaudit_sort_by_saddr(const int);
+extern seaudit_sort_t *seaudit_sort_by_saddr(const int direction);
+%newobject seaudit_sort_by_sport(const int);
+extern seaudit_sort_t *seaudit_sort_by_sport(const int direction);
+%newobject seaudit_sort_by_daddr(const int);
+extern seaudit_sort_t *seaudit_sort_by_daddr(const int direction);
+%newobject seaudit_sort_by_dport(const int);
+extern seaudit_sort_t *seaudit_sort_by_dport(const int direction);
+%newobject seaudit_sort_by_key(const int);
+extern seaudit_sort_t *seaudit_sort_by_key(const int direction);
+%newobject seaudit_sort_by_cap(const int);
+extern seaudit_sort_t *seaudit_sort_by_cap(const int direction);
+
+/* seaudit model */
+#ifdef SWIGPYTHON
+/* handle ownership of filters and sorts passed to the model */
+%typemap(in) seaudit_filter_t *filter {
+ void *x = NULL;
+ Py_IncRef($input);
+ SWIG_ConvertPtr($input, &x,SWIGTYPE_p_seaudit_filter, 0 | 0 );
+ $1 = (seaudit_filter_t*)x;
+}
+%typemap(in) seaudit_sort_t *ssort {
+ void *x = NULL;
+ Py_IncRef($input);
+ SWIG_ConvertPtr($input, &x,SWIGTYPE_p_seaudit_sort, 0 | 0 );
+ $1 = (seaudit_sort_t*)x;
+}
+#endif
+typedef struct seaudit_model {} seaudit_model_t;
+%extend seaudit_model_t {
+ seaudit_model_t(char *name = NULL, seaudit_log_t *slog = NULL) {
+ seaudit_model_t *smod;
+ BEGIN_EXCEPTION
+ smod = seaudit_model_create(name, slog);
+ if (!smod) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return smod;
+ };
+ seaudit_model_t(seaudit_model_t *in) {
+ seaudit_model_t *smod;
+ BEGIN_EXCEPTION
+ smod = seaudit_model_create_from_model(in);
+ if (!smod) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return smod;
+ };
+ seaudit_model_t(char *path) {
+ seaudit_model_t *smod;
+ BEGIN_EXCEPTION
+ smod = seaudit_model_create_from_file(path);
+ if (!smod) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return smod;
+ }
+ ~seaudit_model_t() {
+ seaudit_model_destroy(&self);
+ };
+ void save(char *path) {
+ BEGIN_EXCEPTION
+ if (seaudit_model_save_to_file(self, path)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not save seaudit model");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ }
+ const char *get_name() {
+ return seaudit_model_get_name(self);
+ };
+ void set_name(char *name) {
+ BEGIN_EXCEPTION
+ if (seaudit_model_set_name(self, name)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set model name");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void append_log(seaudit_log_t *slog) {
+ BEGIN_EXCEPTION
+ if (seaudit_model_append_log(self, slog)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not append log to model");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void append_filter(seaudit_filter_t *filter) {
+ BEGIN_EXCEPTION
+#ifdef SWIGJAVA /* duplicate so the garbage collector does not double free */
+ seaudit_filter_t *tmp = seaudit_filter_create_from_filter(filter);
+ if (seaudit_model_append_filter(self, tmp)) {
+ seaudit_filter_destroy(&tmp);
+ SWIG_exception(SWIG_RuntimeError, "Could not append filter to model");
+ }
+#else
+ if (seaudit_model_append_filter(self, filter)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not append filter to model");
+ }
+#endif
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ const apol_vector_t *get_filters() {
+ return seaudit_model_get_filters(self);
+ };
+ %delobject remove_filter();
+ void remove_filter(seaudit_filter_t *filter) {
+ BEGIN_EXCEPTION
+ if (seaudit_model_remove_filter(self, filter)) {
+ SWIG_exception(SWIG_ValueError, "Could not remove filter");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void set_filter_match(seaudit_filter_match_e match) {
+ BEGIN_EXCEPTION
+ if (seaudit_model_set_filter_match(self, match)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set filter matching method for model");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ seaudit_filter_match_e get_filter_match() {
+ return seaudit_model_get_filter_match(self);
+ };
+ void set_filter_visible(seaudit_filter_visible_e vis) {
+ BEGIN_EXCEPTION
+ if (seaudit_model_set_filter_visible(self, vis)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set filter visibility for model");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ seaudit_filter_visible_e get_filter_visible() {
+ return seaudit_model_get_filter_visible(self);
+ };
+ void append_sort(seaudit_sort_t *ssort) {
+ BEGIN_EXCEPTION
+#ifdef SWIGJAVA
+ seaudit_sort_t *tmp = seaudit_sort_create_from_sort(ssort);
+ if (seaudit_model_append_sort(self, tmp)) {
+ seaudit_sort_destroy(&tmp);
+ SWIG_exception(SWIG_RuntimeError, "Could not append sort to model");
+ }
+#else
+ if (seaudit_model_append_sort(self, ssort)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not append sort to model");
+ }
+#endif
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void clear_sorts() {
+ BEGIN_EXCEPTION
+ if (seaudit_model_clear_sorts(self)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not clear model sorting criteria");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ int is_changed() {
+ return seaudit_model_is_changed(self);
+ };
+ %newobject get_messages(seaudit_log_t*);
+ apol_vector_t *get_messages(seaudit_log_t *slog) {
+ apol_vector_t *v = NULL;
+ BEGIN_EXCEPTION
+ v = seaudit_model_get_messages(slog, self);
+ if (!v) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return v;
+ };
+ %newobject get_malformed_messages(seaudit_log_t*);
+ apol_vector_t *get_malformed_messages(seaudit_log_t *slog) {
+ apol_vector_t *v = NULL;
+ BEGIN_EXCEPTION
+ v = seaudit_model_get_malformed_messages(slog, self);
+ if (!v) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return v;
+ };
+ void hide_message(seaudit_message_t *message) {
+ seaudit_model_hide_message(self, message);
+ };
+ size_t get_num_allows(seaudit_log_t *slog) {
+ return seaudit_model_get_num_allows(slog, self);
+ };
+ size_t get_num_denies(seaudit_log_t *slog) {
+ return seaudit_model_get_num_denies(slog, self);
+ };
+ size_t get_num_bools(seaudit_log_t *slog) {
+ return seaudit_model_get_num_bools(slog, self);
+ };
+ size_t get_num_loads(seaudit_log_t *slog) {
+ return seaudit_model_get_num_loads(slog, self);
+ };
+};
+
+/* seaudit report */
+typedef enum seaudit_report_format
+{
+ SEAUDIT_REPORT_FORMAT_TEXT,
+ SEAUDIT_REPORT_FORMAT_HTML
+} seaudit_report_format_e;
+typedef struct seaudit_report {} seaudit_report_t;
+%extend seaudit_report_t {
+ seaudit_report_t(seaudit_model_t *m) {
+ seaudit_report_t *sr;
+ BEGIN_EXCEPTION
+ sr = seaudit_report_create(m);
+ if (!sr) {
+ SWIG_exception(SWIG_MemoryError, "Out of memory");
+ }
+ END_EXCEPTION
+ fail:
+ return sr;
+ };
+ ~seaudit_report_t() {
+ seaudit_report_destroy(&self);
+ };
+ void write(seaudit_log_t *slog, char *path) {
+ BEGIN_EXCEPTION
+ if (seaudit_report_write(slog, self, path)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not write report to file");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void set_format(seaudit_log_t *slog, seaudit_report_format_e format) {
+ BEGIN_EXCEPTION
+ if (seaudit_report_set_format(slog, self, format)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set report format");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void set_configuration(seaudit_log_t *slog, char *path) {
+ BEGIN_EXCEPTION
+ if (seaudit_report_set_configuration(slog, self, path)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set report configuration file");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void set_stylesheet(seaudit_log_t *slog, char *path, int use_stylesheet) {
+ BEGIN_EXCEPTION
+ if (seaudit_report_set_stylesheet(slog, self, path, use_stylesheet)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set report stylesheet");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+ void set_malformed(seaudit_log_t *slog, int do_malformed) {
+ BEGIN_EXCEPTION
+ if (seaudit_report_set_malformed(slog, self, do_malformed)) {
+ SWIG_exception(SWIG_RuntimeError, "Could not set report malformed flag");
+ }
+ END_EXCEPTION
+ fail:
+ return;
+ };
+};
diff --git a/libseaudit/swig/tcl/Makefile.am b/libseaudit/swig/tcl/Makefile.am
new file mode 100644
index 0000000..b3c7c06
--- /dev/null
+++ b/libseaudit/swig/tcl/Makefile.am
@@ -0,0 +1,37 @@
+wrappedso_DATA = libtseaudit.so.@libseaudit_version@
+wrappedso_SONAME = @libseaudit_tswig_soname@
+short_name = libtseaudit.so
+wrappedsodir = $(libdir)/setools/seaudit
+
+package_SCRIPTS = pkgIndex.tcl
+packagedir = $(wrappedsodir)
+
+dist_noinst_DATA = $(srcdir)/../seaudit.i
+BUILT_SOURCES = seaudit_wrap.c
+
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ @QPOL_CFLAGS@ @APOL_CFLAGS@ -I$(top_builddir) -fpic \
+ -I$(top_srcdir)/libseaudit/include
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@ \
+ @SEAUDIT_LIB_FLAG@ @APOL_LIB_FLAG@ @QPOL_LIB_FLAG@ @XML_LIBS@
+DEPENDENCIES = $(top_builddir)/libqpol/src/libqpol.so \
+ $(top_builddir)/libapol/src/libapol.so \
+ $(top_builddir)/libseaudit/src/libseaudit.so
+
+$(BUILT_SOURCES): $(dist_noinst_DATA) $(DEPENDENCIES)
+ $(SWIG) $(SWIG_TCL_OPT) -pkgversion @libseaudit_version@ -o $@ -I$(top_srcdir)/libseaudit/include -I$(top_srcdir)/libapol/include -I$(top_srcdir)/libapol/swig -I$(top_srcdir)/libqpol/swig $<
+
+$(wrappedso_DATA): $(BUILT_SOURCES)
+ $(CC) -shared -o $@ $^ $(AM_CFLAGS) $(CFLAGS) $(SWIG_TCL_CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -Wl,-soname,$(wrappedso_SONAME)
+ $(LN_S) -f $@ $(wrappedso_SONAME)
+ $(LN_S) -f $@ $(short_name)
+
+$(package_SCRIPTS): $(wrappedso_DATA)
+ echo "pkg_mkIndex . $^" | LD_LIBRARY_PATH=$(top_builddir)/libqpol/src:$(top_builddir)/libapol/src:$(top_builddir)/libseaudit/src $(TCLSH_PROG)
+ chmod 644 $@
+ $(mkdir_p) seaudit
+ cp $(wrappedso_DATA) $@ seaudit
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) $(wrappedso_DATA) $(wrappedso_SONAME) $(short_name) $(package_DATA) seaudit/$(wrappedso_DATA) seaudit/$(package_SCRIPTS)
+
+CLEANFILES = $(package_SCRIPTS)
diff --git a/libseaudit/tests/Makefile.am b/libseaudit/tests/Makefile.am
new file mode 100644
index 0000000..47cef42
--- /dev/null
+++ b/libseaudit/tests/Makefile.am
@@ -0,0 +1,16 @@
+TESTS = libseaudit-tests
+check_PROGRAMS = libseaudit-tests
+
+libseaudit_tests_SOURCES = \
+ filters.c filters.h \
+ parse_file.c parse_file.h \
+ libseaudit-tests.c
+
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ @QPOL_CFLAGS@ @APOL_CFLAGS@ @SEAUDIT_CFLAGS@
+
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@
+
+LDADD = @SELINUX_LIB_FLAG@ @SEAUDIT_LIB_FLAG@ @APOL_LIB_FLAG@ @QPOL_LIB_FLAG@ @CUNIT_LIB_FLAG@
+
+libseaudit_tests_DEPENDENCIES = ../src/libseaudit.so
diff --git a/libseaudit/tests/filters.c b/libseaudit/tests/filters.c
new file mode 100644
index 0000000..4279173
--- /dev/null
+++ b/libseaudit/tests/filters.c
@@ -0,0 +1,114 @@
+/**
+ * @file
+ *
+ * Test libseaudit's filtering capabilities.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 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 <CUnit/CUnit.h>
+#include <apol/util.h>
+#include <seaudit/log.h>
+#include <seaudit/message.h>
+#include <seaudit/model.h>
+#include <seaudit/parse.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#define MESSAGES_NOWARNS TEST_POLICIES "/setools-3.1/seaudit/messages-nowarns"
+
+static seaudit_log_t *l = NULL;
+static seaudit_model_t *m = NULL;
+
+static void filters_simple()
+{
+ seaudit_filter_t *f = seaudit_filter_create("simple filter");
+ CU_ASSERT_PTR_NOT_NULL_FATAL(f);
+
+ int retval;
+ apol_vector_t *v = apol_str_split("system_u", ":");
+ CU_ASSERT_PTR_NOT_NULL_FATAL(v);
+ retval = seaudit_filter_set_source_user(f, v);
+ CU_ASSERT(retval == 0);
+ apol_vector_destroy(&v);
+
+ retval = seaudit_model_append_filter(m, f);
+ CU_ASSERT(retval == 0);
+
+ v = seaudit_model_get_messages(l, m);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(v);
+ CU_ASSERT(apol_vector_get_size(v) == 5 + 5);
+ apol_vector_destroy(&v);
+
+ retval = seaudit_filter_set_strict(f, true);
+ CU_ASSERT(retval == 0);
+ v = seaudit_model_get_messages(l, m);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(v);
+ CU_ASSERT(apol_vector_get_size(v) == 5);
+ apol_vector_destroy(&v);
+
+ retval = seaudit_filter_set_strict(f, false);
+ CU_ASSERT(retval == 0);
+ v = seaudit_model_get_messages(l, m);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(v);
+ CU_ASSERT(apol_vector_get_size(v) == 5 + 5);
+ apol_vector_destroy(&v);
+}
+
+CU_TestInfo filters_tests[] = {
+ {"simple filter", filters_simple},
+ CU_TEST_INFO_NULL
+};
+
+int filters_init()
+{
+ l = seaudit_log_create(NULL, NULL);
+ if (l == NULL) {
+ return 1;
+ }
+ m = seaudit_model_create("filters", l);
+ if (m == NULL) {
+ return 1;
+ }
+
+ FILE *f = fopen(MESSAGES_NOWARNS, "r");
+ if (f == NULL) {
+ return 1;
+ }
+ int retval;
+ retval = seaudit_log_parse(l, f);
+ if (retval != 0) {
+ fclose(f);
+ return 1;
+ }
+
+ fclose(f);
+ return 0;
+}
+
+int filters_cleanup()
+{
+ seaudit_log_destroy(&l);
+ seaudit_model_destroy(&m);
+ return 0;
+}
diff --git a/libseaudit/tests/filters.h b/libseaudit/tests/filters.h
new file mode 100644
index 0000000..97f634b
--- /dev/null
+++ b/libseaudit/tests/filters.h
@@ -0,0 +1,35 @@
+/**
+ * @file
+ *
+ * Declarations for using filters in libseaudit.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 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 FILTERS_H
+#define FILTERS_H
+
+#include <CUnit/CUnit.h>
+
+extern CU_TestInfo filters_tests[];
+extern int filters_init();
+extern int filters_cleanup();
+
+#endif
diff --git a/libseaudit/tests/libseaudit-tests.c b/libseaudit/tests/libseaudit-tests.c
new file mode 100644
index 0000000..2b65ec6
--- /dev/null
+++ b/libseaudit/tests/libseaudit-tests.c
@@ -0,0 +1,54 @@
+/**
+ * @file
+ *
+ * CUnit testing framework for libseaudit.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 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 <CUnit/CUnit.h>
+#include <CUnit/Basic.h>
+
+#include "filters.h"
+#include "parse_file.h"
+
+int main(void)
+{
+ if (CU_initialize_registry() != CUE_SUCCESS) {
+ return CU_get_error();
+ }
+
+ CU_SuiteInfo suites[] = {
+ {"Parse File", parse_file_init, parse_file_cleanup, parse_file_tests}
+ ,
+ {"Filters", filters_init, filters_cleanup, filters_tests}
+ ,
+ CU_SUITE_INFO_NULL
+ };
+
+ CU_register_suites(suites);
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+ unsigned int num_failures = CU_get_number_of_failure_records();
+ CU_cleanup_registry();
+ return (int)num_failures;
+}
diff --git a/libseaudit/tests/parse_file.c b/libseaudit/tests/parse_file.c
new file mode 100644
index 0000000..a4bac21
--- /dev/null
+++ b/libseaudit/tests/parse_file.c
@@ -0,0 +1,113 @@
+/**
+ * @file
+ *
+ * Test libseaudit's log file parsing ability.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 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 <CUnit/CUnit.h>
+#include <seaudit/log.h>
+#include <seaudit/parse.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+
+struct log_answer
+{
+ const char *log_name;
+ bool has_warnings;
+};
+
+static void parse_file_test(const struct log_answer *la)
+{
+ seaudit_log_t *l = seaudit_log_create(NULL, NULL);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(l);
+
+ FILE *f = fopen(la->log_name, "r");
+ CU_ASSERT_PTR_NOT_NULL_FATAL(f);
+
+ int retval;
+ retval = seaudit_log_parse(l, f);
+ if (la->has_warnings) {
+ CU_ASSERT(retval > 0);
+ } else {
+ CU_ASSERT(retval == 0);
+ }
+
+ fclose(f);
+ seaudit_log_destroy(&l);
+}
+
+static void parse_file_fc4()
+{
+ struct log_answer l = {
+ TEST_POLICIES "/setools-3.0/seaudit/messages-FC4",
+ false
+ };
+ parse_file_test(&l);
+}
+
+static void parse_file_fc5()
+{
+ struct log_answer l = {
+ TEST_POLICIES "/setools-3.0/seaudit/messages-FC5",
+ false
+ };
+ parse_file_test(&l);
+}
+
+static void parse_file_nowarns()
+{
+ struct log_answer l = {
+ TEST_POLICIES "/setools-3.1/seaudit/messages-nowarns",
+ false
+ };
+ parse_file_test(&l);
+}
+
+static void parse_file_warnings()
+{
+ struct log_answer l = {
+ TEST_POLICIES "/setools-3.1/seaudit/messages-warnings",
+ true
+ };
+ parse_file_test(&l);
+}
+
+CU_TestInfo parse_file_tests[] = {
+ {"FC4 log", parse_file_fc4},
+ {"FC5 log", parse_file_fc5},
+ {"messages-nowarns", parse_file_nowarns},
+ {"messages-warnings", parse_file_warnings},
+ CU_TEST_INFO_NULL
+};
+
+int parse_file_init()
+{
+ return 0;
+}
+
+int parse_file_cleanup()
+{
+ return 0;
+}
diff --git a/libseaudit/tests/parse_file.h b/libseaudit/tests/parse_file.h
new file mode 100644
index 0000000..e403e57
--- /dev/null
+++ b/libseaudit/tests/parse_file.h
@@ -0,0 +1,35 @@
+/**
+ * @file
+ *
+ * Declarations for parsing selinux audit logs from a file pointer.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 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 PARSE_FILE_H
+#define PARSE_FILE_H
+
+#include <CUnit/CUnit.h>
+
+extern CU_TestInfo parse_file_tests[];
+extern int parse_file_init();
+extern int parse_file_cleanup();
+
+#endif