diff options
Diffstat (limited to 'libseaudit')
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(<ime); + 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(<ime)); + } else { + fprintf(outfile, "# Begin\n\n"); + fprintf(outfile, "# Report generated by seaudit-report on %s\n", ctime(<ime)); + } + 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 |