diff options
Diffstat (limited to 'libseaudit/src')
-rw-r--r-- | libseaudit/src/Makefile.am | 52 | ||||
-rw-r--r-- | libseaudit/src/avc_message.c | 630 | ||||
-rw-r--r-- | libseaudit/src/bool_message.c | 153 | ||||
-rw-r--r-- | libseaudit/src/filter-internal.c | 1526 | ||||
-rw-r--r-- | libseaudit/src/filter-internal.h | 109 | ||||
-rw-r--r-- | libseaudit/src/filter.c | 1124 | ||||
-rw-r--r-- | libseaudit/src/libseaudit.map | 88 | ||||
-rw-r--r-- | libseaudit/src/load_message.c | 91 | ||||
-rw-r--r-- | libseaudit/src/log.c | 253 | ||||
-rw-r--r-- | libseaudit/src/message.c | 204 | ||||
-rw-r--r-- | libseaudit/src/model.c | 808 | ||||
-rw-r--r-- | libseaudit/src/parse.c | 1513 | ||||
-rw-r--r-- | libseaudit/src/report.c | 1060 | ||||
-rw-r--r-- | libseaudit/src/seaudit_internal.h | 664 | ||||
-rw-r--r-- | libseaudit/src/sort.c | 744 | ||||
-rw-r--r-- | libseaudit/src/util.c | 32 |
16 files changed, 9051 insertions, 0 deletions
diff --git a/libseaudit/src/Makefile.am b/libseaudit/src/Makefile.am new file mode 100644 index 0000000..74ccb26 --- /dev/null +++ b/libseaudit/src/Makefile.am @@ -0,0 +1,52 @@ +lib_LIBRARIES = libseaudit.a + +seauditso_DATA = libseaudit.so.@libseaudit_version@ +seauditsodir = $(libdir) + +AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \ + @APOL_CFLAGS@ @QPOL_CFLAGS@ @XML_CFLAGS@ -I$(srcdir)/../include -fpic +AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@ + +libseaudit_a_SOURCES = \ + avc_message.c \ + bool_message.c \ + filter.c filter-internal.c filter-internal.h \ + load_message.c \ + log.c \ + message.c \ + model.c \ + parse.c \ + report.c \ + sort.c \ + util.c \ + seaudit_internal.h + +libseaudit_a_DEPENDENCIES = $(top_builddir)/libapol/src/libapol.so + +libseaudit_so_OBJS = $(patsubst %.c,%.o,$(filter %.c,$(libseaudit_a_SOURCES))) +LIBSEAUDIT_SONAME = @libseaudit_soname@ + +dist_noinst_DATA = libseaudit.map + +$(seauditso_DATA): $(libseaudit_so_OBJS) libseaudit.map + $(CC) -shared -o $@ $(libseaudit_so_OBJS) $(AM_LDFLAGS) $(LDFLAGS) -Wl,-soname,$(LIBSEAUDIT_SONAME),--version-script=$(srcdir)/libseaudit.map,-z,defs $(top_builddir)/libqpol/src/libqpol.so $(top_builddir)/libapol/src/libapol.so $(XML_LIBS) -lselinux + $(LN_S) -f $@ @libseaudit_soname@ + $(LN_S) -f $@ libseaudit.so + +libseaudit.so: $(seauditso_DATA) + +$(top_builddir)/libapol/src/libapol.so: + $(MAKE) -C $(top_builddir)/libapol/src $(notdir $@) + +$(top_builddir)/libqpol/src/libqpol.so: + $(MAKE) -C $(top_builddir)/libqpol/src $(notdir $@) + +install-data-hook: + cd $(DESTDIR)$(seauditsodir) && $(LN_S) -f $(seauditso_DATA) @libseaudit_soname@ + cd $(DESTDIR)$(seauditsodir) && $(LN_S) -f $(seauditso_DATA) libseaudit.so + +mostlyclean-local: + -rm -rf *.gcno *.gcda *.gprof *.gcov libseaudit.so @libseaudit_soname@ $(seauditso_DATA) + +uninstall-local: + -rm -rf $(DESTDIR)$(seauditsodir)/$(seauditso_DATA) $(DESTDIR)$(seauditsodir)/@libseaudit_soname@ $(DESTDIR)$(seauditsodir)/libseaudit.so diff --git a/libseaudit/src/avc_message.c b/libseaudit/src/avc_message.c new file mode 100644 index 0000000..c054a72 --- /dev/null +++ b/libseaudit/src/avc_message.c @@ -0,0 +1,630 @@ +/** + * @file + * Implementation of a single avc log message. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Jeremy Solt jsolt@tresys.com + * + * Copyright (C) 2006-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "seaudit_internal.h" + +#include <apol/util.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +seaudit_avc_message_type_e seaudit_avc_message_get_message_type(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return SEAUDIT_AVC_UNKNOWN; + } + return avc->msg; +} + +long seaudit_avc_message_get_timestamp_nano(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return 0; + } + return avc->tm_stmp_sec; +} + +const char *seaudit_avc_message_get_source_user(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->suser; +} + +const char *seaudit_avc_message_get_source_role(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->srole; +} + +const char *seaudit_avc_message_get_source_type(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->stype; +} + +const char *seaudit_avc_message_get_source_mls_lvl(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->smls_lvl; +} + +const char *seaudit_avc_message_get_source_mls_clr(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->smls_clr; +} + +const char *seaudit_avc_message_get_target_user(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->tuser; +} + +const char *seaudit_avc_message_get_target_role(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->trole; +} + +const char *seaudit_avc_message_get_target_type(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->ttype; +} + +const char *seaudit_avc_message_get_target_mls_lvl(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->tmls_lvl; +} + +const char *seaudit_avc_message_get_target_mls_clr(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->tmls_clr; +} + +const char *seaudit_avc_message_get_object_class(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->tclass; +} + +const apol_vector_t *seaudit_avc_message_get_perm(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->perms; +} + +const char *seaudit_avc_message_get_exe(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->exe; +} + +const char *seaudit_avc_message_get_comm(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->comm; +} + +const char *seaudit_avc_message_get_name(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->name; +} + +unsigned int seaudit_avc_message_get_pid(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return 0; + } + if (!avc->is_pid) { + return 0; + } + return avc->pid; +} + +unsigned long seaudit_avc_message_get_inode(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return 0; + } + if (!avc->is_inode) { + return 0; + } + return avc->inode; +} + +const char *seaudit_avc_message_get_path(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->path; +} + +const char *seaudit_avc_message_get_dev(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->dev; +} + +const char *seaudit_avc_message_get_netif(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->netif; +} + +int seaudit_avc_message_get_port(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return 0; + } + return avc->port; +} + +const char *seaudit_avc_message_get_laddr(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->laddr; +} + +int seaudit_avc_message_get_lport(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return 0; + } + return avc->lport; +} + +const char *seaudit_avc_message_get_faddr(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->faddr; +} + +int seaudit_avc_message_get_fport(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return 0; + } + return avc->fport; +} + +const char *seaudit_avc_message_get_saddr(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->saddr; +} + +int seaudit_avc_message_get_sport(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return 0; + } + return avc->source; +} + +const char *seaudit_avc_message_get_daddr(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return NULL; + } + return avc->daddr; +} + +int seaudit_avc_message_get_dport(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return 0; + } + return avc->dest; +} + +int seaudit_avc_message_get_key(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return -1; + } + if (!avc->is_key) { + return -1; + } + return avc->key; +} + +int seaudit_avc_message_get_cap(const seaudit_avc_message_t * avc) +{ + if (avc == NULL) { + errno = EINVAL; + return -1; + } + if (!avc->is_capability) { + return -1; + } + return avc->capability; +} + +/******************** protected functions below ********************/ + +seaudit_avc_message_t *avc_message_create(void) +{ + seaudit_avc_message_t *avc = calloc(1, sizeof(seaudit_avc_message_t)); + if (avc == NULL) { + return NULL; + } + if ((avc->perms = apol_vector_create_with_capacity(1, NULL)) == NULL) { + int error = errno; + avc_message_free(avc); + errno = error; + return NULL; + } + return avc; +} + +void avc_message_free(seaudit_avc_message_t * avc) +{ + if (avc != NULL) { + free(avc->exe); + free(avc->comm); + free(avc->path); + free(avc->dev); + free(avc->netif); + free(avc->laddr); + free(avc->faddr); + free(avc->saddr); + free(avc->daddr); + free(avc->name); + free(avc->ipaddr); + apol_vector_destroy(&avc->perms); + free(avc); + } +} + +/** + * Build the misc string sans timestamp and serial number. + */ +static char *avc_message_get_misc_string(const seaudit_avc_message_t * avc) +{ + char *s = NULL; + size_t len = 0; + if (avc->dev && apol_str_appendf(&s, &len, "dev=%s ", avc->dev) < 0) { + return NULL; + } + if (avc->ipaddr && apol_str_appendf(&s, &len, "ipaddr=%s ", avc->ipaddr) < 0) { + return NULL; + } + if (avc->laddr && apol_str_appendf(&s, &len, "laddr=%s ", avc->laddr) < 0) { + return NULL; + } + if (avc->lport != 0 && apol_str_appendf(&s, &len, "lport=%d ", avc->lport) < 0) { + return NULL; + } + if (avc->faddr && apol_str_appendf(&s, &len, "faddr=%s ", avc->faddr) < 0) { + return NULL; + } + if (avc->fport != 0 && apol_str_appendf(&s, &len, "fport=%d ", avc->fport) < 0) { + return NULL; + } + if (avc->daddr && apol_str_appendf(&s, &len, "daddr=%s ", avc->daddr) < 0) { + return NULL; + } + if (avc->dest != 0 && apol_str_appendf(&s, &len, "dest=%d ", avc->dest) < 0) { + return NULL; + } + if (avc->port != 0 && apol_str_appendf(&s, &len, "port=%d ", avc->port) < 0) { + return NULL; + } + if (avc->saddr && apol_str_appendf(&s, &len, "saddr=%s ", avc->saddr) < 0) { + return NULL; + } + if (avc->source != 0 && apol_str_appendf(&s, &len, "source=%d ", avc->source) < 0) { + return NULL; + } + if (avc->netif && apol_str_appendf(&s, &len, "netif=%s ", avc->netif) < 0) { + return NULL; + } + if (avc->is_key && apol_str_appendf(&s, &len, "key=%d ", avc->key) < 0) { + return NULL; + } + if (avc->is_capability && apol_str_appendf(&s, &len, "capability=%d ", avc->capability) < 0) { + return NULL; + } + if (s == NULL) { + return strdup(""); + } + return s; +} + +char *avc_message_to_string(const seaudit_message_t * msg, const char *date) +{ + seaudit_avc_message_t *avc = msg->data.avc; + const char *host = msg->host; + const char *manager = msg->manager; + char *s = NULL, *misc_string = NULL, *perm; + size_t i, len = 0; + if (apol_str_appendf(&s, &len, "%s %s %s: ", date, host, manager) < 0) { + return NULL; + } + if (!(avc->tm_stmp_sec == 0 && avc->tm_stmp_nano == 0 && avc->serial == 0)) { + if (apol_str_appendf(&s, &len, "audit(%lu.%03lu:%u): ", avc->tm_stmp_sec, avc->tm_stmp_nano, avc->serial) < 0) { + return NULL; + } + } + if (apol_str_appendf(&s, &len, + "avc: %s ", + (avc->msg == SEAUDIT_AVC_DENIED ? "denied" : + avc->msg == SEAUDIT_AVC_GRANTED ? "granted" : "<unknown>")) < 0) { + return NULL; + } + + if (apol_vector_get_size(avc->perms) > 0) { + if (apol_str_append(&s, &len, "{ ") < 0) { + return NULL; + } + for (i = 0; i < apol_vector_get_size(avc->perms); i++) { + perm = apol_vector_get_element(avc->perms, i); + if (apol_str_appendf(&s, &len, "%s ", perm) < 0) { + return NULL; + } + } + if (apol_str_append(&s, &len, "} for ") < 0) { + return NULL; + } + } + if (avc->is_pid && apol_str_appendf(&s, &len, "pid=%d ", avc->pid) < 0) { + return NULL; + } + if (avc->exe && apol_str_appendf(&s, &len, "exe=%s ", avc->exe) < 0) { + return NULL; + } + if (avc->comm && apol_str_appendf(&s, &len, "comm=%s ", avc->comm) < 0) { + return NULL; + } + if (avc->path && apol_str_appendf(&s, &len, "path=%s ", avc->path) < 0) { + return NULL; + } + if (avc->name && apol_str_appendf(&s, &len, "name=%s ", avc->name) < 0) { + return NULL; + } + if (avc->is_inode && apol_str_appendf(&s, &len, "ino=%lu ", avc->inode) < 0) { + return NULL; + } + if ((misc_string = avc_message_get_misc_string(avc)) == NULL || apol_str_append(&s, &len, misc_string) < 0) { + int error = errno; + free(misc_string); + errno = error; + return NULL; + } + free(misc_string); + + if (strcmp(avc->smls_lvl, avc->smls_clr)) { /* level and clearance are not the same - show both */ + if (avc->suser && apol_str_appendf(&s, &len, "scontext=%s:%s:%s:%s-%s ", avc->suser, avc->srole, avc->stype, avc->smls_lvl, avc->smls_clr) < 0) { + return NULL; + } + } else if (avc->suser && apol_str_appendf(&s, &len, "scontext=%s:%s:%s:%s ", avc->suser, avc->srole, avc->stype, avc->smls_lvl) < 0) { + /* level and clearance are the same - only show one */ + return NULL; + } + if (strcmp(avc->tmls_lvl, avc->tmls_clr)) { /* level and clearance are not the same - show both */ + if (avc->tuser && apol_str_appendf(&s, &len, "tcontext=%s:%s:%s:%s-%s ", avc->tuser, avc->trole, avc->ttype, avc->tmls_lvl, avc->tmls_clr) < 0) { + return NULL; + } + } else if (avc->tuser && apol_str_appendf(&s, &len, "tcontext=%s:%s:%s:%s ", avc->tuser, avc->trole, avc->ttype, avc->tmls_lvl) < 0) { + /* level and clearance are the same - only show one */ + return NULL; + } + if (avc->tclass && apol_str_appendf(&s, &len, "tclass=%s ", avc->tclass) < 0) { + return NULL; + } + return s; +} + +char *avc_message_to_string_html(const seaudit_message_t * msg, const char *date) +{ + seaudit_avc_message_t *avc = msg->data.avc; + const char *host = msg->host; + const char *manager = msg->manager; + char *s = NULL, *misc_string = NULL, *perm; + size_t i, len = 0; + if (apol_str_appendf(&s, &len, + "<font class=\"message_date\">%s</font> " + "<font class=\"host_name\">%s</font> " "%s: ", date, host, manager) < 0) { + return NULL; + } + if (!(avc->tm_stmp_sec == 0 && avc->tm_stmp_nano == 0 && avc->serial == 0)) { + if (apol_str_appendf(&s, &len, + "<font class=\"syscall_timestamp\">audit(%lu.%03lu:%u): </font>", + avc->tm_stmp_sec, avc->tm_stmp_nano, avc->serial) < 0) { + return NULL; + } + } + if (apol_str_appendf(&s, &len, + "avc: %s ", + (avc->msg == SEAUDIT_AVC_DENIED ? "<font class=\"avc_deny\">denied</font> " : + avc->msg == SEAUDIT_AVC_GRANTED ? "<font class=\"avc_grant\">granted</font>" : "<unknown>")) < 0) { + return NULL; + } + + if (apol_vector_get_size(avc->perms) > 0) { + if (apol_str_append(&s, &len, "{ ") < 0) { + return NULL; + } + for (i = 0; i < apol_vector_get_size(avc->perms); i++) { + perm = apol_vector_get_element(avc->perms, i); + if (apol_str_appendf(&s, &len, "%s ", perm) < 0) { + return NULL; + } + } + if (apol_str_append(&s, &len, "} for ") < 0) { + return NULL; + } + } + if (avc->is_pid && apol_str_appendf(&s, &len, "pid=%d ", avc->pid) < 0) { + return NULL; + } + if (avc->exe && apol_str_appendf(&s, &len, "<font class=\"exe\">exe=%s</font> ", avc->exe) < 0) { + return NULL; + } + if (avc->comm && apol_str_appendf(&s, &len, "comm=%s ", avc->comm) < 0) { + return NULL; + } + if (avc->path && apol_str_appendf(&s, &len, "path=%s ", avc->path) < 0) { + return NULL; + } + if (avc->name && apol_str_appendf(&s, &len, "name=%s ", avc->name) < 0) { + return NULL; + } + if (avc->is_inode && apol_str_appendf(&s, &len, "ino=%lu ", avc->inode) < 0) { + return NULL; + } + if ((misc_string = avc_message_get_misc_string(avc)) == NULL || apol_str_append(&s, &len, misc_string) < 0) { + int error = errno; + free(misc_string); + errno = error; + return NULL; + } + free(misc_string); + if(strcmp(avc->smls_lvl, avc->smls_clr)) { /* level and clearance are not the same - show both */ + if (avc->suser && + apol_str_appendf(&s, &len, "<font class=\"src_context\">scontext=%s:%s:%s:%s-%s</font> ", + avc->suser, avc->srole, avc->stype, avc->smls_lvl, avc->smls_clr) < 0) { + return NULL; + } + } else if (avc->suser && apol_str_appendf(&s, &len, "<font class=\"src_context\">scontext=%s:%s:%s:%s</font> ", + avc->suser, avc->srole, avc->stype, avc->smls_lvl) < 0) { + /* level and clearance are the same - only show one */ + return NULL; + } + if(strcmp(avc->tmls_lvl, avc->tmls_clr)) { /* level and clearance are not the same - show both */ + if (avc->tuser && + apol_str_appendf(&s, &len, "<font class=\"tgt_context\">tcontext=%s:%s:%s:%s-%s</font> ", + avc->tuser, avc->trole, avc->ttype, avc->tmls_lvl, avc->tmls_clr) < 0) { + return NULL; + } + } else if (avc->tuser && + apol_str_appendf(&s, &len, "<font class=\"tgt_context\">tcontext=%s:%s:%s:%s</font> ", + avc->tuser, avc->trole, avc->ttype, avc->tmls_lvl) < 0) { + /* level and clearance are the same - only show one */ + return NULL; + } + if (avc->tclass && apol_str_appendf(&s, &len, "<font class=\"obj_class\">tclass=%s</font> ", avc->tclass) < 0) { + return NULL; + } + if (apol_str_appendf(&s, &len, "<br>") < 0) { + return NULL; + } + return s; +} + +char *avc_message_to_misc_string(const seaudit_avc_message_t * avc) +{ + char *s = avc_message_get_misc_string(avc); + size_t len; + if (s == NULL) { + return NULL; + } + len = strlen(s) + 1; + if (!(avc->tm_stmp_sec == 0 && avc->tm_stmp_nano == 0 && avc->serial == 0)) { + if (apol_str_appendf(&s, &len, "%stimestamp=%lu.%03lu serial=%u", + (len > 1 ? " " : ""), avc->tm_stmp_sec, avc->tm_stmp_nano, avc->serial) < 0) { + return NULL; + } + } + return s; +} diff --git a/libseaudit/src/bool_message.c b/libseaudit/src/bool_message.c new file mode 100644 index 0000000..f105cf0 --- /dev/null +++ b/libseaudit/src/bool_message.c @@ -0,0 +1,153 @@ +/** + * @file + * Implementation of a single boolean change log message. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2006-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "seaudit_internal.h" + +#include <apol/util.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +/******************** protected functions below ********************/ + +static void seaudit_bool_change_free(void *elem) +{ + if (elem != NULL) { + seaudit_bool_message_change_t *b = elem; + free(b); + } +} + +seaudit_bool_message_t *bool_message_create(void) +{ + seaudit_bool_message_t *boolm = calloc(1, sizeof(seaudit_bool_message_t)); + if (boolm == NULL) { + return NULL; + } + if ((boolm->changes = apol_vector_create(seaudit_bool_change_free)) == NULL) { + bool_message_free(boolm); + return NULL; + } + return boolm; +} + +int bool_change_append(seaudit_log_t * log, seaudit_bool_message_t * boolm, const char *name, int value) +{ + char *s = strdup(name); + seaudit_bool_message_change_t *bc = NULL; + int error; + if (s == NULL || apol_bst_insert_and_get(log->bools, (void **)&s, NULL) < 0) { + error = errno; + free(s); + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + if ((bc = calloc(1, sizeof(*bc))) == NULL || apol_vector_append(boolm->changes, bc) < 0) { + error = errno; + free(s); + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + bc->boolean = s; + bc->value = value; + return 0; +} + +void bool_message_free(seaudit_bool_message_t * boolm) +{ + if (boolm != NULL) { + apol_vector_destroy(&boolm->changes); + free(boolm); + } +} + +char *bool_message_to_string(const seaudit_message_t * msg, const char *date) +{ + seaudit_bool_message_t *boolm = msg->data.boolm; + const char *host = msg->host; + const char *manager = msg->manager; + char *s = NULL, *misc_string; + size_t len = 0; + char *open_brace = "", *close_brace = ""; + if (apol_vector_get_size(boolm->changes) > 0) { + open_brace = "{ "; + close_brace = " }"; + } + if (apol_str_appendf(&s, &len, "%s %s %s: security: committed booleans: %s", date, host, manager, open_brace) < 0) { + return NULL; + } + if ((misc_string = bool_message_to_misc_string(boolm)) == NULL || + apol_str_appendf(&s, &len, misc_string) < 0 || apol_str_append(&s, &len, close_brace) < 0) { + free(misc_string); + return NULL; + } + free(misc_string); + return s; +} + +char *bool_message_to_string_html(const seaudit_message_t * msg, const char *date) +{ + seaudit_bool_message_t *boolm = msg->data.boolm; + const char *host = msg->host; + const char *manager = msg->manager; + char *s = NULL, *misc_string; + size_t len = 0; + char *open_brace = "", *close_brace = ""; + if (apol_vector_get_size(boolm->changes) > 0) { + open_brace = "{ "; + close_brace = " }"; + } + if (apol_str_appendf(&s, &len, + "<font class=\"message_date\">%s</font> " + "<font class=\"host_name\">%s</font> " + "%s: security: committed booleans: %s", date, host, manager, open_brace) < 0) { + return NULL; + } + if ((misc_string = bool_message_to_misc_string(boolm)) == NULL || + apol_str_appendf(&s, &len, misc_string) < 0 || apol_str_appendf(&s, &len, "%s%s<br>", s, close_brace) < 0) { + free(misc_string); + return NULL; + } + free(misc_string); + return s; +} + +char *bool_message_to_misc_string(const seaudit_bool_message_t * boolm) +{ + char *s = NULL; + size_t len = 0, i; + for (i = 0; i < apol_vector_get_size(boolm->changes); i++) { + seaudit_bool_message_change_t *bc = apol_vector_get_element(boolm->changes, i); + if (apol_str_appendf(&s, &len, "%s%s:%d", (i == 0 ? "" : ", "), bc->boolean, bc->value) < 0) { + return NULL; + } + } + if (s == NULL) { + return strdup(""); + } + return s; +} diff --git a/libseaudit/src/filter-internal.c b/libseaudit/src/filter-internal.c new file mode 100644 index 0000000..9aa7c86 --- /dev/null +++ b/libseaudit/src/filter-internal.c @@ -0,0 +1,1526 @@ +/** + * @file + * Implementation of seaudit filters private functions. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Jeremy Solt jsolt@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "seaudit_internal.h" +#include "filter-internal.h" + +#include <apol/util.h> + +#include <errno.h> +#include <fnmatch.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <libxml/uri.h> + +/******************** support functions ********************/ + +static int filter_string_vector_read(apol_vector_t ** v, const xmlChar * ch) +{ + char *s; + if (*v == NULL && (*v = apol_vector_create_with_capacity(1, free)) == NULL) { + return -1; + } + if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL || apol_vector_append(*v, s) < 0) { + free(s); + return -1; + } + return 0; +} + +static int filter_string_read(char **dest, const xmlChar * ch) +{ + free(*dest); + *dest = NULL; + if ((*dest = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) { + return -1; + } + return 0; +} + +static int filter_ulong_read(unsigned long *dest, const xmlChar * ch) +{ + char *s, *endptr; + int retval = -1; + if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) { + return -1; + } + *dest = strtoul(s, &endptr, 10); + if (*s != '\0' && *endptr == '\0') { + retval = 0; + } + free(s); + return retval; +} + +static unsigned int filter_uint_read(unsigned int *dest, const xmlChar * ch) +{ + char *s, *endptr; + int retval = -1; + if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) { + return -1; + } + *dest = (unsigned int)(strtoul(s, &endptr, 10)); + if (*s != '\0' && *endptr == '\0') { + retval = 0; + } + free(s); + return retval; +} + +static int filter_int_read(int *dest, const xmlChar * ch) +{ + char *s, *endptr; + int retval = -1; + if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) { + return -1; + } + *dest = (int)(strtol(s, &endptr, 10)); + if (*s != '\0' && *endptr == '\0') { + retval = 0; + } + free(s); + return retval; +} + +static void filter_string_vector_print(const char *criteria_name, apol_vector_t * v, FILE * f, int tabs) +{ + int i; + size_t j; + if (v == NULL) { + return; + } + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "<criteria type=\"%s\">\n", criteria_name); + for (j = 0; j < apol_vector_get_size(v); j++) { + xmlChar *s = xmlCharStrdup(apol_vector_get_element(v, j)); + xmlChar *escaped = xmlURIEscapeStr(s, NULL); + for (i = 0; i < tabs + 1; i++) { + fprintf(f, "\t"); + } + fprintf(f, "<item>%s</item>\n", escaped); + free(escaped); + free(s); + } + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "</criteria>\n"); +} + +static void filter_string_print(const char *criteria_name, const char *s, FILE * f, int tabs) +{ + int i; + xmlChar *t, *escaped; + if (s == NULL) { + return; + } + t = xmlCharStrdup(s); + escaped = xmlURIEscapeStr(t, NULL); + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "<criteria type=\"%s\">\n", criteria_name); + for (i = 0; i < tabs + 1; i++) { + fprintf(f, "\t"); + } + fprintf(f, "<item>%s</item>\n", escaped); + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "</criteria>\n"); + free(escaped); + free(t); +} + +static void filter_ulong_print(const char *criteria_name, const unsigned long val, FILE * f, int tabs) +{ + int i; + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "<criteria type=\"%s\">\n", criteria_name); + for (i = 0; i < tabs + 1; i++) { + fprintf(f, "\t"); + } + fprintf(f, "<item>%lu</item>\n", val); + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "</criteria>\n"); +} + +static void filter_uint_print(const char *criteria_name, const unsigned int val, FILE * f, int tabs) +{ + int i; + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "<criteria type=\"%s\">\n", criteria_name); + for (i = 0; i < tabs + 1; i++) { + fprintf(f, "\t"); + } + fprintf(f, "<item>%u</item>\n", val); + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "</criteria>\n"); +} + +static void filter_int_print(const char *criteria_name, const int val, FILE * f, int tabs) +{ + int i; + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "<criteria type=\"%s\">\n", criteria_name); + for (i = 0; i < tabs + 1; i++) { + fprintf(f, "\t"); + } + fprintf(f, "<item>%d</item>\n", val); + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "</criteria>\n"); +} + +/******************** filter private functions ********************/ + +static bool filter_src_user_is_set(const seaudit_filter_t * filter) +{ + return filter->src_users != NULL; +} + +static int filter_src_user_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->suser != NULL; +} + +static int filter_src_user_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + return apol_vector_get_index(filter->src_users, msg->data.avc->suser, apol_str_strcmp, NULL, &i) == 0; +} + +static int filter_src_user_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_vector_read(&filter->src_users, ch); +} + +static void filter_src_user_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_vector_print(name, filter->src_users, f, tabs); +} + +static bool filter_src_role_is_set(const seaudit_filter_t * filter) +{ + return filter->src_roles != NULL; +} + +static int filter_src_role_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->srole != NULL; +} + +static int filter_src_role_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + return apol_vector_get_index(filter->src_roles, msg->data.avc->srole, apol_str_strcmp, NULL, &i) == 0; +} + +static int filter_src_role_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_vector_read(&filter->src_roles, ch); +} + +static void filter_src_role_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_vector_print(name, filter->src_roles, f, tabs); +} + +static bool filter_src_type_is_set(const seaudit_filter_t * filter) +{ + return filter->src_types != NULL; +} + +static int filter_src_type_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->stype != NULL; +} + +static int filter_src_type_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_vector_read(&filter->src_types, ch); +} + +static int filter_src_type_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + return apol_vector_get_index(filter->src_types, msg->data.avc->stype, apol_str_strcmp, NULL, &i) == 0; +} + +static void filter_src_type_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_vector_print(name, filter->src_types, f, tabs); +} + +static bool filter_src_mls_lvl_is_set(const seaudit_filter_t * filter) +{ + return filter->src_mls_lvl != NULL; +} + +static int filter_src_mls_lvl_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->smls_lvl != NULL; +} + +static int filter_src_mls_lvl_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_vector_read(&filter->src_mls_lvl, ch); +} + +static int filter_src_mls_lvl_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + return apol_vector_get_index(filter->src_mls_lvl, msg->data.avc->smls_lvl, apol_str_strcmp, NULL, &i) == 0; +} + +static void filter_src_mls_lvl_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_vector_print(name, filter->src_mls_lvl, f, tabs); +} + +static bool filter_src_mls_clr_is_set(const seaudit_filter_t * filter) +{ + return filter->src_mls_clr != NULL; +} + +static int filter_src_mls_clr_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->smls_clr != NULL; +} + +static int filter_src_mls_clr_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_vector_read(&filter->src_mls_clr, ch); +} + +static int filter_src_mls_clr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + return apol_vector_get_index(filter->src_mls_clr, msg->data.avc->smls_clr, apol_str_strcmp, NULL, &i) == 0; +} + +static void filter_src_mls_clr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_vector_print(name, filter->src_mls_clr, f, tabs); +} + +static bool filter_tgt_user_is_set(const seaudit_filter_t * filter) +{ + return filter->tgt_users != NULL; +} + +static int filter_tgt_user_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tuser != NULL; +} + +static int filter_tgt_user_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + return apol_vector_get_index(filter->tgt_users, msg->data.avc->tuser, apol_str_strcmp, NULL, &i) == 0; +} + +static int filter_tgt_user_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_vector_read(&filter->tgt_users, ch); +} + +static void filter_tgt_user_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_vector_print(name, filter->tgt_users, f, tabs); +} + +static bool filter_tgt_role_is_set(const seaudit_filter_t * filter) +{ + return filter->tgt_roles != NULL; +} + +static int filter_tgt_role_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->trole != NULL; +} + +static int filter_tgt_role_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + return apol_vector_get_index(filter->tgt_roles, msg->data.avc->trole, apol_str_strcmp, NULL, &i) == 0; +} + +static int filter_tgt_role_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_vector_read(&filter->tgt_roles, ch); +} + +static void filter_tgt_role_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_vector_print(name, filter->tgt_roles, f, tabs); +} + +static bool filter_tgt_type_is_set(const seaudit_filter_t * filter) +{ + return filter->tgt_types != NULL; +} + +static int filter_tgt_type_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->ttype != NULL; +} + +static int filter_tgt_type_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + return apol_vector_get_index(filter->tgt_types, msg->data.avc->ttype, apol_str_strcmp, NULL, &i) == 0; +} + +static int filter_tgt_type_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_vector_read(&filter->tgt_types, ch); +} + +static void filter_tgt_type_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_vector_print(name, filter->tgt_types, f, tabs); +} + +static bool filter_tgt_mls_lvl_is_set(const seaudit_filter_t * filter) +{ + return filter->tgt_mls_lvl != NULL; +} + +static int filter_tgt_mls_lvl_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tmls_lvl != NULL; +} + +static int filter_tgt_mls_lvl_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_vector_read(&filter->tgt_mls_lvl, ch); +} + +static int filter_tgt_mls_lvl_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + return apol_vector_get_index(filter->tgt_mls_lvl, msg->data.avc->tmls_lvl, apol_str_strcmp, NULL, &i) == 0; +} + +static void filter_tgt_mls_lvl_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_vector_print(name, filter->tgt_mls_lvl, f, tabs); +} + +static bool filter_tgt_mls_clr_is_set(const seaudit_filter_t * filter) +{ + return filter->tgt_mls_clr != NULL; +} + +static int filter_tgt_mls_clr_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tmls_clr != NULL; +} + +static int filter_tgt_mls_clr_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_vector_read(&filter->tgt_mls_clr, ch); +} + +static int filter_tgt_mls_clr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + return apol_vector_get_index(filter->tgt_mls_clr, msg->data.avc->tmls_clr, apol_str_strcmp, NULL, &i) == 0; +} + +static void filter_tgt_mls_clr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_vector_print(name, filter->tgt_mls_clr, f, tabs); +} + + +static bool filter_tgt_class_is_set(const seaudit_filter_t * filter) +{ + return filter->tgt_classes != NULL; +} + +static int filter_tgt_class_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->tclass != NULL; +} + +static int filter_tgt_class_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + return apol_vector_get_index(filter->tgt_classes, msg->data.avc->tclass, apol_str_strcmp, NULL, &i) == 0; +} + +static int filter_tgt_class_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_vector_read(&filter->tgt_classes, ch); +} + +static void filter_tgt_class_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_vector_print(name, filter->tgt_classes, f, tabs); +} + +static bool filter_perm_is_set(const seaudit_filter_t * filter) +{ + return filter->perm != NULL; +} + +static int filter_perm_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->perms != NULL && + apol_vector_get_size(msg->data.avc->perms) >= 1; +} + +static int filter_perm_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + size_t i; + for (i = 0; i < apol_vector_get_size(msg->data.avc->perms); i++) { + const char *p = apol_vector_get_element(msg->data.avc->perms, i); + if (fnmatch(filter->perm, p, 0) == 0) { + return 1; + } + } + return 0; +} + +static int filter_perm_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_read(&filter->perm, ch); +} + +static void filter_perm_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_print(name, filter->perm, f, tabs); +} + +static bool filter_exe_is_set(const seaudit_filter_t * filter) +{ + return filter->exe != NULL; +} + +static int filter_exe_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->exe != NULL; +} + +static int filter_exe_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return fnmatch(filter->exe, msg->data.avc->exe, 0) == 0; +} + +static int filter_exe_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_read(&filter->exe, ch); +} + +static void filter_exe_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_print(name, filter->exe, f, tabs); +} + +static bool filter_host_is_set(const seaudit_filter_t * filter) +{ + return filter->host != NULL; +} + +static int filter_host_support(const seaudit_message_t * msg) +{ + return msg->host != NULL; +} + +static int filter_host_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return fnmatch(filter->host, msg->host, 0) == 0; +} + +static int filter_host_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_read(&filter->host, ch); +} + +static void filter_host_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_print(name, filter->host, f, tabs); +} + +static bool filter_path_is_set(const seaudit_filter_t * filter) +{ + return filter->path != NULL; +} + +static int filter_path_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->path != NULL; +} + +static int filter_path_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return fnmatch(filter->path, msg->data.avc->path, 0) == 0; +} + +static int filter_path_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_read(&filter->path, ch); +} + +static void filter_path_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_print(name, filter->path, f, tabs); +} + +static bool filter_inode_is_set(const seaudit_filter_t * filter) +{ + return filter->inode != 0; +} + +static int filter_inode_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->is_inode; +} + +static int filter_inode_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return filter->inode == msg->data.avc->inode; +} + +static int filter_inode_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_ulong_read(&filter->inode, ch); +} + +static void filter_inode_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_ulong_print(name, filter->inode, f, tabs); +} + +static bool filter_pid_is_set(const seaudit_filter_t * filter) +{ + return filter->pid != 0; +} + +static int filter_pid_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->is_pid; +} + +static int filter_pid_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return filter->pid == msg->data.avc->pid; +} + +static int filter_pid_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_uint_read(&filter->pid, ch); +} + +static void filter_pid_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_uint_print(name, filter->pid, f, tabs); +} + +static bool filter_comm_is_set(const seaudit_filter_t * filter) +{ + return filter->comm != NULL; +} + +static int filter_comm_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->comm != NULL; +} + +static int filter_comm_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return fnmatch(filter->comm, msg->data.avc->comm, 0) == 0; +} + +static int filter_comm_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_read(&filter->comm, ch); +} + +static void filter_comm_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_print(name, filter->comm, f, tabs); +} + +static bool filter_anyaddr_is_set(const seaudit_filter_t * filter) +{ + return filter->anyaddr != NULL; +} + +static int filter_anyaddr_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && (msg->data.avc->saddr != NULL + || msg->data.avc->daddr != NULL + || msg->data.avc->faddr != NULL + || msg->data.avc->laddr != NULL || msg->data.avc->ipaddr != NULL); +} + +static int filter_anyaddr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + if (msg->data.avc->saddr && fnmatch(filter->anyaddr, msg->data.avc->saddr, 0) == 0) + return 1; + if (msg->data.avc->daddr && fnmatch(filter->anyaddr, msg->data.avc->daddr, 0) == 0) + return 1; + if (msg->data.avc->faddr && fnmatch(filter->anyaddr, msg->data.avc->faddr, 0) == 0) + return 1; + if (msg->data.avc->laddr && fnmatch(filter->anyaddr, msg->data.avc->laddr, 0) == 0) + return 1; + if (msg->data.avc->ipaddr && fnmatch(filter->anyaddr, msg->data.avc->ipaddr, 0) == 0) + return 1; + return 0; +} + +static int filter_anyaddr_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_read(&filter->anyaddr, ch); +} + +static void filter_anyaddr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_print(name, filter->anyaddr, f, tabs); +} + +static bool filter_anyport_is_set(const seaudit_filter_t * filter) +{ + return filter->anyport != 0; +} + +static int filter_anyport_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && (msg->data.avc->port != 0 || + msg->data.avc->source != 0 || + msg->data.avc->dest != 0 || + msg->data.avc->fport != 0 || msg->data.avc->lport != 0); +} + +static int filter_anyport_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + if (msg->data.avc->port != 0 && filter->anyport == msg->data.avc->port) { + return 1; + } + if (msg->data.avc->source != 0 && filter->anyport == msg->data.avc->source) { + return 1; + } + if (msg->data.avc->dest != 0 && filter->anyport == msg->data.avc->dest) { + return 1; + } + if (msg->data.avc->fport != 0 && filter->anyport == msg->data.avc->fport) { + return 1; + } + if (msg->data.avc->lport != 0 && filter->anyport == msg->data.avc->lport) { + return 1; + } + return 0; +} + +static int filter_anyport_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_int_read(&filter->anyport, ch); +} + +static void filter_anyport_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_int_print(name, filter->anyport, f, tabs); +} + +static bool filter_laddr_is_set(const seaudit_filter_t * filter) +{ + return filter->laddr != NULL; +} + +static int filter_laddr_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->laddr != NULL; +} + +static int filter_laddr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return fnmatch(filter->laddr, msg->data.avc->laddr, 0) == 0; +} + +static int filter_laddr_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_read(&filter->laddr, ch); +} + +static void filter_laddr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_print(name, filter->laddr, f, tabs); +} + +static bool filter_lport_is_set(const seaudit_filter_t * filter) +{ + return filter->lport != 0; +} + +static int filter_lport_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->lport != 0; +} + +static int filter_lport_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return filter->lport == msg->data.avc->lport; +} + +static int filter_lport_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_int_read(&filter->lport, ch); +} + +static void filter_lport_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_int_print(name, filter->lport, f, tabs); +} + +static bool filter_faddr_is_set(const seaudit_filter_t * filter) +{ + return filter->faddr != NULL; +} + +static int filter_faddr_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->faddr != NULL; +} + +static int filter_faddr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return fnmatch(filter->faddr, msg->data.avc->faddr, 0) == 0; +} + +static int filter_faddr_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_read(&filter->faddr, ch); +} + +static void filter_faddr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_print(name, filter->faddr, f, tabs); +} + +static bool filter_fport_is_set(const seaudit_filter_t * filter) +{ + return filter->fport != 0; +} + +static int filter_fport_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->fport != 0; +} + +static int filter_fport_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return filter->fport == msg->data.avc->fport; +} + +static int filter_fport_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_int_read(&filter->fport, ch); +} + +static void filter_fport_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_int_print(name, filter->fport, f, tabs); +} + +static bool filter_saddr_is_set(const seaudit_filter_t * filter) +{ + return filter->saddr != NULL; +} + +static int filter_saddr_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->saddr != NULL; +} + +static int filter_saddr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return fnmatch(filter->saddr, msg->data.avc->saddr, 0) == 0; +} + +static int filter_saddr_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_read(&filter->saddr, ch); +} + +static void filter_saddr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_print(name, filter->saddr, f, tabs); +} + +static bool filter_sport_is_set(const seaudit_filter_t * filter) +{ + return filter->sport != 0; +} + +static int filter_sport_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->source != 0; +} + +static int filter_sport_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return filter->sport == msg->data.avc->source; +} + +static int filter_sport_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_int_read(&filter->sport, ch); +} + +static void filter_sport_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_int_print(name, filter->sport, f, tabs); +} + +static bool filter_daddr_is_set(const seaudit_filter_t * filter) +{ + return filter->daddr != NULL; +} + +static int filter_daddr_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->daddr != NULL; +} + +static int filter_daddr_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return fnmatch(filter->daddr, msg->data.avc->daddr, 0) == 0; +} + +static int filter_daddr_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_read(&filter->daddr, ch); +} + +static void filter_daddr_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_print(name, filter->daddr, f, tabs); +} + +static bool filter_dport_is_set(const seaudit_filter_t * filter) +{ + return filter->dport != 0; +} + +static int filter_dport_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->dest != 0; +} + +static int filter_dport_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return filter->dport == msg->data.avc->dest; +} + +static int filter_dport_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_int_read(&filter->dport, ch); +} + +static void filter_dport_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_int_print(name, filter->dport, f, tabs); +} + +static bool filter_port_is_set(const seaudit_filter_t * filter) +{ + return filter->port != 0; +} + +static int filter_port_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->port != 0; +} + +static int filter_port_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return filter->port == msg->data.avc->port; +} + +static int filter_port_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_int_read(&filter->port, ch); +} + +static void filter_port_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_int_print(name, filter->port, f, tabs); +} + +static bool filter_netif_is_set(const seaudit_filter_t * filter) +{ + return filter->netif != NULL; +} + +static int filter_netif_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->netif != NULL; +} + +static int filter_netif_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return strcmp(filter->netif, msg->data.avc->netif) == 0; +} + +static int filter_netif_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_string_read(&filter->netif, ch); +} + +static void filter_netif_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_string_print(name, filter->netif, f, tabs); +} + +static bool filter_key_is_set(const seaudit_filter_t * filter) +{ + return filter->key != 0; +} + +static int filter_key_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->is_key; +} + +static int filter_key_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return filter->key == msg->data.avc->key; +} + +static int filter_key_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_int_read(&filter->key, ch); +} + +static void filter_key_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_int_print(name, filter->key, f, tabs); +} + +static bool filter_cap_is_set(const seaudit_filter_t * filter) +{ + return filter->cap != 0; +} + +static int filter_cap_support(const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && msg->data.avc->is_capability; +} + +static int filter_cap_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return filter->key == msg->data.avc->capability; +} + +static int filter_cap_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + return filter_int_read(&filter->cap, ch); +} + +static void filter_cap_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + filter_int_print(name, filter->cap, f, tabs); +} + +static bool filter_avc_msg_type_is_set(const seaudit_filter_t * filter) +{ + return filter->avc_msg_type != SEAUDIT_AVC_UNKNOWN; +} + +static int filter_avc_msg_type_support(const seaudit_message_t * msg __attribute__ ((unused))) +{ + return 1; +} + +static int filter_avc_msg_type_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + return msg->type == SEAUDIT_MESSAGE_TYPE_AVC && filter->avc_msg_type == msg->data.avc->msg; +} + +static int filter_avc_msg_type_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + char *s; + if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) { + return -1; + } + filter->avc_msg_type = atoi(s); + free(s); + return 0; +} + +static void filter_avc_msg_type_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + int i; + if (filter->avc_msg_type == SEAUDIT_AVC_UNKNOWN) { + return; + } + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "<criteria type=\"%s\">\n", name); + for (i = 0; i < tabs + 1; i++) { + fprintf(f, "\t"); + } + fprintf(f, "<item>%d</item>\n", filter->avc_msg_type); + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "</criteria>\n"); +} + +static bool filter_date_is_set(const seaudit_filter_t * filter) +{ + return filter->start != NULL; +} + +static int filter_date_support(const seaudit_message_t * msg) +{ + return msg->date_stamp != NULL; +} + +/** + * Given two dates compare them. If both structs have years that are + * not zeroes then also compare their years. + */ +static int filter_date_comp(const struct tm *t1, const struct tm *t2) +{ + /* tm has year, month, day, hour, min, sec */ + /* check if we should compare the years */ + int retval; + if (t1->tm_year != 0 && t2->tm_year != 0 && (retval = t1->tm_year - t2->tm_year) != 0) { + return retval; + } + if ((retval = t1->tm_mon - t2->tm_mon) != 0) { + return retval; + } + if ((retval = t1->tm_mday - t2->tm_mday) != 0) { + return retval; + } + if ((retval = t1->tm_hour - t2->tm_hour) != 0) { + return retval; + } + if ((retval = t1->tm_min - t2->tm_min) != 0) { + return retval; + } + if ((retval = t1->tm_sec - t2->tm_sec) != 0) { + return retval; + } + return 0; +} + +static int filter_date_accept(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + int compval = filter_date_comp(filter->start, msg->date_stamp); + if (filter->date_match == SEAUDIT_FILTER_DATE_MATCH_BEFORE) { + return compval > 0; + } else if (filter->date_match == SEAUDIT_FILTER_DATE_MATCH_AFTER) { + return compval < 0; + } else { + if (compval > 0) + return 0; + compval = filter_date_comp(msg->date_stamp, filter->end); + return compval < 0; + } +} + +static int filter_date_read(seaudit_filter_t * filter, const xmlChar * ch) +{ + char *s; + if ((s = xmlURIUnescapeString((const char *)ch, 0, NULL)) == NULL) { + return -1; + } + if (filter->start == NULL) { + if ((filter->start = calloc(1, sizeof(*(filter->start)))) == NULL) { + free(s); + return -1; + } + strptime(s, "%a %b %d %T %Y", filter->start); + } else if (filter->end == NULL) { + if ((filter->end = calloc(1, sizeof(*(filter->end)))) == NULL) { + free(s); + return -1; + } + strptime(s, "%a %b %d %T %Y", filter->end); + } else { + filter->date_match = atoi(s); + } + free(s); + return 0; +} + +static void filter_date_print(const seaudit_filter_t * filter, const char *name, FILE * f, int tabs) +{ + int i; + xmlChar *s, *escaped; + if (filter->start == NULL) { + return; + } + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "<criteria type=\"%s\">\n", name); + s = xmlCharStrdup(asctime(filter->start)); + escaped = xmlURIEscapeStr(s, NULL); + for (i = 0; i < tabs + 1; i++) { + fprintf(f, "\t"); + } + fprintf(f, "<item>%s</item>\n", escaped); + free(s); + free(escaped); + s = xmlCharStrdup(asctime(filter->end)); + escaped = xmlURIEscapeStr(s, NULL); + for (i = 0; i < tabs + 1; i++) + fprintf(f, "\t"); + fprintf(f, "<item>%s</item>\n", escaped); + free(s); + free(escaped); + for (i = 0; i < tabs + 1; i++) + fprintf(f, "\t"); + fprintf(f, "<item>%d</item>\n", filter->date_match); + for (i = 0; i < tabs; i++) + fprintf(f, "\t"); + fprintf(f, "</criteria>\n"); +} + +typedef bool(filter_is_set_func) (const seaudit_filter_t * filter); +typedef int (filter_support_func) (const seaudit_message_t * msg); +typedef int (filter_accept_func) (const seaudit_filter_t * filter, const seaudit_message_t * msg); +typedef void (filter_print_func) (const seaudit_filter_t * filter, const char *name, FILE * f, int tabs); + +struct filter_criteria_t +{ + const char *name; + filter_is_set_func *is_set; + filter_support_func *support; + filter_accept_func *accept; + filter_read_func *read; + filter_print_func *print; +}; + +/** + * Filter criteria are actually implemented as entries within this + * function pointer table. During filter_is_accepted() each element + * of this table is retrieved; if the support functions returns + * non-zero then the accept function is called. To add new filter + * criteria, implement their support and accept functions and then + * append new entries to this table. + */ +static const struct filter_criteria_t filter_criteria[] = { + {"src_user", filter_src_user_is_set, filter_src_user_support, filter_src_user_accept, filter_src_user_read, + filter_src_user_print}, + {"src_role", filter_src_role_is_set, filter_src_role_support, filter_src_role_accept, filter_src_role_read, + filter_src_role_print}, + {"src_type", filter_src_type_is_set, filter_src_type_support, filter_src_type_accept, filter_src_type_read, + filter_src_type_print}, + {"src_mls_lvl", filter_src_mls_lvl_is_set, filter_src_mls_lvl_support, filter_src_mls_lvl_accept, filter_src_mls_lvl_read, + filter_src_mls_lvl_print}, + {"src_mls_clr", filter_src_mls_clr_is_set, filter_src_mls_clr_support, filter_src_mls_clr_accept, filter_src_mls_clr_read, + filter_src_mls_clr_print}, + {"tgt_user", filter_tgt_user_is_set, filter_tgt_user_support, filter_tgt_user_accept, filter_tgt_user_read, + filter_tgt_user_print}, + {"tgt_role", filter_tgt_role_is_set, filter_tgt_role_support, filter_tgt_role_accept, filter_tgt_role_read, + filter_tgt_role_print}, + {"tgt_type", filter_tgt_type_is_set, filter_tgt_type_support, filter_tgt_type_accept, filter_tgt_type_read, + filter_tgt_type_print}, + {"tgt_mls_lvl", filter_tgt_mls_lvl_is_set, filter_tgt_mls_lvl_support, filter_tgt_mls_lvl_accept, filter_tgt_mls_lvl_read, + filter_src_mls_lvl_print}, + {"tgt_mls_clr", filter_tgt_mls_clr_is_set, filter_tgt_mls_clr_support, filter_tgt_mls_clr_accept, filter_tgt_mls_clr_read, + filter_src_mls_clr_print}, + {"obj_class", filter_tgt_class_is_set, filter_tgt_class_support, filter_tgt_class_accept, filter_tgt_class_read, + filter_tgt_class_print}, + {"perm", filter_perm_is_set, filter_perm_support, filter_perm_accept, filter_perm_read, filter_perm_print}, + {"exe", filter_exe_is_set, filter_exe_support, filter_exe_accept, filter_exe_read, filter_exe_print}, + {"host", filter_host_is_set, filter_host_support, filter_host_accept, filter_host_read, filter_host_print}, + {"path", filter_path_is_set, filter_path_support, filter_path_accept, filter_path_read, filter_path_print}, + {"inode", filter_inode_is_set, filter_inode_support, filter_inode_accept, filter_inode_read, filter_inode_print}, + {"pid", filter_pid_is_set, filter_pid_support, filter_pid_accept, filter_pid_read, filter_pid_print}, + {"comm", filter_comm_is_set, filter_comm_support, filter_comm_accept, filter_comm_read, filter_comm_print}, + {"ipaddr", filter_anyaddr_is_set, filter_anyaddr_support, filter_anyaddr_accept, filter_anyaddr_read, filter_anyaddr_print}, + {"anyport", filter_anyport_is_set, filter_anyport_support, filter_anyport_accept, filter_anyport_read, + filter_anyport_print}, + {"laddr", filter_laddr_is_set, filter_laddr_support, filter_laddr_accept, filter_laddr_read, filter_laddr_print}, + {"lport", filter_lport_is_set, filter_lport_support, filter_lport_accept, filter_lport_read, filter_lport_print}, + {"faddr", filter_faddr_is_set, filter_faddr_support, filter_faddr_accept, filter_faddr_read, filter_faddr_print}, + {"fport", filter_fport_is_set, filter_fport_support, filter_fport_accept, filter_fport_read, filter_fport_print}, + {"saddr", filter_saddr_is_set, filter_saddr_support, filter_saddr_accept, filter_saddr_read, filter_saddr_print}, + {"sport", filter_sport_is_set, filter_sport_support, filter_sport_accept, filter_sport_read, filter_sport_print}, + {"daddr", filter_daddr_is_set, filter_daddr_support, filter_daddr_accept, filter_daddr_read, filter_daddr_print}, + {"dport", filter_dport_is_set, filter_dport_support, filter_dport_accept, filter_dport_read, filter_dport_print}, + {"port", filter_port_is_set, filter_port_support, filter_port_accept, filter_port_read, filter_port_print}, + {"netif", filter_netif_is_set, filter_netif_support, filter_netif_accept, filter_netif_read, filter_netif_print}, + {"key", filter_key_is_set, filter_key_support, filter_key_accept, filter_key_read, filter_key_print}, + {"cap", filter_cap_is_set, filter_cap_support, filter_cap_accept, filter_cap_read, filter_cap_print}, + {"msg", filter_avc_msg_type_is_set, filter_avc_msg_type_support, filter_avc_msg_type_accept, filter_avc_msg_type_read, + filter_avc_msg_type_print}, + {"date_time", filter_date_is_set, filter_date_support, filter_date_accept, filter_date_read, filter_date_print} +}; + +/******************** protected functions below ********************/ + +int filter_is_accepted(const seaudit_filter_t * filter, const seaudit_message_t * msg) +{ + bool tried_criterion = false; + int acceptval; + size_t i; + + for (i = 0; i < sizeof(filter_criteria) / sizeof(filter_criteria[0]); i++) { + if (filter_criteria[i].is_set(filter)) { + tried_criterion = true; + if (filter_criteria[i].support(msg)) { + acceptval = filter_criteria[i].accept(filter, msg); + } else if (filter->strict) { + /* if filter is strict, then an + unsupported criterion is assumed to + not match */ + acceptval = 0; + } else { + /* for unstrict filters, unsupported + criterion is assumed to be a don't + care state */ + continue; + } + if (filter->match == SEAUDIT_FILTER_MATCH_ANY && acceptval == 1) { + return 1; + } + if (filter->match == SEAUDIT_FILTER_MATCH_ALL && acceptval == 0) { + return 0; + } + } + } + if (!tried_criterion) { + /* if got here, then the filter had no set criterion */ + if (filter->strict) { + /* a strict empty filter matches nothing */ + return 0; + } + return 1; + } + if (filter->match == SEAUDIT_FILTER_MATCH_ANY) { + /* if got here, then no criterion was met */ + return 0; + } + /* if got here, then all criteria were met */ + return 1; +} + +static bool filter_parse_is_valid_tag(const xmlChar * tag) +{ + static const char *parse_valid_tags[] = { "item", "criteria", "view", "filter", "desc", NULL }; + size_t i; + for (i = 0; parse_valid_tags[i] != NULL; i++) { + if (xmlStrcmp(tag, (xmlChar *) parse_valid_tags[i]) == 0) { + return 1; + } + } + return 0; +} + +static filter_read_func *filter_get_read_func(const xmlChar * name) +{ + size_t i; + for (i = 0; i < sizeof(filter_criteria) / sizeof(filter_criteria[0]); i++) { + if (xmlStrcmp(name, (xmlChar *) filter_criteria[i].name) == 0) { + return filter_criteria[i].read; + } + } + return NULL; +} + +static void filter_parse_start_element(void *user_data, const xmlChar * name, const xmlChar ** attrs) +{ + struct filter_parse_state *state = user_data; + size_t i; + if (!filter_parse_is_valid_tag(name)) { + state->warnings = 1; + return; + } + if (xmlStrcmp(name, (xmlChar *) "view") == 0) { + for (i = 0; attrs[i] != NULL && attrs[i + 1] != NULL; i += 2) { + if (xmlStrcmp(attrs[i], (xmlChar *) "name") == 0) { + free(state->view_name); + state->view_name = xmlURIUnescapeString((const char *)attrs[i + 1], 0, NULL); + } else if (xmlStrcmp(attrs[i], (xmlChar *) "match") == 0) { + if (xmlStrcmp(attrs[i + 1], (xmlChar *) "all") == 0) { + state->view_match = SEAUDIT_FILTER_MATCH_ALL; + } else if (xmlStrcmp(attrs[i + 1], (xmlChar *) "any") == 0) { + state->view_match = SEAUDIT_FILTER_MATCH_ANY; + } + } else if (xmlStrcmp(attrs[i], (xmlChar *) "show") == 0) { + if (xmlStrcmp(attrs[i + 1], (xmlChar *) "true") == 0) { + state->view_visible = SEAUDIT_FILTER_VISIBLE_SHOW; + } else if (xmlStrcmp(attrs[i + 1], (xmlChar *) "hide") == 0) { + state->view_visible = SEAUDIT_FILTER_VISIBLE_HIDE; + } + } + } + } else if (xmlStrcmp(name, (xmlChar *) "filter") == 0) { + /* create a new filter and set it to be the one that is currently being parsed */ + char *filter_name = NULL; + seaudit_filter_match_e match = SEAUDIT_FILTER_MATCH_ALL; + bool strict = false; + for (i = 0; attrs[i] != NULL && attrs[i + 1] != NULL; i += 2) { + if (xmlStrcmp(attrs[i], (xmlChar *) "name") == 0) { + free(filter_name); + filter_name = xmlURIUnescapeString((const char *)attrs[i + 1], 0, NULL); + } else if (xmlStrcmp(attrs[i], (xmlChar *) "match") == 0) { + if (xmlStrcmp(attrs[i + 1], (xmlChar *) "all") == 0) { + match = SEAUDIT_FILTER_MATCH_ALL; + } else if (xmlStrcmp(attrs[i + 1], (xmlChar *) "any") == 0) { + match = SEAUDIT_FILTER_MATCH_ANY; + } + } else if (xmlStrcmp(attrs[i], (xmlChar *) "strict") == 0) { + if (xmlStrcmp(attrs[i + 1], (xmlChar *) "true") == 0) { + strict = true; + } else if (xmlStrcmp(attrs[i + 1], (xmlChar *) "false") == 0) { + strict = false; + } + } + } + if ((state->cur_filter = seaudit_filter_create(filter_name)) != NULL) { + if (apol_vector_append(state->filters, state->cur_filter) < 0) { + seaudit_filter_destroy(&state->cur_filter); + } else { + seaudit_filter_set_match(state->cur_filter, match); + seaudit_filter_set_strict(state->cur_filter, strict); + } + } + free(filter_name); + } else if (xmlStrcmp(name, (xmlChar *) "criteria") == 0) { + for (i = 0; attrs[i] != NULL && attrs[i + 1] != NULL; i += 2) { + if (xmlStrcmp(attrs[i], (xmlChar *) "type") == 0) { + state->cur_filter_read = filter_get_read_func(attrs[i + 1]); + } + } + } + free(state->cur_string); + state->cur_string = NULL; +} + +static void filter_parse_end_element(void *user_data, const xmlChar * name) +{ + struct filter_parse_state *state = user_data; + char *s; + if (!filter_parse_is_valid_tag(name)) { + state->warnings = 1; + return; + } + if (xmlStrcmp(name, (xmlChar *) "desc") == 0) { + if (state->cur_filter == NULL) { + state->warnings = 1; + } else { + s = xmlURIUnescapeString((const char *)state->cur_string, 0, NULL); + seaudit_filter_set_description(state->cur_filter, s); + free(s); + } + } else if (xmlStrcmp(name, (xmlChar *) "item") == 0) { + if (state->cur_filter == NULL || state->cur_filter_read == NULL) { + state->warnings = 1; + } else { + state->cur_filter_read(state->cur_filter, state->cur_string); + } + } else if (xmlStrcmp(name, (xmlChar *) "filter") == 0) { + state->cur_filter = NULL; + } else if (xmlStrcmp(name, (xmlChar *) "criteria") == 0) { + state->cur_filter_read = NULL; + } + free(state->cur_string); + state->cur_string = NULL; +} + +static void filter_parse_characters(void *user_data, const xmlChar * ch, int len) +{ + struct filter_parse_state *state = user_data; + free(state->cur_string); + state->cur_string = xmlStrndup(ch, len); +} + +int filter_parse_xml(struct filter_parse_state *state, const char *filename) +{ + xmlSAXHandler handler; + int err; + + memset(&handler, 0, sizeof(xmlSAXHandler)); + handler.startElement = filter_parse_start_element; + handler.endElement = filter_parse_end_element; + handler.characters = filter_parse_characters; + err = xmlSAXUserParseFile(&handler, state, filename); + free(state->cur_string); + state->cur_string = NULL; + if (err) { + errno = EIO; + return -1; + } + if (state->warnings) { + return 1; + } + return 0; +} + +void filter_append_to_file(const seaudit_filter_t * filter, FILE * file, int tabs) +{ + xmlChar *escaped; + xmlChar *str_xml; + int i; + size_t j; + + if (filter == NULL || file == NULL) { + errno = EINVAL; + return; + } + + if (filter->name == NULL) { + str_xml = xmlCharStrdup("Unnamed"); + } else { + str_xml = xmlCharStrdup(filter->name); + } + escaped = xmlURIEscapeStr(str_xml, NULL); + for (i = 0; i < tabs; i++) + fprintf(file, "\t"); + fprintf(file, "<filter name=\"%s\" match=\"%s\" strict=\"%s\">\n", escaped, + filter->match == SEAUDIT_FILTER_MATCH_ALL ? "all" : "any", filter->strict ? "true" : "false"); + free(escaped); + free(str_xml); + + if (filter->desc != NULL) { + str_xml = xmlCharStrdup(filter->desc); + escaped = xmlURIEscapeStr(str_xml, NULL); + for (i = 0; i < tabs + 1; i++) + fprintf(file, "\t"); + fprintf(file, "<desc>%s</desc>\n", escaped); + free(escaped); + free(str_xml); + } + for (j = 0; j < sizeof(filter_criteria) / sizeof(filter_criteria[0]); j++) { + filter_criteria[j].print(filter, filter_criteria[j].name, file, tabs + 1); + } + for (i = 0; i < tabs; i++) + fprintf(file, "\t"); + fprintf(file, "</filter>\n"); +} diff --git a/libseaudit/src/filter-internal.h b/libseaudit/src/filter-internal.h new file mode 100644 index 0000000..abfa908 --- /dev/null +++ b/libseaudit/src/filter-internal.h @@ -0,0 +1,109 @@ +/** + * @file + * Protected interface for seaudit filters. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Jeremy Solt jsolt@tresys.com + * + * Copyright (C) 2006-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SEAUDIT_FILTER_INTERNAL_H +#define SEAUDIT_FILTER_INTERNAL_H + +#include "seaudit_internal.h" + +struct seaudit_filter +{ + seaudit_filter_match_e match; + char *name; + char *desc; + bool strict; + /** model that is watching this filter */ + seaudit_model_t *model; + /** vector of strings, for source users */ + apol_vector_t *src_users; + /** vector of strings, for source roles */ + apol_vector_t *src_roles; + /** vector of strings, for source types */ + apol_vector_t *src_types; + /** vector of strings, for source mls levels */ + apol_vector_t *src_mls_lvl; + /** vector of strings, for source mls clearance */ + apol_vector_t *src_mls_clr; + /** vector of strings, for target users */ + apol_vector_t *tgt_users; + /** vector of strings, for target roles */ + apol_vector_t *tgt_roles; + /** vector of strings, for target types */ + apol_vector_t *tgt_types; + /** vector of strings, for target mls levels */ + apol_vector_t *tgt_mls_lvl; + /** vector of strings, for target mls clearance */ + apol_vector_t *tgt_mls_clr; + /** vector of strings, for target object classes */ + apol_vector_t *tgt_classes; + /** criteria for permissions, glob expression */ + char *perm; + /** criteria for executable, glob expression */ + char *exe; + /** criteria for host, glob expression */ + char *host; + /** criteria for path, glob expression */ + char *path; + /** inode criterion, as a literal value */ + unsigned long inode; + /** pid criterion, as a literal value */ + unsigned int pid; + /** criterion for command, glob expression */ + char *comm; + /** criterion for IP address, glob expression */ + char *anyaddr; + /** criterion for local address, glob expression */ + char *laddr; + /** criterion for foreign address, glob expression */ + char *faddr; + /** criterion for source address, glob expression */ + char *saddr; + /** criterion for destination address, glob expression */ + char *daddr; + /** criterion for any of the ports, exact match */ + int anyport; + /** criterion for local port, exact match */ + int lport; + /** criterion for foreign port, exact match */ + int fport; + /** criterion for source port, exact match */ + int sport; + /** criterion for destination port, exact match */ + int dport; + /** criterion for just plain port, exact match */ + int port; + /** criterion for netif, exact match */ + char *netif; + /** criterion for IPC key, exact match */ + int key; + /** criterion for capability, exact match */ + int cap; + /** criterion for AVC message type */ + seaudit_avc_message_type_e avc_msg_type; + struct tm *start, *end; + seaudit_filter_date_match_e date_match; +}; + +#endif diff --git a/libseaudit/src/filter.c b/libseaudit/src/filter.c new file mode 100644 index 0000000..298a309 --- /dev/null +++ b/libseaudit/src/filter.c @@ -0,0 +1,1124 @@ +/** + * @file + * Implementation of seaudit filters. + * + * If adding new filter criteria, make sure you do the following: + * + * <ol> + * <li>add field(s) to seaudit_filter_t</li> + * <li>update filter constructor, seaudit_filter_create()</li> + * <li>update copy-constructor, seaudit_filter_create_from_filter()</li> + * <li>update destructor, seaudit_filter_destroy()</li> + * <li>add accessor(s) and modifier(s) as necessary</li> + * <li>add a record to filter_criteria table (in filter-internal.c), + * implementing the five necessary functions</li> + * </ol> + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Jeremy Solt jsolt@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "seaudit_internal.h" +#include "filter-internal.h" + +#include <apol/util.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +seaudit_filter_t *seaudit_filter_create(const char *name) +{ + seaudit_filter_t *s = calloc(1, sizeof(*s)); + if (s == NULL) { + return NULL; + } + if (name == NULL) { + name = "Untitled"; + } + if ((s->name = strdup(name)) == NULL) { + int error = errno; + seaudit_filter_destroy(&s); + errno = error; + return NULL; + } + return s; +} + +seaudit_filter_t *seaudit_filter_create_from_filter(const seaudit_filter_t * filter) +{ + seaudit_filter_t *f = NULL; + int error = 0; + if (filter == NULL) { + error = EINVAL; + goto cleanup; + } + if ((f = seaudit_filter_create(filter->name)) == NULL || (filter->desc != NULL && (f->desc = strdup(filter->desc)) == NULL)) { + error = errno; + goto cleanup; + } + f->strict = filter->strict; + if ((filter->src_users != NULL + && (f->src_users = apol_vector_create_from_vector(filter->src_users, apol_str_strdup, NULL, free)) == NULL) + || (filter->src_roles != NULL + && (f->src_roles = apol_vector_create_from_vector(filter->src_roles, apol_str_strdup, NULL, free)) == NULL) + || (filter->src_types != NULL + && (f->src_types = apol_vector_create_from_vector(filter->src_types, apol_str_strdup, NULL, free)) == NULL) + || (filter->src_mls_lvl != NULL + && (f->src_mls_lvl = apol_vector_create_from_vector(filter->src_mls_lvl, apol_str_strdup, NULL, free)) == NULL) + || (filter->src_mls_clr != NULL + && (f->src_mls_clr = apol_vector_create_from_vector(filter->src_mls_clr, apol_str_strdup, NULL, free)) == NULL) + || (filter->tgt_users != NULL + && (f->tgt_users = apol_vector_create_from_vector(filter->tgt_users, apol_str_strdup, NULL, free)) == NULL) + || (filter->tgt_roles != NULL + && (f->tgt_roles = apol_vector_create_from_vector(filter->tgt_roles, apol_str_strdup, NULL, free)) == NULL) + || (filter->tgt_types != NULL + && (f->tgt_types = apol_vector_create_from_vector(filter->tgt_types, apol_str_strdup, NULL, free)) == NULL) + || (filter->tgt_mls_lvl != NULL + && (f->tgt_mls_lvl = apol_vector_create_from_vector(filter->tgt_mls_lvl, apol_str_strdup, NULL, free)) == NULL) + || (filter->tgt_mls_clr != NULL + && (f->tgt_mls_clr = apol_vector_create_from_vector(filter->tgt_mls_clr, apol_str_strdup, NULL, free)) == NULL) + || (filter->tgt_classes != NULL + && (f->tgt_classes = apol_vector_create_from_vector(filter->tgt_classes, apol_str_strdup, NULL, free)) == NULL)) { + error = errno; + goto cleanup; + } + if ((filter->perm != NULL && (f->perm = strdup(filter->perm)) == NULL) || + (filter->exe != NULL && (f->exe = strdup(filter->exe)) == NULL) || + (filter->host != NULL && (f->host = strdup(filter->host)) == NULL) || + (filter->path != NULL && (f->path = strdup(filter->path)) == NULL) || + (filter->comm != NULL && (f->comm = strdup(filter->comm)) == NULL) || + (filter->anyaddr != NULL && (f->anyaddr = strdup(filter->anyaddr)) == NULL) || + (filter->netif != NULL && (f->netif = strdup(filter->netif)) == NULL)) { + error = errno; + goto cleanup; + } + if ((filter->laddr != NULL && (f->laddr = strdup(filter->laddr)) == NULL) || + (filter->faddr != NULL && (f->faddr = strdup(filter->faddr)) == NULL) || + (filter->saddr != NULL && (f->saddr = strdup(filter->saddr)) == NULL) || + (filter->daddr != NULL && (f->daddr = strdup(filter->daddr)) == NULL)) { + error = errno; + goto cleanup; + } + f->match = filter->match; + f->inode = filter->inode; + f->pid = filter->pid; + f->anyport = filter->anyport; + f->lport = filter->lport; + f->fport = filter->fport; + f->sport = filter->sport; + f->dport = filter->dport; + f->port = filter->port; + f->key = filter->key; + f->cap = filter->cap; + f->avc_msg_type = filter->avc_msg_type; + if (filter->start != NULL) { + if ((f->start = calloc(1, sizeof(*f->start))) == NULL) { + error = errno; + goto cleanup; + } + memcpy(f->start, filter->start, sizeof(*f->start)); + } + if (filter->end != NULL) { + if ((f->end = calloc(1, sizeof(*f->end))) == NULL) { + error = errno; + goto cleanup; + } + memcpy(f->end, filter->end, sizeof(*f->end)); + } + f->date_match = filter->date_match; + f->model = NULL; + cleanup: + if (error != 0) { + seaudit_filter_destroy(&f); + errno = error; + return NULL; + } + return f; +} + +/** + * Callback invoked when free()ing a vector of filters. + * + * @param v Filter object to free. + */ +static void filter_free(void *v) +{ + seaudit_filter_t *f = v; + seaudit_filter_destroy(&f); +} + +apol_vector_t *seaudit_filter_create_from_file(const char *filename) +{ + struct filter_parse_state state; + int retval, error; + memset(&state, 0, sizeof(state)); + if ((state.filters = apol_vector_create(filter_free)) == NULL) { + return NULL; + } + retval = filter_parse_xml(&state, filename); + error = errno; + free(state.view_name); + if (retval < 0) { + apol_vector_destroy(&state.filters); + errno = error; + return NULL; + } + return state.filters; +} + +void seaudit_filter_destroy(seaudit_filter_t ** filter) +{ + if (filter != NULL && *filter != NULL) { + free((*filter)->name); + free((*filter)->desc); + apol_vector_destroy(&(*filter)->src_users); + apol_vector_destroy(&(*filter)->src_roles); + apol_vector_destroy(&(*filter)->src_types); + apol_vector_destroy(&(*filter)->src_mls_lvl); + apol_vector_destroy(&(*filter)->src_mls_clr); + apol_vector_destroy(&(*filter)->tgt_users); + apol_vector_destroy(&(*filter)->tgt_roles); + apol_vector_destroy(&(*filter)->tgt_types); + apol_vector_destroy(&(*filter)->tgt_mls_lvl); + apol_vector_destroy(&(*filter)->tgt_mls_clr); + apol_vector_destroy(&(*filter)->tgt_classes); + free((*filter)->perm); + free((*filter)->exe); + free((*filter)->host); + free((*filter)->path); + free((*filter)->comm); + free((*filter)->anyaddr); + free((*filter)->laddr); + free((*filter)->faddr); + free((*filter)->saddr); + free((*filter)->daddr); + free((*filter)->netif); + free((*filter)->start); + free((*filter)->end); + free(*filter); + *filter = NULL; + } +} + +int seaudit_filter_set_match(seaudit_filter_t * filter, seaudit_filter_match_e match) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + filter->match = match; + if (filter->model != NULL) { + model_notify_filter_changed(filter->model, filter); + } + return 0; +} + +seaudit_filter_match_e seaudit_filter_get_match(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter->match; +} + +int seaudit_filter_set_name(seaudit_filter_t * filter, const char *name) +{ + char *new_name = NULL; + if (filter == NULL) { + errno = EINVAL; + return -1; + } + if (name != filter->name) { + if (name != NULL && (new_name = strdup(name)) == NULL) { + return -1; + } + free(filter->name); + filter->name = new_name;; + } + return 0; +} + +const char *seaudit_filter_get_name(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->name; +} + +int seaudit_filter_set_description(seaudit_filter_t * filter, const char *desc) +{ + char *new_desc = NULL; + if (filter == NULL) { + errno = EINVAL; + return -1; + } + if (desc != filter->desc) { + if (desc != NULL && (new_desc = strdup(desc)) == NULL) { + return -1; + } + free(filter->desc); + filter->desc = new_desc; + } + return 0; +} + +const char *seaudit_filter_get_description(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->desc; +} + +int seaudit_filter_set_strict(seaudit_filter_t * filter, bool is_strict) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + if (filter->strict != is_strict) { + filter->strict = is_strict; + if (filter->model != NULL) { + model_notify_filter_changed(filter->model, filter); + } + } + return 0; +} + +bool seaudit_filter_get_strict(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return false; + } + return filter->strict; +} + +/** + * Helper function to set a criterion's vector, by duping the vector + * and its strings. Dupe the vector before destroying the existing + * one, in case v is the same as tgt. + */ +static int filter_set_vector(seaudit_filter_t * filter, apol_vector_t ** tgt, const apol_vector_t * v) +{ + apol_vector_t *new_v = NULL; + if (v != NULL) { + if ((new_v = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + return -1; + } + } + apol_vector_destroy(tgt); + *tgt = new_v; + if (filter->model != NULL) { + model_notify_filter_changed(filter->model, filter); + } + return 0; +} + +/** + * Helper function to set a criterion string, by dupping the src + * string. As a check, if the pointers are already the same then do + * nothing. + */ +static int filter_set_string(seaudit_filter_t * filter, char **dest, const char *src) +{ + if (src != *dest) { + char *new_s = NULL; + if (src != NULL && (new_s = strdup(src)) == NULL) { + return -1; + } + free(*dest); + *dest = new_s; + if (filter->model != NULL) { + model_notify_filter_changed(filter->model, filter); + } + } + return 0; +} + +static int filter_set_ulong(seaudit_filter_t * filter, unsigned long *dest, const ulong src) +{ + if (src != *dest) { + *dest = src; + if (filter->model != NULL) { + model_notify_filter_changed(filter->model, filter); + } + } + return 0; +} + +static int filter_set_uint(seaudit_filter_t * filter, unsigned int *dest, const ulong src) +{ + if (src != *dest) { + *dest = src; + if (filter->model != NULL) { + model_notify_filter_changed(filter->model, filter); + } + } + return 0; +} + +static int filter_set_int(seaudit_filter_t * filter, int *dest, const int src) +{ + int s = src; + if (src <= 0) { + s = 0; + } + if (s != *dest) { + *dest = s; + if (filter->model != NULL) { + model_notify_filter_changed(filter->model, filter); + } + } + return 0; +} + +/******************** public accessors / modifiers ********************/ + +int seaudit_filter_set_source_user(seaudit_filter_t * filter, const apol_vector_t * v) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_vector(filter, &filter->src_users, v); +} + +const apol_vector_t *seaudit_filter_get_source_user(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->src_users; +} + +int seaudit_filter_set_source_role(seaudit_filter_t * filter, const apol_vector_t * v) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_vector(filter, &filter->src_roles, v); +} + +const apol_vector_t *seaudit_filter_get_source_role(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->src_roles; +} + +int seaudit_filter_set_source_type(seaudit_filter_t * filter, const apol_vector_t * v) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_vector(filter, &filter->src_types, v); +} + +const apol_vector_t *seaudit_filter_get_source_type(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->src_types; +} + +int seaudit_filter_set_source_mls_lvl(seaudit_filter_t * filter, const apol_vector_t * v) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_vector(filter, &filter->src_mls_lvl, v); +} + +const apol_vector_t *seaudit_filter_get_source_mls_lvl(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->src_mls_lvl; +} + +int seaudit_filter_set_source_mls_clr(seaudit_filter_t * filter, const apol_vector_t * v) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_vector(filter, &filter->src_mls_clr, v); +} + +const apol_vector_t *seaudit_filter_get_source_mls_clr(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->src_mls_clr; +} +int seaudit_filter_set_target_user(seaudit_filter_t * filter, const apol_vector_t * v) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_vector(filter, &filter->tgt_users, v); +} + +const apol_vector_t *seaudit_filter_get_target_user(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->tgt_users; +} + +int seaudit_filter_set_target_role(seaudit_filter_t * filter, const apol_vector_t * v) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_vector(filter, &filter->tgt_roles, v); +} + +const apol_vector_t *seaudit_filter_get_target_role(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->tgt_roles; +} + +int seaudit_filter_set_target_type(seaudit_filter_t * filter, const apol_vector_t * v) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_vector(filter, &filter->tgt_types, v); +} + +const apol_vector_t *seaudit_filter_get_target_type(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->tgt_types; +} + +int seaudit_filter_set_target_mls_lvl(seaudit_filter_t * filter, const apol_vector_t * v) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_vector(filter, &filter->tgt_mls_lvl, v); +} + +const apol_vector_t *seaudit_filter_get_target_mls_lvl(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->tgt_mls_lvl; +} + +int seaudit_filter_set_target_mls_clr(seaudit_filter_t * filter, const apol_vector_t * v) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_vector(filter, &filter->tgt_mls_clr, v); +} + +const apol_vector_t *seaudit_filter_get_target_mls_clr(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->tgt_mls_clr; +} + +int seaudit_filter_set_target_class(seaudit_filter_t * filter, const apol_vector_t * v) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_vector(filter, &filter->tgt_classes, v); +} + +const apol_vector_t *seaudit_filter_get_target_class(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->tgt_classes; +} + +int seaudit_filter_set_permission(seaudit_filter_t * filter, const char *perm) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_string(filter, &filter->perm, perm); +} + +const char *seaudit_filter_get_permission(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->perm; +} + +int seaudit_filter_set_executable(seaudit_filter_t * filter, const char *exe) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_string(filter, &filter->exe, exe); +} + +const char *seaudit_filter_get_executable(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->exe; +} + +int seaudit_filter_set_host(seaudit_filter_t * filter, const char *host) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_string(filter, &filter->host, host); +} + +const char *seaudit_filter_get_host(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->host; +} + +int seaudit_filter_set_path(seaudit_filter_t * filter, const char *path) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_string(filter, &filter->path, path); +} + +const char *seaudit_filter_get_path(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->path; +} + +int seaudit_filter_set_inode(seaudit_filter_t * filter, unsigned long inode) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_ulong(filter, &filter->inode, inode); + return 0; +} + +unsigned long seaudit_filter_get_inode(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter->inode; +} + +int seaudit_filter_set_pid(seaudit_filter_t * filter, unsigned int pid) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_uint(filter, &filter->pid, pid); + return 0; +} + +unsigned int seaudit_filter_get_pid(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter->pid; +} + +int seaudit_filter_set_command(seaudit_filter_t * filter, const char *command) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_string(filter, &filter->comm, command); +} + +const char *seaudit_filter_get_command(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->comm; +} + +int seaudit_filter_set_anyaddr(seaudit_filter_t * filter, const char *ipaddr) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_string(filter, &filter->anyaddr, ipaddr); +} + +const char *seaudit_filter_get_anyaddr(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->anyaddr; +} + +int seaudit_filter_set_anyport(seaudit_filter_t * filter, const int port) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter_set_int(filter, &filter->anyport, port); +} + +int seaudit_filter_get_anyport(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter->anyport; +} + +int filter_set_ipaddress_vers_4_1(seaudit_filter_t * filter, const char *ipaddr) +{ + return seaudit_filter_set_anyaddr(filter, ipaddr); +} + +const char *filter_get_ipaddress_vers_4_1(const seaudit_filter_t * filter) +{ + return seaudit_filter_get_anyaddr(filter); +} + +int filter_set_port_vers_4_1(seaudit_filter_t * filter, const int port) +{ + return seaudit_filter_set_anyport(filter, port); +} + +int filter_get_port_vers_4_1(const seaudit_filter_t * filter) +{ + return seaudit_filter_get_anyport(filter); +} + +#if LINK_SHARED == 1 +__asm__(".symver filter_set_ipaddress_vers_4_1,seaudit_filter_set_ipaddress@VERS_4.1"); +__asm__(".symver filter_get_ipaddress_vers_4_1,seaudit_filter_get_ipaddress@VERS_4.1"); +__asm__(".symver filter_set_port_vers_4_1,seaudit_filter_set_port@VERS_4.1"); +__asm__(".symver filter_get_port_vers_4_1,seaudit_filter_get_port@VERS_4.1"); +#endif + +int seaudit_filter_set_laddr(seaudit_filter_t * filter, const char *laddr) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_string(filter, &filter->laddr, laddr); +} + +const char *seaudit_filter_get_laddr(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->laddr; +} + +int seaudit_filter_set_lport(seaudit_filter_t * filter, const int lport) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter_set_int(filter, &filter->lport, lport); +} + +int seaudit_filter_get_lport(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter->lport; +} + +int seaudit_filter_set_faddr(seaudit_filter_t * filter, const char *faddr) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_string(filter, &filter->faddr, faddr); +} + +const char *seaudit_filter_get_faddr(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->faddr; +} + +int seaudit_filter_set_fport(seaudit_filter_t * filter, const int fport) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter_set_int(filter, &filter->fport, fport); +} + +int seaudit_filter_get_fport(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter->fport; +} + +int seaudit_filter_set_saddr(seaudit_filter_t * filter, const char *saddr) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_string(filter, &filter->saddr, saddr); +} + +const char *seaudit_filter_get_saddr(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->saddr; +} + +int seaudit_filter_set_sport(seaudit_filter_t * filter, const int sport) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter_set_int(filter, &filter->sport, sport); +} + +int seaudit_filter_get_sport(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter->sport; +} + +int seaudit_filter_set_daddr(seaudit_filter_t * filter, const char *daddr) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_string(filter, &filter->daddr, daddr); +} + +const char *seaudit_filter_get_daddr(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->daddr; +} + +int seaudit_filter_set_dport(seaudit_filter_t * filter, const int dport) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter_set_int(filter, &filter->dport, dport); +} + +int seaudit_filter_get_dport(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter->dport; +} + +int filter_set_port_vers_4_2(seaudit_filter_t * filter, const int port) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter_set_int(filter, &filter->port, port); +} + +int filter_get_port_vers_4_2(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter->port; +} + +#if LINK_SHARED == 1 +__asm__(".symver filter_set_port_vers_4_2,seaudit_filter_set_port@@VERS_4.2"); +__asm__(".symver filter_get_port_vers_4_2,seaudit_filter_get_port@@VERS_4.2"); +#endif + +int seaudit_filter_set_key(seaudit_filter_t * filter, const int key) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter_set_int(filter, &filter->key, key); +} + +int seaudit_filter_get_key(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter->key; +} + +int seaudit_filter_set_cap(seaudit_filter_t * filter, const int cap) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter_set_int(filter, &filter->cap, cap); +} + +int seaudit_filter_get_cap(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return 0; + } + return filter->cap; +} + +int seaudit_filter_set_netif(seaudit_filter_t * filter, const char *netif) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + return filter_set_string(filter, &filter->netif, netif); +} + +const char *seaudit_filter_get_netif(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return NULL; + } + return filter->netif; +} + +int seaudit_filter_set_message_type(seaudit_filter_t * filter, const seaudit_avc_message_type_e message_type) +{ + if (filter == NULL) { + errno = EINVAL; + return -1; + } + filter->avc_msg_type = message_type; + if (filter->model != NULL) { + model_notify_filter_changed(filter->model, filter); + } + return 0; +} + +seaudit_avc_message_type_e seaudit_filter_get_message_type(const seaudit_filter_t * filter) +{ + if (filter == NULL) { + errno = EINVAL; + return SEAUDIT_AVC_UNKNOWN; + } + return filter->avc_msg_type; +} + +int seaudit_filter_set_date(seaudit_filter_t * filter, const struct tm *start, const struct tm *end, + seaudit_filter_date_match_e date_match) +{ + struct tm *new_tm = NULL; + if (filter == NULL) { + errno = EINVAL; + return -1; + } + /* the following weird branching exists because start and end + * could be shadowing filter->start and filter->end. if + * filters->start and filter->end are free()d to early, then + * there may be a dereference of free()d memory */ + if (filter->start != start) { + new_tm = NULL; + if (start != NULL) { + if ((new_tm = calloc(1, sizeof(*new_tm))) == NULL) { + return -1; + } + memcpy(new_tm, start, sizeof(*start)); + } + free(filter->start); + filter->start = new_tm; + } + if (start != NULL) { + if (filter->end != end) { + new_tm = NULL; + if (end != NULL) { + if ((new_tm = calloc(1, sizeof(*new_tm))) == NULL) { + return -1; + } + memcpy(new_tm, end, sizeof(*end)); + } + free(filter->end); + filter->end = new_tm; + } + } else { + free(filter->end); + filter->end = NULL; + } + filter->date_match = date_match; + if (filter->model != NULL) { + model_notify_filter_changed(filter->model, filter); + } + return 0; +} + +void seaudit_filter_get_date(const seaudit_filter_t * filter, const struct tm **start, const struct tm **end, + seaudit_filter_date_match_e * match) +{ + if (start != NULL) { + *start = NULL; + } + if (end != NULL) { + *end = NULL; + } + if (match != NULL) { + *match = SEAUDIT_FILTER_DATE_MATCH_BEFORE; + } + if (filter == NULL || start == NULL || end == NULL || match == NULL) { + errno = EINVAL; + return; + } + *start = filter->start; + *end = filter->end; + *match = filter->date_match; +} + +int seaudit_filter_save_to_file(const seaudit_filter_t * filter, const char *filename) +{ + FILE *file; + const char *XML_VER = "<?xml version=\"1.0\"?>\n"; + + if (filter == NULL || filename == NULL) { + errno = EINVAL; + return -1; + } + if ((file = fopen(filename, "w")) == NULL) { + return -1; + } + fprintf(file, XML_VER); + fprintf(file, "<view xmlns=\"http://oss.tresys.com/projects/setools/seaudit-%s/\">\n", FILTER_FILE_FORMAT_VERSION); + filter_append_to_file(filter, file, 1); + fprintf(file, "</view>\n"); + fclose(file); + return 0; +} + +/******************** protected functions below ********************/ + +void filter_set_model(seaudit_filter_t * filter, seaudit_model_t * model) +{ + filter->model = model; +} diff --git a/libseaudit/src/libseaudit.map b/libseaudit/src/libseaudit.map new file mode 100644 index 0000000..e0ad723 --- /dev/null +++ b/libseaudit/src/libseaudit.map @@ -0,0 +1,88 @@ +VERS_4.1{ + global: + seaudit_avc_message_*; + seaudit_filter_*; + seaudit_handle_msg; + seaudit_log_*; + seaudit_message_*; + seaudit_model_*; + seaudit_report_*; + seaudit_sort_*; + libseaudit_get_version; + local: *; +}; + +VERS_4.2{ + global: + seaudit_avc_message_get_port; + seaudit_filter_get_anyaddr; + seaudit_filter_set_anyaddr; + seaudit_filter_get_anyport; + seaudit_filter_set_anyport; + seaudit_filter_get_cap; + seaudit_filter_set_cap; + seaudit_filter_get_daddr; + seaudit_fliter_set_daddr; + seaudit_filter_get_dport; + seaudit_filter_set_dport; + seaudit_filter_get_faddr; + seaudit_fliter_set_faddr; + seaudit_filter_get_fport; + seaudit_filter_set_fport; + seaudit_filter_get_inode; + seaudit_filter_set_inode; + seaudit_filter_get_key; + seaudit_filter_set_key; + seaudit_filter_get_laddr; + seaudit_fliter_set_laddr; + seaudit_filter_get_lport; + seaudit_filter_set_lport; + seaudit_filter_get_permission; + seaudit_filter_set_permission; + seaudit_filter_get_pid; + seaudit_filter_set_pid; + seaudit_filter_get_port; + seaudit_filter_set_port; + seaudit_filter_get_saddr; + seaudit_fliter_set_saddr; + seaudit_filter_get_sport; + seaudit_filter_set_sport; + seaudit_filter_get_strict; + seaudit_filter_set_strict; + seaudit_log_clear; + seaudit_model_hide_message; + seaudit_sort_by_cap; + seaudit_sort_by_daddr; + seaudit_sort_by_dport; + seaudit_sort_by_faddr; + seaudit_sort_by_fport; + seaudit_sort_by_key; + seaudit_sort_by_laddr; + seaudit_sort_by_lport; + seaudit_sort_by_port; + seaudit_sort_by_saddr; + seaudit_sort_by_sport; + seaudit_sort_create_from_sort; +} VERS_4.1; + +VERS_4.3{ + global: + seaudit_avc_message_get_source__mls_lvl; + seaudit_avc_message_get_source__mls_clr; + seaudit_avc_message_get_target_mls_lvl; + seaudit_avc_message_get_target_mls_clr; + seaudit_filter_get_source_mls_lvl; + seaudit_filter_get_source_mls_clr; + seaudit_filter_set_source_mls_lvl; + seaudit_filter_set_source_mls_clr; + seaudit_filter_get_target_mls_lvl; + seaudit_filter_get_target_mls_clr; + seaudit_filter_set_target_mls_lvl; + seaudit_filter_set_target_mls_clr; + seaudit_log_get_mls_lvl; + seaudit_log_get_mls_clr; + seaudit_sort_by_source_mls_lvl; + seaudit_sort_by_source_mls_clr; + seaudit_sort_by_target_mls_lvl; + seaudit_sort_by_target_mls_clr; +} VERS_4.2; diff --git a/libseaudit/src/load_message.c b/libseaudit/src/load_message.c new file mode 100644 index 0000000..7951eb2 --- /dev/null +++ b/libseaudit/src/load_message.c @@ -0,0 +1,91 @@ +/** + * @file + * Implementation of a single policy load log message. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2006-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "seaudit_internal.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +/******************** protected functions below ********************/ + +seaudit_load_message_t *load_message_create(void) +{ + return calloc(1, sizeof(seaudit_load_message_t)); +} + +void load_message_free(seaudit_load_message_t * msg) +{ + if (msg != NULL) { + free(msg->binary); + free(msg); + } +} + +char *load_message_to_string(const seaudit_message_t * msg, const char *date) +{ + seaudit_load_message_t *load = msg->data.load; + const char *host = msg->host; + const char *manager = msg->manager; + char *s = NULL; + if (asprintf(&s, + "%s %s %s: security: %d users, %d roles, %d types, %d bools\n" + "%s %s %s: security: %d classes, %d rules", + date, host, manager, load->users, load->roles, load->types, load->bools, date, host, manager, load->classes, + load->rules) < 0) { + return NULL; + } + return s; +} + +char *load_message_to_string_html(const seaudit_message_t * msg, const char *date) +{ + seaudit_load_message_t *load = msg->data.load; + const char *host = msg->host; + const char *manager = msg->manager; + char *s = NULL; + if (asprintf(&s, + "<font class=\"message_date\">%s</font> " + "<font class=\"host_name\">%s</font> " + "%s: security: %d users, %d roles, %d types, %d bools<br>\n" + "<font class=\"message_date\">%s</font> " + "<font class=\"host_name\">%s</font> " + "%s: security: %d classes, %d rules<br>", + date, host, manager, load->users, load->roles, load->types, load->bools, date, host, manager, load->classes, + load->rules) < 0) { + return NULL; + } + return s; +} + +char *load_message_to_misc_string(const seaudit_load_message_t * load) +{ + char *s = NULL; + if (asprintf(&s, + "users=%d roles=%d types=%d bools=%d classes=%d rules=%d", + load->users, load->roles, load->types, load->bools, load->classes, load->rules) < 0) { + return NULL; + } + return s; +} diff --git a/libseaudit/src/log.c b/libseaudit/src/log.c new file mode 100644 index 0000000..6665cd0 --- /dev/null +++ b/libseaudit/src/log.c @@ -0,0 +1,253 @@ +/** + * @file + * Implementation for the main libseaudit object, seaudit_log_t. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Jeremy Solt jsolt@tresys.com + * + * Copyright (C) 2003-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "seaudit_internal.h" + +#include <apol/util.h> + +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +seaudit_log_t *seaudit_log_create(seaudit_handle_fn_t fn, void *callback_arg) +{ + seaudit_log_t *log = NULL; + int error; + if ((log = calloc(1, sizeof(*log))) == NULL) { + return NULL; + } + log->fn = fn; + log->handle_arg = callback_arg; + if ((log->messages = apol_vector_create(message_free)) == NULL || + (log->malformed_msgs = apol_vector_create(free)) == NULL || + (log->models = apol_vector_create(NULL)) == NULL || + (log->types = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->classes = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->roles = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->users = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->perms = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->mls_lvl = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->mls_clr = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->hosts = apol_bst_create(apol_str_strcmp, free)) == NULL + || (log->bools = apol_bst_create(apol_str_strcmp, free)) == NULL + || (log->managers = apol_bst_create(apol_str_strcmp, free)) == NULL) { + error = errno; + seaudit_log_destroy(&log); + errno = error; + return NULL; + } + return log; +} + +void seaudit_log_destroy(seaudit_log_t ** log) +{ + size_t i; + if (log == NULL || *log == NULL) { + return; + } + for (i = 0; i < apol_vector_get_size((*log)->models); i++) { + seaudit_model_t *m = apol_vector_get_element((*log)->models, i); + model_remove_log(m, *log); + } + apol_vector_destroy(&(*log)->messages); + apol_vector_destroy(&(*log)->malformed_msgs); + apol_vector_destroy(&(*log)->models); + apol_bst_destroy(&(*log)->types); + apol_bst_destroy(&(*log)->classes); + apol_bst_destroy(&(*log)->roles); + apol_bst_destroy(&(*log)->users); + apol_bst_destroy(&(*log)->perms); + apol_bst_destroy(&(*log)->hosts); + apol_bst_destroy(&(*log)->bools); + apol_bst_destroy(&(*log)->managers); + apol_bst_destroy(&(*log)->mls_lvl); + apol_bst_destroy(&(*log)->mls_clr); + free(*log); + *log = NULL; +} + +void seaudit_log_clear(seaudit_log_t * log) +{ + if (log == NULL) { + errno = EINVAL; + return; + } + apol_vector_destroy(&log->messages); + apol_vector_destroy(&log->malformed_msgs); + apol_bst_destroy(&log->types); + apol_bst_destroy(&log->classes); + apol_bst_destroy(&log->roles); + apol_bst_destroy(&log->users); + apol_bst_destroy(&log->perms); + apol_bst_destroy(&log->hosts); + apol_bst_destroy(&log->bools); + apol_bst_destroy(&log->managers); + apol_bst_destroy(&log->mls_lvl); + apol_bst_destroy(&log->mls_clr); + if ((log->messages = apol_vector_create(message_free)) == NULL || + (log->malformed_msgs = apol_vector_create(free)) == NULL || + (log->types = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->classes = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->roles = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->users = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->perms = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->mls_lvl = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->mls_clr = apol_bst_create(apol_str_strcmp, free)) == NULL || + (log->hosts = apol_bst_create(apol_str_strcmp, free)) == NULL + || (log->bools = apol_bst_create(apol_str_strcmp, free)) == NULL + || (log->managers = apol_bst_create(apol_str_strcmp, free)) == NULL) { + /* hopefully will never get here... */ + return; + } + for (size_t i = 0; i < apol_vector_get_size(log->models); i++) { + seaudit_model_t *m = apol_vector_get_element(log->models, i); + model_notify_log_changed(m, log); + } +} + +apol_vector_t *seaudit_log_get_users(const seaudit_log_t * log) +{ + if (log == NULL) { + errno = EINVAL; + return NULL; + } + return apol_bst_get_vector(log->users, 0); +} + +apol_vector_t *seaudit_log_get_roles(const seaudit_log_t * log) +{ + if (log == NULL) { + errno = EINVAL; + return NULL; + } + return apol_bst_get_vector(log->roles, 0); +} + +apol_vector_t *seaudit_log_get_types(const seaudit_log_t * log) +{ + if (log == NULL) { + errno = EINVAL; + return NULL; + } + return apol_bst_get_vector(log->types, 0); +} + +apol_vector_t *seaudit_log_get_mls_lvl(const seaudit_log_t * log) +{ + if (log == NULL) { + errno = EINVAL; + return NULL; + } + return apol_bst_get_vector(log->mls_lvl, 0); +} + +apol_vector_t *seaudit_log_get_mls_clr(const seaudit_log_t * log) +{ + if (log == NULL) { + errno = EINVAL; + return NULL; + } + return apol_bst_get_vector(log->mls_clr, 0); +} + +apol_vector_t *seaudit_log_get_classes(const seaudit_log_t * log) +{ + if (log == NULL) { + errno = EINVAL; + return NULL; + } + return apol_bst_get_vector(log->classes, 0); +} + +/******************** protected functions below ********************/ + +int log_append_model(seaudit_log_t * log, seaudit_model_t * model) +{ + if (apol_vector_append(log->models, model) < 0) { + int error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + return 0; +} + +void log_remove_model(seaudit_log_t * log, seaudit_model_t * model) +{ + size_t i; + if (apol_vector_get_index(log->models, model, NULL, NULL, &i) == 0) { + apol_vector_remove(log->models, i); + } +} + +const apol_vector_t *log_get_messages(const seaudit_log_t * log) +{ + return log->messages; +} + +const apol_vector_t *log_get_malformed_messages(const seaudit_log_t * log) +{ + return log->malformed_msgs; +} + +static void seaudit_handle_default_callback(void *arg __attribute__ ((unused)), + const seaudit_log_t * log __attribute__ ((unused)), + int level, const char *fmt, va_list va_args) +{ + switch (level) { + case SEAUDIT_MSG_INFO: + { + /* by default do not display these messages */ + return; + } + case SEAUDIT_MSG_WARN: + { + fprintf(stderr, "WARNING: "); + break; + } + case SEAUDIT_MSG_ERR: + default: + { + fprintf(stderr, "ERROR: "); + break; + } + } + vfprintf(stderr, fmt, va_args); + fprintf(stderr, "\n"); +} + +void seaudit_handle_msg(const seaudit_log_t * log, int level, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (log == NULL || log->fn == NULL) { + seaudit_handle_default_callback(NULL, NULL, level, fmt, ap); + } else { + log->fn(log->handle_arg, log, level, fmt, ap); + } + va_end(ap); +} diff --git a/libseaudit/src/message.c b/libseaudit/src/message.c new file mode 100644 index 0000000..4e767d0 --- /dev/null +++ b/libseaudit/src/message.c @@ -0,0 +1,204 @@ +/** + * @file + * Implementation of a single seaudit log message. Because C does + * not have RTTI, fake it below. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2006-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "seaudit_internal.h" + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +void *seaudit_message_get_data(const seaudit_message_t * msg, seaudit_message_type_e * type) +{ + if (type != NULL) { + *type = SEAUDIT_MESSAGE_TYPE_INVALID; + } + if (msg == NULL || type == NULL || msg->type == SEAUDIT_MESSAGE_TYPE_INVALID) { + errno = EINVAL; + return NULL; + } + switch ((*type = msg->type)) { + case SEAUDIT_MESSAGE_TYPE_AVC: + return msg->data.avc; + case SEAUDIT_MESSAGE_TYPE_BOOL: + return msg->data.boolm; + case SEAUDIT_MESSAGE_TYPE_LOAD: + return msg->data.load; + default: + errno = EINVAL; + return NULL; + } +} + +const struct tm *seaudit_message_get_time(const seaudit_message_t * msg) +{ + if (!msg) { + errno = EINVAL; + return NULL; + } + return msg->date_stamp; +} + +const char *seaudit_message_get_host(const seaudit_message_t * msg) +{ + if (!msg) { + errno = EINVAL; + return NULL; + } + return msg->host; +} + +#define DATE_STR_SIZE 256 + +char *seaudit_message_to_string(const seaudit_message_t * msg) +{ + char date[DATE_STR_SIZE]; + if (msg == NULL) { + errno = EINVAL; + return NULL; + } + strftime(date, DATE_STR_SIZE, "%b %d %H:%M:%S", msg->date_stamp); + switch (msg->type) { + case SEAUDIT_MESSAGE_TYPE_AVC: + return avc_message_to_string(msg, date); + case SEAUDIT_MESSAGE_TYPE_BOOL: + return bool_message_to_string(msg, date); + case SEAUDIT_MESSAGE_TYPE_LOAD: + return load_message_to_string(msg, date); + default: + errno = EINVAL; + return NULL; + } +} + +char *seaudit_message_to_string_html(const seaudit_message_t * msg) +{ + char date[DATE_STR_SIZE]; + if (msg == NULL) { + errno = EINVAL; + return NULL; + } + strftime(date, DATE_STR_SIZE, "%b %d %H:%M:%S", msg->date_stamp); + switch (msg->type) { + case SEAUDIT_MESSAGE_TYPE_AVC: + return avc_message_to_string_html(msg, date); + case SEAUDIT_MESSAGE_TYPE_BOOL: + return bool_message_to_string_html(msg, date); + case SEAUDIT_MESSAGE_TYPE_LOAD: + return load_message_to_string_html(msg, date); + default: + errno = EINVAL; + return NULL; + } +} + +char *seaudit_message_to_misc_string(const seaudit_message_t * msg) +{ + if (msg == NULL) { + errno = EINVAL; + return NULL; + } + switch (msg->type) { + case SEAUDIT_MESSAGE_TYPE_AVC: + return avc_message_to_misc_string(msg->data.avc); + case SEAUDIT_MESSAGE_TYPE_BOOL: + return bool_message_to_misc_string(msg->data.boolm); + case SEAUDIT_MESSAGE_TYPE_LOAD: + return load_message_to_misc_string(msg->data.load); + default: + errno = EINVAL; + return NULL; + } +} + +/******************** protected functions below ********************/ + +seaudit_message_t *message_create(seaudit_log_t * log, seaudit_message_type_e type) +{ + seaudit_message_t *m; + int error, rt = 0; + if (type == SEAUDIT_MESSAGE_TYPE_INVALID) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return NULL; + } + if ((m = calloc(1, sizeof(*m))) == NULL || apol_vector_append(log->messages, m) < 0) { + error = errno; + message_free(m); + ERR(log, "%s", strerror(error)); + errno = errno; + return NULL; + } + m->type = type; + switch (m->type) { + case SEAUDIT_MESSAGE_TYPE_AVC: + if ((m->data.avc = avc_message_create()) == NULL) { + rt = -1; + } + break; + case SEAUDIT_MESSAGE_TYPE_BOOL: + if ((m->data.boolm = bool_message_create()) == NULL) { + rt = -1; + } + break; + case SEAUDIT_MESSAGE_TYPE_LOAD: + if ((m->data.load = load_message_create()) == NULL) { + rt = -1; + } + break; + default: /* shouldn't get here */ + assert(0); + } + if (rt < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = errno; + return NULL; + } + return m; +} + +void message_free(void *msg) +{ + if (msg != NULL) { + seaudit_message_t *m = (seaudit_message_t *) msg; + free(m->date_stamp); + switch (m->type) { + case SEAUDIT_MESSAGE_TYPE_AVC: + avc_message_free(m->data.avc); + break; + case SEAUDIT_MESSAGE_TYPE_BOOL: + bool_message_free(m->data.boolm); + break; + case SEAUDIT_MESSAGE_TYPE_LOAD: + load_message_free(m->data.load); + break; + default: + break; + } + free(m); + } +} diff --git a/libseaudit/src/model.c b/libseaudit/src/model.c new file mode 100644 index 0000000..1bc4a23 --- /dev/null +++ b/libseaudit/src/model.c @@ -0,0 +1,808 @@ +/** + * @file + * Implementation of seaudit_model_t. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "seaudit_internal.h" + +#include <apol/bst.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <libxml/uri.h> + +#define DEFAULT_MODEL_NAME "Untitled" + +struct seaudit_model +{ + char *name; + /** vector of seaudit_log_t pointers; this model will get + * messages from these logs */ + apol_vector_t *logs; + /** vector of seaudit_message_t pointers; these point into + * messages from the watched logs (only valid if dirty == 0) */ + apol_vector_t *messages; + /** vector of char * pointers; these point into malformed + * messages from the watched logs (only valid if dirty == 0) */ + apol_vector_t *malformed_messages; + /** list of messages to hide */ + apol_bst_t *hidden_messages; + /** vector of seaudit_filter_t */ + apol_vector_t *filters; + /** if more than one filter is being applied, then accept + * messages if any match or if all match */ + seaudit_filter_match_e match; + /** if a filter is being applied, then either show/hide + * messages selected by filter */ + seaudit_filter_visible_e visible; + /** vector of seaudit_sort_t, order from highest priority to lowest */ + apol_vector_t *sorts; + /** number of allow messages in the model (only valid if dirty == 0) */ + size_t num_allows; + /** number of deny messages in the model (only valid if dirty == 0) */ + size_t num_denies; + /** number of boolean changes in the model (only valid if dirty == 0) */ + size_t num_bools; + /** number of policy loads in the model (only valid if dirty == 0) */ + size_t num_loads; + /** non-zero whenever this model needs to be recalculated */ + int dirty; +}; + +/** + * Apply all of the model's filters to the message. + * + * @param model Model containing filters to apply. + * @param m Message to check. + * + * @return Non-zero if the message is accepted by the filters, 0 if not. + */ +static int model_filter_message(seaudit_model_t * model, const seaudit_message_t * m) +{ + size_t i; + int compval, filters_passed = 0; + if (apol_vector_get_size(model->filters) == 0) { + return 1; + } + for (i = 0; i < apol_vector_get_size(model->filters); i++) { + seaudit_filter_t *f = apol_vector_get_element(model->filters, i); + compval = filter_is_accepted(f, m); + if (compval) { + if (model->match == SEAUDIT_FILTER_MATCH_ANY) { + return 1; + } + filters_passed++; + } else { + if (model->match == SEAUDIT_FILTER_MATCH_ALL) { + return 0; + } + } + } + if (model->match == SEAUDIT_FILTER_MATCH_ANY) { + /* if got here, then no filters were met */ + return 0; + } + /* if got here, then all criteria were met */ + if (filters_passed) { + return 1; + } + return 0; +} + +/** + * Callback for sorting the model's messages vector. + * + * @param a First message to compare. + * @param b Second message to compare. + * @param data Pointer to the model being sorted. + * + * @return 0 if the messages are equivalent, < 0 if a is first, > 0 if + * b is first. + */ +static int message_comp(const void *a, const void *b, void *data) +{ + const seaudit_message_t *m1 = a; + const seaudit_message_t *m2 = b; + seaudit_model_t *model = data; + size_t i; + seaudit_sort_t *s; + int compval, s1, s2; + for (i = 0; i < apol_vector_get_size(model->sorts); i++) { + s = apol_vector_get_element(model->sorts, i); + s1 = sort_is_supported(s, m1); + s2 = sort_is_supported(s, m2); + if (!s1 && !s2) { + continue; + } + if (!s2) { + return -1; + } + if (!s1) { + return 1; + } + if ((compval = sort_comp(s, m1, m2)) != 0) { + return compval; + } + } + return 0; +} + +/** + * Sort the model's messages. Create two temporary vectors. The + * first holds messages that are sortable, according to the list of + * sort objects. Sort them in their priority order. The second + * vector holds messages that are not sortable; append those messages + * to the end of the first (now sorted) vector. + * + * @param log Error handling log. + * @param model Model to sort. + * + * @return 0 on successful sort, < 0 on error. + */ +static int model_sort(const seaudit_log_t * log, seaudit_model_t * model) +{ + size_t i, j, num_messages = apol_vector_get_size(model->messages); + apol_vector_t *sup = NULL, *unsup = NULL; + seaudit_message_t *m; + seaudit_sort_t *s; + int supported = 0, retval = -1, error = 0; + if (apol_vector_get_size(model->sorts) == 0) { + retval = 0; + goto cleanup; + } + + if ((sup = apol_vector_create_with_capacity(num_messages, NULL)) == NULL || + (unsup = apol_vector_create_with_capacity(num_messages, NULL)) == NULL) { + error = errno; + ERR(log, "%s", strerror(error)); + goto cleanup; + } + for (i = 0; i < num_messages; i++) { + m = apol_vector_get_element(model->messages, i); + supported = 0; + for (j = 0; j < apol_vector_get_size(model->sorts); j++) { + s = apol_vector_get_element(model->sorts, j); + if ((supported = sort_is_supported(s, m)) != 0) { + break; + } + } + if ((supported && apol_vector_append(sup, m) < 0) || (!supported && apol_vector_append(unsup, m) < 0)) { + error = errno; + ERR(log, "%s", strerror(error)); + goto cleanup; + } + } + apol_vector_sort(sup, message_comp, model); + if (apol_vector_cat(sup, unsup) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + goto cleanup; + } + apol_vector_destroy(&model->messages); + model->messages = sup; + sup = NULL; + retval = 0; + cleanup: + apol_vector_destroy(&sup); + apol_vector_destroy(&unsup); + if (retval != 0) { + errno = error; + } + return retval; +} + +/** + * Iterate through the model's messages and recalculate the number of + * each type of message is stored within. + * + * @param model Model to recalculate. + */ +static void model_recalc_stats(seaudit_model_t * model) +{ + size_t i; + seaudit_message_t *msg; + seaudit_message_type_e type; + void *v; + seaudit_avc_message_t *avc; + model->num_allows = model->num_denies = model->num_bools = model->num_loads = 0; + for (i = 0; i < apol_vector_get_size(model->messages); i++) { + msg = apol_vector_get_element(model->messages, i); + v = seaudit_message_get_data(msg, &type); + if (type == SEAUDIT_MESSAGE_TYPE_AVC) { + avc = (seaudit_avc_message_t *) v; + if (avc->msg == SEAUDIT_AVC_DENIED) { + model->num_denies++; + } else if (avc->msg == SEAUDIT_AVC_GRANTED) { + model->num_allows++; + } + } else if (type == SEAUDIT_MESSAGE_TYPE_BOOL) { + model->num_bools++; + } else if (type == SEAUDIT_MESSAGE_TYPE_LOAD) { + model->num_loads++; + } + } +} + +/** + * Recalculate all of the messages associated with a particular model, + * based upon that model's criteria. If the model is marked as not + * dirty then do nothing and return success. + * + * @param log Log to which report error messages. + * @param model Model whose messages list to refresh. + * + * @return 0 on success, < 0 on error. + */ +static int model_refresh(const seaudit_log_t * log, seaudit_model_t * model) +{ + size_t i, j; + seaudit_log_t *l; + const apol_vector_t *v; + seaudit_message_t *message; + void *result; + int error, filter_match; + + if (!model->dirty) { + return 0; + } + apol_vector_destroy(&model->messages); + apol_vector_destroy(&model->malformed_messages); + if ((model->messages = apol_vector_create(NULL)) == NULL || (model->malformed_messages = apol_vector_create(NULL)) == NULL) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + for (i = 0; i < apol_vector_get_size(model->logs); i++) { + l = apol_vector_get_element(model->logs, i); + v = log_get_messages(l); + for (j = 0; j < apol_vector_get_size(v); j++) { + message = apol_vector_get_element(v, j); + if (apol_bst_get_element(model->hidden_messages, message, NULL, &result) == 0) { + continue; + } + filter_match = model_filter_message(model, message); + if (((filter_match && model->visible == SEAUDIT_FILTER_VISIBLE_SHOW) || + (!filter_match && model->visible == SEAUDIT_FILTER_VISIBLE_HIDE)) && + apol_vector_append(model->messages, message) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + } + v = log_get_malformed_messages(l); + if (apol_vector_cat(model->malformed_messages, v) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + } + if (model_sort(log, model) < 0) { + return -1; + } + model_recalc_stats(model); + model->dirty = 0; + return 0; +} + +/** + * Callback invoked when free()ing a vector of filters. + * + * @param v Filter object to free. + */ +static void filter_free(void *v) +{ + seaudit_filter_t *f = v; + seaudit_filter_destroy(&f); +} + +/** + * Callback invoked when free()ing a vector of sort objects. + * + * @param v Sort object to free. + */ +static void sort_free(void *v) +{ + seaudit_sort_t *sort = v; + seaudit_sort_destroy(&sort); +} + +seaudit_model_t *seaudit_model_create(const char *name, seaudit_log_t * log) +{ + seaudit_model_t *m = NULL; + int error; + if ((m = calloc(1, sizeof(*m))) == NULL) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return NULL; + } + if (name == NULL) { + name = DEFAULT_MODEL_NAME; + } + if ((m->name = strdup(name)) == NULL || + (m->logs = apol_vector_create_with_capacity(1, NULL)) == NULL || + (m->hidden_messages = apol_bst_create(NULL, NULL)) == NULL || + (m->filters = apol_vector_create_with_capacity(1, filter_free)) == NULL || + (m->sorts = apol_vector_create_with_capacity(1, sort_free)) == NULL) { + error = errno; + seaudit_model_destroy(&m); + ERR(log, "%s", strerror(error)); + errno = error; + return NULL; + } + if (log != NULL) { + if (apol_vector_append(m->logs, log) < 0 || log_append_model(log, m)) { + error = errno; + seaudit_model_destroy(&m); + ERR(log, "%s", strerror(error)); + errno = error; + return NULL; + } + } + m->dirty = 1; + return m; +} + +static void *model_filter_dup(const void *elem, void *data) +{ + const seaudit_filter_t *filter = elem; + seaudit_model_t *model = data; + seaudit_filter_t *f; + if ((f = seaudit_filter_create_from_filter(filter)) == NULL) { + return NULL; + } + filter_set_model(f, model); + return f; +} + +static void *model_sort_dup(const void *elem, void *data __attribute__ ((unused))) +{ + const seaudit_sort_t *sort = elem; + seaudit_model_t *model = data; + seaudit_sort_t *s; + if ((s = sort_create_from_sort(sort)) == NULL) { + return NULL; + } + if (seaudit_model_append_sort(model, s) < 0) { + seaudit_sort_destroy(&s); + return NULL; + } + return s; +} + +seaudit_model_t *seaudit_model_create_from_model(const seaudit_model_t * model) +{ + seaudit_model_t *m = NULL; + int error = 0; + size_t i; + const char *name; + + if (model == NULL) { + error = EINVAL; + goto cleanup; + } + if ((m = calloc(1, sizeof(*m))) == NULL) { + error = errno; + goto cleanup; + } + if ((name = model->name) == NULL) { + name = "Untitled"; + } + if ((m->name = strdup(name)) == NULL) { + error = errno; + goto cleanup; + } + m->dirty = 1; + if ((m->logs = apol_vector_create_from_vector(model->logs, NULL, NULL, NULL)) == NULL) { + error = errno; + goto cleanup; + } + if ((m->filters = apol_vector_create_from_vector(model->filters, model_filter_dup, (void *)m, filter_free)) == NULL) { + error = errno; + goto cleanup; + } + if ((m->sorts = apol_vector_create_from_vector(model->sorts, model_sort_dup, (void *)m, sort_free)) == NULL) { + error = errno; + goto cleanup; + } + m->match = model->match; + m->visible = model->visible; + /* link this new model to the old model's logs */ + for (i = 0; i < apol_vector_get_size(m->logs); i++) { + seaudit_log_t *log = apol_vector_get_element(m->logs, i); + if (log_append_model(log, m) < 0) { + error = errno; + goto cleanup; + } + } + cleanup: + if (error != 0) { + seaudit_model_destroy(&m); + errno = error; + return NULL; + } + return m; +} + +seaudit_model_t *seaudit_model_create_from_file(const char *filename) +{ + struct filter_parse_state state; + int retval, error; + seaudit_model_t *m; + memset(&state, 0, sizeof(state)); + if ((state.filters = apol_vector_create(filter_free)) == NULL) { + return NULL; + } + retval = filter_parse_xml(&state, filename); + if (retval < 0) { + error = errno; + free(state.view_name); + apol_vector_destroy(&state.filters); + errno = errno; + return NULL; + } + if ((m = seaudit_model_create(state.view_name, NULL)) == NULL) { + error = errno; + free(state.view_name); + apol_vector_destroy(&state.filters); + errno = error; + return NULL; + } + free(state.view_name); + apol_vector_destroy(&m->filters); + m->filters = state.filters; + state.filters = NULL; + seaudit_model_set_filter_match(m, state.view_match); + seaudit_model_set_filter_visible(m, state.view_visible); + return m; +} + +void seaudit_model_destroy(seaudit_model_t ** model) +{ + size_t i; + if (model == NULL || *model == NULL) { + return; + } + for (i = 0; i < apol_vector_get_size((*model)->logs); i++) { + seaudit_log_t *l = apol_vector_get_element((*model)->logs, i); + log_remove_model(l, *model); + } + free((*model)->name); + apol_vector_destroy(&(*model)->logs); + apol_vector_destroy(&(*model)->filters); + apol_vector_destroy(&(*model)->sorts); + apol_vector_destroy(&(*model)->messages); + apol_vector_destroy(&(*model)->malformed_messages); + apol_bst_destroy(&(*model)->hidden_messages); + free(*model); + *model = NULL; +} + +int seaudit_model_save_to_file(const seaudit_model_t * model, const char *filename) +{ + FILE *file; + const char *XML_VER = "<?xml version=\"1.0\"?>\n"; + seaudit_filter_t *filter; + size_t i; + + if (model == NULL || filename == NULL) { + errno = EINVAL; + return -1; + } + if ((file = fopen(filename, "w")) == NULL) { + return -1; + } + fprintf(file, XML_VER); + fprintf(file, "<view xmlns=\"http://oss.tresys.com/projects/setools/seaudit-%s/\" name=\"%s\" match=\"%s\" show=\"%s\">\n", + FILTER_FILE_FORMAT_VERSION, model->name, + model->match == SEAUDIT_FILTER_MATCH_ALL ? "all" : "any", + model->visible == SEAUDIT_FILTER_VISIBLE_SHOW ? "true" : "false"); + for (i = 0; i < apol_vector_get_size(model->filters); i++) { + filter = apol_vector_get_element(model->filters, i); + filter_append_to_file(filter, file, 1); + } + fprintf(file, "</view>\n"); + fclose(file); + return 0; +} + +const char *seaudit_model_get_name(const seaudit_model_t * model) +{ + if (model == NULL) { + errno = EINVAL; + return NULL; + } + return model->name; +} + +int seaudit_model_set_name(seaudit_model_t * model, const char *name) +{ + char *s; + if (model == NULL) { + errno = EINVAL; + return -1; + } + if (name == NULL) { + name = DEFAULT_MODEL_NAME; + } + if ((s = strdup(name)) == NULL) { + return -1; + } + free(model->name); + model->name = s; + return 0; +} + +int seaudit_model_append_log(seaudit_model_t * model, seaudit_log_t * log) +{ + if (model == NULL || log == NULL) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + if (apol_vector_append(model->logs, log) < 0 || log_append_model(log, model) < 0) { + int error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + model->dirty = 1; + return 0; +} + +int seaudit_model_append_filter(seaudit_model_t * model, seaudit_filter_t * filter) +{ + if (model == NULL || filter == NULL) { + errno = EINVAL; + return -1; + } + if (apol_vector_append(model->filters, filter) < 0) { + return -1; + } + filter_set_model(filter, model); + model->dirty = 1; + return 0; +} + +const apol_vector_t *seaudit_model_get_filters(const seaudit_model_t * model) +{ + if (model == NULL) { + errno = EINVAL; + return NULL; + } + return model->filters; +} + +int seaudit_model_remove_filter(seaudit_model_t * model, seaudit_filter_t * filter) +{ + size_t i; + if (model == NULL || filter == NULL) { + errno = EINVAL; + return -1; + } + if (apol_vector_get_index(model->filters, filter, NULL, NULL, &i) < 0) { + errno = EINVAL; + return -1; + } + seaudit_filter_destroy(&filter); + apol_vector_remove(model->filters, i); + model->dirty = 1; + return 0; +} + +int seaudit_model_set_filter_match(seaudit_model_t * model, seaudit_filter_match_e match) +{ + if (model == NULL) { + errno = EINVAL; + return -1; + } + model->match = match; + model->dirty = 1; + return 0; +} + +seaudit_filter_match_e seaudit_model_get_filter_match(const seaudit_model_t * model) +{ + if (model == NULL) { + errno = EINVAL; + return SEAUDIT_FILTER_MATCH_ALL; + } + return model->match; +} + +int seaudit_model_set_filter_visible(seaudit_model_t * model, seaudit_filter_visible_e visible) +{ + if (model == NULL) { + errno = EINVAL; + return -1; + } + model->visible = visible; + model->dirty = 1; + return 0; +} + +seaudit_filter_visible_e seaudit_model_get_filter_visible(const seaudit_model_t * model) +{ + if (model == NULL) { + errno = EINVAL; + return SEAUDIT_FILTER_VISIBLE_SHOW; + } + return model->visible; +} + +int seaudit_model_append_sort(seaudit_model_t * model, seaudit_sort_t * sort) +{ + if (model == NULL || sort == NULL) { + errno = EINVAL; + return -1; + } + if (apol_vector_append(model->sorts, sort) < 0) { + return -1; + } + model->dirty = 1; + return 0; +} + +int seaudit_model_clear_sorts(seaudit_model_t * model) +{ + if (model == NULL) { + errno = EINVAL; + return -1; + } + apol_vector_destroy(&model->sorts); + if ((model->sorts = apol_vector_create_with_capacity(1, sort_free)) == NULL) { + return -1; + } + model->dirty = 1; + return 0; +} + +int seaudit_model_is_changed(const seaudit_model_t * model) +{ + if (model == NULL) { + errno = EINVAL; + return -1; + } + return model->dirty; +} + +apol_vector_t *seaudit_model_get_messages(const seaudit_log_t * log, seaudit_model_t * model) +{ + if (log == NULL || model == NULL) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return NULL; + } + if (model_refresh(log, model) < 0) { + return NULL; + } + return apol_vector_create_from_vector(model->messages, NULL, NULL, NULL); +} + +apol_vector_t *seaudit_model_get_malformed_messages(const seaudit_log_t * log, seaudit_model_t * model) +{ + if (log == NULL || model == NULL) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return NULL; + } + if (model_refresh(log, model) < 0) { + return NULL; + } + return apol_vector_create_from_vector(model->malformed_messages, NULL, NULL, NULL); +} + +void seaudit_model_hide_message(seaudit_model_t * model, const seaudit_message_t * message) +{ + if (model == NULL) { + errno = EINVAL; + return; + } + if (message == NULL) { + return; + } + if (apol_bst_insert(model->hidden_messages, (seaudit_message_t *) message, NULL) == 0) { + model->dirty = 1; + } +} + +size_t seaudit_model_get_num_allows(const seaudit_log_t * log, seaudit_model_t * model) +{ + if (log == NULL || model == NULL) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return 0; + } + if (model_refresh(log, model) < 0) { + return 0; + } + return model->num_allows; +} + +size_t seaudit_model_get_num_denies(const seaudit_log_t * log, seaudit_model_t * model) +{ + if (log == NULL || model == NULL) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return 0; + } + if (model_refresh(log, model) < 0) { + return 0; + } + return model->num_denies; +} + +size_t seaudit_model_get_num_bools(const seaudit_log_t * log, seaudit_model_t * model) +{ + if (log == NULL || model == NULL) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return 0; + } + if (model_refresh(log, model) < 0) { + return 0; + } + return model->num_bools; +} + +size_t seaudit_model_get_num_loads(const seaudit_log_t * log, seaudit_model_t * model) +{ + if (log == NULL || model == NULL) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return 0; + } + if (model_refresh(log, model) < 0) { + return 0; + } + return model->num_loads; +} + +/******************** protected functions below ********************/ + +void model_remove_log(seaudit_model_t * model, seaudit_log_t * log) +{ + size_t i; + if (apol_vector_get_index(model->logs, log, NULL, NULL, &i) == 0) { + apol_vector_remove(model->logs, i); + model->dirty = 1; + } +} + +void model_notify_log_changed(seaudit_model_t * model, seaudit_log_t * log) +{ + size_t i; + if (apol_vector_get_index(model->logs, log, NULL, NULL, &i) == 0) { + model->dirty = 1; + } +} + +void model_notify_filter_changed(seaudit_model_t * model, seaudit_filter_t * filter) +{ + size_t i; + if (apol_vector_get_index(model->filters, filter, NULL, NULL, &i) == 0) { + model->dirty = 1; + } +} diff --git a/libseaudit/src/parse.c b/libseaudit/src/parse.c new file mode 100644 index 0000000..f1d44ba --- /dev/null +++ b/libseaudit/src/parse.c @@ -0,0 +1,1513 @@ +/** + * @file + * Implementation for the audit log parser. + * + * @author Meggan Whalen mwhalen@tresys.com + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Jeremy Solt jsolt@tresys.com + * + * Copyright (C) 2003-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "seaudit_internal.h" +#include <seaudit/parse.h> +#include <apol/util.h> + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include <selinux/context.h> + +#define ALT_SYSCALL_STRING "msg=audit(" /* should contain SYSCALL_STRING */ +#define AUDITD_MSG "type=" +#define AVCMSG " avc: " +#define BOOLMSG "committed booleans" +#define LOADMSG " security: " +#define NUM_TIME_COMPONENTS 3 +#define OLD_LOAD_POLICY_STRING "loadingpolicyconfigurationfrom" +#define PARSE_NUM_SYSCALL_FIELDS 3 +#define SYSCALL_STRING "audit(" + +/** + * Given a line from an audit log, create and return a vector of + * tokens from that line. The caller is responsible for calling + * apol_vector_destroy() upon that vector. Note that this function + * will modify the passed in line. + */ +static int get_tokens(seaudit_log_t * log, char *line, apol_vector_t ** tokens) +{ + char *line_ptr, *next; + *tokens = NULL; + int error = 0; + + if ((*tokens = apol_vector_create(NULL)) == NULL) { + error = errno; + ERR(log, "%s", strerror(error)); + goto cleanup; + } + line_ptr = line; + /* Tokenize line while ignoring any adjacent whitespace chars. */ + while ((next = strsep(&line_ptr, " ")) != NULL) { + if (strcmp(next, "") && !apol_str_is_only_white_space(next)) { + if (apol_vector_append(*tokens, next) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + goto cleanup; + } + } + } + cleanup: + if (error != 0) { + apol_vector_destroy(tokens); + errno = error; + return -1; + } + return 0; +} + +/** + * Given a line, determine what type of audit message it is. + */ +static seaudit_message_type_e is_selinux(const char *line) +{ + if (strstr(line, BOOLMSG) && (strstr(line, "kernel") || strstr(line, AUDITD_MSG))) + return SEAUDIT_MESSAGE_TYPE_BOOL; + else if (strstr(line, LOADMSG) && (strstr(line, "kernel") || strstr(line, AUDITD_MSG))) + return SEAUDIT_MESSAGE_TYPE_LOAD; + else if (strstr(line, AVCMSG) && (strstr(line, "kernel") || strstr(line, AUDITD_MSG))) + return SEAUDIT_MESSAGE_TYPE_AVC; + else + return SEAUDIT_MESSAGE_TYPE_INVALID; +} + +extern int daylight; + + /** + * Fill in the date_stamp field of a message. If the stamp was not + * already allocated space then do it here. + * + * @return 0 on success, > 0 on warning, < 0 on error. + */ +static int insert_time(const seaudit_log_t * log, const apol_vector_t * tokens, size_t * position, seaudit_message_t * msg) +{ + char *t = NULL; + size_t i, length = 0; + int error; + + if (*position + NUM_TIME_COMPONENTS >= apol_vector_get_size(tokens)) { + WARN(log, "%s", "Not enough tokens for time."); + return 1; + } + for (i = 0; i < NUM_TIME_COMPONENTS; i++) { + length += strlen((char *)apol_vector_get_element(tokens, i + *position)); + } + + /* Increase size for terminating string char and whitespace within. */ + length += NUM_TIME_COMPONENTS; + if ((t = (char *)calloc(1, length)) == NULL) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + + for (i = 0; i < NUM_TIME_COMPONENTS; i++) { + if (i > 0) { + strcat(t, " "); + } + strcat(t, (char *)apol_vector_get_element(tokens, *position)); + (*position)++; + } + + if (!msg->date_stamp) { + if ((msg->date_stamp = (struct tm *)calloc(1, sizeof(struct tm))) == NULL) { + error = errno; + ERR(log, "%s", strerror(error)); + free(t); + errno = error; + return -1; + } + } + + if (strptime(t, "%b %d %T", msg->date_stamp) != NULL) { + /* set year to 1900 since we know no valid logs were + * generated. this will tell us that the msg does not + * really have a year */ + msg->date_stamp->tm_isdst = 0; + msg->date_stamp->tm_year = 0; + } + free(t); + return 0; +} + +/** + * Fill in the host field of a message. + * + * @return 0 on success, > 0 on warning, < 0 on error. + */ +static int insert_hostname(const seaudit_log_t * log, const apol_vector_t * tokens, size_t * position, seaudit_message_t * msg) +{ + char *s, *host; + if (*position >= apol_vector_get_size(tokens)) { + WARN(log, "%s", "Not enough tokens for hostname."); + return 1; + } + s = apol_vector_get_element(tokens, *position); + /* Make sure this is not the kernel string identifier, which + * may indicate that the hostname is empty. */ + if (strstr(s, "kernel")) { + msg->host = NULL; + return 1; + } + (*position)++; + if ((host = strdup(s)) == NULL || apol_bst_insert_and_get(log->hosts, (void **)&host, NULL) < 0) { + int error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + msg->host = host; + return 0; +} + +static int insert_standard_msg_header(const seaudit_log_t * log, const apol_vector_t * tokens, size_t * position, + seaudit_message_t * msg) +{ + int ret = 0; + if ((ret = insert_time(log, tokens, position, msg)) != 0) { + return ret; + } + if ((ret = insert_hostname(log, tokens, position, msg)) != 0) { + return ret; + } + return ret; +} + +/** + * Parse the object manager that generated this audit message. + */ +static int insert_manager(const seaudit_log_t * log, seaudit_message_t * msg, const char *manager) +{ + char *m; + if ((m = strdup(manager)) == NULL || apol_bst_insert_and_get(log->managers, (void **)&m, NULL) < 0) { + int error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + msg->manager = m; + return 0; +} + +/** + * Parse a context (user:role:type). For each of the pieces, add them + * to the log's BSTs. Set reference pointers to those strings. + */ +static int parse_context(seaudit_log_t * log, char *token, char **user, char **role, char **type, char **mls_lvl, char **mls_clr) +{ + char *s, *range; + int error, ret = 0; + context_t con = context_new(token); + *user = *role = *type = *mls_lvl = *mls_clr = NULL; + + if (con == NULL) { + WARN(log, "%s", "Error parsing context."); + ret = 1; + goto out; + } + + if ((s = strdup(context_user_get(con))) == NULL || apol_bst_insert_and_get(log->users, (void **)&s, NULL) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + ret = -1; + goto out; + } + *user = s; + + if ((s = strdup(context_role_get(con))) == NULL || apol_bst_insert_and_get(log->roles, (void **)&s, NULL) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + ret = -1; + goto out; + } + *role = s; + + if ((s = strdup(context_type_get(con))) == NULL || apol_bst_insert_and_get(log->types, (void **)&s, NULL) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + ret = -1; + goto out; + } + *type = s; + + if (range = context_range_get(con)) { + char *lvl, *clr; + lvl = strsep(&range, "-"); + clr = strsep(&range, "-"); + if (clr == NULL) + /* level and clearance are the same */ + clr = lvl; + + if ((s = strdup(lvl)) == NULL || apol_bst_insert_and_get(log->mls_lvl, (void **)&s, NULL) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + ret = -1; + goto out; + } + *mls_lvl = s; + + if ((s = strdup(clr)) == NULL || apol_bst_insert_and_get(log->mls_clr, (void **)&s, NULL) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + ret = -1; + goto out; + } + *mls_clr = s; + } + +out: + context_free(con); + return ret; +} + +/******************** AVC message parsing ********************/ + +/** + * Given a token, determine if it is the new AVC header or not. + */ +static int avc_msg_is_token_new_audit_header(const char *token) +{ + return (strstr(token, SYSCALL_STRING) ? 1 : 0); +} + +/** + * If the given token begins with prefix, then set reference pointer + * result to everything following prefix and return 1. Otherwise + * return 0. + */ +static int avc_msg_is_prefix(char *token, char *prefix, char **result) +{ + size_t i = 0, length; + + length = strlen(prefix); + if (strlen(token) < length) + return 0; + + for (i = 0; i < length; i++) { + if (token[i] != prefix[i]) { + return 0; + } + } + + *result = token + length; + return 1; +} + +/** + * Beginning with element *position, fill in the given avc message + * with all permissions found. Afterwards update *position to point + * to the next unprocessed token. Permissions should start and end + * with braces and if not, then this is invalid. + * + * @return 0 on success, > 0 on warning, < 0 on error. + */ +static int avc_msg_insert_perms(const seaudit_log_t * log, apol_vector_t * tokens, size_t * position, seaudit_avc_message_t * avc) +{ + char *s, *perm; + int error; + if ((s = apol_vector_get_element(tokens, *position)) == NULL || strcmp(s, "{") != 0) { + WARN(log, "%s", "Expected an opening brace while parsing permissions."); + return 1; + } + (*position)++; + + while (*position < apol_vector_get_size(tokens)) { + s = apol_vector_get_element(tokens, *position); + assert(s != NULL); + (*position)++; + if (strcmp(s, "}") == 0) { + return 0; + } + + if ((perm = strdup(s)) == NULL || + apol_bst_insert_and_get(log->perms, (void **)&perm, NULL) < 0 || apol_vector_append(avc->perms, perm) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + } + + /* if got here, then message is too short */ + WARN(log, "%s", "Expected a closing brace while parsing permissions."); + return 1; +} + +static int avc_msg_insert_syscall_info(const seaudit_log_t * log, char *token, seaudit_message_t * msg, seaudit_avc_message_t * avc) +{ + size_t length, header_len = 0, i = 0; + char *fields[PARSE_NUM_SYSCALL_FIELDS]; + char *time_str = NULL; + time_t temp; + + length = strlen(token); + + /* Chop off the ':' at the end of the syscall info token */ + if (token[length - 1] == ':') { + token[length - 1] = '\0'; + length--; + } + /* Chop off the ')' at the end of the syscall info token */ + if (token[length - 1] == ')') { + token[length - 1] = '\0'; + length--; + } + header_len = strlen(SYSCALL_STRING); + + /* Check to see if variations on syscall header exist */ + if (strstr(token, ALT_SYSCALL_STRING)) { + header_len = strlen(ALT_SYSCALL_STRING); + } + + time_str = token + header_len; + /* Parse seconds.nanoseconds:serial */ + while (i < PARSE_NUM_SYSCALL_FIELDS && (fields[i] = strsep(&time_str, ".:")) != NULL) { + i++; + } + + if (i != PARSE_NUM_SYSCALL_FIELDS) { + WARN(log, "%s", "Not enough fields for syscall info."); + return 1; + } + + temp = (time_t) atol(fields[0]); + avc->tm_stmp_sec = temp; + avc->tm_stmp_nano = atoi(fields[1]); + avc->serial = atoi(fields[2]); + + if (msg->date_stamp == NULL) { + if ((msg->date_stamp = (struct tm *)malloc(sizeof(struct tm))) == NULL) { + int error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + } + localtime_r(&temp, msg->date_stamp); + return 0; +} + +static int avc_msg_insert_access_type(const seaudit_log_t * log, const char *token, seaudit_avc_message_t * avc) +{ + if (strcmp(token, "granted") == 0) { + avc->msg = SEAUDIT_AVC_GRANTED; + return 0; + } else if (strcmp(token, "denied") == 0) { + avc->msg = SEAUDIT_AVC_DENIED; + return 0; + } + WARN(log, "%s", "No AVC message type found, assuming it was a denial."); + avc->msg = SEAUDIT_AVC_DENIED; + return 1; +} + +static int avc_msg_insert_scon(seaudit_log_t * log, seaudit_avc_message_t * avc, char *tmp) +{ + char *user, *role, *type, *mls_lvl, *mls_clr; + int retval; + if (tmp == NULL) { + WARN(log, "%s", "Invalid source context."); + return 1; + } + retval = parse_context(log, tmp, &user, &role, &type, &mls_lvl, &mls_clr); + if (retval != 0) { + return retval; + } + avc->suser = user; + avc->srole = role; + avc->stype = type; + avc->smls_lvl = mls_lvl; + avc->smls_clr = mls_clr; + return 0; +} + +static int avc_msg_insert_tcon(seaudit_log_t * log, seaudit_avc_message_t * avc, char *tmp) +{ + char *user, *role, *type, *mls_lvl, *mls_clr; + int retval; + if (tmp == NULL) { + WARN(log, "%s", "Invalid target context."); + return 1; + } + retval = parse_context(log, tmp, &user, &role, &type, &mls_lvl, &mls_clr); + if (retval != 0) { + return retval; + } + avc->tuser = user; + avc->trole = role; + avc->ttype = type; + avc->tmls_lvl = mls_lvl; + avc->tmls_clr = mls_clr; + return 0; +} + +static int avc_msg_insert_tclass(seaudit_log_t * log, seaudit_avc_message_t * avc, const char *tmp) +{ + char *tclass; + if ((tclass = strdup(tmp)) == NULL || apol_bst_insert_and_get(log->classes, (void **)&tclass, NULL) < 0) { + int error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + avc->tclass = tclass; + return 0; +} + +static int avc_msg_insert_string(const seaudit_log_t * log, char *src, char **dest) +{ + if ((*dest = strdup(src)) == NULL) { + int error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + return 0; +} + +/** + * Removes quotes from a string, this is currently to remove quotes + * from the command argument. + */ +static int avc_msg_remove_quotes_insert_string(const seaudit_log_t * log, char *src, char **dest) +{ + size_t i, j, l; + + l = strlen(src); + /* see if there are any quotes to begin with if there aren't + * just run insert string */ + if (src[0] == '\"' && l > 0 && src[l - 1] == '\"') { + if ((*dest = calloc(1, l + 1)) == NULL) { + int error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + for (i = 0, j = 0; i < l; i++) { + if (src[i] != '\"') { + (*dest)[j] = src[i]; + j++; + } + } + return 0; + } else + return avc_msg_insert_string(log, src, dest); +} + +/** + * If there is exactly one equal sign in orig_token then return 1. + * Otherwise return 0. + */ +static int avc_msg_is_valid_additional_field(const char *orig_token) +{ + char *first_eq = strchr(orig_token, '='); + + if (first_eq == NULL) { + return 0; + } + if (strchr(first_eq + 1, '=') != NULL) { + return 0; + } + return 1; +} + +static int avc_msg_reformat_path(const seaudit_log_t * log, seaudit_avc_message_t * avc, const char *token) +{ + int error; + if (avc->path == NULL) { + if ((avc->path = strdup(token)) == NULL) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + } else { + size_t len = strlen(avc->path) + strlen(token) + 2; + char *s = realloc(avc->path, len); + if (s == NULL) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + avc->path = s; + strcat(avc->path, " "); + strcat(avc->path, token); + } + return 0; +} + +/** + * Parse the remaining tokens of an AVC message, filling as much + * information as possible. + * + * @return 0 on success, > 0 if warnings, < 0 on error + */ +static int avc_msg_insert_additional_field_data(seaudit_log_t * log, apol_vector_t * tokens, seaudit_avc_message_t * avc, + size_t * position) +{ + char *token, *v; + int retval, has_warnings = 0; + + avc->avc_type = SEAUDIT_AVC_DATA_FS; + for (; (*position) < apol_vector_get_size(tokens); (*position)++) { + token = apol_vector_get_element(tokens, (*position)); + v = NULL; + if (strcmp(token, "") == 0) { + break; + } + + if (!avc->is_pid && avc_msg_is_prefix(token, "pid=", &v)) { + avc->pid = atoi(v); + avc->is_pid = 1; + continue; + } + + if (!avc->exe && avc_msg_is_prefix(token, "exe=", &v)) { + if (avc_msg_insert_string(log, v, &avc->exe) < 0) { + return -1; + } + continue; + } + + if (!avc->comm && avc_msg_is_prefix(token, "comm=", &v)) { + if (avc_msg_remove_quotes_insert_string(log, v, &avc->comm) < 0) { + return -1; + } + continue; + } + + /* Gather all tokens located after the path=XXXX token + * until we encounter a valid additional field. This + * is because a path name file name may be seperated + * by whitespace. Look ahead at the next token, but we + * make sure not to access memory beyond the total + * number of tokens. */ + if (!avc->path && avc_msg_is_prefix(token, "path=", &v)) { + if (avc_msg_reformat_path(log, avc, v) < 0) { + return -1; + } + while (*position + 1 < apol_vector_get_size(tokens)) { + token = apol_vector_get_element(tokens, *position + 1); + if (avc_msg_is_valid_additional_field(token)) { + break; + } + (*position)++; + if (avc_msg_reformat_path(log, avc, token) < 0) { + return -1; + } + } + continue; + } + + if (!avc->name && avc_msg_is_prefix(token, "name=", &v)) { + if (avc_msg_remove_quotes_insert_string(log, v, &avc->name) < 0) { + return -1; + } + continue; + } + + if (!avc->dev && avc_msg_is_prefix(token, "dev=", &v)) { + if (avc_msg_insert_string(log, v, &avc->dev) < 0) { + return -1; + } + continue; + } + + if (!avc->saddr && avc_msg_is_prefix(token, "saddr=", &v)) { + if (avc_msg_insert_string(log, v, &avc->saddr) < 0) { + return -1; + } + continue; + } + + if (!avc->source && (avc_msg_is_prefix(token, "source=", &v) || avc_msg_is_prefix(token, "src=", &v))) { + avc->source = atoi(v); + continue; + } + + if (!avc->daddr && avc_msg_is_prefix(token, "daddr=", &v)) { + if (avc_msg_insert_string(log, v, &avc->daddr)) { + return -1; + } + continue; + } + + if (!avc->dest && avc_msg_is_prefix(token, "dest=", &v)) { + avc->dest = atoi(v); + continue; + } + + if (!avc->netif && avc_msg_is_prefix(token, "netif=", &v)) { + if (avc_msg_insert_string(log, v, &avc->netif)) { + return -1; + } + avc->avc_type = SEAUDIT_AVC_DATA_NET; + continue; + } + + if (!avc->laddr && avc_msg_is_prefix(token, "laddr=", &v)) { + if (avc_msg_insert_string(log, v, &avc->laddr)) { + return -1; + } + continue; + } + + if (!avc->lport && avc_msg_is_prefix(token, "lport=", &v)) { + avc->lport = atoi(v); + avc->avc_type = SEAUDIT_AVC_DATA_NET; + continue; + } + + if (!avc->faddr && avc_msg_is_prefix(token, "faddr=", &v)) { + if (avc_msg_insert_string(log, v, &avc->faddr)) { + return -1; + } + continue; + } + + if (!avc->fport && avc_msg_is_prefix(token, "fport=", &v)) { + avc->fport = atoi(v); + continue; + } + + if (!avc->port && avc_msg_is_prefix(token, "port=", &v)) { + avc->port = atoi(v); + avc->avc_type = SEAUDIT_AVC_DATA_NET; + continue; + } + + if (!avc->is_src_sid && avc_msg_is_prefix(token, "ssid=", &v)) { + avc->src_sid = (unsigned int)strtoul(v, NULL, 10); + avc->is_src_sid = 1; + continue; + } + + if (!avc->is_tgt_sid && avc_msg_is_prefix(token, "tsid=", &v)) { + avc->tgt_sid = (unsigned int)strtoul(v, NULL, 10); + avc->is_tgt_sid = 1; + continue; + } + + if (!avc->is_capability && avc_msg_is_prefix(token, "capability=", &v)) { + avc->capability = atoi(v); + avc->is_capability = 1; + avc->avc_type = SEAUDIT_AVC_DATA_CAP; + continue; + } + + if (!avc->is_key && avc_msg_is_prefix(token, "key=", &v)) { + avc->key = atoi(v); + avc->is_key = 1; + avc->avc_type = SEAUDIT_AVC_DATA_IPC; + continue; + } + + if (!avc->is_inode && avc_msg_is_prefix(token, "ino=", &v)) { + avc->inode = strtoul(v, NULL, 10); + avc->is_inode = 1; + continue; + } + + if (!avc->ipaddr && avc_msg_is_prefix(token, "ipaddr=", &v)) { + if (avc_msg_insert_string(log, v, &avc->ipaddr)) { + return -1; + } + continue; + } + + if (!avc->suser && avc_msg_is_prefix(token, "scontext=", &v)) { + retval = avc_msg_insert_scon(log, avc, v); + if (retval < 0) { + return retval; + } else if (retval > 0) { + has_warnings = 1; + } + continue; + } + + if (!avc->tuser && avc_msg_is_prefix(token, "tcontext=", &v)) { + retval = avc_msg_insert_tcon(log, avc, v); + if (retval < 0) { + return retval; + } else if (retval > 0) { + has_warnings = 1; + } + continue; + } + + if (!avc->tclass && avc_msg_is_prefix(token, "tclass=", &v)) { + if (avc_msg_insert_tclass(log, avc, v) < 0) { + return -1; + } + continue; + } + /* found a field that this parser did not understand, + * so flag the entire message as a warning */ + has_warnings = 1; + } + + /* can't have both a sid and a context */ + if ((avc->is_src_sid && avc->suser) || (avc->is_tgt_sid && avc->tuser)) { + has_warnings = 1; + } + + if (!avc->tclass) { + has_warnings = 1; + } + + if (has_warnings) { + avc->avc_type = SEAUDIT_AVC_DATA_MALFORMED; + } + + return has_warnings; +} + +static int avc_parse(seaudit_log_t * log, apol_vector_t * tokens) +{ + seaudit_message_t *msg; + seaudit_avc_message_t *avc; + seaudit_message_type_e type; + int ret, has_warnings = 0; + size_t position = 0, num_tokens = apol_vector_get_size(tokens); + char *token, *t; + + if ((msg = message_create(log, SEAUDIT_MESSAGE_TYPE_AVC)) == NULL) { + return -1; + } + avc = seaudit_message_get_data(msg, &type); + + token = apol_vector_get_element(tokens, position); + + /* Check for new auditd log format */ + if (strstr(token, AUDITD_MSG)) { + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for audit header."); + return 1; + } + log->logtype = SEAUDIT_LOG_TYPE_AUDITD; + token = apol_vector_get_element(tokens, position); + } + + /* Insert the audit header if it exists */ + if (avc_msg_is_token_new_audit_header(token)) { + ret = avc_msg_insert_syscall_info(log, token, msg, avc); + if (ret < 0) { + return ret; + } else if (ret > 0) { + has_warnings = 1; + } else { + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for new audit header."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + } else { + ret = insert_standard_msg_header(log, tokens, &position, msg); + if (ret < 0) { + return ret; + } else if (ret > 0) { + has_warnings = 1; + } + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for new audit header."); + return 1; + } + token = apol_vector_get_element(tokens, position); + + /* for now, only let avc messages set their object + * manager */ + if ((t = strrchr(token, ':')) == NULL) { + WARN(log, "%s", "Expected to find an object manager here."); + has_warnings = 1; + /* Hold the position */ + } else { + *t = '\0'; + if ((ret = insert_manager(log, msg, token)) < 0) { + return ret; + } + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for new audit header."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + + /* new style audit messages can show up in syslog + * files starting with FC5. This means that both the + * old kernel: header and the new audit header might + * be present. So, here we check again for the audit + * message. + */ + if (avc_msg_is_token_new_audit_header(token)) { + ret = avc_msg_insert_syscall_info(log, token, msg, avc); + if (ret < 0) { + return ret; + } else if (ret > 0) { + has_warnings = 1; + } else { + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for new audit header."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + } + } + + /* Make sure the following token is the string "avc:" */ + if (strcmp(token, "avc:") != 0) { + /* Hold the position */ + has_warnings = 1; + WARN(log, "%s", "Expected an avc: token here."); + } else { + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for new audit header."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + + /* Insert denied or granted */ + if (avc_msg_insert_access_type(log, token, avc)) { + has_warnings = 1; + } else { + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for new audit header."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + + /* Insert perm(s) */ + ret = avc_msg_insert_perms(log, tokens, &position, avc); + if (ret < 0) { + return ret; + } else if (ret > 0) { + has_warnings = 1; + } + if (position >= num_tokens) { + WARN(log, "%s", "Message appears to be truncated."); + return 1; + } + token = apol_vector_get_element(tokens, position); + + if (strcmp(token, "for") != 0) { + /* Hold the position */ + has_warnings = 1; + WARN(log, "%s", "Expected a 'for' token here."); + } else { + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for new audit header."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + + /* At this point we have a valid message, for we have gathered + * all of the standard fields so insert anything else. If + * nothing else is left, the message is still considered + * valid. */ + ret = avc_msg_insert_additional_field_data(log, tokens, avc, &position); + if (ret < 0) { + return ret; + } else if (ret > 0) { + has_warnings = 1; + } + + return has_warnings; +} + +/******************** boolean parsing ********************/ + +static int boolean_msg_insert_bool(seaudit_log_t * log, seaudit_bool_message_t * boolm, char *token) +{ + size_t len = strlen(token); + int value; + + /* Strip off ending comma */ + if (token[len - 1] == ',') { + token[len - 1] = '\0'; + len--; + } + + if (token[len - 2] != ':') { + WARN(log, "%s", "Boolean change was not in correct format."); + return 1; + } + + if (token[len - 1] == '0') + value = 0; + else if (token[len - 1] == '1') + value = 1; + else { + WARN(log, "%s", "Invalid new boolean value."); + return 1; + } + + token[len - 2] = '\0'; + + return bool_change_append(log, boolm, token, value); +} + +static int bool_parse(seaudit_log_t * log, apol_vector_t * tokens) +{ + seaudit_message_t *msg; + seaudit_bool_message_t *boolm; + seaudit_message_type_e type; + int ret, has_warnings = 0, next_line = log->next_line; + size_t position = 0, num_tokens = apol_vector_get_size(tokens); + char *token; + + if (log->next_line) { + /* still processing a boolean change message, so don't + * create a new one */ + size_t num_messages = apol_vector_get_size(log->messages); + assert(num_messages > 0); + msg = apol_vector_get_element(log->messages, num_messages - 1); + log->next_line = 0; + } else { + if ((msg = message_create(log, SEAUDIT_MESSAGE_TYPE_BOOL)) == NULL) { + return -1; + } + } + boolm = seaudit_message_get_data(msg, &type); + + ret = insert_standard_msg_header(log, tokens, &position, msg); + if (ret < 0) { + return ret; + } else if (ret > 0) { + has_warnings = 1; + } + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for boolean change."); + return 1; + } + token = apol_vector_get_element(tokens, position); + + /* Make sure the following token is the string "kernel:" */ + if (!strstr(token, "kernel:")) { + WARN(log, "%s", "Expected to see kernel here."); + has_warnings = 1; + /* Hold the position */ + } else { + if ((ret = insert_manager(log, msg, "kernel")) < 0) { + return ret; + } + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for boolean change."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + + if (!next_line) { + if (!strstr(token, "security:")) { + WARN(log, "%s", "Expected to see security here."); + has_warnings = 1; + /* Hold the position */ + } else { + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for boolean change."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + + if (!strstr(token, "committed")) { + WARN(log, "%s", "Expected to see committed here."); + has_warnings = 1; + /* Hold the position */ + } else { + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for boolean change."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + + if (!strstr(token, "booleans")) { + WARN(log, "%s", "Expected to see booleans here."); + has_warnings = 1; + /* Hold the position */ + } else { + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for boolean change."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + + if (!strstr(token, "{")) { + WARN(log, "%s", "Expected to see '{' here."); + has_warnings = 1; + /* Hold the position */ + } else { + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for boolean change."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + } + + /* keep parsing until a closing brace is found. if end of + * tokens is reached, then keep parsing the next line */ + while (position < num_tokens) { + token = apol_vector_get_element(tokens, position); + position++; + + if (!strcmp(token, "}")) { + if (position < num_tokens) { + WARN(log, "%s", "Excess tokens after closing brace"); + has_warnings = 1; + } + return has_warnings; + } + + ret = boolean_msg_insert_bool(log, boolm, token); + if (ret < 0) { + return ret; + } else if (ret > 0) { + has_warnings = 1; + } + } + + /* did not find a closing brace yet */ + log->next_line = 1; + return has_warnings; +} + +/******************** policy load parsing ********************/ + +/** + * Determine if a series of tokens represents the older style of a + * policy load. + * + * @return 0 if not older style, 1 if it is the older style, < 0 on + * error. If it is the older style, then increment reference pointer + * position to point to the next unprocessed token. + */ +static int load_policy_msg_is_old_load_policy_string(const seaudit_log_t * log, const apol_vector_t * tokens, size_t * position) +{ + size_t i, length = 0; + int rt; + char *tmp = NULL; + if (*position + 4 >= apol_vector_get_size(tokens)) { + return 0; + } + + for (i = 0; i < 4; i++) { + length += strlen((char *)apol_vector_get_element(tokens, i + *position)); + } + + if ((tmp = (char *)calloc(length + 1, sizeof(char))) == NULL) { + int error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + + for (i = 0; i < 4; i++) { + strcat(tmp, (char *)apol_vector_get_element(tokens, i + *position)); + } + + rt = strcmp(tmp, OLD_LOAD_POLICY_STRING); + free(tmp); + + if (rt == 0) { + *position += 4; + return 1; + } else + return 0; +} + +static void load_policy_msg_get_policy_components(seaudit_load_message_t * load, const apol_vector_t * tokens, size_t * position) +{ + char *arg = apol_vector_get_element(tokens, *position); + char *endptr; + unsigned int val = (unsigned int)strtoul(arg, &endptr, 10); + if (*endptr != '\0') { + /* found a key-value pair where the key is not a + * number, so skip this */ + (*position)++; + return; + } + char *id = apol_vector_get_element(tokens, *position + 1); + assert(id != NULL && arg != NULL); + if (load->classes == 0 && strstr(id, "classes")) { + load->classes = val; + } else if (load->rules == 0 && strstr(id, "rules")) { + load->rules = val; + } else if (load->users == 0 && strstr(id, "users")) { + load->users = val; + } else if (load->roles == 0 && strstr(id, "roles")) { + load->roles = val; + } else if (load->types == 0 && strstr(id, "types")) { + load->types = val; + } else if (load->bools == 0 && strstr(id, "bools")) { + load->bools = val; + } + *position += 2; +} + +static int load_parse(seaudit_log_t * log, const apol_vector_t * tokens) +{ + seaudit_message_t *msg; + seaudit_load_message_t *load; + seaudit_message_type_e type; + int ret, error, has_warnings = 0; + size_t position = 0, num_tokens = apol_vector_get_size(tokens); + char *token; + + if (log->next_line) { + /* still processing a load message, so don't create a + * new one */ + size_t num_messages = apol_vector_get_size(log->messages); + assert(num_messages > 0); + msg = apol_vector_get_element(log->messages, num_messages - 1); + log->next_line = 0; + } else { + if ((msg = message_create(log, SEAUDIT_MESSAGE_TYPE_LOAD)) == NULL) { + return -1; + } + } + load = seaudit_message_get_data(msg, &type); + + ret = insert_standard_msg_header(log, tokens, &position, msg); + if (ret < 0) { + return ret; + } else if (ret > 0) { + has_warnings = 1; + } + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for policy load."); + return 1; + } + token = apol_vector_get_element(tokens, position); + + if (strcmp(token, "invalidating") == 0) { + WARN(log, "%s", "Got an unexpected invalidating message."); + return 1; + } + + if (position + 1 >= num_tokens) { + WARN(log, "%s", "Not enough tokens for policy load."); + return 1; + } + if (strcmp((char *)apol_vector_get_element(tokens, position + 1), "bools") == 0) { + WARN(log, "%s", "Got an unexpected bools message."); + return 1; + } + + /* Check the following token for the string "kernel:" */ + if (!strstr(token, "kernel:")) { + WARN(log, "%s", "Expected to see kernel here."); + has_warnings = 1; + /* Hold the position */ + } else { + if ((ret = insert_manager(log, msg, "kernel")) < 0) { + return ret; + } + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for policy load."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + + if (strcmp(token, "security:")) { + WARN(log, "%s", "Expected to see security here."); + has_warnings = 1; + /* Hold the position */ + } else { + position++; + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for policy load."); + return 1; + } + token = apol_vector_get_element(tokens, position); + } + + ret = load_policy_msg_is_old_load_policy_string(log, tokens, &position); + if (ret < 0) { + return ret; + } else if (ret > 0) { + if (position >= num_tokens) { + WARN(log, "%s", "Not enough tokens for policy load."); + return 1; + } + token = apol_vector_get_element(tokens, position); + if ((load->binary = strdup(token)) == NULL) { + error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + log->next_line = 1; + } else { + while (position < num_tokens) { + load_policy_msg_get_policy_components(load, tokens, &position); + } + /* Check to see if we have gathered ALL policy + * components. If not, we need to load the next + * line. */ + if (load->classes == 0 || load->rules == 0 || load->users == 0 || load->roles == 0 || load->types == 0) { + log->next_line = 1; + } + } + return has_warnings; +} + +/** + * Parse a single nul-terminated line from an selinux audit log. + */ +static int seaudit_log_parse_line(seaudit_log_t * log, char *line) +{ + char *orig_line = NULL; + seaudit_message_t *prev_message; + seaudit_message_type_e is_sel, prev_message_type; + apol_vector_t *tokens = NULL; + int retval = -1, retval2, has_warnings = 0, error = 0; + + is_sel = is_selinux(line); + if (log->next_line) { + prev_message = apol_vector_get_element(log->messages, apol_vector_get_size(log->messages) - 1); + seaudit_message_get_data(prev_message, &prev_message_type); + if (!(is_sel == SEAUDIT_MESSAGE_TYPE_INVALID && prev_message_type == SEAUDIT_MESSAGE_TYPE_BOOL) && + !(is_sel == SEAUDIT_MESSAGE_TYPE_LOAD && prev_message_type == SEAUDIT_MESSAGE_TYPE_LOAD)) { + WARN(log, "%s", "Parser was in the middle of a line, but next message was not the correct format."); + has_warnings = 1; + log->next_line = 0; + } else { + is_sel = prev_message_type; + } + } + if (is_sel == SEAUDIT_MESSAGE_TYPE_INVALID) { + /* unknown line, so ignore it */ + return 0; + } + + if ((orig_line = strdup(line)) == NULL) { + error = errno; + ERR(log, "%s", strerror(error)); + goto cleanup; + } + if (get_tokens(log, line, &tokens) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + goto cleanup; + } + + switch (is_sel) { + case SEAUDIT_MESSAGE_TYPE_AVC: + retval2 = avc_parse(log, tokens); + break; + case SEAUDIT_MESSAGE_TYPE_BOOL: + retval2 = bool_parse(log, tokens); + break; + case SEAUDIT_MESSAGE_TYPE_LOAD: + retval2 = load_parse(log, tokens); + break; + default: + /* should never get here */ + assert(0); + errno = EINVAL; + retval2 = -1; + } + if (retval2 < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + goto cleanup; + } else if (retval2 > 0) { + if (apol_vector_append(log->malformed_msgs, orig_line) < 0) { + error = errno; + ERR(log, "%s", strerror(error)); + goto cleanup; + } + orig_line = NULL; + has_warnings = 1; + } + + retval = 0; + cleanup: + free(orig_line); + apol_vector_destroy(&tokens); + if (retval < 0) { + errno = error; + return -1; + } + return has_warnings; +} + +/******************** public functions below ********************/ + +int seaudit_log_parse(seaudit_log_t * log, FILE * syslog) +{ + FILE *audit_file = syslog; + char *line = NULL; + int retval = -1, retval2, has_warnings = 0, error = 0; + size_t line_size = 0, i; + + if (log == NULL || syslog == NULL) { + ERR(log, "%s", strerror(EINVAL)); + error = EINVAL; + goto cleanup; + } + + if (!log->tz_initialized) { + tzset(); + log->tz_initialized = 1; + } + + clearerr(audit_file); + + while (1) { + if (getline(&line, &line_size, audit_file) < 0) { + error = errno; + if (!feof(audit_file)) { + ERR(log, "%s", strerror(error)); + goto cleanup; + } + break; + } + apol_str_trim(line); + retval2 = seaudit_log_parse_line(log, line); + if (retval2 < 0) { + error = errno; + goto cleanup; + } else if (retval2 > 0) { + has_warnings = 1; + } + } + + retval = 0; + cleanup: + free(line); + for (i = 0; i < apol_vector_get_size(log->models); i++) { + seaudit_model_t *m = apol_vector_get_element(log->models, i); + model_notify_log_changed(m, log); + } + if (retval < 0) { + errno = error; + return -1; + } + if (has_warnings) { + WARN(log, "%s", "Audit log was parsed, but there were one or more invalid message found within it."); + } + return has_warnings; +} + +int seaudit_log_parse_buffer(seaudit_log_t * log, const char *buffer, const size_t bufsize) +{ + const char *s; + char *line = NULL, *l; + int retval = -1, retval2, has_warnings = 0, error = 0; + size_t offset = 0, line_size, i; + + if (log == NULL || buffer == NULL) { + ERR(log, "%s", strerror(EINVAL)); + error = EINVAL; + goto cleanup; + } + + if (!log->tz_initialized) { + tzset(); + log->tz_initialized = 1; + } + + while (offset < bufsize) { + /* create a new string up to the first newline or end of + * buffer, whichever comes first */ + for (s = buffer + offset; s < buffer + bufsize && *s != '\n'; s++) ; + line_size = s - (buffer + offset); + assert(line_size > 0); + if ((l = realloc(line, line_size + 1)) == NULL) { + error = errno; + ERR(log, "%s", strerror(error)); + goto cleanup; + } + line = l; + memcpy(line, buffer + offset, line_size); + line[line_size] = '\0'; + offset += line_size; + if (s < buffer + bufsize) { + /* this branch can only be true if not at end of file */ + assert(*s == '\n'); + offset++; + } + apol_str_trim(line); + retval2 = seaudit_log_parse_line(log, line); + if (retval2 < 0) { + error = errno; + goto cleanup; + } else if (retval2 > 0) { + has_warnings = 1; + } + } + + retval = 0; + cleanup: + free(line); + for (i = 0; i < apol_vector_get_size(log->models); i++) { + seaudit_model_t *m = apol_vector_get_element(log->models, i); + model_notify_log_changed(m, log); + } + if (retval < 0) { + errno = error; + return -1; + } + if (has_warnings) { + WARN(log, "%s", "Audit log was parsed, but there were one or more invalid message found within it."); + } + return has_warnings; +} diff --git a/libseaudit/src/report.c b/libseaudit/src/report.c new file mode 100644 index 0000000..9b198c5 --- /dev/null +++ b/libseaudit/src/report.c @@ -0,0 +1,1060 @@ +/** + * @file + * Implementation of seaudit report generator. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "seaudit_internal.h" + +#include <seaudit/report.h> + +#include <apol/util.h> +#include <libxml/xmlreader.h> + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define CONFIG_FILE "seaudit-report.conf" +#define STYLESHEET_FILE "seaudit-report.css" +#define LINE_MAX 1024 + +struct seaudit_report +{ + /** output format for the report */ + seaudit_report_format_e format; + /** path to configuration file, or NULL to use system configuration */ + char *config; + /** path to HTML stylesheet, or NULL to use system stylesheet */ + char *stylesheet; + /** if non-zero, then use a stylesheet when generating HTML reports */ + int use_stylesheet; + /** if non-zero, then print malformed messages */ + int malformed; + /** model from which messages will be obtained */ + seaudit_model_t *model; +}; + +static const char *seaudit_report_node_names[] = { + "seaudit-report", + "standard-section", + "custom-section", + "view", + NULL +}; + +static const char *seaudit_standard_section_names[] = { + "PolicyLoads", + "EnforcementToggles", + "PolicyBooleans", + "Statistics", + "AllowListing", + "DenyListing", + NULL +}; + +seaudit_report_t *seaudit_report_create(seaudit_model_t * model) +{ + seaudit_report_t *r = calloc(1, sizeof(*r)); + if (r == NULL) { + return NULL; + } + r->model = model; + return r; +} + +void seaudit_report_destroy(seaudit_report_t ** report) +{ + if (report == NULL || *report == NULL) { + return; + } + free((*report)->config); + free((*report)->stylesheet); + free(*report); + *report = NULL; +} + +int seaudit_report_set_format(const seaudit_log_t * log, seaudit_report_t * report, seaudit_report_format_e format) +{ + if (report == NULL) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + report->format = format; + return 0; +} + +/** + * Set the report's configuration file to the default system file. + */ +static int report_set_default_configuration(const seaudit_log_t * log, seaudit_report_t * report) +{ + char *config_dir = apol_file_find(CONFIG_FILE); + int error; + + if (config_dir == NULL) { + error = errno; + ERR(log, "%s", "Could not find default configuration file."); + errno = error; + return -1; + } + if (asprintf(&report->config, "%s/%s", config_dir, CONFIG_FILE) < 0) { + error = errno; + report->config = NULL; + free(config_dir); + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + free(config_dir); + + /* check if can read the file */ + if (access(report->config, R_OK) != 0) { + error = errno; + ERR(log, "Could not read default config file %s.", report->config); + errno = error; + return -1; + } + return 0; +} + +int seaudit_report_set_configuration(const seaudit_log_t * log, seaudit_report_t * report, const char *file) +{ + if (report == NULL) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + free(report->config); + report->config = NULL; + if (file == NULL) { + return report_set_default_configuration(log, report); + } else { + if ((report->config = strdup(file)) == NULL) { + int error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + return 0; + } +} + +/** + * Set the report's stylesheet to the default system stylesheet. + */ +static int report_set_default_stylesheet(const seaudit_log_t * log, seaudit_report_t * report) +{ + char *dir = apol_file_find(STYLESHEET_FILE); + int error; + if (dir == NULL) { + error = errno; + ERR(log, "%s", "Could not find default stylesheet."); + errno = error; + return -1; + } + + if (asprintf(&report->stylesheet, "%s/%s", dir, STYLESHEET_FILE) < 0) { + error = errno; + report->stylesheet = NULL; + free(dir); + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + free(dir); + + return 0; +} + +int seaudit_report_set_stylesheet(const seaudit_log_t * log, seaudit_report_t * report, const char *file, const int use_stylesheet) +{ + if (report == NULL) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + free(report->stylesheet); + report->stylesheet = NULL; + report->use_stylesheet = use_stylesheet; + if (file == NULL) { + return report_set_default_stylesheet(log, report); + } else { + if ((report->stylesheet = strdup(file)) == NULL) { + return -1; + int error = errno; + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + return 0; + } +} + +int seaudit_report_set_malformed(const seaudit_log_t * log, seaudit_report_t * report, const int do_malformed) +{ + if (report == NULL) { + ERR(log, "%s", strerror(EINVAL)); + errno = EINVAL; + return -1; + } + report->malformed = do_malformed; + return 0; +} + +/** + * Insert the contents of the stylesheet into the output file. If it + * is not readable then generate a warning. This is not an error + * because the stylesheet is not strictly necessary. + */ +static int report_import_html_stylesheet(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile) +{ + char line[LINE_MAX], *line_ptr = NULL; + FILE *fp; + + if (report->use_stylesheet) { + fp = fopen(report->stylesheet, "r"); + if (fp == NULL) { + WARN(log, "Cannot open stylesheet file %s.", report->stylesheet); + return 1; + } + fprintf(outfile, "<style type=\"text/css\">\n"); + + while (fgets(line, LINE_MAX, fp) != NULL) { + free(line_ptr); + line_ptr = NULL; + if ((line_ptr = strdup(line)) == NULL) { + int error = errno; + free(line_ptr); + fclose(fp); + ERR(log, "%s", strerror(error)); + errno = error; + return -1; + } + apol_str_trim(line_ptr); + if (line_ptr[0] == '#' || apol_str_is_only_white_space(line_ptr)) + continue; + fprintf(outfile, "%s\n", line_ptr); + } + fprintf(outfile, "</style>\n"); + fclose(fp); + free(line_ptr); + } + return 0; +} + +static int report_print_header(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile) +{ + time_t ltime; + + time(<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; +} |