diff options
Diffstat (limited to 'seaudit')
40 files changed, 17468 insertions, 0 deletions
diff --git a/seaudit/Makefile.am b/seaudit/Makefile.am new file mode 100644 index 0000000..1987c99 --- /dev/null +++ b/seaudit/Makefile.am @@ -0,0 +1,90 @@ +setoolsdir = @setoolsdir@ +bin_PROGRAMS = seaudit-report +sbin_PROGRAMS = seaudit + +AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \ + @QPOL_CFLAGS@ @APOL_CFLAGS@ @SEAUDIT_CFLAGS@ + +seaudit_CFLAGS = $(AM_CFLAGS) \ + @GTK_CFLAGS@ @PIXBUF_CFLAGS@ @GLADE_CFLAGS@ @GTHREAD_CFLAGS@ +seaudit_report_CFLAGS = $(AM_CFLAGS) -DAPOL_INSTALL_DIR='"${setoolsdir}"' + +AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@ + +# need the -rdynamic flag below - glade uses dlopen() upon seaudit callbacks +seaudit_LDFLAGS = $(AM_LDFLAGS) \ + @GTK_LIBS@ @PIXBUF_LIBS@ @GLADE_LIBS@ @GTHREAD_LIBS@ -rdynamic + +LDADD = @SELINUX_LIB_FLAG@ @SEAUDIT_LIB_FLAG@ @APOL_LIB_FLAG@ @QPOL_LIB_FLAG@ + +dist_setools_DATA = \ + seaudit.glade \ + seaudit_help.txt \ + seaudit-report.conf \ + seaudit-report.css \ + seaudit.png seaudit-small.png + +nodist_setools_DATA = \ + dot_seaudit \ + seaudit-report-service + +seaudit_SOURCES = \ + filter_view.c filter_view.h \ + message_view.c message_view.h \ + modify_view.c modify_view.h \ + open_policy_window.c open_policy_window.h \ + policy_components_view.c policy_components_view.h \ + policy_view.c policy_view.h \ + preferences.c preferences.h \ + preferences_view.c preferences_view.h \ + progress.c progress.h \ + report_window.c report_window.h \ + seaudit.c seaudit.h \ + toplevel.c toplevel.h \ + utilgui.c utilgui.h + +seaudit_DEPENDENCIES = $(top_builddir)/libseaudit/src/libseaudit.so \ + $(top_builddir)/libapol/src/libapol.so \ + $(top_builddir)/libqpol/src/libqpol.so + +dot_seaudit: dot_seaudit.in Makefile + sed -e 's|\@setoolsdir\@|$(setoolsdir)|g' $< > $@ + +seaudit_report_SOURCES = seaudit-report.c +seaudit_report_DEPENDENCIES = $(top_builddir)/libseaudit/src/libseaudit.so \ + $(top_builddir)/libapol/src/libapol.so \ + $(top_builddir)/libqpol/src/libqpol.so + +logwatch = $(DESTDIR)/etc/logwatch +LOGWATCH_GROUP = $(logwatch)/conf/logfiles +LOGWATCH_SERVICE = $(logwatch)/conf/services +LOGWATCH_FILTER = $(logwatch)/scripts/services + +dist_noinst_DATA = dot_seaudit.in \ + seaudit-report-group.conf \ + seaudit-report-service.conf \ + seaudit-report-service.in + +seaudit-report-service: seaudit-report-service.in Makefile + sed -e 's|\@bindir\@|$(bindir)|g' $< > $@ + +install-logwatch: $(dist_noinst_DATA) seaudit-report-service + mkdir -p -- $(LOGWATCH_GROUP) + install -m 644 seaudit-report-group.conf $(LOGWATCH_GROUP) + mkdir -p -- $(LOGWATCH_SERVICE) + install -m 644 seaudit-report-service.conf $(LOGWATCH_SERVICE) + mkdir -p -- $(LOGWATCH_FILTER) + install -m 755 seaudit-report-service $(LOGWATCH_FILTER) + +$(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 $@) + +$(top_builddir)/libsefs/src/libsefs.so: + $(MAKE) -C $(top_builddir)/libsefs/src $(notdir $@) + +.PHONY: install-logwatch + +CLEANFILES = dot_seaudit seaudit-report-service diff --git a/seaudit/dot_seaudit.in b/seaudit/dot_seaudit.in new file mode 100644 index 0000000..2852819 --- /dev/null +++ b/seaudit/dot_seaudit.in @@ -0,0 +1,12 @@ +# Configuration file for seaudit - an audit log tool for Security +# Enhanced Linux. This file is auto-generated by the build system. + +DEFAULT_LOG_FILE /var/log/audit/audit.log +DEFAULT_POLICY_FILE +DEFAULT_REPORT_CONFIG_FILE @setoolsdir@/seaudit-report.conf +DEFAULT_REPORT_CSS_FILE @setoolsdir@/seaudit-report.css +RECENT_LOG_FILES +RECENT_POLICY_FILES +LOG_COLUMNS_HIDDEN path_field:src_usr_field:src_role_field:tgt_usr_field:tgt_role_field:inode_field:pid_field: +REAL_TIME_LOG_MONITORING 0 +REAL_TIME_UPDATE_INTERVAL 1000 diff --git a/seaudit/filter_view.c b/seaudit/filter_view.c new file mode 100644 index 0000000..e0d8745 --- /dev/null +++ b/seaudit/filter_view.c @@ -0,0 +1,1127 @@ +/** + * @file + * Run the dialog to modify a particular filter. + * + * @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 program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "filter_view.h" +#include "policy_components_view.h" + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <apol/policy-query.h> +#include <apol/mls-query.h> +#include <apol/util.h> +#include <glade/glade.h> + +struct context_item +{ + GtkButton *button; + GtkEntry *entry; + apol_vector_t *items; +}; + +struct date_item +{ + GtkComboBox *month; + GtkSpinButton *day, *hour, *minute, *second; + GtkFrame *frame; +}; + +struct filter_view +{ + toplevel_t *top; + seaudit_filter_t *filter; + GladeXML *xml; + + GtkDialog *dialog; + + GtkEntry *name_entry; + GtkComboBox *match_combo; + + struct context_item suser, srole, stype, smls_lvl, smls_clr, tuser, trole, ttype, tmls_lvl, tmls_clr, obj_class; + GtkButton *context_clear_button; + + GtkEntry *ipaddr_entry, *port_entry, *netif_entry, *exe_entry, *path_entry, *host_entry, *comm_entry; + GtkComboBox *message_combo; + GtkButton *other_clear_button; + + GtkRadioButton *date_none_radio, *date_before_radio, *date_after_radio, *date_between_radio; + struct date_item dates[2]; + GtkTextBuffer *description_buffer; +}; + +/** + * Initialize pointers to widgets on the context tab. + */ +static void filter_view_init_widgets_context(struct filter_view *fv) +{ + fv->suser.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewSUserButton")); + fv->srole.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewSRoleButton")); + fv->stype.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewSTypeButton")); + fv->smls_lvl.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewSMLSLVLButton")); + fv->smls_clr.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewSMLSCLRButton")); + fv->tuser.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewTUserButton")); + fv->trole.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewTRoleButton")); + fv->ttype.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewTTypeButton")); + fv->tmls_lvl.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewTMLSLVLButton")); + fv->tmls_clr.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewTMLSCLRButton")); + fv->obj_class.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewClassButton")); + assert(fv->suser.button != NULL && fv->srole.button != NULL && fv->stype.button != NULL && fv->smls_lvl.button != NULL && fv->smls_clr.button != NULL && + fv->tuser.button != NULL && fv->trole.button != NULL && fv->ttype.button != NULL && fv->tmls_lvl.button != NULL && fv->tmls_clr.button != NULL && fv->obj_class.button != NULL); + + fv->suser.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewSUserEntry")); + fv->srole.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewSRoleEntry")); + fv->stype.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewSTypeEntry")); + fv->smls_lvl.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewSMLSLVLEntry")); + fv->smls_clr.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewSMLSCLREntry")); + fv->tuser.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewTUserEntry")); + fv->trole.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewTRoleEntry")); + fv->ttype.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewTTypeEntry")); + fv->tmls_lvl.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewTMLSLVLEntry")); + fv->tmls_clr.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewTMLSCLREntry")); + fv->obj_class.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewClassEntry")); + assert(fv->suser.entry != NULL && fv->srole.entry != NULL && fv->stype.entry != NULL && fv->smls_lvl.entry != NULL && fv->smls_clr.entry != NULL && + fv->tuser.entry != NULL && fv->trole.entry != NULL && fv->ttype.entry != NULL && fv->tmls_lvl.entry != NULL && fv->tmls_clr.entry != NULL && fv->obj_class.entry != NULL); + g_object_set_data(G_OBJECT(fv->suser.entry), "data", &fv->suser); + g_object_set_data(G_OBJECT(fv->srole.entry), "data", &fv->srole); + g_object_set_data(G_OBJECT(fv->stype.entry), "data", &fv->stype); + g_object_set_data(G_OBJECT(fv->smls_lvl.entry), "data", &fv->smls_lvl); + g_object_set_data(G_OBJECT(fv->smls_clr.entry), "data", &fv->smls_clr); + g_object_set_data(G_OBJECT(fv->tuser.entry), "data", &fv->tuser); + g_object_set_data(G_OBJECT(fv->trole.entry), "data", &fv->trole); + g_object_set_data(G_OBJECT(fv->ttype.entry), "data", &fv->ttype); + g_object_set_data(G_OBJECT(fv->tmls_lvl.entry), "data", &fv->tmls_lvl); + g_object_set_data(G_OBJECT(fv->tmls_clr.entry), "data", &fv->tmls_clr); + g_object_set_data(G_OBJECT(fv->obj_class.entry), "data", &fv->obj_class); + + fv->context_clear_button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewContextClearButton")); + assert(fv->context_clear_button != NULL); +} + +/** + * Initialize pointers to widgets on the other tab. + */ +static void filter_view_init_widgets_other(struct filter_view *fv) +{ + fv->ipaddr_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewIPAddrEntry")); + fv->port_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewPortEntry")); + fv->netif_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewNetIfEntry")); + assert(fv->ipaddr_entry != NULL && fv->port_entry != NULL && fv->netif_entry != NULL); + + fv->exe_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewExeEntry")); + fv->path_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewPathEntry")); + fv->host_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewHostEntry")); + fv->comm_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewCommEntry")); + assert(fv->exe_entry != NULL && fv->path_entry != NULL && fv->host_entry != NULL && fv->comm_entry != NULL); + + fv->message_combo = GTK_COMBO_BOX(glade_xml_get_widget(fv->xml, "FilterViewMessageCombo")); + assert(fv->message_combo != NULL); + + fv->other_clear_button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewOtherClearButton")); + assert(fv->other_clear_button != NULL); +} + +/** + * Initialize pointers to widgets on the date tab. + */ +static void filter_view_init_widgets_date(struct filter_view *fv) +{ + static const char *widgets[2][6] = { + {"FilterViewDateStartFrame", "FilterViewDateStartMonthCombo", "FilterViewDateStartDaySpin", + "FilterViewDateStartHourSpin", "FilterViewDateStartMinuteSpin", "FilterViewDateStartSecondSpin"}, + {"FilterViewDateEndFrame", "FilterViewDateEndMonthCombo", "FilterViewDateEndDaySpin", + "FilterViewDateEndHourSpin", "FilterViewDateEndMinuteSpin", "FilterViewDateEndSecondSpin"} + }; + size_t i; + fv->date_none_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewDateNoneRadio")); + fv->date_before_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewDateBeforeRadio")); + fv->date_after_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewDateAfterRadio")); + fv->date_between_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewDateBetweenRadio")); + assert(fv->date_none_radio != NULL && fv->date_before_radio != NULL && fv->date_after_radio != NULL + && fv->date_between_radio != NULL); + + for (i = 0; i < 2; i++) { + fv->dates[i].frame = GTK_FRAME(glade_xml_get_widget(fv->xml, widgets[i][0])); + fv->dates[i].month = GTK_COMBO_BOX(glade_xml_get_widget(fv->xml, widgets[i][1])); + fv->dates[i].day = GTK_SPIN_BUTTON(glade_xml_get_widget(fv->xml, widgets[i][2])); + fv->dates[i].hour = GTK_SPIN_BUTTON(glade_xml_get_widget(fv->xml, widgets[i][3])); + fv->dates[i].minute = GTK_SPIN_BUTTON(glade_xml_get_widget(fv->xml, widgets[i][4])); + fv->dates[i].second = GTK_SPIN_BUTTON(glade_xml_get_widget(fv->xml, widgets[i][5])); + assert(fv->dates[i].frame != NULL && fv->dates[i].month != NULL && fv->dates[i].day != NULL && + fv->dates[i].hour != NULL && fv->dates[i].minute != NULL && fv->dates[i].second != NULL); + } +} + +static void filter_view_init_widgets(struct filter_view *fv, GtkWindow * parent) +{ + GtkTextView *description_view; + + fv->dialog = GTK_DIALOG(glade_xml_get_widget(fv->xml, "FilterWindow")); + assert(fv->dialog != NULL); + gtk_window_set_transient_for(GTK_WINDOW(fv->dialog), parent); + + fv->name_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewNameEntry")); + fv->match_combo = GTK_COMBO_BOX(glade_xml_get_widget(fv->xml, "FilterViewMatchCombo")); + assert(fv->name_entry != NULL && fv->match_combo); + + filter_view_init_widgets_context(fv); + filter_view_init_widgets_other(fv); + filter_view_init_widgets_date(fv); + + fv->description_buffer = gtk_text_buffer_new(NULL); +#ifdef GTK_2_8 + g_object_ref_sink(fv->description_buffer); +#endif + description_view = GTK_TEXT_VIEW(glade_xml_get_widget(fv->xml, "FilterViewDescView")); + assert(description_view != NULL); + gtk_text_view_set_buffer(description_view, fv->description_buffer); +} + +/********** functions that copies filter object values to widget **********/ + +/** + * Get the vector of strings from the accessor function. If the + * vector is NULL then clear the entry's contents; otherwies set the + * entry to the vector of strings, comma delimited. + */ +static void filter_view_context_item_to_entry(struct filter_view *fv, struct context_item *item) +{ + if (item->items == NULL) { + gtk_entry_set_text(item->entry, ""); + } else { + GString *s = g_string_new(""); + size_t i; + for (i = 0; i < apol_vector_get_size(item->items); i++) { + char *t = apol_vector_get_element(item->items, i); + if (i > 0) { + g_string_append(s, ", "); + } + g_string_append(s, t); + } + gtk_entry_set_text(item->entry, s->str); + g_string_free(s, TRUE); + } +} + +static void filter_view_context_items_to_entries(struct filter_view *fv) +{ + filter_view_context_item_to_entry(fv, &fv->suser); + filter_view_context_item_to_entry(fv, &fv->srole); + filter_view_context_item_to_entry(fv, &fv->stype); + filter_view_context_item_to_entry(fv, &fv->smls_lvl); + filter_view_context_item_to_entry(fv, &fv->smls_clr); + filter_view_context_item_to_entry(fv, &fv->tuser); + filter_view_context_item_to_entry(fv, &fv->trole); + filter_view_context_item_to_entry(fv, &fv->ttype); + filter_view_context_item_to_entry(fv, &fv->tmls_lvl); + filter_view_context_item_to_entry(fv, &fv->tmls_clr); + filter_view_context_item_to_entry(fv, &fv->obj_class); +} + +static void filter_view_init_context(struct filter_view *fv) +{ + const apol_vector_t *v; + v = seaudit_filter_get_source_user(fv->filter); + if (v != NULL && (fv->suser.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno)); + return; + } + v = seaudit_filter_get_source_role(fv->filter); + if (v != NULL && (fv->srole.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno)); + return; + } + v = seaudit_filter_get_source_type(fv->filter); + if (v != NULL && (fv->stype.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno)); + return; + } + v = seaudit_filter_get_source_mls_lvl(fv->filter); + if (v != NULL && (fv->smls_lvl.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno)); + return; + } + v = seaudit_filter_get_source_mls_clr(fv->filter); + if (v != NULL && (fv->smls_clr.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno)); + return; + } + + v = seaudit_filter_get_target_user(fv->filter); + if (v != NULL && (fv->tuser.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno)); + return; + } + v = seaudit_filter_get_target_role(fv->filter); + if (v != NULL && (fv->trole.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno)); + return; + } + v = seaudit_filter_get_target_type(fv->filter); + if (v != NULL && (fv->ttype.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno)); + return; + } + v = seaudit_filter_get_target_mls_lvl(fv->filter); + if (v != NULL && (fv->tmls_lvl.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno)); + return; + } + v = seaudit_filter_get_target_mls_clr(fv->filter); + if (v != NULL && (fv->tmls_clr.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno)); + return; + } + + v = seaudit_filter_get_target_class(fv->filter); + if (v != NULL && (fv->obj_class.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) { + toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno)); + return; + } + filter_view_context_items_to_entries(fv); +} + +/** + * Get the string from the accessor function. If the returned string + * is NULL then clear the entry's contents; otherwise set the entry to + * the returned string. + */ +static void filter_view_init_entry(struct filter_view *fv, const char *(*accessor) (const seaudit_filter_t *), GtkEntry * entry) +{ + const char *s = accessor(fv->filter); + if (s == NULL) { + s = ""; + } + gtk_entry_set_text(entry, s); +} + +static void filter_view_init_other(struct filter_view *fv) +{ + char s[32]; + filter_view_init_entry(fv, seaudit_filter_get_anyaddr, fv->ipaddr_entry); + if (seaudit_filter_get_anyport(fv->filter) <= 0) { + s[0] = '\0'; + } else { + snprintf(s, 32, "%d", seaudit_filter_get_anyport(fv->filter)); + } + gtk_entry_set_text(fv->port_entry, s); + filter_view_init_entry(fv, seaudit_filter_get_netif, fv->netif_entry); + filter_view_init_entry(fv, seaudit_filter_get_executable, fv->exe_entry); + filter_view_init_entry(fv, seaudit_filter_get_path, fv->path_entry); + filter_view_init_entry(fv, seaudit_filter_get_host, fv->host_entry); + filter_view_init_entry(fv, seaudit_filter_get_command, fv->comm_entry); + switch (seaudit_filter_get_message_type(fv->filter)) { + case SEAUDIT_AVC_DENIED: + gtk_combo_box_set_active(fv->message_combo, 1); + break; + case SEAUDIT_AVC_GRANTED: + gtk_combo_box_set_active(fv->message_combo, 2); + break; + default: + gtk_combo_box_set_active(fv->message_combo, 0); + } +} + +static void filter_view_init_date(struct filter_view *fv) +{ + const struct tm *start, *end; + struct tm values[2]; + int has_value[2] = { 0, 0 }; + seaudit_filter_date_match_e match; + size_t i; + + seaudit_filter_get_date(fv->filter, &start, &end, &match); + if (start == NULL && end == NULL) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fv->date_none_radio), TRUE); + } else { + if (match == SEAUDIT_FILTER_DATE_MATCH_BEFORE) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fv->date_before_radio), TRUE); + } else if (match == SEAUDIT_FILTER_DATE_MATCH_AFTER) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fv->date_after_radio), TRUE); + } + memcpy(values + 0, start, sizeof(values[0])); + has_value[0] = 1; + } + if (match == SEAUDIT_FILTER_DATE_MATCH_BETWEEN) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fv->date_between_radio), TRUE); + memcpy(values + 1, end, sizeof(values[1])); + has_value[1] = 1; + } + for (i = 0; i < 2; i++) { + if (has_value[i]) { + gtk_combo_box_set_active(fv->dates[i].month, values[i].tm_mon); + gtk_spin_button_set_value(fv->dates[i].day, values[i].tm_mday); + gtk_spin_button_set_value(fv->dates[i].hour, values[i].tm_hour); + gtk_spin_button_set_value(fv->dates[i].minute, values[i].tm_min); + gtk_spin_button_set_value(fv->dates[i].second, values[i].tm_sec); + } else { + gtk_combo_box_set_active(fv->dates[i].month, 0); + } + } +} + +/** + * Copy values from seaudit filter object to GTK+ widgets. + */ +static void filter_view_init_dialog(struct filter_view *fv) +{ + const char *name = seaudit_filter_get_name(fv->filter); + const char *desc = seaudit_filter_get_description(fv->filter);; + if (name == NULL) { + name = "Untitled"; + } + gtk_entry_set_text(fv->name_entry, name); + gtk_combo_box_set_active(fv->match_combo, seaudit_filter_get_match(fv->filter)); + + filter_view_init_context(fv); + filter_view_init_other(fv); + filter_view_init_date(fv); + + if (desc == NULL) { + desc = ""; + } + gtk_text_buffer_set_text(fv->description_buffer, desc, -1); +} + +/********** functions that copies widget values to filter object **********/ + +static void filter_view_apply_context(struct filter_view *fv) +{ + if (seaudit_filter_set_source_user(fv->filter, fv->suser.items) < 0 || + seaudit_filter_set_source_role(fv->filter, fv->srole.items) < 0 || + seaudit_filter_set_source_type(fv->filter, fv->stype.items) < 0 || + seaudit_filter_set_source_mls_lvl(fv->filter, fv->smls_lvl.items) < 0 || + seaudit_filter_set_source_mls_clr(fv->filter, fv->smls_clr.items) < 0 || + seaudit_filter_set_target_user(fv->filter, fv->tuser.items) < 0 || + seaudit_filter_set_target_role(fv->filter, fv->trole.items) < 0 || + seaudit_filter_set_target_type(fv->filter, fv->ttype.items) < 0 || + seaudit_filter_set_target_mls_lvl(fv->filter, fv->tmls_lvl.items) < 0 || + seaudit_filter_set_target_mls_clr(fv->filter, fv->tmls_clr.items) < 0 || + seaudit_filter_set_target_class(fv->filter, fv->obj_class.items) < 0) { + toplevel_ERR(fv->top, "Error applying context: %s", strerror(errno)); + } +} + +/** + * If the entry is empty, then call the modifier function passing NULL + * as the second parameter. Else call the function with the entry's + * contents. + */ +static void filter_view_apply_entry(struct filter_view *fv, GtkEntry * entry, int (*modifier) (seaudit_filter_t *, const char *)) +{ + const char *s = gtk_entry_get_text(entry); + if (strcmp(s, "") == 0) { + s = NULL; + } + if (modifier(fv->filter, s) < 0) { + toplevel_ERR(fv->top, "Error apply settings: %s", strerror(errno)); + } +} + +/** + * Copy values from the other tab to filter object. + */ +static void filter_view_apply_other(struct filter_view *fv) +{ + const char *s; + int port = 0; + seaudit_avc_message_type_e message_type; + + filter_view_apply_entry(fv, fv->ipaddr_entry, seaudit_filter_set_anyaddr); + s = gtk_entry_get_text(fv->port_entry); + if (strcmp(s, "") != 0) { + port = atoi(s); + } + if (seaudit_filter_set_anyport(fv->filter, port) < 0) { + toplevel_ERR(fv->top, "Error setting filter: %s", strerror(errno)); + return; + } + filter_view_apply_entry(fv, fv->netif_entry, seaudit_filter_set_netif); + filter_view_apply_entry(fv, fv->exe_entry, seaudit_filter_set_executable); + filter_view_apply_entry(fv, fv->path_entry, seaudit_filter_set_path); + filter_view_apply_entry(fv, fv->host_entry, seaudit_filter_set_host); + filter_view_apply_entry(fv, fv->comm_entry, seaudit_filter_set_command); + switch (gtk_combo_box_get_active(fv->message_combo)) { + case 1: + message_type = SEAUDIT_AVC_DENIED; + break; + case 2: + message_type = SEAUDIT_AVC_GRANTED; + break; + default: + message_type = SEAUDIT_AVC_UNKNOWN; + } + if (seaudit_filter_set_message_type(fv->filter, message_type) < 0) { + toplevel_ERR(fv->top, "Error setting filter: %s", strerror(errno)); + return; + } +} + +/** + * Returns which date radio button is active: + * + * -1 if date_none_radio, + * else something that can be casted to seaudit_filter_date_match + */ +static int filter_view_get_date_match(struct filter_view *fv) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fv->date_before_radio))) { + return SEAUDIT_FILTER_DATE_MATCH_BEFORE; + } + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fv->date_after_radio))) { + return SEAUDIT_FILTER_DATE_MATCH_AFTER; + } + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fv->date_between_radio))) { + return SEAUDIT_FILTER_DATE_MATCH_BETWEEN; + } + return -1; +} + +/** + * Copy values from date tab to the seaudit filter object. + */ +static void filter_view_apply_date(struct filter_view *fv) +{ + struct tm tm[2]; + size_t i; + int date_match = filter_view_get_date_match(fv); + memset(&tm, 0, sizeof(tm)); + for (i = 0; i < 2; i++) { + tm[i].tm_mon = gtk_combo_box_get_active(fv->dates[i].month); + tm[i].tm_mday = gtk_spin_button_get_value_as_int(fv->dates[i].day); + tm[i].tm_year = 0; + tm[i].tm_hour = gtk_spin_button_get_value_as_int(fv->dates[i].hour); + tm[i].tm_min = gtk_spin_button_get_value_as_int(fv->dates[i].minute); + tm[i].tm_sec = gtk_spin_button_get_value_as_int(fv->dates[i].second); + } + if (date_match < 0) { + seaudit_filter_set_date(fv->filter, NULL, NULL, 0); + } else { + seaudit_filter_set_date(fv->filter, tm + 0, tm + 1, (seaudit_filter_date_match_e) date_match); + } +} + +/** + * Copy values from GTK+ widgets to the seaudit filter object. + */ +static void filter_view_apply(struct filter_view *fv) +{ + GtkTextIter start, end; + char *s; + seaudit_filter_match_e match = SEAUDIT_FILTER_MATCH_ALL; + + filter_view_apply_entry(fv, fv->name_entry, seaudit_filter_set_name); + if (gtk_combo_box_get_active(fv->match_combo) == 1) { + match = SEAUDIT_FILTER_MATCH_ANY; + } + if (seaudit_filter_set_match(fv->filter, match) < 0) { + toplevel_ERR(fv->top, "Error setting filter: %s", strerror(errno)); + } + + filter_view_apply_context(fv); + filter_view_apply_other(fv); + filter_view_apply_date(fv); + + gtk_text_buffer_get_bounds(fv->description_buffer, &start, &end); + s = gtk_text_buffer_get_text(fv->description_buffer, &start, &end, FALSE); + if (strcmp(s, "") == 0) { + free(s); + s = NULL; + } + if (seaudit_filter_set_description(fv->filter, s) < 0) { + toplevel_ERR(fv->top, "Error setting filter: %s", strerror(errno)); + } + free(s); +} + +/******************** signal handlers for dialog ********************/ + +/** + * Return a list of users within the currently loaded policy, sorted + * alphabetically. If there is no policy loaded then return NULL. + */ +static apol_vector_t *filter_view_get_policy_users(struct filter_view *fv) +{ + apol_vector_t *policy_items = NULL, *v = NULL; + apol_policy_t *p = toplevel_get_policy(fv->top); + size_t i; + if (p == NULL) { + return NULL; + } + if (apol_user_get_by_query(p, NULL, &v) < 0 || (policy_items = apol_vector_create(NULL)) == NULL) { + toplevel_ERR(fv->top, "Error getting a list of policy users: %s", strerror(errno)); + apol_vector_destroy(&policy_items); + return NULL; + } + for (i = 0; i < apol_vector_get_size(v); i++) { + const qpol_user_t *e = apol_vector_get_element(v, i); + const char *name; + qpol_user_get_name(apol_policy_get_qpol(p), e, &name); + if (apol_vector_append(policy_items, (void *)name) < 0) { + toplevel_ERR(fv->top, "Error getting a list of policy users: %s", strerror(errno)); + apol_vector_destroy(&v); + apol_vector_destroy(&policy_items); + } + } + apol_vector_destroy(&v); + apol_vector_sort(policy_items, apol_str_strcmp, NULL); + return policy_items; +} + +/** + * Return a list of roles within the currently loaded policy, sorted + * alphabetically. If there is no policy loaded then return NULL. + */ +static apol_vector_t *filter_view_get_policy_roles(struct filter_view *fv) +{ + apol_vector_t *policy_items = NULL, *v = NULL; + apol_policy_t *p = toplevel_get_policy(fv->top); + size_t i; + if (p == NULL) { + return NULL; + } + if (apol_role_get_by_query(p, NULL, &v) < 0 || (policy_items = apol_vector_create(NULL)) == NULL) { + toplevel_ERR(fv->top, "Error getting a list of policy roles: %s", strerror(errno)); + apol_vector_destroy(&policy_items); + return NULL; + } + for (i = 0; i < apol_vector_get_size(v); i++) { + const qpol_role_t *e = apol_vector_get_element(v, i); + const char *name; + qpol_role_get_name(apol_policy_get_qpol(p), e, &name); + if (apol_vector_append(policy_items, (void *)name) < 0) { + toplevel_ERR(fv->top, "Error getting a list of policy roles: %s", strerror(errno)); + apol_vector_destroy(&v); + apol_vector_destroy(&policy_items); + } + } + apol_vector_destroy(&v); + apol_vector_sort(policy_items, apol_str_strcmp, NULL); + return policy_items; +} + +/** + * Return a list of types (not attributes nor aliases) within the + * currently loaded policy, sorted alphabetically. If there is no + * policy loaded then return NULL. + */ +static apol_vector_t *filter_view_get_policy_types(struct filter_view *fv) +{ + apol_vector_t *policy_items = NULL, *v = NULL; + apol_policy_t *p = toplevel_get_policy(fv->top); + size_t i; + if (p == NULL) { + return NULL; + } + if (apol_type_get_by_query(p, NULL, &v) < 0 || (policy_items = apol_vector_create(NULL)) == NULL) { + toplevel_ERR(fv->top, "Error getting a list of policy types: %s", strerror(errno)); + apol_vector_destroy(&policy_items); + return NULL; + } + for (i = 0; i < apol_vector_get_size(v); i++) { + const qpol_type_t *e = apol_vector_get_element(v, i); + const char *name; + qpol_type_get_name(apol_policy_get_qpol(p), e, &name); + if (apol_vector_append(policy_items, (void *)name) < 0) { + toplevel_ERR(fv->top, "Error getting a list of policy types: %s", strerror(errno)); + apol_vector_destroy(&v); + apol_vector_destroy(&policy_items); + } + } + apol_vector_destroy(&v); + apol_vector_sort(policy_items, apol_str_strcmp, NULL); + return policy_items; +} + +/** + * Return a list of mls levels/clearance (not aliases) within the + * currently loaded policy, sorted alphabetically. If there is no + * policy loaded then return NULL. + */ +static apol_vector_t *filter_view_get_policy_mls_lvl(struct filter_view *fv) +{ + apol_vector_t *policy_items = NULL, *v = NULL; + apol_policy_t *p = toplevel_get_policy(fv->top); + const qpol_iterator_t **cats = NULL; + + size_t i; + + if (p == NULL) { + return NULL; + } + + if (apol_level_get_by_query(p, NULL, &v) < 0 || (policy_items = apol_vector_create(&free)) == NULL) { + toplevel_ERR(fv->top, "Error getting a list of policy mls levels: %s", strerror(errno)); + apol_vector_destroy(&policy_items); + return NULL; + } + + for (i = 0; i < apol_vector_get_size(v); i++) + { + const char *name = NULL; + const char *mls = malloc(100*sizeof(mls)); + + const char *cat_name1 = NULL, *cat_name2 = NULL; + uint32_t *cat_val1, *cat_val2; + const char *cat_low = NULL; + const char *cat_high = NULL; + bool isrange = false, isrange_end = false, isempty = true; + size_t k; + qpol_cat_t *c = NULL; + const qpol_level_t *e = apol_vector_get_element(v, i); + + qpol_level_get_name(apol_policy_get_qpol(p), e, &name); + strcpy(mls, name); + if (qpol_level_get_cat_iter(apol_policy_get_qpol(p), e, &cats) < 0){ + toplevel_ERR(fv->top, "Error getting categories for level: %s", strerror(errno)); + qpol_iterator_destroy(&cats); + } + qpol_iterator_get_size(cats, &k); + + if (k > 0){ + strcat(mls, ":"); + isempty = true; + } + if (qpol_iterator_get_item(cats, &c) < 0){ + toplevel_ERR(fv->top, "Error getting category: %s", strerror(errno)); + qpol_iterator_destroy(&cats); + } + qpol_cat_get_value(apol_policy_get_qpol(p), c, &cat_val1); + qpol_cat_get_name(apol_policy_get_qpol(p), c, &cat_name1); + isrange = false; + isrange_end = false; + + for (; !qpol_iterator_end(cats); qpol_iterator_next(cats)) + { + if (qpol_iterator_get_item(cats, &c) < 0){ + toplevel_ERR(fv->top, "Error getting category: %s", strerror(errno)); + qpol_iterator_destroy(&cats); + } + qpol_cat_get_value(apol_policy_get_qpol(p), c, &cat_val2); + qpol_cat_get_name(apol_policy_get_qpol(p), c, &cat_name2); + if (((int)cat_val2 == ((int)cat_val1 + 1)) && (isrange == false)) + { + cat_low = cat_name1; + strcat(mls, cat_low); + strcat(mls, "."); + isrange = true; + isempty = false; + } + if ((isrange == true) && ((int)cat_val2 == ((int)cat_val1 + 1))) + { + cat_high = cat_name2; + } + else if ((isrange == true) && ((int)cat_val2 != ((int)cat_val1 + 1))) + { + cat_high = cat_name1; + isrange_end = true; + strcat(mls, cat_high); + isempty=false; + } + if ((isrange == false) && (isempty == false) && ((int)cat_val2 != ((int)cat_val1 + 1))) + { + strcat(mls, ","); + strcat(mls, cat_name2); + } + cat_val1 = cat_val2; + cat_name1 = cat_name2; + + } + if ((isrange == true) && (isrange_end == false)) + { + strcat(mls, cat_high); + } + if (apol_vector_append(policy_items, (void *)mls) < 0) { + toplevel_ERR(fv->top, "Error getting a list of policy mls levels: %s", strerror(errno)); + apol_vector_destroy(&v); + apol_vector_destroy(&policy_items); + } + } + + apol_vector_destroy(&v); + qpol_iterator_destroy(&cats); + apol_vector_sort(policy_items, apol_str_strcmp, NULL); + return policy_items; +} + +/** + * Return a list of object classeswithin the currently loaded policy, + * sorted alphabetically. If there is no policy loaded then return + * NULL. + */ +static apol_vector_t *filter_view_get_policy_classes(struct filter_view *fv) +{ + apol_vector_t *policy_items = NULL, *v = NULL; + apol_policy_t *p = toplevel_get_policy(fv->top); + size_t i; + if (p == NULL) { + return NULL; + } + if (apol_class_get_by_query(p, NULL, &v) < 0 || (policy_items = apol_vector_create(NULL)) == NULL) { + toplevel_ERR(fv->top, "Error getting a list of policy classes: %s", strerror(errno)); + apol_vector_destroy(&policy_items); + return NULL; + } + for (i = 0; i < apol_vector_get_size(v); i++) { + const qpol_class_t *e = apol_vector_get_element(v, i); + const char *name; + qpol_class_get_name(apol_policy_get_qpol(p), e, &name); + if (apol_vector_append(policy_items, (void *)name) < 0) { + toplevel_ERR(fv->top, "Error getting a list of policy classes: %s", strerror(errno)); + apol_vector_destroy(&v); + apol_vector_destroy(&policy_items); + } + } + apol_vector_destroy(&v); + apol_vector_sort(policy_items, apol_str_strcmp, NULL); + return policy_items; +} + +static void filter_view_on_suser_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + apol_vector_t *log_items = toplevel_get_log_users(fv->top); + apol_vector_t *policy_items = filter_view_get_policy_users(fv); + fv->suser.items = + policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Source User Items", log_items, policy_items, + fv->suser.items); + apol_vector_destroy(&log_items); + apol_vector_destroy(&policy_items); + filter_view_context_item_to_entry(fv, &fv->suser); +} + +static void filter_view_on_srole_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + apol_vector_t *log_items = toplevel_get_log_roles(fv->top); + apol_vector_t *policy_items = filter_view_get_policy_roles(fv); + fv->srole.items = + policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Source Role Items", log_items, policy_items, + fv->srole.items); + apol_vector_destroy(&log_items); + apol_vector_destroy(&policy_items); + filter_view_context_item_to_entry(fv, &fv->srole); +} + +static void filter_view_on_stype_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + apol_vector_t *log_items = toplevel_get_log_types(fv->top); + apol_vector_t *policy_items = filter_view_get_policy_types(fv); + fv->stype.items = + policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Source Type Items", log_items, policy_items, + fv->stype.items); + apol_vector_destroy(&log_items); + apol_vector_destroy(&policy_items); + filter_view_context_item_to_entry(fv, &fv->stype); +} + +static void filter_view_on_smls_lvl_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + + apol_vector_t *log_items = toplevel_get_log_mls_lvl(fv->top); + apol_vector_t *policy_items = filter_view_get_policy_mls_lvl(fv); + fv->smls_lvl.items = + policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Source MLS Level Items", log_items, policy_items, + fv->smls_lvl.items); + apol_vector_destroy(&log_items); + apol_vector_destroy(&policy_items); + filter_view_context_item_to_entry(fv, &fv->smls_lvl); +} + +static void filter_view_on_smls_clr_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + apol_vector_t *log_items = toplevel_get_log_mls_clr(fv->top); + apol_vector_t *policy_items = filter_view_get_policy_mls_lvl(fv); + fv->smls_clr.items = + policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Source MLS Clearance Items", log_items, policy_items, + fv->smls_clr.items); + apol_vector_destroy(&log_items); + apol_vector_destroy(&policy_items); + filter_view_context_item_to_entry(fv, &fv->smls_clr); +} + +static void filter_view_on_tuser_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + apol_vector_t *log_items = toplevel_get_log_users(fv->top); + apol_vector_t *policy_items = filter_view_get_policy_users(fv); + fv->tuser.items = + policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Target User Items", log_items, policy_items, + fv->tuser.items); + apol_vector_destroy(&log_items); + apol_vector_destroy(&policy_items); + filter_view_context_item_to_entry(fv, &fv->tuser); +} + +static void filter_view_on_trole_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + apol_vector_t *log_items = toplevel_get_log_roles(fv->top); + apol_vector_t *policy_items = filter_view_get_policy_roles(fv); + fv->trole.items = + policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Target Role Items", log_items, policy_items, + fv->trole.items); + apol_vector_destroy(&log_items); + apol_vector_destroy(&policy_items); + filter_view_context_item_to_entry(fv, &fv->trole); +} + +static void filter_view_on_ttype_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + apol_vector_t *log_items = toplevel_get_log_types(fv->top); + apol_vector_t *policy_items = filter_view_get_policy_types(fv); + fv->ttype.items = + policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Target Type Items", log_items, policy_items, + fv->ttype.items); + apol_vector_destroy(&log_items); + apol_vector_destroy(&policy_items); + filter_view_context_item_to_entry(fv, &fv->ttype); +} + +static void filter_view_on_tmls_lvl_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + apol_vector_t *log_items = toplevel_get_log_mls_lvl(fv->top); + apol_vector_t *policy_items = filter_view_get_policy_mls_lvl(fv); + fv->tmls_lvl.items = + policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Target MLS Level Items", log_items, policy_items, + fv->tmls_lvl.items); + apol_vector_destroy(&log_items); + apol_vector_destroy(&policy_items); + filter_view_context_item_to_entry(fv, &fv->tmls_lvl); +} + +static void filter_view_on_tmls_clr_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + apol_vector_t *log_items = toplevel_get_log_mls_clr(fv->top); + apol_vector_t *policy_items = filter_view_get_policy_mls_lvl(fv); + fv->tmls_clr.items = + policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Target MLS Clearance Items", log_items, policy_items, + fv->tmls_clr.items); + apol_vector_destroy(&log_items); + apol_vector_destroy(&policy_items); + filter_view_context_item_to_entry(fv, &fv->tmls_clr); +} + +static void filter_view_on_class_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + apol_vector_t *log_items = toplevel_get_log_classes(fv->top); + apol_vector_t *policy_items = filter_view_get_policy_classes(fv); + fv->obj_class.items = + policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Object Class Items", log_items, policy_items, + fv->obj_class.items); + apol_vector_destroy(&log_items); + apol_vector_destroy(&policy_items); + filter_view_context_item_to_entry(fv, &fv->obj_class); +} + +/** + * Whenever the user finished manually editing a context entry, + * convert the entry's string into the underlying vector. + */ +static gboolean filter_view_on_entry_focus_out(GtkWidget * widget, GdkEventFocus * event + __attribute__ ((unused)), gpointer user_data) +{ + struct context_item *item = g_object_get_data(G_OBJECT(widget), "data"); + struct filter_view *fv = (struct filter_view *)user_data; + gchar **strs = g_strsplit(gtk_entry_get_text(GTK_ENTRY(widget)), ",", -1); + gchar *s; + size_t i = 0; + char *t; + apol_vector_t *new_v = NULL; + while (1) { + s = strs[i++]; + if (s == NULL) { + break; + } + if (new_v == NULL && (new_v = apol_vector_create(free)) == NULL) { + toplevel_ERR(fv->top, "Could not interpret entry contents: %s", strerror(errno)); + break; + } + if ((t = strdup(s)) == NULL) { + toplevel_ERR(fv->top, "Could not interpret entry contents: %s", strerror(errno)); + free(t); + break; + } + apol_str_trim(t); + if (apol_vector_append(new_v, t) < 0) { + toplevel_ERR(fv->top, "Could not interpret entry contents: %s", strerror(errno)); + free(t); + break; + } + } + g_strfreev(strs); + apol_vector_destroy(&item->items); + item->items = new_v; + filter_view_context_item_to_entry(fv, item); + return FALSE; +} + +static void filter_view_destroy_context_vectors(struct filter_view *fv) +{ + apol_vector_destroy(&fv->suser.items); + apol_vector_destroy(&fv->srole.items); + apol_vector_destroy(&fv->stype.items); + apol_vector_destroy(&fv->smls_lvl.items); + apol_vector_destroy(&fv->smls_clr.items); + apol_vector_destroy(&fv->tuser.items); + apol_vector_destroy(&fv->trole.items); + apol_vector_destroy(&fv->ttype.items); + apol_vector_destroy(&fv->tmls_lvl.items); + apol_vector_destroy(&fv->tmls_clr.items); + apol_vector_destroy(&fv->obj_class.items); +} + +static void filter_view_on_context_clear_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + filter_view_destroy_context_vectors(fv); + filter_view_context_items_to_entries(fv); +} + +static void filter_view_init_context_signals(struct filter_view *fv) +{ + g_signal_connect(fv->suser.button, "clicked", G_CALLBACK(filter_view_on_suser_context_click), fv); + g_signal_connect(fv->suser.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv); + g_signal_connect(fv->srole.button, "clicked", G_CALLBACK(filter_view_on_srole_context_click), fv); + g_signal_connect(fv->srole.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv); + g_signal_connect(fv->stype.button, "clicked", G_CALLBACK(filter_view_on_stype_context_click), fv); + g_signal_connect(fv->stype.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv); + g_signal_connect(fv->smls_lvl.button, "clicked", G_CALLBACK(filter_view_on_smls_lvl_context_click), fv); + g_signal_connect(fv->smls_lvl.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv); + g_signal_connect(fv->smls_clr.button, "clicked", G_CALLBACK(filter_view_on_smls_clr_context_click), fv); + g_signal_connect(fv->smls_clr.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv); + g_signal_connect(fv->tuser.button, "clicked", G_CALLBACK(filter_view_on_tuser_context_click), fv); + g_signal_connect(fv->tuser.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv); + g_signal_connect(fv->trole.button, "clicked", G_CALLBACK(filter_view_on_trole_context_click), fv); + g_signal_connect(fv->trole.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv); + g_signal_connect(fv->ttype.button, "clicked", G_CALLBACK(filter_view_on_ttype_context_click), fv); + g_signal_connect(fv->ttype.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv); + g_signal_connect(fv->tmls_lvl.button, "clicked", G_CALLBACK(filter_view_on_tmls_lvl_context_click), fv); + g_signal_connect(fv->tmls_lvl.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv); + g_signal_connect(fv->tmls_clr.button, "clicked", G_CALLBACK(filter_view_on_tmls_clr_context_click), fv); + g_signal_connect(fv->tmls_clr.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv); + g_signal_connect(fv->obj_class.button, "clicked", G_CALLBACK(filter_view_on_class_context_click), fv); + g_signal_connect(fv->obj_class.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv); + g_signal_connect(fv->context_clear_button, "clicked", G_CALLBACK(filter_view_on_context_clear_click), fv); +} + +static void filter_view_on_other_clear_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + gtk_entry_set_text(fv->ipaddr_entry, ""); + gtk_entry_set_text(fv->port_entry, ""); + gtk_entry_set_text(fv->netif_entry, ""); + gtk_entry_set_text(fv->exe_entry, ""); + gtk_entry_set_text(fv->path_entry, ""); + gtk_entry_set_text(fv->host_entry, ""); + gtk_entry_set_text(fv->comm_entry, ""); + gtk_combo_box_set_active(fv->message_combo, 0); +} + +static void filter_view_on_date_toggle(GtkToggleButton * widget, gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + int match; + /* clicking on the radio buttons emit two toggle signals, one for + * the original button and one for the new one. thus only need to + * handle half of all signals */ + if (!gtk_toggle_button_get_active(widget)) { + return; + } + match = filter_view_get_date_match(fv); + gtk_widget_set_sensitive(GTK_WIDGET(fv->dates[0].frame), (match != -1)); + gtk_widget_set_sensitive(GTK_WIDGET(fv->dates[1].frame), (match == SEAUDIT_FILTER_DATE_MATCH_BETWEEN)); +} + +/* Given the year and the month set the spin button to have the + correct number of days for that month */ +static void filter_view_date_set_number_days(int month, GtkSpinButton * button) +{ + static const int days[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + int cur_day; + /* get the current day because set_range moves the current day + * by the difference minus 1 day. e.g., going from jan 20 to + * february the day would automatically become 18 */ + cur_day = gtk_spin_button_get_value_as_int(button); + gtk_spin_button_set_range(button, 1, days[month]); + /* return to current day, or to the max value allowed in range */ + gtk_spin_button_set_value(button, cur_day); +} + +static void filter_view_on_month0_change(GtkComboBox * widget, gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + filter_view_date_set_number_days(gtk_combo_box_get_active(widget), fv->dates[0].day); +} + +static void filter_view_on_month1_change(GtkComboBox * widget, gpointer user_data) +{ + struct filter_view *fv = (struct filter_view *)user_data; + filter_view_date_set_number_days(gtk_combo_box_get_active(widget), fv->dates[1].day); +} + +static void filter_view_init_signals(struct filter_view *fv) +{ + filter_view_init_context_signals(fv); + g_signal_connect(fv->other_clear_button, "clicked", G_CALLBACK(filter_view_on_other_clear_click), fv); + g_signal_connect(fv->date_none_radio, "toggled", G_CALLBACK(filter_view_on_date_toggle), fv); + g_signal_connect(fv->date_before_radio, "toggled", G_CALLBACK(filter_view_on_date_toggle), fv); + g_signal_connect(fv->date_after_radio, "toggled", G_CALLBACK(filter_view_on_date_toggle), fv); + g_signal_connect(fv->date_between_radio, "toggled", G_CALLBACK(filter_view_on_date_toggle), fv); + g_signal_connect(fv->dates[0].month, "changed", G_CALLBACK(filter_view_on_month0_change), fv); + g_signal_connect(fv->dates[1].month, "changed", G_CALLBACK(filter_view_on_month1_change), fv); +} + +/******************** public function below ********************/ + +void filter_view_run(seaudit_filter_t * filter, toplevel_t * top, GtkWindow * parent) +{ + struct filter_view fv; + gint response; + + memset(&fv, 0, sizeof(fv)); + fv.top = top; + fv.filter = filter; + fv.xml = glade_xml_new(toplevel_get_glade_xml(top), "FilterWindow", NULL); + filter_view_init_widgets(&fv, parent); + filter_view_init_signals(&fv); + filter_view_init_dialog(&fv); + do { + response = gtk_dialog_run(fv.dialog); + } while (response != GTK_RESPONSE_CLOSE); + + filter_view_apply(&fv); + g_object_unref(fv.description_buffer); + gtk_widget_destroy(GTK_WIDGET(fv.dialog)); + filter_view_destroy_context_vectors(&fv); +} diff --git a/seaudit/filter_view.h b/seaudit/filter_view.h new file mode 100644 index 0000000..d94ece3 --- /dev/null +++ b/seaudit/filter_view.h @@ -0,0 +1,42 @@ +/** + * @file + * Dialog that allows the user to modify a particular filter. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef FILTER_VIEW_H +#define FILTER_VIEW_H + +#include "toplevel.h" +#include <seaudit/filter.h> +#include <gtk/gtk.h> + +/** + * Display and run a dialog that allows the user to modify a single + * filter. + * + * @param top Toplevel containing message view. + * @param view Message view to modify. + * @param parent Parent window upon which to center this dialog. + */ +void filter_view_run(seaudit_filter_t * filter, toplevel_t * top, GtkWindow * parent); + +#endif diff --git a/seaudit/message_view.c b/seaudit/message_view.c new file mode 100644 index 0000000..64d625f --- /dev/null +++ b/seaudit/message_view.c @@ -0,0 +1,1341 @@ +/** + * @file + * Implementation of the view for a libseaudit model. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * @author Jeremy Solt jsolt@tresys.com + * + * Copyright (C) 2003-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "message_view.h" +#include "modify_view.h" +#include "utilgui.h" + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <apol/util.h> + +/** + * A custom model that implements the interfaces GtkTreeModel and + * GtkTreeSortable. + */ +typedef struct message_view_store +{ + /** this must be the first field, to satisfy glib */ + GObject parent; + /** pointer to the store's controller */ + message_view_t *view; + /** vector of seaudit_message_t, as returned by + * seaudit_model_get_messages() */ + apol_vector_t *messages; + /** column that is currently being sorted; use OTHER_FIELD to + * indicate no sorting */ + gint sort_field; + /** current sort direction, either 1 or ascending or -1 for + * descending */ + int sort_dir; + /** unique integer for each instance of a model */ + gint stamp; +} message_view_store_t; + +typedef struct message_view_store_class +{ + GObjectClass parent_class; +} message_view_store_class_t; + +static GType message_view_store_get_type(void); +#define SEAUDIT_TYPE_MESSAGE_VIEW_STORE (message_view_store_get_type()) +#define SEAUDIT_IS_MESSAGE_VIEW_STORE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAUDIT_TYPE_MESSAGE_VIEW_STORE)) + +struct message_view +{ + seaudit_model_t *model; + toplevel_t *top; + /** toplevel of the view, currently a scrolled_window */ + GtkWidget *w; + /** actual GTK+ tree view widget that displays the rows and + * columns of message data */ + GtkTreeView *view; + /** GTK+ store that models messages within the tree */ + message_view_store_t *store; + /** filename for when this view was saved (could be NULL) */ + char *filename; + /** most recent filename for exported messages (could be NULL) */ + char *export_filename; +}; + +typedef seaudit_sort_t *(*sort_generator_fn_t) (int direction); + +struct view_column_record +{ + preference_field_e id; + const char *name; + const char *sample_text; + sort_generator_fn_t sort; +}; + +static const struct view_column_record column_data[] = { + {HOST_FIELD, "Hostname", "Hostname", seaudit_sort_by_host}, + {MESSAGE_FIELD, "Message", "Message", seaudit_sort_by_message_type}, + {DATE_FIELD, "Date", "Jan 01 00:00:00", seaudit_sort_by_date}, + {SUSER_FIELD, "Source\nUser", "Source", seaudit_sort_by_source_user}, + {SROLE_FIELD, "Source\nRole", "Source", seaudit_sort_by_source_role}, + {STYPE_FIELD, "Source\nType", "unlabeled_t", seaudit_sort_by_source_type}, + {SMLS_LVL_FIELD, "Source\nMLS Level", "MLS Level", seaudit_sort_by_source_mls_lvl}, + {SMLS_CLR_FIELD, "Source\nMLS Clearance", "MLS Clearance", seaudit_sort_by_source_mls_clr}, + {TUSER_FIELD, "Target\nUser", "Target", seaudit_sort_by_target_user}, + {TROLE_FIELD, "Target\nRole", "Target", seaudit_sort_by_target_role}, + {TTYPE_FIELD, "Target\nType", "unlabeled_t", seaudit_sort_by_target_type}, + {TMLS_LVL_FIELD, "Target\nMLS Level", "MLS Level", seaudit_sort_by_target_mls_lvl}, + {TMLS_CLR_FIELD, "Target\nMLS Clearance", "MLS Clearance", seaudit_sort_by_target_mls_clr}, + {OBJCLASS_FIELD, "Object\nClass", "Object", seaudit_sort_by_object_class}, + {PERM_FIELD, "Permission", "Permission", seaudit_sort_by_permission}, + {EXECUTABLE_FIELD, "Executable", "/usr/bin/cat", seaudit_sort_by_executable}, + {COMMAND_FIELD, "Command", "/usr/bin/cat", seaudit_sort_by_command}, + {NAME_FIELD, "Name", "iceweasel", seaudit_sort_by_name}, + {PID_FIELD, "PID", "12345", seaudit_sort_by_pid}, + {INODE_FIELD, "Inode", "123456", seaudit_sort_by_inode}, + {PATH_FIELD, "Path", "/home/gburdell/foo", seaudit_sort_by_path}, + {OTHER_FIELD, "Other", "Lorem ipsum dolor sit amet, consectetur", NULL} +}; + +static const size_t num_columns = sizeof(column_data) / sizeof(column_data[0]); + +/** + * (Re)sort the view based upon which column is clicked. If already + * sorting on this column, then reverse the sort direction. Also + * update the sort indicator for this column. + */ +static gboolean message_view_on_column_click(GtkTreeViewColumn * column, gpointer user_data) +{ + gint column_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column id")); + message_view_t *view = (message_view_t *) user_data; + int dir = 0; + seaudit_sort_t *sort; + GtkTreeViewColumn *prev_column; + if (column_id == view->store->sort_field) { + dir = view->store->sort_dir * -1; + } else { + dir = 1; + } + + if ((sort = column_data[(preference_field_e) column_id].sort(dir)) == NULL) { + toplevel_ERR(view->top, "%s", strerror(errno)); + return TRUE; + } + seaudit_model_clear_sorts(view->model); + if (seaudit_model_append_sort(view->model, sort) < 0) { + seaudit_sort_destroy(&sort); + toplevel_ERR(view->top, "%s", strerror(errno)); + } + prev_column = gtk_tree_view_get_column(view->view, view->store->sort_field); + if (prev_column != NULL) { + gtk_tree_view_column_set_sort_indicator(prev_column, FALSE); + } + gtk_tree_view_column_set_sort_indicator(column, TRUE); + if (dir > 0) { + gtk_tree_view_column_set_sort_order(column, GTK_SORT_ASCENDING); + } else { + gtk_tree_view_column_set_sort_order(column, GTK_SORT_DESCENDING); + } + + view->store->sort_field = column_id; + view->store->sort_dir = dir; + message_view_update_rows(view); + return TRUE; +} + +/*************** implementation of a custom GtkTreeModel ***************/ + +static GObjectClass *parent_class = NULL; + +static void message_view_store_init(message_view_store_t * m); +static void message_view_store_class_init(message_view_store_class_t * c); +static void message_view_store_tree_init(GtkTreeModelIface * iface); +static void message_view_store_finalize(GObject * object); +static GtkTreeModelFlags message_view_store_get_flags(GtkTreeModel * tree_model); +static gint message_view_store_get_n_columns(GtkTreeModel * tree_model); +static GType message_view_store_get_column_type(GtkTreeModel * tree_model, gint index); +static gboolean message_view_store_get_iter(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreePath * path); +static GtkTreePath *message_view_store_get_path(GtkTreeModel * tree_model, GtkTreeIter * iter); +static void message_view_store_get_value(GtkTreeModel * tree_model, GtkTreeIter * iter, gint column, GValue * value); +static gboolean message_view_store_iter_next(GtkTreeModel * tree_model, GtkTreeIter * iter); +static gboolean message_view_store_iter_children(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent); +static gboolean message_view_store_iter_has_child(GtkTreeModel * tree_model, GtkTreeIter * iter); +static gint message_view_store_iter_n_children(GtkTreeModel * tree_model, GtkTreeIter * iter); +static gboolean message_view_store_iter_nth_child(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent, gint n); +static gboolean message_view_store_iter_parent(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * child); + +static GType message_view_store_get_type(void) +{ + static GType store_type = 0; + static const GTypeInfo store_info = { + sizeof(message_view_store_class_t), + NULL, + NULL, + (GClassInitFunc) message_view_store_class_init, + NULL, + NULL, + sizeof(message_view_store_t), + 0, + (GInstanceInitFunc) message_view_store_init + }; + static const GInterfaceInfo tree_model_info = { + (GInterfaceInitFunc) message_view_store_tree_init, + NULL, + NULL + }; + + if (store_type) + return store_type; + + store_type = g_type_register_static(G_TYPE_OBJECT, "message_view_store", &store_info, (GTypeFlags) 0); + g_type_add_interface_static(store_type, GTK_TYPE_TREE_MODEL, &tree_model_info); + return store_type; +} + +static void message_view_store_init(message_view_store_t * m) +{ + static int next_stamp = 0; + m->messages = NULL; + m->sort_field = OTHER_FIELD; + m->sort_dir = 1; + m->stamp = next_stamp++; +} + +static void message_view_store_class_init(message_view_store_class_t * c) +{ + GObjectClass *object_class; + parent_class = g_type_class_peek_parent(c); + object_class = (GObjectClass *) c; + object_class->finalize = message_view_store_finalize; +} + +static void message_view_store_tree_init(GtkTreeModelIface * iface) +{ + iface->get_flags = message_view_store_get_flags; + iface->get_n_columns = message_view_store_get_n_columns; + iface->get_column_type = message_view_store_get_column_type; + iface->get_iter = message_view_store_get_iter; + iface->get_path = message_view_store_get_path; + iface->get_value = message_view_store_get_value; + iface->iter_next = message_view_store_iter_next; + iface->iter_children = message_view_store_iter_children; + iface->iter_has_child = message_view_store_iter_has_child; + iface->iter_n_children = message_view_store_iter_n_children; + iface->iter_nth_child = message_view_store_iter_nth_child; + iface->iter_parent = message_view_store_iter_parent; +} + +static void message_view_store_finalize(GObject * object) +{ + (*parent_class->finalize) (object); +} + +static GtkTreeModelFlags message_view_store_get_flags(GtkTreeModel * tree_model) +{ + g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), 0); + return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY; +} + +static gint message_view_store_get_n_columns(GtkTreeModel * tree_model __attribute__ ((unused))) +{ + return OTHER_FIELD + 1; +} + +static GType message_view_store_get_column_type(GtkTreeModel * tree_model, gint idx __attribute__ ((unused))) +{ + g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), G_TYPE_INVALID); + /* everything is a string for now */ + return G_TYPE_STRING; +} + +static gboolean message_view_store_get_iter(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreePath * path) +{ + gint i; + message_view_store_t *store = (message_view_store_t *) tree_model; + g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), FALSE); + g_return_val_if_fail(gtk_tree_path_get_depth(path) > 0, FALSE); + i = gtk_tree_path_get_indices(path)[0]; + if (i >= apol_vector_get_size(store->messages)) + return FALSE; + + iter->stamp = store->stamp; + iter->user_data = apol_vector_get_element(store->messages, i); + iter->user_data2 = GINT_TO_POINTER(i); + iter->user_data3 = store->view; + return TRUE; +} + +static GtkTreePath *message_view_store_get_path(GtkTreeModel * tree_model, GtkTreeIter * iter) +{ + GtkTreePath *retval; + message_view_store_t *store = (message_view_store_t *) tree_model; + g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), NULL); + g_return_val_if_fail(iter->stamp == store->stamp, NULL); + retval = gtk_tree_path_new(); + gtk_tree_path_append_index(retval, GPOINTER_TO_INT(iter->user_data2)); + return retval; +} + +/** + * Given a string, check that it is UTF8 legal. If not, or if the + * string is NULL, then return an empty string. Otherwise return the + * original string. + */ +static void message_view_to_utf8(GValue * value, const char *s) +{ + if (s == NULL || !g_utf8_validate(s, -1, NULL)) { + g_value_set_string(value, ""); + } + g_value_set_string(value, s); +} + +static void message_view_store_get_value(GtkTreeModel * tree_model, GtkTreeIter * iter, gint column, GValue * value) +{ + message_view_store_t *store; + message_view_t *view; + seaudit_message_t *m; + seaudit_message_type_e type; + void *data; + seaudit_avc_message_t *avc; + g_return_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model)); + g_return_if_fail(iter != NULL); + g_return_if_fail(column <= OTHER_FIELD); + g_value_init(value, G_TYPE_STRING); + store = (message_view_store_t *) tree_model; + view = store->view; + m = (seaudit_message_t *) iter->user_data; + data = seaudit_message_get_data(m, &type); + preference_field_e field = column; + + switch (field) { + case HOST_FIELD: + { + message_view_to_utf8(value, seaudit_message_get_host(m)); + return; + } + case MESSAGE_FIELD: + { + char *message = "Invalid"; + switch (type) { + case SEAUDIT_MESSAGE_TYPE_BOOL: + { + message = "Boolean"; + break; + } + case SEAUDIT_MESSAGE_TYPE_LOAD: + { + message = "Load"; + break; + } + case SEAUDIT_MESSAGE_TYPE_AVC: + { + avc = (seaudit_avc_message_t *) data; + seaudit_avc_message_type_e avc_type; + avc_type = seaudit_avc_message_get_message_type(avc); + switch (avc_type) { + case SEAUDIT_AVC_DENIED: + { + message = "Denied"; + break; + } + case SEAUDIT_AVC_GRANTED: + { + message = "Granted"; + break; + } + default: + { + /* should never get here */ + toplevel_ERR(view->top, "Got an invalid AVC message type %d!", avc_type); + assert(0); + return; + } + } + break; + } + default: + { + /* should never get here */ + toplevel_ERR(view->top, "Got an invalid message type %d!", type); + assert(0); + return; + } + } + message_view_to_utf8(value, message); + return; + } + case DATE_FIELD: + { + const struct tm *tm = seaudit_message_get_time(m); + char date[256]; + /* check to see if we have been given a valid year, if + * so display, otherwise no year displayed */ + if (tm->tm_year == 0) { + strftime(date, 256, "%b %d %H:%M:%S", tm); + } else { + strftime(date, 256, "%b %d %H:%M:%S %Y", tm); + } + message_view_to_utf8(value, date); + return; + } + case OTHER_FIELD: + { + char *other = seaudit_message_to_misc_string(m);; + if (other == NULL) { + toplevel_ERR(view->top, "%s", strerror(errno)); + return; + } + message_view_to_utf8(value, other); + free(other); + return; + } + default: /* FALLTHROUGH */ + break; + } + + if (type != SEAUDIT_MESSAGE_TYPE_AVC) { + /* the rest of the columns are blank for non-AVC + * messages */ + message_view_to_utf8(value, ""); + return; + } + avc = (seaudit_avc_message_t *) data; + + switch (field) { + case SUSER_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_source_user(avc)); + return; + } + case SROLE_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_source_role(avc)); + return; + } + case STYPE_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_source_type(avc)); + return; + } + case SMLS_LVL_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_source_mls_lvl(avc)); + return; + } + case SMLS_CLR_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_source_mls_clr(avc)); + return; + } + case TUSER_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_target_user(avc)); + return; + } + case TROLE_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_target_role(avc)); + return; + } + case TTYPE_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_target_type(avc)); + return; + } + case TMLS_LVL_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_target_mls_lvl(avc)); + return; + } + case TMLS_CLR_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_target_mls_clr(avc)); + return; + } + case OBJCLASS_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_object_class(avc)); + return; + } + case PERM_FIELD: + { + const apol_vector_t *perms = seaudit_avc_message_get_perm(avc); + char *perm = NULL; + size_t i, len = 0; + for (i = 0; perms != NULL && i < apol_vector_get_size(perms); i++) { + char *p = apol_vector_get_element(perms, i); + if (apol_str_appendf(&perm, &len, "%s%s", (i > 0 ? "," : ""), p) < 0) { + toplevel_ERR(view->top, "%s", strerror(errno)); + return; + } + } + message_view_to_utf8(value, perm); + free(perm); + return; + } + case EXECUTABLE_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_exe(avc)); + return; + } + case COMMAND_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_comm(avc)); + return; + } + case NAME_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_name(avc)); + return; + } + case PID_FIELD: + { + char *s; + if (asprintf(&s, "%u", seaudit_avc_message_get_pid(avc)) < 0) { + toplevel_ERR(view->top, "%s", strerror(errno)); + return; + } + message_view_to_utf8(value, s); + free(s); + return; + } + case INODE_FIELD: + { + char *s; + if (asprintf(&s, "%lu", seaudit_avc_message_get_inode(avc)) < 0) { + toplevel_ERR(view->top, "%s", strerror(errno)); + return; + } + message_view_to_utf8(value, s); + free(s); + return; + } + case PATH_FIELD: + { + message_view_to_utf8(value, seaudit_avc_message_get_path(avc)); + return; + } + default: /* FALLTHROUGH */ + break; + } + /* should never get here */ + toplevel_ERR(view->top, "Got an invalid column %d!", field); + assert(0); +} + +static gboolean message_view_store_iter_next(GtkTreeModel * tree_model, GtkTreeIter * iter) +{ + gint i; + message_view_store_t *store = (message_view_store_t *) tree_model; + g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), FALSE); + g_return_val_if_fail(iter->stamp == store->stamp, FALSE); + if (iter == NULL || iter->user_data == NULL) + return FALSE; + i = GPOINTER_TO_INT(iter->user_data2) + 1; + if (i >= apol_vector_get_size(store->messages)) { + return FALSE; + } + iter->user_data = apol_vector_get_element(store->messages, i); + iter->user_data2 = GINT_TO_POINTER(i); + iter->user_data3 = store->view; + return TRUE; +} + +static gboolean message_view_store_iter_children(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent) +{ + message_view_store_t *store; + g_return_val_if_fail(parent == NULL || parent->user_data != NULL, FALSE); + if (parent) + return FALSE; + g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), FALSE); + + /* set iterator to first row, if possible */ + store = (message_view_store_t *) tree_model; + if (store->messages == NULL || apol_vector_get_size(store->messages) == 0) + return FALSE; + + iter->stamp = store->stamp; + iter->user_data = apol_vector_get_element(store->messages, 0); + iter->user_data2 = GINT_TO_POINTER(0); + iter->user_data3 = store->view; + return TRUE; +} + +static gboolean message_view_store_iter_has_child(GtkTreeModel * tree_model __attribute__ ((unused)), GtkTreeIter * iter + __attribute__ ((unused))) +{ + return FALSE; +} + +static gint message_view_store_iter_n_children(GtkTreeModel * tree_model, GtkTreeIter * iter) +{ + message_view_store_t *store; + g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), -1); + g_return_val_if_fail(iter == NULL || iter->user_data != NULL, 0); + store = (message_view_store_t *) tree_model; + /* return the number of rows, if iterator is at the top; + * otherwise return 0 because this store is just a list */ + if (iter != NULL || store->messages == NULL) { + return 0; + } + return apol_vector_get_size(store->messages); +} + +static gboolean message_view_store_iter_nth_child(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent, gint n) +{ + message_view_store_t *store; + g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), FALSE); + store = (message_view_store_t *) tree_model; + if (store->messages == NULL || parent != NULL) { + return FALSE; + } + if (n >= apol_vector_get_size(store->messages)) { + return FALSE; + } + iter->stamp = store->stamp; + iter->user_data = apol_vector_get_element(store->messages, n); + iter->user_data2 = GINT_TO_POINTER(n); + iter->user_data3 = store->view; + return TRUE; +} + +static gboolean message_view_store_iter_parent(GtkTreeModel * tree_model __attribute__ ((unused)), GtkTreeIter * iter + __attribute__ ((unused)), GtkTreeIter * child __attribute__ ((unused))) +{ + return FALSE; +} + +/*************** end of custom GtkTreeModel implementation ***************/ + +/*************** message_view_messages_vector() callbacks ******************/ +#define LBACK 1 +#define LFORWARD 2 +#define LNOOP 255 + +typedef struct _msg_user_data +{ + message_view_t *view; + apol_vector_t *messages; + GtkDialog *dialog; + GtkTextBuffer *buffer; + gint handle_id; +} _msg_user_data_t; + +static void message_view_dialog_change(GtkTreeModel * tree_model, + GtkTreePath * path __attribute__ ((unused)), + GtkTreeIter * iter __attribute__ ((unused)), gpointer user_data) +{ + _msg_user_data_t *d = (_msg_user_data_t *) user_data; + /* Disconnect this signal handler after it fires. It's one + * shot, nothing should be able to bring the next and previous + * buttons back from the dead if the view ever changes. + */ + g_signal_handler_disconnect(tree_model, d->handle_id); + d->view = NULL; + gtk_dialog_set_response_sensitive(d->dialog, LBACK, FALSE); + gtk_dialog_set_response_sensitive(d->dialog, LFORWARD, FALSE); +} + +static void message_view_dialog_response(GtkDialog * dialog, gint response, gpointer user_data) +{ + _msg_user_data_t *d = (_msg_user_data_t *) user_data; + GtkTreePath *p; + GtkTreeIter tree_iter; + GtkTextIter text_iter; + size_t i; + gboolean go_back = FALSE; + gboolean go_forward = FALSE; + + gtk_text_buffer_set_text(d->buffer, "", -1); + p = apol_vector_get_element(d->messages, 0); + assert(p != NULL); + switch (response) { + case LNOOP: + break; /* no-op response, display and test only */ + case LBACK: + gtk_tree_path_prev(p); + break; + case LFORWARD: + gtk_tree_path_next(p); + break; + case GTK_RESPONSE_DELETE_EVENT: + case GTK_RESPONSE_CLOSE: + apol_vector_destroy(&d->messages); + if (d->view != NULL) { + g_signal_handler_disconnect(d->view->store, d->handle_id); + } + free(d); + gtk_widget_destroy(GTK_WIDGET(dialog)); + return; + default: + /* should never get here */ + toplevel_ERR(d->view->top, "Unhandled response type (%d).\n", response); + assert(0); + return; + } + assert(d->view != NULL); + + /* determine if the forward and backward buttons should be + enabled or not */ + if (apol_vector_get_size(d->messages) == 1) { + GtkTreePath *dupe_p = gtk_tree_path_copy(p); + if (dupe_p == NULL) { + toplevel_ERR(d->view->top, "%s", strerror(errno)); + return; + } + go_back = gtk_tree_path_prev(dupe_p); + gtk_tree_path_free(dupe_p); + + message_view_store_get_iter(GTK_TREE_MODEL(d->view->store), &tree_iter, p); + go_forward = gtk_tree_model_iter_next(GTK_TREE_MODEL(d->view->store), &tree_iter); + } + gtk_dialog_set_response_sensitive(dialog, LBACK, go_back); + gtk_dialog_set_response_sensitive(dialog, LFORWARD, go_forward); + + gtk_text_buffer_get_start_iter(d->buffer, &text_iter); + for (i = 0; i < apol_vector_get_size(d->messages); i++) { + char *s; + p = apol_vector_get_element(d->messages, i); + message_view_store_get_iter(GTK_TREE_MODEL(d->view->store), &tree_iter, p); + if ((s = seaudit_message_to_string(tree_iter.user_data)) == NULL) { + toplevel_ERR(d->view->top, "%s", strerror(errno)); + continue; + } + + gtk_text_buffer_insert(d->buffer, &text_iter, s, -1); + gtk_text_buffer_insert(d->buffer, &text_iter, "\n", -1); + free(s); + } +} + +/** + * Show all messages within the messages vector (vector of + * GtkTreePaths into the view's store). + * + * Callback function cb_view_message takes ownership of messages + * vector and state. + */ +static void message_view_messages_vector(message_view_t * view, apol_vector_t * messages) +{ + GtkWidget *window = NULL; + GtkWidget *scroll; + GtkWidget *text_view; + GtkTextBuffer *buffer; + _msg_user_data_t *state; + + state = malloc(sizeof(_msg_user_data_t)); + if (state == NULL) { + toplevel_ERR(view->top, "%s", strerror(errno)); + apol_vector_destroy(&messages); + return; + } + + window = gtk_dialog_new_with_buttons("View Messages", + toplevel_get_window(view->top), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_GO_BACK, LBACK, + GTK_STOCK_GO_FORWARD, LFORWARD, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); + gtk_dialog_set_default_response(GTK_DIALOG(window), GTK_RESPONSE_CLOSE); + gtk_window_set_modal(GTK_WINDOW(window), FALSE); + scroll = gtk_scrolled_window_new(NULL, NULL); + text_view = gtk_text_view_new(); + gtk_window_set_default_size(GTK_WINDOW(window), 480, 300); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->vbox), scroll); + gtk_container_add(GTK_CONTAINER(scroll), text_view); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_view), GTK_WRAP_WORD); + gtk_widget_show(text_view); + gtk_widget_show(scroll); + + gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view), FALSE); + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT); + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view)); + state->view = view; + state->messages = messages; + state->dialog = GTK_DIALOG(window); + state->buffer = buffer; + g_signal_connect(window, "response", G_CALLBACK(message_view_dialog_response), state); + state->handle_id = g_signal_connect(view->store, "row-changed", G_CALLBACK(message_view_dialog_change), state); + message_view_dialog_response(GTK_DIALOG(window), LNOOP, state); + + gtk_widget_show_all(GTK_WIDGET(window)); +} + +/******************** handlers for right click menu ********************/ + +static void message_view_popup_on_view_message_activate(GtkMenuItem * menuitem, gpointer user_data __attribute__ ((unused))) +{ + message_view_t *v = g_object_get_data(G_OBJECT(menuitem), "view-object"); + message_view_entire_message(v); +} + +static void message_view_popup_on_find_terules_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + message_view_t *v = g_object_get_data(G_OBJECT(menuitem), "view-object"); + toplevel_find_terules(v->top, (seaudit_message_t *) user_data); +} + +static void message_view_popup_on_export_selected_messages_activate(GtkMenuItem * menuitem, gpointer user_data + __attribute__ ((unused))) +{ + message_view_t *v = g_object_get_data(G_OBJECT(menuitem), "view-object"); + message_view_export_selected_messages(v); +} + +static void message_view_popup_menu(GtkWidget * treeview, GdkEventButton * event, message_view_t * view, + seaudit_message_t * message) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + gint num_selected_rows = gtk_tree_selection_count_selected_rows(selection); + GtkWidget *menu, *menuitem, *menuitem2, *menuitem3; + int button, event_time; + + menu = gtk_menu_new(); + if (num_selected_rows == 1) { + menuitem = gtk_menu_item_new_with_label("View Selected Message"); + menuitem3 = gtk_menu_item_new_with_label("Export Selected Message..."); + } else { + menuitem = gtk_menu_item_new_with_label("View Selected Messages"); + menuitem3 = gtk_menu_item_new_with_label("Export Selected Messages..."); + } + menuitem2 = gtk_menu_item_new_with_label("Find TERules using Message..."); + g_signal_connect(menuitem, "activate", (GCallback) message_view_popup_on_view_message_activate, message); + g_signal_connect(menuitem2, "activate", (GCallback) message_view_popup_on_find_terules_activate, message); + g_signal_connect(menuitem3, "activate", (GCallback) message_view_popup_on_export_selected_messages_activate, NULL); + g_object_set_data(G_OBJECT(menuitem), "view-object", view); + g_object_set_data(G_OBJECT(menuitem2), "view-object", view); + g_object_set_data(G_OBJECT(menuitem3), "view-object", view); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem2); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem3); + gtk_widget_show_all(menu); + if (toplevel_get_policy(view->top) == NULL) { + gtk_widget_set_sensitive(menuitem2, FALSE); + } + + if (event) { + button = event->button; + event_time = event->time; + } else { + button = 0; + event_time = gtk_get_current_event_time(); + } + gtk_menu_attach_to_widget(GTK_MENU(menu), treeview, NULL); + gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, event_time); +} + +static gboolean message_view_delayed_selection_menu_item(gpointer data) +{ + message_view_t *view = (message_view_t *) data; + toplevel_update_selection_menu_item(view->top); + return FALSE; +} + +static gboolean message_view_on_button_press(GtkWidget * treeview, GdkEventButton * event, gpointer user_data) +{ + message_view_t *view = (message_view_t *) user_data; + if (event->type == GDK_BUTTON_PRESS && event->button == 3) { + GtkTreePath *path = NULL; + GtkTreeIter iter; + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), event->x, event->y, &path, NULL, NULL, NULL)) { + return FALSE; + } + /* if the right click occurred on an unselected row, remove + * all selections and select the item under the pointer */ + if (!gtk_tree_selection_path_is_selected(selection, path)) { + gtk_tree_selection_unselect_all(selection); + gtk_tree_selection_select_path(selection, path); + } + message_view_store_get_iter(GTK_TREE_MODEL(view->store), &iter, path); + /* popup a menu for the row that was clicked */ + message_view_popup_menu(treeview, event, view, (seaudit_message_t *) iter.user_data); + return TRUE; + } else if (event->type == GDK_BUTTON_PRESS && event->button == 1) { + /* n.b.: rows can be selected but never deselected. + * delay updating the menu, for upon the first click + * there is not a selection yet */ + g_idle_add(&message_view_delayed_selection_menu_item, view); + return FALSE; + } else if (event->type == GDK_2BUTTON_PRESS && event->button == 1){ + /* Show message on double click */ + message_view_entire_message(view); + } + return FALSE; +} + +static void message_view_gtk_tree_path_free(gpointer data, gpointer user_data __attribute__ ((unused))) +{ + gtk_tree_path_free((GtkTreePath *) data); +} + +static gboolean message_view_on_popup_menu(GtkWidget * treeview, gpointer user_data) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + GList *glist = gtk_tree_selection_get_selected_rows(selection, NULL); + message_view_t *view = (message_view_t *) user_data; + GtkTreePath *path; + GtkTreeIter iter; + if (glist == NULL) { + return FALSE; + } + path = g_list_nth_data(glist, 0); + message_view_store_get_iter(GTK_TREE_MODEL(view->store), &iter, path); + g_list_foreach(glist, message_view_gtk_tree_path_free, NULL); + g_list_free(glist); + message_view_popup_menu(treeview, NULL, view, (seaudit_message_t *) iter.user_data); + return TRUE; +} + +static void message_view_on_row_activate(GtkTreeView * tree_view __attribute__ ((unused)), GtkTreePath * path + __attribute__ ((unused)), GtkTreeViewColumn * column + __attribute__ ((unused)), gpointer user_data) +{ + message_view_t *view = (message_view_t *) user_data; + toplevel_update_selection_menu_item(view->top); +} + +/******************** other public functions below ********************/ + +message_view_t *message_view_create(toplevel_t * top, seaudit_model_t * model, const char *filename) +{ + message_view_t *view; + GtkTreeSelection *selection; + GtkCellRenderer *renderer; + size_t i; + + if ((view = calloc(1, sizeof(*view))) == NULL || (filename != NULL && (view->filename = strdup(filename)) == NULL)) { + int error = errno; + toplevel_ERR(top, "%s", strerror(error)); + message_view_destroy(&view); + errno = error; + return NULL; + } + view->top = top; + view->model = model; + view->store = (message_view_store_t *) g_object_new(SEAUDIT_TYPE_MESSAGE_VIEW_STORE, NULL); + view->store->view = view; + view->store->sort_field = OTHER_FIELD; + view->store->sort_dir = 1; + view->w = gtk_scrolled_window_new(NULL, NULL); + view->view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(view->store))); + selection = gtk_tree_view_get_selection(view->view); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); + gtk_container_add(GTK_CONTAINER(view->w), GTK_WIDGET(view->view)); + gtk_widget_show(GTK_WIDGET(view->view)); + gtk_widget_show(view->w); + + renderer = gtk_cell_renderer_text_new(); + for (i = 0; i < num_columns; i++) { + struct view_column_record r = column_data[i]; + PangoLayout *layout = gtk_widget_create_pango_layout(GTK_WIDGET(view->view), r.sample_text); + gint width; + GtkTreeViewColumn *column; + pango_layout_get_pixel_size(layout, &width, NULL); + g_object_unref(G_OBJECT(layout)); + width += 12; + column = gtk_tree_view_column_new_with_attributes(r.name, renderer, "text", r.id, NULL); + gtk_tree_view_column_set_clickable(column, TRUE); + gtk_tree_view_column_set_resizable(column, TRUE); + if (r.sort != NULL) { + g_object_set_data(G_OBJECT(column), "column id", GINT_TO_POINTER(r.id)); + g_signal_connect_after(G_OBJECT(column), "clicked", G_CALLBACK(message_view_on_column_click), view); + } + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_set_fixed_width(column, width); + gtk_tree_view_append_column(view->view, column); + } + + g_signal_connect(G_OBJECT(view->view), "button-press-event", G_CALLBACK(message_view_on_button_press), view); + g_signal_connect(G_OBJECT(view->view), "popup-menu", G_CALLBACK(message_view_on_popup_menu), view); + g_signal_connect(G_OBJECT(view->view), "row-activated", G_CALLBACK(message_view_on_row_activate), view); + message_view_update_visible_columns(view); + message_view_update_rows(view); + return view; +} + +void message_view_destroy(message_view_t ** view) +{ + if (view != NULL && *view != NULL) { + /* emit a signal to force all message view dialogs to + disable their scroll buttons. need to pass a + non-NULL path in the signal handler to make GTK + shut up */ + GtkTreePath *path = gtk_tree_path_new_first(); + GtkTreeIter iter; + gtk_tree_model_get_iter(GTK_TREE_MODEL((*view)->store), &iter, path); + g_signal_emit_by_name((*view)->store, "row-changed", path, &iter); + gtk_tree_path_free(path); + seaudit_model_destroy(&(*view)->model); + apol_vector_destroy(&((*view)->store->messages)); + g_free((*view)->filename); + g_free((*view)->export_filename); + /* let glib handle destruction of object */ + g_object_unref((*view)->store); + free(*view); + *view = NULL; + } +} + +seaudit_model_t *message_view_get_model(message_view_t * view) +{ + return view->model; +} + +void message_view_set_model(message_view_t * view, seaudit_model_t * model) +{ + seaudit_model_destroy(&view->model); + view->model = model; + toplevel_update_tabs(view->top); + message_view_update_rows(view); +} + +GtkWidget *message_view_get_view(message_view_t * view) +{ + return view->w; +} + +size_t message_view_get_num_log_messages(message_view_t * view) +{ + if (view->store->messages == NULL) { + return 0; + } + return apol_vector_get_size(view->store->messages); +} + +gboolean message_view_is_message_selected(message_view_t * view) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(view->view); + GList *glist = gtk_tree_selection_get_selected_rows(selection, NULL); + if (glist == NULL) { + return FALSE; + } + g_list_foreach(glist, message_view_gtk_tree_path_free, NULL); + g_list_free(glist); + return TRUE; +} + +void message_view_vector_gtk_tree_path_free(void *elem) +{ + GtkTreePath *path = (GtkTreePath *) elem; + gtk_tree_path_free(path); +} + +void message_view_entire_message(message_view_t * view) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(view->view); + GList *glist = gtk_tree_selection_get_selected_rows(selection, NULL); + GList *l; + apol_vector_t *messages; + if (glist == NULL) { + return; + } + if ((messages = apol_vector_create(message_view_vector_gtk_tree_path_free)) == NULL) { + toplevel_ERR(view->top, "%s", strerror(errno)); + g_list_foreach(glist, message_view_gtk_tree_path_free, NULL); + g_list_free(glist); + return; + } + for (l = glist; l != NULL; l = l->next) { + GtkTreePath *path = gtk_tree_path_copy((GtkTreePath *) l->data); + if (path == NULL || apol_vector_append(messages, path) < 0) { + toplevel_ERR(view->top, "%s", strerror(errno)); + gtk_tree_path_free(path); + g_list_foreach(glist, message_view_gtk_tree_path_free, NULL); + g_list_free(glist); + apol_vector_destroy(&messages); + return; + } + } + /* the following function takes ownership of messages vector */ + message_view_messages_vector(view, messages); + g_list_foreach(glist, message_view_gtk_tree_path_free, NULL); + g_list_free(glist); +} + +void message_view_save(message_view_t * view) +{ + if (view->filename == NULL) { + GtkWindow *parent = toplevel_get_window(view->top); + char *path = util_save_file(parent, "Save View", NULL); + if (path == NULL) { + return; + } + view->filename = path; + } + if (seaudit_model_save_to_file(view->model, view->filename) < 0) { + toplevel_ERR(view->top, "Error saving view: %s", strerror(errno)); + } +} + +void message_view_saveas(message_view_t * view) +{ + GtkWindow *parent = toplevel_get_window(view->top); + char *path = util_save_file(parent, "Save View As", view->filename); + if (path == NULL) { + return; + } + g_free(view->filename); + view->filename = path; + if (seaudit_model_save_to_file(view->model, view->filename) < 0) { + toplevel_ERR(view->top, "Error saving view: %s", strerror(errno)); + } +} + +void message_view_modify(message_view_t * view) +{ + if (modify_view_run(view->top, view)) { + toplevel_update_status_bar(view->top); + } +} + +void message_view_clear(message_view_t * view) +{ + size_t i; + for (i = 0; i < apol_vector_get_size(view->store->messages); i++) { + seaudit_message_t *m = apol_vector_get_element(view->store->messages, i); + seaudit_model_hide_message(view->model, m); + } + message_view_update_rows(view); +} + +/** + * Write to a file all messages in the given vector. Upon success, + * update the view object's export filename. + * + * @param view View containing messages to write. + * @param path Destination to write file, overwriting existing files + * as necessary. + * @param messages Vector of seaudit_message_t. + */ +static void message_view_export_messages_vector(message_view_t * view, char *path, apol_vector_t * messages) +{ + FILE *f = NULL; + size_t i; + g_free(view->export_filename); + view->export_filename = path; + if ((f = fopen(path, "w")) == NULL) { + toplevel_ERR(view->top, "Could not open %s for writing.", path); + goto cleanup; + } + for (i = 0; i < apol_vector_get_size(messages); i++) { + seaudit_message_t *m = apol_vector_get_element(messages, i); + char *s = seaudit_message_to_string(m); + if (s == NULL || fprintf(f, "%s\n", s) < 0) { + toplevel_ERR(view->top, "Error writing string: %s", strerror(errno)); + goto cleanup; + } + free(s); + } + cleanup: + if (f != NULL) { + fclose(f); + } +} + +void message_view_export_all_messages(message_view_t * view) +{ + GtkWindow *parent = toplevel_get_window(view->top); + char *path = util_save_file(parent, "Export Messages", view->export_filename); + apol_vector_t *messages = view->store->messages; + if (path == NULL) { + return; + } + message_view_export_messages_vector(view, path, messages); +} + +void message_view_export_selected_messages(message_view_t * view) +{ + GtkWindow *parent = toplevel_get_window(view->top); + char *path; + GtkTreeSelection *selection = gtk_tree_view_get_selection(view->view); + GList *glist = gtk_tree_selection_get_selected_rows(selection, NULL); + GList *l; + apol_vector_t *messages; + if (glist == NULL) { + return; + } + path = util_save_file(parent, "Export Selected Messages", view->export_filename); + if (path == NULL) { + return; + } + if ((messages = apol_vector_create(NULL)) == NULL) { + toplevel_ERR(view->top, "%s", strerror(errno)); + g_list_foreach(glist, message_view_gtk_tree_path_free, NULL); + g_list_free(glist); + return; + } + for (l = glist; l != NULL; l = l->next) { + GtkTreePath *tree_path = (GtkTreePath *) l->data; + GtkTreeIter iter; + message_view_store_get_iter(GTK_TREE_MODEL(view->store), &iter, tree_path); + if (apol_vector_append(messages, iter.user_data) < 0) { + toplevel_ERR(view->top, "%s", strerror(errno)); + g_list_foreach(glist, message_view_gtk_tree_path_free, NULL); + g_list_free(glist); + apol_vector_destroy(&messages); + return; + } + } + message_view_export_messages_vector(view, path, messages); + g_list_foreach(glist, message_view_gtk_tree_path_free, NULL); + g_list_free(glist); + apol_vector_destroy(&messages); +} + +/** + * Given the name of a column, return its column record data. + */ +static const struct view_column_record *get_record(const char *name) +{ + size_t i; + for (i = 0; i < num_columns; i++) { + const struct view_column_record *r = column_data + i; + if (strcmp(r->name, name) == 0) { + return r; + } + } + return NULL; +} + +void message_view_update_visible_columns(message_view_t * view) +{ + GList *columns, *c; + preferences_t *prefs = toplevel_get_prefs(view->top); + columns = gtk_tree_view_get_columns(view->view); + c = columns; + while (c != NULL) { + GtkTreeViewColumn *vc = GTK_TREE_VIEW_COLUMN(c->data); + const gchar *title = gtk_tree_view_column_get_title(vc); + const struct view_column_record *r = get_record(title); + if (preferences_is_column_visible(prefs, r->id)) { + gtk_tree_view_column_set_visible(vc, TRUE); + } else { + gtk_tree_view_column_set_visible(vc, FALSE); + } + c = g_list_next(c); + } + g_list_free(columns); +} + +void message_view_update_rows(message_view_t * view) +{ + /* remove all existing rows, then insert them back into the + * view according to the model. automatically scroll to the + * same seleceted row(s). */ + GtkTreeSelection *selection; + GList *rows, *r, *selected = NULL; + GtkTreePath *path; + GtkTreeIter iter; + seaudit_log_t *log; + size_t i, num_old_messages = 0, num_new_messages = 0, num_changed; + int first_scroll = 0; + + if (!seaudit_model_is_changed(view->model)) { + return; + } + + /* convert the current selection into a GList of message + * pointers */ + selection = gtk_tree_view_get_selection(view->view); + rows = gtk_tree_selection_get_selected_rows(selection, NULL); + for (r = rows; r != NULL; r = r->next) { + path = (GtkTreePath *) r->data; + message_view_store_get_iter(GTK_TREE_MODEL(view->store), &iter, path); + selected = g_list_prepend(selected, iter.user_data); + } + g_list_foreach(rows, message_view_gtk_tree_path_free, NULL); + g_list_free(rows); + + log = toplevel_get_log(view->top); + if (view->store->messages != NULL) { + num_old_messages = apol_vector_get_size(view->store->messages); + } + apol_vector_destroy(&view->store->messages); + if (log != NULL) { + view->store->messages = seaudit_model_get_messages(log, view->model); + num_new_messages = apol_vector_get_size(view->store->messages); + } + gtk_tree_selection_unselect_all(selection); + + /* mark which rows have been changed/removed/inserted. do + * this as a single pass, rather than a two pass + * mark-and-sweep, for GTK+ tree views can be somewhat slow */ + num_changed = num_old_messages; + if (num_new_messages < num_changed) { + num_changed = num_new_messages; + } + for (i = 0; i < num_changed; i++) { + path = gtk_tree_path_new(); + gtk_tree_path_append_index(path, i); + iter.user_data = apol_vector_get_element(view->store->messages, i); + iter.user_data2 = GINT_TO_POINTER(i); + iter.user_data3 = view; + gtk_tree_model_row_changed(GTK_TREE_MODEL(view->store), path, &iter); + for (r = selected; r != NULL; r = r->next) { + if (r->data == iter.user_data) { + gtk_tree_selection_select_iter(selection, &iter); + if (!first_scroll) { + gtk_tree_view_scroll_to_cell(view->view, path, NULL, FALSE, 0.0, 0.0); + first_scroll = 1; + } + break; + } + } + gtk_tree_path_free(path); + } + if (num_old_messages > num_changed) { + /* delete in reverse order, else indices get renumbered */ + for (i = num_old_messages; i > num_changed; i--) { + path = gtk_tree_path_new(); + gtk_tree_path_append_index(path, i - 1); + gtk_tree_model_row_deleted(GTK_TREE_MODEL(view->store), path); + gtk_tree_path_free(path); + } + } else { + for (; i < num_new_messages; i++) { + path = gtk_tree_path_new(); + gtk_tree_path_append_index(path, i); + iter.user_data = apol_vector_get_element(view->store->messages, i); + iter.user_data2 = GINT_TO_POINTER(i); + iter.user_data3 = view; + gtk_tree_model_row_inserted(GTK_TREE_MODEL(view->store), path, &iter); + for (r = selected; r != NULL; r = r->next) { + if (r->data == iter.user_data) { + gtk_tree_selection_select_iter(selection, &iter); + if (!first_scroll) { + gtk_tree_view_scroll_to_cell(view->view, path, NULL, FALSE, 0.0, 0.0); + first_scroll = 1; + } + break; + } + } + gtk_tree_path_free(path); + } + } + g_list_free(selected); +} diff --git a/seaudit/message_view.h b/seaudit/message_view.h new file mode 100644 index 0000000..5b9bdd6 --- /dev/null +++ b/seaudit/message_view.h @@ -0,0 +1,178 @@ +/** + * @file + * Declaration of a single tab within the main notebook, showing + * all messages within a libseaudit model. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2003-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MESSAGE_VIEW_H +#define MESSAGE_VIEW_H + +#include "toplevel.h" + +#include <gtk/gtk.h> +#include <seaudit/model.h> + +typedef struct message_view message_view_t; + +/** + * Allocate a new view for a particular model. + * + * @param top Handle to the controlling toplevel widget. + * @param model libseaudit model to display. The view takes ownership + * of the model afterwards. + * @param filename Initial filename for the view, or NULL if none. + * This function will duplicate the string. + * + * @return A newly allocated view, or NULL upon error. The caller is + * responsible for calling message_view_destroy() afterwards. + */ +message_view_t *message_view_create(toplevel_t * top, seaudit_model_t * model, const char *filename); + +/** + * Destroy a view and free its memory. This does nothing if the + * pointer is set to NULL. + * + * @param view Reference to a toplevel object. Afterwards the pointer + * will be set to NULL. + */ +void message_view_destroy(message_view_t ** view); + +/** + * Get the message view's model. If the caller changes the model then + * he is responsible for calling message_view_update_rows() to update + * the view. + * + * @param view View whose model to obtain. + * + * @return View's model. + */ +seaudit_model_t *message_view_get_model(message_view_t * view); + +/** + * Replace a message view's model with a different model. The + * previous model will be destroyed. Afterwards the view will update + * its rows. + * + * @param view View to modify. + * @param libseaudit model to display. The view takes ownership + * of the model afterwards. + */ +void message_view_set_model(message_view_t * view, seaudit_model_t * model); + +/** + * Get the message view's widget display. This widget will be placed + * in a container for the user to see. + * + * @param view View whose widget to obtain. + * + * @return View's widget. + */ +GtkWidget *message_view_get_view(message_view_t * view); + +/** + * Return the number of messages currently in this view. + * + * @param view View object to query. + * + * @return Number of log messages, or 0 if no model is associated with + * the view. + */ +size_t message_view_get_num_log_messages(message_view_t * view); + +/** + * Return TRUE if the message view has one or more messages selected, + * FALSE if not. + * + * @param view View object to query. + * + * @return TRUE if any messages are selected. + */ +gboolean message_view_is_message_selected(message_view_t * view); + +/** + * Save the current view to disk. + * + * @param view View to save. + */ +void message_view_save(message_view_t * view); + +/** + * Save the current view to disk under a new filename. + * + * @param view View to save. + */ +void message_view_saveas(message_view_t * view); + +/** + * Modify the settings for this view. + * + * @param view View to modify. + */ +void message_view_modify(message_view_t * view); + +/** + * Clear all messages from this view. + * + * @param view View to clear. + */ +void message_view_clear(message_view_t * view); + +/** + * Export to file all messages in a particular view. + * + * @param view View whose messages to export. + */ +void message_view_export_all_messages(message_view_t * view); + +/** + * Export to file all messages selected in a particular view. + * + * @param view View whose messages to export. + */ +void message_view_export_selected_messages(message_view_t * view); + +/** + * Open a dialog that shows an approximation of the message(s) + * currently selected. + * + * @param view View whose messages to show. + */ +void message_view_entire_message(message_view_t * view); + +/** + * Show/hide columns in a view based upon the user's current + * preferences. + * + * @param view View's columns to update. + */ +void message_view_update_visible_columns(message_view_t * view); + +/** + * (Re)synchronize the messages displayed in a view with its + * underlying model. This needs to be called when a model's filter + * changes or if new messages are found within the model's log. + * + * @param view View's rows to update. + */ +void message_view_update_rows(message_view_t * view); + +#endif diff --git a/seaudit/modify_view.c b/seaudit/modify_view.c new file mode 100644 index 0000000..abfbcc4 --- /dev/null +++ b/seaudit/modify_view.c @@ -0,0 +1,327 @@ +/** + * @file + * Run the dialog to modify a view. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "filter_view.h" +#include "modify_view.h" +#include "utilgui.h" + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <glade/glade.h> + +struct modify_view +{ + toplevel_t *top; + message_view_t *view; + GladeXML *xml; + /** the model currently being modified -- note that this is a + * deep copy of the message_view's model */ + seaudit_model_t *model; + + /** model containing a list of filter names, needs to be + * destroyed afterwords */ + GtkListStore *filter_store; + GtkDialog *dialog; + GtkEntry *name_entry; + GtkComboBox *visible_combo, *match_combo; + GtkTreeView *filter_view; + GtkButton *add_button, *edit_button, *remove_button, *import_button, *export_button; + + /** keep track of most recent filter filename */ + char *filter_filename; +}; + +/** + * Return the currently selected filter, or NULL if no filter is + * selected. + */ +static seaudit_filter_t *modify_view_get_current_filter(struct modify_view *mv) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(mv->filter_view); + GtkTreeIter iter; + seaudit_filter_t *filter; + if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) { + return NULL; + } + gtk_tree_model_get(GTK_TREE_MODEL(mv->filter_store), &iter, 0, &filter, -1); + return filter; +} + +/** + * Rebuild the filter store, preserving the current selection if + * possible. + */ +static void modify_view_update_filter_store(struct modify_view *mv) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(mv->filter_view); + GtkTreeIter old_iter, iter; + gboolean selection_existed = gtk_tree_selection_get_selected(selection, NULL, &old_iter); + const apol_vector_t *filters = seaudit_model_get_filters(mv->model); + size_t i; + gtk_list_store_clear(mv->filter_store); + for (i = 0; i < apol_vector_get_size(filters); i++) { + seaudit_filter_t *filter = apol_vector_get_element(filters, i); + gtk_list_store_append(mv->filter_store, &iter); + gtk_list_store_set(mv->filter_store, &iter, 0, filter, 1, seaudit_filter_get_name(filter), -1); + } + /* initially select the last thing, then reset selection */ + if (i > 0) { + gtk_tree_selection_select_iter(selection, &iter); + } + if (selection_existed && gtk_list_store_iter_is_valid(mv->filter_store, &old_iter)) { + gtk_tree_selection_select_iter(selection, &old_iter); + } +} + +static void modify_view_on_selection_change(GtkTreeSelection * selection, gpointer user_data) +{ + struct modify_view *mv = (struct modify_view *)user_data; + gboolean sens = gtk_tree_selection_get_selected(selection, NULL, NULL); + gtk_widget_set_sensitive(GTK_WIDGET(mv->edit_button), sens); + gtk_widget_set_sensitive(GTK_WIDGET(mv->remove_button), sens); + gtk_widget_set_sensitive(GTK_WIDGET(mv->export_button), sens); +} + +static void modify_view_on_add_click(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + struct modify_view *mv = (struct modify_view *)user_data; + seaudit_filter_t *filter = NULL; + GtkTreeSelection *selection = gtk_tree_view_get_selection(mv->filter_view); + + if ((filter = seaudit_filter_create("Untitled")) == NULL || (seaudit_model_append_filter(mv->model, filter) < 0)) { + toplevel_ERR(mv->top, "Error adding new filter: %s", strerror(errno)); + seaudit_filter_destroy(&filter); + return; + } + /* select the filter that was just created, by removing the + * selection and letting the following function select it */ + gtk_tree_selection_unselect_all(selection); + modify_view_update_filter_store(mv); + filter_view_run(filter, mv->top, GTK_WINDOW(mv->dialog)); + modify_view_update_filter_store(mv); +} + +static void modify_view_on_edit_click(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + struct modify_view *mv = (struct modify_view *)user_data; + seaudit_filter_t *filter = modify_view_get_current_filter(mv); + assert(filter != NULL); + filter_view_run(filter, mv->top, GTK_WINDOW(mv->dialog)); + modify_view_update_filter_store(mv); +} + +static void modify_view_on_remove_click(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + struct modify_view *mv = (struct modify_view *)user_data; + seaudit_filter_t *filter = modify_view_get_current_filter(mv); + assert(filter != NULL); + seaudit_model_remove_filter(mv->model, filter); + modify_view_update_filter_store(mv); +} + +static void modify_view_on_import_click(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + struct modify_view *mv = (struct modify_view *)user_data; + apol_vector_t *paths = util_open_file(GTK_WINDOW(mv->dialog), "Import Filter", mv->filter_filename, 0); + apol_vector_t *filters; + size_t i; + if (paths == NULL) { + return; + } + free(mv->filter_filename); + if ((mv->filter_filename = strdup(apol_vector_get_element(paths, 0))) == NULL) { + toplevel_ERR(mv->top, "Error importing filter: %s", strerror(errno)); + apol_vector_destroy(&paths); + return; + } + apol_vector_destroy(&paths); + if ((filters = seaudit_filter_create_from_file(mv->filter_filename)) == NULL) { + toplevel_ERR(mv->top, "Error importing filter: %s", strerror(errno)); + apol_vector_destroy(&paths); + return; + } + for (i = 0; i < apol_vector_get_size(filters); i++) { + seaudit_filter_t *filter = apol_vector_get_element(filters, i); + seaudit_filter_t *new_f = NULL; + if ((new_f = seaudit_filter_create_from_filter(filter)) == NULL || + seaudit_model_append_filter(mv->model, new_f) < 0) { + toplevel_ERR(mv->top, "Error importing filter: %s", strerror(errno)); + seaudit_filter_destroy(&new_f); + apol_vector_destroy(&filters); + return; + } + modify_view_update_filter_store(mv); + } + apol_vector_destroy(&filters); +} + +static void modify_view_on_export_click(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + struct modify_view *mv = (struct modify_view *)user_data; + char *path = util_save_file(GTK_WINDOW(mv->dialog), "Export Filter", mv->filter_filename); + seaudit_filter_t *filter = modify_view_get_current_filter(mv); + assert(filter != NULL); + if (path == NULL) { + return; + } + g_free(mv->filter_filename); + mv->filter_filename = path; + if (seaudit_filter_save_to_file(filter, mv->filter_filename) < 0) { + toplevel_ERR(mv->top, "Error exporting filter: %s", strerror(errno)); + } +} + +/** + * Make libglade calls to fill in struct modify_view widget + * references. + */ +static void modify_view_init_widgets(struct modify_view *mv) +{ + mv->dialog = GTK_DIALOG(glade_xml_get_widget(mv->xml, "ModifyViewWindow")); + assert(mv->dialog != NULL); + gtk_window_set_transient_for(GTK_WINDOW(mv->dialog), toplevel_get_window(mv->top)); + + mv->name_entry = GTK_ENTRY(glade_xml_get_widget(mv->xml, "ModifyViewNameEntry")); + assert(mv->name_entry != NULL); + + mv->visible_combo = GTK_COMBO_BOX(glade_xml_get_widget(mv->xml, "ModifyViewVisibleCombo")); + mv->match_combo = GTK_COMBO_BOX(glade_xml_get_widget(mv->xml, "ModifyViewMatchCombo")); + assert(mv->visible_combo != NULL && mv->match_combo != NULL); + + mv->filter_view = GTK_TREE_VIEW(glade_xml_get_widget(mv->xml, "ModifyViewFilterView")); + assert(mv->filter_view != NULL); + mv->filter_store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING); + gtk_tree_view_set_model(mv->filter_view, GTK_TREE_MODEL(mv->filter_store)); + + mv->add_button = GTK_BUTTON(glade_xml_get_widget(mv->xml, "ModifyViewAddButton")); + mv->edit_button = GTK_BUTTON(glade_xml_get_widget(mv->xml, "ModifyViewEditButton")); + mv->remove_button = GTK_BUTTON(glade_xml_get_widget(mv->xml, "ModifyViewRemoveButton")); + mv->import_button = GTK_BUTTON(glade_xml_get_widget(mv->xml, "ModifyViewImportButton")); + mv->export_button = GTK_BUTTON(glade_xml_get_widget(mv->xml, "ModifyViewExportButton")); + assert(mv->add_button != NULL && mv->edit_button != NULL && mv->remove_button != NULL && + mv->import_button != NULL && mv->export_button != NULL); +} + +static void modify_view_init_signals(struct modify_view *mv) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes("Filter names", renderer, "text", 1, NULL); + gtk_tree_view_column_set_clickable(column, FALSE); + gtk_tree_view_column_set_resizable(column, FALSE); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_visible(column, TRUE); + gtk_tree_view_append_column(mv->filter_view, column); + + selection = gtk_tree_view_get_selection(mv->filter_view); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); + g_signal_connect(selection, "changed", G_CALLBACK(modify_view_on_selection_change), mv); + + g_signal_connect(mv->add_button, "clicked", G_CALLBACK(modify_view_on_add_click), mv); + g_signal_connect(mv->edit_button, "clicked", G_CALLBACK(modify_view_on_edit_click), mv); + g_signal_connect(mv->remove_button, "clicked", G_CALLBACK(modify_view_on_remove_click), mv); + g_signal_connect(mv->import_button, "clicked", G_CALLBACK(modify_view_on_import_click), mv); + g_signal_connect(mv->export_button, "clicked", G_CALLBACK(modify_view_on_export_click), mv); +} + +/** + * Set up the window to reflect the current view's values. + */ +static void modify_view_init_dialog(struct modify_view *mv) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(mv->filter_view); + GtkTreeIter iter; + + gtk_entry_set_text(mv->name_entry, seaudit_model_get_name(mv->model)); + + gtk_combo_box_set_active(mv->visible_combo, seaudit_model_get_filter_visible(mv->model)); + gtk_combo_box_set_active(mv->match_combo, seaudit_model_get_filter_match(mv->model)); + + gtk_tree_selection_unselect_all(selection); + modify_view_update_filter_store(mv); + /* automatically select the first filter upon dialog + * startup */ + + if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(mv->filter_store), &iter)) { + gtk_tree_selection_select_iter(selection, &iter); + } +} + +int modify_view_run(toplevel_t * top, message_view_t * view) +{ + struct modify_view mv; + seaudit_model_t *orig_model = message_view_get_model(view); + gint response; + int retval; + + memset(&mv, 0, sizeof(mv)); + mv.top = top; + mv.view = view; + mv.xml = glade_xml_new(toplevel_get_glade_xml(top), "ModifyViewWindow", NULL); + mv.filter_filename = NULL; + if ((mv.model = seaudit_model_create_from_model(orig_model)) == NULL) { + toplevel_ERR(mv.top, "Error duplicating model: %s", strerror(errno)); + return 0; + } + modify_view_init_widgets(&mv); + modify_view_init_signals(&mv); + modify_view_init_dialog(&mv); + + do { + response = gtk_dialog_run(mv.dialog); + const gchar *text = gtk_entry_get_text(mv.name_entry); + + if (seaudit_model_set_name(mv.model, text) < 0) { + toplevel_ERR(mv.top, "Could not set name: %s", strerror(errno)); + } + seaudit_model_set_filter_visible(mv.model, gtk_combo_box_get_active(mv.visible_combo)); + seaudit_model_set_filter_match(mv.model, gtk_combo_box_get_active(mv.match_combo)); + if (response == GTK_RESPONSE_APPLY) { + seaudit_model_t *new_model; + if ((new_model = seaudit_model_create_from_model(mv.model)) == NULL) { + toplevel_ERR(mv.top, "Error applying model: %s", strerror(errno)); + break; + } + message_view_set_model(mv.view, new_model); + toplevel_update_status_bar(mv.top); + } + } while (response == GTK_RESPONSE_APPLY); + + if (response == GTK_RESPONSE_OK) { + message_view_set_model(mv.view, mv.model); + retval = 1; + } else { + seaudit_model_destroy(&mv.model); + retval = 0; + } + gtk_widget_destroy(GTK_WIDGET(mv.dialog)); + g_object_unref(mv.filter_store); + return retval; +} diff --git a/seaudit/modify_view.h b/seaudit/modify_view.h new file mode 100644 index 0000000..06993f3 --- /dev/null +++ b/seaudit/modify_view.h @@ -0,0 +1,41 @@ +/** + * @file + * Dialog that allows the user to modify the current view. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MODIFY_VIEW_H +#define MODIFY_VIEW_H + +#include "toplevel.h" +#include "message_view.h" + +/** + * Display and run a dialog that allows the user to modify a view. + * + * @param top Toplevel containing message view. + * @param view Message view to modify. + * + * @return Non-zero if the view changed, zero if not. + */ +int modify_view_run(toplevel_t * top, message_view_t * view); + +#endif diff --git a/seaudit/open_policy_window.c b/seaudit/open_policy_window.c new file mode 100644 index 0000000..ca8a511 --- /dev/null +++ b/seaudit/open_policy_window.c @@ -0,0 +1,469 @@ +/** + * @file + * Run the dialog to allow the user to open a policy. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "open_policy_window.h" +#include "utilgui.h" + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <apol/util.h> +#include <apol/vector.h> +#include <glade/glade.h> +#include <gtk/gtk.h> + +struct open_policy +{ + GladeXML *xml; + toplevel_t *top; + char *last_module_path; + GtkDialog *dialog; + + GtkRadioButton *monolithic_radio, *modular_radio; + GtkLabel *main_label; + + GtkHBox *bottom_hbox; + GtkListStore *module_store; + + GtkEntry *base_entry; + GtkButton *base_browse_button; + + GtkTreeView *module_view; + GtkButton *add_button, *remove_button, *import_button, *export_button; + GtkButton *ok_button; +}; + +enum module_columns +{ + PATH_COLUMN = 0, NAME_COLUMN, VERSION_COLUMN, NUM_COLUMNS +}; + +/** + * Sort columns in alphabetical order. + */ +static gint open_policy_sort(GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b, gpointer user_data) +{ + GValue value_a = { 0 }, value_b = { + 0}; + const char *name_a, *name_b; + int retval, column_id = GPOINTER_TO_INT(user_data); + + gtk_tree_model_get_value(model, a, column_id, &value_a); + gtk_tree_model_get_value(model, b, column_id, &value_b); + name_a = g_value_get_string(&value_a); + name_b = g_value_get_string(&value_b); + retval = strcmp(name_a, name_b); + g_value_unset(&value_a); + g_value_unset(&value_b); + return retval; +} + +static void open_policy_init_widgets(struct open_policy *op) +{ + GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + + op->dialog = GTK_DIALOG(glade_xml_get_widget(op->xml, "PolicyOpenWindow")); + assert(op->dialog != NULL); + gtk_window_set_transient_for(GTK_WINDOW(op->dialog), toplevel_get_window(op->top)); + + op->monolithic_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(op->xml, "monolithic radio")); + op->modular_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(op->xml, "modular radio")); + op->main_label = GTK_LABEL(glade_xml_get_widget(op->xml, "main filename label")); + assert(op->monolithic_radio != NULL && op->modular_radio != NULL && op->main_label != NULL); + + op->base_entry = GTK_ENTRY(glade_xml_get_widget(op->xml, "base entry")); + op->base_browse_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "base browse")); + assert(op->base_entry != NULL && op->base_browse_button != NULL); + + op->bottom_hbox = GTK_HBOX(glade_xml_get_widget(op->xml, "hbox.3")); + assert(op->bottom_hbox != NULL); + + op->module_view = GTK_TREE_VIEW(glade_xml_get_widget(op->xml, "module view")); + assert(op->module_view != NULL); + op->module_store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_view_set_model(op->module_view, GTK_TREE_MODEL(op->module_store)); + + op->add_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "module add button")); + op->remove_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "module remove button")); + op->import_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "module list import button")); + op->export_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "module list export button")); + op->ok_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "ok button")); + assert(op->add_button != NULL && op->remove_button != NULL && + op->import_button != NULL && op->export_button != NULL && op->ok_button != NULL); + + selection = gtk_tree_view_get_selection(op->module_view); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); + + column = gtk_tree_view_column_new_with_attributes("Module", renderer, "text", NAME_COLUMN, NULL); + gtk_tree_view_column_set_sort_column_id(column, NAME_COLUMN); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column(op->module_view, column); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(op->module_store), NAME_COLUMN, open_policy_sort, (gpointer) NAME_COLUMN, + NULL); + + column = gtk_tree_view_column_new_with_attributes("Version", renderer, "text", VERSION_COLUMN, NULL); + gtk_tree_view_column_set_sort_column_id(column, VERSION_COLUMN); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column(op->module_view, column); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(op->module_store), VERSION_COLUMN, open_policy_sort, + (gpointer) VERSION_COLUMN, NULL); + + column = gtk_tree_view_column_new_with_attributes("Path", renderer, "text", PATH_COLUMN, NULL); + gtk_tree_view_column_set_sort_column_id(column, PATH_COLUMN); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column(op->module_view, column); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(op->module_store), PATH_COLUMN, open_policy_sort, (gpointer) PATH_COLUMN, + NULL); + + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(op->module_store), NAME_COLUMN, GTK_SORT_ASCENDING); +} + +static void open_policy_on_policy_type_toggle(GtkToggleButton * widget, gpointer user_data) +{ + struct open_policy *op = (struct open_policy *)user_data; + /* clicking on the radio buttons emit two toggle signals, one for + * the original button and one for the new one. thus only need to + * handle half of all signals */ + if (!gtk_toggle_button_get_active(widget)) { + return; + } + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(op->monolithic_radio))) { + gtk_widget_set_sensitive(GTK_WIDGET(op->bottom_hbox), FALSE); + gtk_label_set_markup(op->main_label, "<b>Policy Filename:</b>"); + } else { + gtk_widget_set_sensitive(GTK_WIDGET(op->bottom_hbox), TRUE); + gtk_label_set_markup(op->main_label, "<b>Base Filename:</b>"); + } +} + +static void open_policy_on_entry_event_after(GtkWidget * widget __attribute__ ((unused)), GdkEvent * event + __attribute__ ((unused)), gpointer user_data) +{ + struct open_policy *op = (struct open_policy *)user_data; + gboolean sens = FALSE; + if (strcmp(gtk_entry_get_text(op->base_entry), "") != 0) { + sens = TRUE; + } + gtk_widget_set_sensitive(GTK_WIDGET(op->export_button), sens); + gtk_widget_set_sensitive(GTK_WIDGET(op->ok_button), sens); +} + +static void open_policy_on_base_browse_click(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + struct open_policy *op = (struct open_policy *)user_data; + const char *current_path = gtk_entry_get_text(op->base_entry); + char *title; + apol_vector_t *paths; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(op->monolithic_radio))) { + title = "Open Monolithic Policy"; + } else { + title = "Open Modular Policy"; + } + if (strcmp(current_path, "") == 0) { + current_path = NULL; + } + if ((paths = util_open_file(GTK_WINDOW(op->dialog), title, current_path, 0)) == NULL) { + return; + } + gtk_entry_set_text(op->base_entry, apol_vector_get_element(paths, 0)); + apol_vector_destroy(&paths); +} + +/** + * Attempt to load a module and retrieve its name and version. Upon + * success add an entry to the list store. + * + * @return 0 on success, < 0 on error. + */ +static int open_policy_load_module(struct open_policy *op, const char *path) +{ + const char *module_name, *version_string; + int module_type; + qpol_module_t *module = NULL; + GtkTreeIter iter; + + /* check if modulue was already loaded */ + gboolean iter_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(op->module_store), &iter); + while (iter_valid) { + char *s; + gtk_tree_model_get(GTK_TREE_MODEL(op->module_store), &iter, PATH_COLUMN, &s, -1); + if (strcmp(s, path) == 0) { + toplevel_ERR(op->top, "Module %s was already added.", path); + return -1; + } + iter_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(op->module_store), &iter); + } + if ((qpol_module_create_from_file(path, &module)) < 0) { + toplevel_ERR(op->top, "Error opening module %s: %s", path, strerror(errno)); + return -1; + } + if (qpol_module_get_name(module, &module_name) < 0 || + qpol_module_get_version(module, &version_string) < 0 || qpol_module_get_type(module, &module_type) < 0) { + toplevel_ERR(op->top, "Error reading module %s: %s", path, strerror(errno)); + qpol_module_destroy(&module); + return -1; + } + if (module_type != QPOL_MODULE_OTHER) { + toplevel_ERR(op->top, "%s is not a loadable module.", path); + qpol_module_destroy(&module); + return -1; + } + gtk_list_store_append(op->module_store, &iter); + gtk_list_store_set(op->module_store, &iter, PATH_COLUMN, path, NAME_COLUMN, module_name, VERSION_COLUMN, version_string, + -1); + qpol_module_destroy(&module); + return 0; +} + +static void open_policy_on_add_click(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + struct open_policy *op = (struct open_policy *)user_data; + apol_vector_t *paths; + const char *path = NULL, *prev_path; + size_t i; + if ((prev_path = op->last_module_path) == NULL) { + prev_path = gtk_entry_get_text(op->base_entry); + if (strcmp(prev_path, "") == 0) { + prev_path = NULL; + } + } + paths = util_open_file(GTK_WINDOW(op->dialog), "Open Module", prev_path, 1); + if (paths == NULL) { + return; + } + int all_succeed = 1; + for (i = 0; i < apol_vector_get_size(paths); i++) { + path = apol_vector_get_element(paths, i); + if (open_policy_load_module(op, path) < 0) { + all_succeed = 0; + } + } + if (all_succeed) { + assert(path != NULL); + free(op->last_module_path); + op->last_module_path = strdup(path); + } + apol_vector_destroy(&paths); +} + +static void open_policy_on_remove_click(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + struct open_policy *op = (struct open_policy *)user_data; + GtkTreeSelection *selection = gtk_tree_view_get_selection(op->module_view); + GtkTreeIter iter; + char *path; + if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) { + return; + } + gtk_tree_model_get(GTK_TREE_MODEL(op->module_store), &iter, 0, &path, -1); + gtk_list_store_remove(op->module_store, &iter); +} + +static void open_policy_on_import_click(GtkButton * button __attribute__ ((unused)), gpointer user_data); +static void open_policy_on_export_click(GtkButton * button __attribute__ ((unused)), gpointer user_data); + +static void open_policy_on_selection_change(GtkTreeSelection * selection, gpointer user_data) +{ + struct open_policy *op = (struct open_policy *)user_data; + gboolean sens = gtk_tree_selection_get_selected(selection, NULL, NULL); + gtk_widget_set_sensitive(GTK_WIDGET(op->remove_button), sens); +} + +static void open_policy_init_signals(struct open_policy *op) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(op->module_view); + g_signal_connect(op->monolithic_radio, "toggled", G_CALLBACK(open_policy_on_policy_type_toggle), op); + g_signal_connect(op->modular_radio, "toggled", G_CALLBACK(open_policy_on_policy_type_toggle), op); + g_signal_connect(op->base_entry, "event-after", G_CALLBACK(open_policy_on_entry_event_after), op); + g_signal_connect(op->base_browse_button, "clicked", G_CALLBACK(open_policy_on_base_browse_click), op); + g_signal_connect(selection, "changed", G_CALLBACK(open_policy_on_selection_change), op); + g_signal_connect(op->add_button, "clicked", G_CALLBACK(open_policy_on_add_click), op); + g_signal_connect(op->remove_button, "clicked", G_CALLBACK(open_policy_on_remove_click), op); + g_signal_connect(op->import_button, "clicked", G_CALLBACK(open_policy_on_import_click), op); + g_signal_connect(op->export_button, "clicked", G_CALLBACK(open_policy_on_export_click), op); +} + +static void open_policy_init_values(struct open_policy *op, const apol_policy_path_t * path) +{ + if (path != NULL) { + apol_policy_path_type_e path_type = apol_policy_path_get_type(path); + const char *primary_path = apol_policy_path_get_primary(path); + gtk_entry_set_text(op->base_entry, primary_path); + gtk_list_store_clear(op->module_store); + if (path_type == APOL_POLICY_PATH_TYPE_MONOLITHIC) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(op->monolithic_radio), TRUE); + } else if (path_type == APOL_POLICY_PATH_TYPE_MODULAR) { + const apol_vector_t *modules = apol_policy_path_get_modules(path); + size_t i; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(op->modular_radio), TRUE); + for (i = 0; i < apol_vector_get_size(modules); i++) { + char *module_path = apol_vector_get_element(modules, i); + if (open_policy_load_module(op, module_path) < 0) { + break; + } + } + } else { + /* should never get here */ + toplevel_ERR(op->top, "Unknown policy path type %d.", path_type); + } + } +} + +/** + * Build the policy path corresponding to the user's inputs on this + * dialog. + * + * @return path for the dialog, or NULL upon error. The caller must + * call apol_policy_path_destroy() afterwards. + */ +static apol_policy_path_t *open_policy_build_path(struct open_policy *op) +{ + const char *primary_path = gtk_entry_get_text(op->base_entry); + apol_policy_path_type_e path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC; + apol_vector_t *modules = NULL; + apol_policy_path_t *path = NULL; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(op->modular_radio))) { + path_type = APOL_POLICY_PATH_TYPE_MODULAR; + GtkTreeIter iter; + if ((modules = apol_vector_create(free)) == NULL) { + toplevel_ERR(op->top, "%s", strerror(errno)); + return NULL; + } + if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(op->module_store), &iter)) { + do { + GValue value = { 0 }; + char *module_path; + gtk_tree_model_get_value(GTK_TREE_MODEL(op->module_store), &iter, PATH_COLUMN, &value); + module_path = g_value_dup_string(&value); + g_value_unset(&value); + if (apol_vector_append(modules, module_path) < 0) { + toplevel_ERR(op->top, "%s", strerror(errno)); + free(module_path); + apol_vector_destroy(&modules); + return NULL; + } + } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(op->module_store), &iter)); + } + } + path = apol_policy_path_create(path_type, primary_path, modules); + apol_vector_destroy(&modules); + if (path == NULL) { + toplevel_ERR(op->top, "%s", strerror(errno)); + return NULL; + } + return path; +} + +static void open_policy_on_import_click(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + struct open_policy *op = (struct open_policy *)user_data; + apol_vector_t *paths = NULL; + apol_policy_path_t *ppath = NULL; + const char *path = NULL, *prev_path; + if ((prev_path = op->last_module_path) == NULL) { + prev_path = gtk_entry_get_text(op->base_entry); + if (strcmp(prev_path, "") == 0) { + prev_path = NULL; + } + } + paths = util_open_file(GTK_WINDOW(op->dialog), "Import Policy List", prev_path, 1); + if (paths == NULL) { + return; + } + path = apol_vector_get_element(paths, 0); + ppath = apol_policy_path_create_from_file(path); + if (ppath == NULL) { + toplevel_ERR(op->top, "Error importing policy list %s: %s", path, strerror(errno)); + goto cleanup; + } + open_policy_init_values(op, ppath); + free(op->last_module_path); + op->last_module_path = strdup(path); + cleanup: + apol_vector_destroy(&paths); + apol_policy_path_destroy(&ppath); +} + +static void open_policy_on_export_click(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + struct open_policy *op = (struct open_policy *)user_data; + char *path = util_save_file(GTK_WINDOW(op->dialog), "Export Policy List", NULL); + apol_policy_path_t *ppath = NULL; + if (path == NULL) { + return; + } + ppath = open_policy_build_path(op); + if (ppath == NULL) { + goto cleanup; + } + if (apol_policy_path_to_file(ppath, path) < 0) { + toplevel_ERR(op->top, "Error exporting policy list %s: %s", path, strerror(errno)); + } + cleanup: + g_free(path); + apol_policy_path_destroy(&ppath); +} + +void open_policy_window_run(toplevel_t * top, const apol_policy_path_t * path, apol_policy_path_t ** selection) +{ + struct open_policy op; + gint response; + apol_policy_path_t *input; + + memset(&op, 0, sizeof(op)); + op.top = top; + op.xml = glade_xml_new(toplevel_get_glade_xml(top), "PolicyOpenWindow", NULL); + + open_policy_init_widgets(&op); + open_policy_init_signals(&op); + open_policy_init_values(&op, path); + if (selection != NULL) { + *selection = NULL; + } + + while (1) { + response = gtk_dialog_run(op.dialog); + if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT) { + break; + } + if ((input = open_policy_build_path(&op)) == NULL) { + continue; + } + if (selection == NULL) { + if (toplevel_open_policy(op.top, input) == 0) { + break; + } + } else { + *selection = input; + break; + } + } + gtk_widget_destroy(GTK_WIDGET(op.dialog)); + free(op.last_module_path); + g_object_unref(op.module_store); +} diff --git a/seaudit/open_policy_window.h b/seaudit/open_policy_window.h new file mode 100644 index 0000000..2b57e9d --- /dev/null +++ b/seaudit/open_policy_window.h @@ -0,0 +1,46 @@ +/** + * @file + * Dialog that allows the user to select either a monolithic policy + * or a base policy + list of modules. The dialog may also actually + * open the policy or it may be used simply as a file chooser. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef OPEN_POLICY_WINDOW_H +#define OPEN_POLICY_WINDOW_H + +#include "toplevel.h" +#include <apol/policy-path.h> + +/** + * Display and run a dialog that allows the user open a policy, either + * a monolithic or a modular policy. + * + * @param top Toplevel for the application. + * @param path If not NULL, the default path for the policy. + * @param selection If non-NULL, then allocate and set this reference + * pointer to the path selected; caller must call + * apol_policy_path_destroy() afterwards. Otherwise if NULL then + * actually load the policy and set the path tloplvel_open_policy(). + */ +void open_policy_window_run(toplevel_t * top, const apol_policy_path_t * path, apol_policy_path_t ** selection); + +#endif diff --git a/seaudit/policy_components_view.c b/seaudit/policy_components_view.c new file mode 100644 index 0000000..c2f1d02 --- /dev/null +++ b/seaudit/policy_components_view.c @@ -0,0 +1,373 @@ +/** + * @file + * Run the dialog to select from lists of strings. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "policy_components_view.h" + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <apol/util.h> +#include <glade/glade.h> + +struct polcomp_view +{ + GladeXML *xml; + toplevel_t *top; + apol_vector_t *log_items, *policy_items, *both_items, *included_items; + GtkDialog *dialog; + + GtkRadioButton *log_radio, *policy_radio, *both_radio; + + GtkListStore *master_store; + GtkTreeModel *inc_store, *exc_store; + GtkTreeView *inc_view, *exc_view; + GtkButton *inc_select_button, *inc_unselect_button, *exc_select_button, *exc_unselect_button; + + GtkButton *to_exc_button, *to_inc_button; +}; + +enum polcom_columns +{ + POINTER_COLUMN = 0, NAME_COLUMN, ISLOG_COLUMN, ISPOLICY_COLUMN, ISINC_COLUMN +}; + +static void policy_components_view_init_widgets(struct polcomp_view *pv) +{ + pv->dialog = GTK_DIALOG(glade_xml_get_widget(pv->xml, "PolicyComponentListsWindow")); + assert(pv->dialog != NULL); + gtk_window_set_transient_for(GTK_WINDOW(pv->dialog), toplevel_get_window(pv->top)); + + pv->log_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompLogRadio")); + pv->policy_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompPolicyRadio")); + pv->both_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompBothRadio")); + assert(pv->log_radio != NULL && pv->policy_radio != NULL && pv->both_radio != NULL); + + pv->inc_view = GTK_TREE_VIEW(glade_xml_get_widget(pv->xml, "PolicyCompIncView")); + pv->exc_view = GTK_TREE_VIEW(glade_xml_get_widget(pv->xml, "PolicyCompExcView")); + assert(pv->inc_view != NULL && pv->exc_view != NULL); + + pv->inc_select_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompIncSelectButton")); + pv->inc_unselect_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompIncUnselectButton")); + pv->exc_select_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompExcSelectButton")); + pv->exc_unselect_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompExcUnselectButton")); + assert(pv->inc_select_button != NULL && pv->inc_unselect_button && + pv->exc_select_button != NULL && pv->exc_unselect_button); + + pv->to_exc_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompToExcButton")); + pv->to_inc_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompToIncButton")); + assert(pv->to_exc_button != NULL && pv->to_inc_button); +} + +/******************** functions to build the lists ********************/ + +/** + * Determine if a particular row should be visible based upon the + * current radio button selection. If the current item source is + * 'Log' then return TRUE if the islog attribute is enabled. If the + * source is 'Policy' then return TRUE if ispolicy is enabled. + * Otherwise the item is visible by default. + */ +static gboolean policy_components_view_is_visible_radio(struct polcomp_view *pv, gboolean islog, gboolean ispolicy) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pv->log_radio))) { + return islog; + } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pv->policy_radio))) { + return ispolicy; + } + return TRUE; +} + +/** + * Callback invoked to determine if a row should be visible to the + * included view. + */ +static gboolean policy_components_view_is_visible_included(GtkTreeModel * model, GtkTreeIter * iter, gpointer data) +{ + struct polcomp_view *pv = (struct polcomp_view *)data; + gboolean islog, ispolicy, isinc; + gtk_tree_model_get(model, iter, ISLOG_COLUMN, &islog, ISPOLICY_COLUMN, &ispolicy, ISINC_COLUMN, &isinc, -1); + if (!isinc) { + return FALSE; + } + return policy_components_view_is_visible_radio(pv, islog, ispolicy); +} + +/** + * Callback invoked to determine if a row should be visible in the + * included view. + */ +static gboolean policy_components_view_is_visible_excluded(GtkTreeModel * model, GtkTreeIter * iter, gpointer data) +{ + struct polcomp_view *pv = (struct polcomp_view *)data; + gboolean islog, ispolicy, isinc; + gtk_tree_model_get(model, iter, ISLOG_COLUMN, &islog, ISPOLICY_COLUMN, &ispolicy, ISINC_COLUMN, &isinc, -1); + if (isinc) { + return FALSE; + } + return policy_components_view_is_visible_radio(pv, islog, ispolicy); +} + +static void policy_components_view_init_lists(struct polcomp_view *pv) +{ + GtkTreeIter iter; + size_t i, j; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + + if ((pv->both_items = apol_vector_create_from_vector(pv->log_items, NULL, NULL, NULL)) == NULL) { + toplevel_ERR(pv->top, "Error generating union list: %s", strerror(errno)); + return; + } + if (pv->policy_items == NULL) { + gtk_widget_set_sensitive(GTK_WIDGET(pv->policy_radio), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(pv->both_radio), FALSE); + } else { + if (apol_vector_cat(pv->both_items, pv->policy_items) < 0) { + toplevel_ERR(pv->top, "Error generating union list: %s", strerror(errno)); + return; + } + apol_vector_sort_uniquify(pv->both_items, apol_str_strcmp, NULL); + } + pv->master_store = + gtk_list_store_new(ISINC_COLUMN + 1, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN); + for (i = 0; i < apol_vector_get_size(pv->both_items); i++) { + char *s = apol_vector_get_element(pv->both_items, i); + gboolean is_log = FALSE, is_policy = FALSE, is_included = FALSE; + if (apol_vector_get_index(pv->log_items, s, NULL, NULL, &j) == 0) { + is_log = TRUE; + } + if (pv->policy_items != NULL && apol_vector_get_index(pv->policy_items, s, NULL, NULL, &j) == 0) { + is_policy = TRUE; + } + if (apol_vector_get_index(pv->included_items, s, apol_str_strcmp, NULL, &j) == 0) { + is_included = TRUE; + } + gtk_list_store_append(pv->master_store, &iter); + gtk_list_store_set(pv->master_store, &iter, + POINTER_COLUMN, s, + NAME_COLUMN, s, ISLOG_COLUMN, is_log, ISPOLICY_COLUMN, is_policy, ISINC_COLUMN, is_included, -1); + } + + pv->inc_store = gtk_tree_model_filter_new(GTK_TREE_MODEL(pv->master_store), NULL); + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(pv->inc_store), policy_components_view_is_visible_included, pv, + NULL); + pv->exc_store = gtk_tree_model_filter_new(GTK_TREE_MODEL(pv->master_store), NULL); + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(pv->exc_store), policy_components_view_is_visible_excluded, pv, + NULL); + gtk_tree_view_set_model(pv->inc_view, pv->inc_store); + gtk_tree_view_set_model(pv->exc_view, pv->exc_store); + + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes("Item names", renderer, "text", NAME_COLUMN, NULL); + gtk_tree_view_column_set_clickable(column, FALSE); + gtk_tree_view_column_set_resizable(column, FALSE); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_visible(column, TRUE); + gtk_tree_view_append_column(pv->inc_view, column); + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes("Item names", renderer, "text", NAME_COLUMN, NULL); + gtk_tree_view_column_set_clickable(column, FALSE); + gtk_tree_view_column_set_resizable(column, FALSE); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_visible(column, TRUE); + gtk_tree_view_append_column(pv->exc_view, column); + + selection = gtk_tree_view_get_selection(pv->inc_view); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); + selection = gtk_tree_view_get_selection(pv->exc_view); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); +} + +/******************** signal handlers ********************/ + +static void policy_components_view_on_source_toggle(GtkToggleButton * widget, gpointer user_data) +{ + struct polcomp_view *pv = (struct polcomp_view *)user_data; + /* clicking on the radio buttons emit two toggle signals, one for + * the original button and one for the new one. thus only need to + * handle half of all signals */ + if (!gtk_toggle_button_get_active(widget)) { + return; + } + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->inc_store)); + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->exc_store)); +} + +static void policy_components_gtk_tree_path_free(gpointer data, gpointer user_data __attribute__ ((unused))) +{ + gtk_tree_path_free((GtkTreePath *) data); +} + +static void policy_components_gtk_tree_row_reference_free(gpointer data, gpointer user_data __attribute__ ((unused))) +{ + gtk_tree_row_reference_free((GtkTreeRowReference *) data); +} + +static void policy_components_view_on_to_exc_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct polcomp_view *pv = (struct polcomp_view *)user_data; + GtkTreeSelection *selection = gtk_tree_view_get_selection(pv->inc_view); + GList *r, *rows = gtk_tree_selection_get_selected_rows(selection, NULL); + GList *refs = NULL; + + /* use references because the filtered store will be changing + * as master_store's ISINC_COLUMN value changes */ + for (r = rows; r != NULL; r = r->next) { + GtkTreePath *path = (GtkTreePath *) r->data; + GtkTreeRowReference *ref = gtk_tree_row_reference_new(pv->inc_store, path); + refs = g_list_prepend(refs, ref); + } + + for (r = refs; r != NULL; r = r->next) { + GtkTreeRowReference *ref = (GtkTreeRowReference *) r->data; + GtkTreePath *path = gtk_tree_row_reference_get_path(ref); + GtkTreeIter iter, child_iter; + char *name; + size_t i = 0; + int retval; + gtk_tree_model_get_iter(pv->inc_store, &iter, path); + gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(pv->inc_store), &child_iter, &iter); + gtk_tree_model_get(GTK_TREE_MODEL(pv->master_store), &child_iter, NAME_COLUMN, &name, -1); + gtk_list_store_set(pv->master_store, &child_iter, ISINC_COLUMN, FALSE, -1); + retval = apol_vector_get_index(pv->included_items, name, apol_str_strcmp, NULL, &i); + assert(retval == 0); + name = apol_vector_get_element(pv->included_items, i); + free(name); + apol_vector_remove(pv->included_items, i); + } + + g_list_foreach(refs, policy_components_gtk_tree_row_reference_free, NULL); + g_list_free(refs); + g_list_foreach(rows, policy_components_gtk_tree_path_free, NULL); + g_list_free(rows); + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->inc_store)); + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->exc_store)); +} + +static void policy_components_view_on_to_inc_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + struct polcomp_view *pv = (struct polcomp_view *)user_data; + GtkTreeSelection *selection = gtk_tree_view_get_selection(pv->exc_view); + GList *r, *rows = gtk_tree_selection_get_selected_rows(selection, NULL); + + /* use references because the filtered store will be changing + * as master_store's ISINC_COLUMN value changes */ + GList *refs = NULL; + for (r = rows; r != NULL; r = r->next) { + GtkTreePath *path = (GtkTreePath *) r->data; + GtkTreeRowReference *ref = gtk_tree_row_reference_new(pv->exc_store, path); + refs = g_list_prepend(refs, ref); + } + + for (r = refs; r != NULL; r = r->next) { + GtkTreeRowReference *ref = (GtkTreeRowReference *) r->data; + GtkTreePath *path = gtk_tree_row_reference_get_path(ref); + GtkTreeIter iter, child_iter; + char *name; + gtk_tree_model_get_iter(pv->exc_store, &iter, path); + gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(pv->exc_store), &child_iter, &iter); + gtk_tree_model_get(GTK_TREE_MODEL(pv->master_store), &child_iter, NAME_COLUMN, &name, -1); + gtk_list_store_set(pv->master_store, &child_iter, ISINC_COLUMN, TRUE, -1); + apol_vector_append(pv->included_items, strdup(name)); + } + apol_vector_sort_uniquify(pv->included_items, apol_str_strcmp, NULL); + g_list_foreach(refs, policy_components_gtk_tree_row_reference_free, NULL); + g_list_free(refs); + g_list_foreach(rows, policy_components_gtk_tree_path_free, NULL); + g_list_free(rows); + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->inc_store)); + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->exc_store)); +} + +static void policy_components_view_on_select_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + GtkTreeView *tv = GTK_TREE_VIEW(user_data); + GtkTreeSelection *selection = gtk_tree_view_get_selection(tv); + gtk_tree_selection_select_all(selection); +} + +static void policy_components_view_on_unselect_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data) +{ + GtkTreeView *tv = GTK_TREE_VIEW(user_data); + GtkTreeSelection *selection = gtk_tree_view_get_selection(tv); + gtk_tree_selection_unselect_all(selection); +} + +static void policy_components_view_init_signals(struct polcomp_view *pv) +{ + g_signal_connect(pv->log_radio, "toggled", G_CALLBACK(policy_components_view_on_source_toggle), pv); + g_signal_connect(pv->policy_radio, "toggled", G_CALLBACK(policy_components_view_on_source_toggle), pv); + g_signal_connect(pv->both_radio, "toggled", G_CALLBACK(policy_components_view_on_source_toggle), pv); + g_signal_connect(pv->to_exc_button, "clicked", G_CALLBACK(policy_components_view_on_to_exc_click), pv); + g_signal_connect(pv->to_inc_button, "clicked", G_CALLBACK(policy_components_view_on_to_inc_click), pv); + g_signal_connect(pv->inc_select_button, "clicked", G_CALLBACK(policy_components_view_on_select_click), pv->inc_view); + g_signal_connect(pv->inc_unselect_button, "clicked", G_CALLBACK(policy_components_view_on_unselect_click), pv->inc_view); + g_signal_connect(pv->exc_select_button, "clicked", G_CALLBACK(policy_components_view_on_select_click), pv->exc_view); + g_signal_connect(pv->exc_unselect_button, "clicked", G_CALLBACK(policy_components_view_on_unselect_click), pv->exc_view); +} + +apol_vector_t *policy_components_view_run(toplevel_t * top, GtkWindow * parent __attribute__ ((unused)), const char *title, + apol_vector_t * log_items, apol_vector_t * policy_items, apol_vector_t * included) +{ + struct polcomp_view pv; + gint response; + + memset(&pv, 0, sizeof(pv)); + pv.top = top; + pv.xml = glade_xml_new(toplevel_get_glade_xml(top), "PolicyComponentListsWindow", NULL); + pv.log_items = log_items; + pv.policy_items = policy_items; + if (included == NULL) { + pv.included_items = apol_vector_create(free); + } else { + pv.included_items = apol_vector_create_from_vector(included, apol_str_strdup, NULL, free); + } + apol_vector_destroy(&included); + if (pv.included_items == NULL) { + toplevel_ERR(pv.top, "Error creating dialog: %s", strerror(errno)); + return NULL; + } + + policy_components_view_init_widgets(&pv); + policy_components_view_init_lists(&pv); + policy_components_view_init_signals(&pv); + gtk_window_set_title(GTK_WINDOW(pv.dialog), title); + do { + response = gtk_dialog_run(pv.dialog); + } while (response != GTK_RESPONSE_CLOSE); + + gtk_widget_destroy(GTK_WIDGET(pv.dialog)); + g_object_unref(pv.master_store); + g_object_unref(pv.inc_store); + g_object_unref(pv.exc_store); + apol_vector_destroy(&pv.both_items); + if (apol_vector_get_size(pv.included_items) == 0) { + apol_vector_destroy(&pv.included_items); + return NULL; + } + return pv.included_items; +} diff --git a/seaudit/policy_components_view.h b/seaudit/policy_components_view.h new file mode 100644 index 0000000..eece365 --- /dev/null +++ b/seaudit/policy_components_view.h @@ -0,0 +1,56 @@ +/** + * @file + * Dialog that shows two columns of strings, an included list and an + * excluded list. The user then moves items between the two lists. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef POLICY_COMPONENTS_VIEW_H +#define POLICY_COMPONENTS_VIEW_H + +#include "toplevel.h" +#include <apol/vector.h> +#include <gtk/gtk.h> + +/** + * Display and run a dialog that allows the user to select items from + * arrays of strings. + * + * @param top Toplevel containing message view. + * @param parent Parent window upon which to center this dialog. + * @param title Title for the dialog window. + * @param log_items Vector of strings that the log has. The function + * will not modify this vector. + * @param policy_items Vector of strings that the policy has. If + * NULL, then no policy is loaded. The function will not modify this + * vector. + * @param included List of strings to be included. The strings are + * assumed to have been strdup()ped from some other source. This + * function takes ownership of the vector and its contents. + * + * @return A vector newly allocated strings corresponding to the items + * to be included, or NULL upon error. The caller must call + * apol_vector_destroy() upon the return value. + */ +apol_vector_t *policy_components_view_run(toplevel_t * top, GtkWindow * parent, const char *title, + apol_vector_t * log_items, apol_vector_t * policy_items, apol_vector_t * included); + +#endif diff --git a/seaudit/policy_view.c b/seaudit/policy_view.c new file mode 100644 index 0000000..5fdc9c0 --- /dev/null +++ b/seaudit/policy_view.c @@ -0,0 +1,573 @@ +/** + * @file + * Implementation of policy viewer. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2003-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "policy_view.h" +#include "utilgui.h" + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <apol/policy-query.h> +#include <apol/util.h> +#include <glade/glade.h> +#include <qpol/policy.h> +#include <qpol/policy_extend.h> +#include <seaudit/avc_message.h> + +/* these are for mmaping the policy file */ +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +struct policy_view +{ + toplevel_t *top; + GladeXML *xml; + GtkWindow *window; + GtkNotebook *notebook; + GtkToggleButton *stype_check, *ttype_check, *class_check; + GtkComboBoxEntry *stype_combo, *ttype_combo, *class_combo; + GtkToggleButton *stype_direct, *ttype_direct; + GtkListStore *type_model, *class_model; + apol_vector_t *type_list, *class_list; + GtkTextBuffer *rules_text, *policy_text; + char *policy_text_mmap; + size_t policy_text_len; +}; + +/** + * Display a vector of rules (either qpol_avrule_t or + * qpol_syn_avrule_t) in the rules text buffer. + */ +static void policy_view_display_avrule_results(policy_view_t * pv, apol_vector_t * results, int is_syn_rules) +{ + apol_policy_t *policy = toplevel_get_policy(pv->top); + qpol_policy_t *qp = apol_policy_get_qpol(policy); + GtkTextIter start, end; + char *string, buf[64]; + size_t i; + + gtk_text_buffer_get_start_iter(pv->rules_text, &start); + gtk_text_buffer_get_end_iter(pv->rules_text, &end); + gtk_text_buffer_delete(pv->rules_text, &start, &end); + + snprintf(buf, 64, "%zd rule(s) match the search criteria.\n\n", apol_vector_get_size(results)); + gtk_text_buffer_insert_with_tags_by_name(pv->rules_text, &end, buf, -1, "summary", NULL); + for (i = 0; i < apol_vector_get_size(results); i++) { + if (!is_syn_rules) { + qpol_avrule_t *rule = apol_vector_get_element(results, i); + string = apol_avrule_render(policy, rule); + } else { + qpol_syn_avrule_t *rule = apol_vector_get_element(results, i); + string = apol_syn_avrule_render(policy, rule); + unsigned long lineno; + if (qpol_policy_has_capability(qp, QPOL_CAP_LINE_NUMBERS)) { + qpol_syn_avrule_get_lineno(qp, rule, &lineno); + sprintf(buf, "%ld", lineno); + gtk_text_buffer_insert_with_tags_by_name(pv->rules_text, &end, "[", -1, "rule", NULL); + gtk_text_buffer_insert_with_tags_by_name(pv->rules_text, &end, buf, -1, "line-number", NULL); + gtk_text_buffer_insert_with_tags_by_name(pv->rules_text, &end, "] ", -1, "rule", NULL); + } + } + if (string == NULL) { + toplevel_ERR(pv->top, "Error displaying rule: %s", strerror(errno)); + return; + } + gtk_text_buffer_insert_with_tags_by_name(pv->rules_text, &end, string, -1, "rule", NULL); + free(string); + gtk_text_buffer_insert(pv->rules_text, &end, "\n", -1); + } +} + +struct find_terules_datum +{ + apol_policy_t *policy; + apol_avrule_query_t *query; + apol_vector_t *results; + int is_syn_rules, retval; + progress_t *progress; +}; + +/** + * Perform the rule query within a thread. + */ +static gpointer policy_view_find_terules_runner(gpointer data) +{ + struct find_terules_datum *run = (struct find_terules_datum *)data; + run->results = NULL; + qpol_policy_t *q = apol_policy_get_qpol(run->policy); + if (!qpol_policy_has_capability(q, QPOL_CAP_SYN_RULES)) { + progress_update(run->progress, "Searching AV rules"); + run->retval = apol_avrule_get_by_query(run->policy, run->query, &run->results); + run->is_syn_rules = 0; + } else { + qpol_policy_build_syn_rule_table(q); + progress_update(run->progress, "Searching syntactic AV rules"); + run->retval = apol_syn_avrule_get_by_query(run->policy, run->query, &run->results); + run->is_syn_rules = 1; + } + if (run->retval == 0) { + progress_done(run->progress); + } else { + progress_abort(run->progress, NULL); + } + return NULL; +} + +/** + * Collect the rule search criteria into an avrule_query_t object. + * Actually execute the query in a progress thread. + */ +static void policy_view_on_find_terules_click(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + policy_view_t *pv = (policy_view_t *) user_data; + apol_policy_t *policy = toplevel_get_policy(pv->top); + apol_avrule_query_t *query = apol_avrule_query_create(); + apol_avrule_query_set_regex(policy, query, 1); + struct find_terules_datum run; + const char *s; + gboolean only_direct; + apol_avrule_query_set_rules(policy, query, QPOL_RULE_ALLOW); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pv->stype_check))) { + s = util_combo_box_get_active_text(GTK_COMBO_BOX(pv->stype_combo)); + only_direct = gtk_toggle_button_get_active(pv->stype_direct); + if (strcmp(s, "") == 0) { + toplevel_ERR(pv->top, "No source type was selected."); + return; + } + apol_avrule_query_set_source(policy, query, s, only_direct == FALSE); + apol_avrule_query_set_source_component(policy, query, APOL_QUERY_SYMBOL_IS_TYPE); + } + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pv->ttype_check))) { + s = util_combo_box_get_active_text(GTK_COMBO_BOX(pv->ttype_combo)); + only_direct = gtk_toggle_button_get_active(pv->ttype_direct); + if (strcmp(s, "") == 0) { + toplevel_ERR(pv->top, "No target type was selected."); + return; + } + apol_avrule_query_set_target(policy, query, s, only_direct == FALSE); + apol_avrule_query_set_source_component(policy, query, APOL_QUERY_SYMBOL_IS_TYPE); + } + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pv->class_check))) { + s = util_combo_box_get_active_text(GTK_COMBO_BOX(pv->class_combo)); + if (strcmp(s, "") == 0) { + toplevel_ERR(pv->top, "No object class was selected."); + return; + } + apol_avrule_query_append_class(policy, query, s); + } + + util_cursor_wait(GTK_WIDGET(pv->window)); + run.policy = policy; + run.query = query; + run.progress = toplevel_get_progress(pv->top); + progress_show(run.progress, "Finding TE Rules"); + g_thread_create(policy_view_find_terules_runner, &run, FALSE, NULL); + progress_wait(run.progress); + progress_hide(run.progress); + util_cursor_clear(GTK_WIDGET(pv->window)); + apol_avrule_query_destroy(&query); + if (run.retval == 0) { + policy_view_display_avrule_results(pv, run.results, run.is_syn_rules); + } + apol_vector_destroy(&run.results); +} + +static void policy_view_close(GtkButton * button __attribute__ ((unused)), gpointer user_data) +{ + policy_view_t *pv = (policy_view_t *) user_data; + gtk_widget_hide(GTK_WIDGET(pv->window)); +} + +static gboolean policy_view_on_delete_event(GtkWidget * widget, GdkEvent * event __attribute__ ((unused)), gpointer user_data + __attribute__ ((unused))) +{ + gtk_widget_hide(widget); + return TRUE; +} + +static void policy_view_on_stype_toggle(GtkToggleButton * toggle, gpointer user_data) +{ + gboolean sens = gtk_toggle_button_get_active(toggle); + policy_view_t *pv = (policy_view_t *) user_data; + gtk_widget_set_sensitive(GTK_WIDGET(pv->stype_combo), sens); + gtk_widget_set_sensitive(GTK_WIDGET(pv->stype_direct), sens); +} + +static void policy_view_on_ttype_toggle(GtkToggleButton * toggle, gpointer user_data) +{ + gboolean sens = gtk_toggle_button_get_active(toggle); + policy_view_t *pv = (policy_view_t *) user_data; + gtk_widget_set_sensitive(GTK_WIDGET(pv->ttype_combo), sens); + gtk_widget_set_sensitive(GTK_WIDGET(pv->ttype_direct), sens); +} + +static void policy_view_on_class_toggle(GtkToggleButton * toggle, gpointer user_data) +{ + gboolean sens = gtk_toggle_button_get_active(toggle); + policy_view_t *pv = (policy_view_t *) user_data; + gtk_widget_set_sensitive(GTK_WIDGET(pv->class_combo), sens); + +} + +static gboolean policy_view_on_line_event(GtkTextTag * tag + __attribute__ ((unused)), GObject * event_object + __attribute__ ((unused)), GdkEvent * event, const GtkTextIter * iter, gpointer user_data) +{ + policy_view_t *pv = (policy_view_t *) user_data; + GtkTextIter start, end; + int line; + GtkTextView *view; + if (event->type != GDK_BUTTON_PRESS) { + return FALSE; + } + start = *iter; + while (!gtk_text_iter_starts_word(&start)) + gtk_text_iter_backward_char(&start); + end = start; + while (!gtk_text_iter_ends_word(&end)) + gtk_text_iter_forward_char(&end); + /* subtract 1 because text buffers are indexed from 0 */ + line = atoi(gtk_text_iter_get_slice(&start, &end)) - 1; + view = GTK_TEXT_VIEW(glade_xml_get_widget(pv->xml, "PolicyWindowPolicyText")); + assert(view != NULL); + gtk_notebook_set_current_page(pv->notebook, 1); + gtk_text_buffer_get_start_iter(pv->policy_text, &start); + gtk_text_iter_set_line(&start, line); + gtk_text_view_scroll_to_iter(view, &start, 0.0001, TRUE, 0.0, 0.5); + gtk_text_buffer_place_cursor(pv->policy_text, &start); + gtk_text_view_set_cursor_visible(view, TRUE); + return TRUE; +} + +static gboolean policy_view_on_rules_motion(GtkWidget * widget, GdkEventMotion * event, gpointer user_data __attribute__ ((unused))) +{ + GtkTextView *textview = GTK_TEXT_VIEW(widget); + gint x, ex, y, ey; + GtkTextIter iter; + GSList *tags, *tagp; + int hovering = 0; + if (event->is_hint) { + gdk_window_get_pointer(event->window, &ex, &ey, NULL); + } else { + ex = event->x; + ey = event->y; + } + gtk_text_view_window_to_buffer_coords(textview, GTK_TEXT_WINDOW_WIDGET, ex, ey, &x, &y); + gtk_text_view_get_iter_at_location(textview, &iter, x, y); + tags = gtk_text_iter_get_tags(&iter); + for (tagp = tags; tagp != NULL; tagp = tagp->next) { + if (strcmp(GTK_TEXT_TAG(tagp->data)->name, "line-number") == 0) { + hovering = TRUE; + break; + } + } + if (hovering) { + GdkCursor *cursor = gdk_cursor_new(GDK_HAND2); + gdk_window_set_cursor(event->window, cursor); + gdk_cursor_unref(cursor); + gdk_flush(); + } else { + gdk_window_set_cursor(event->window, NULL); + } + g_slist_free(tags); + return FALSE; +} + +/** + * Create a text buffer to hold the results of running the TE rules + * search. Initialize its tags and add event handlers to the + * "line-number" tag, such that clicking on the tag jumps to the + * policy's line and hovering over the tag changes the cursor. + */ +static void policy_view_create_rules_buffer(policy_view_t * pv) +{ + GtkTextView *rules_textview; + GtkTextTagTable *table; + GtkTextTag *tag; + rules_textview = GTK_TEXT_VIEW(glade_xml_get_widget(pv->xml, "PolicyWindowTERulesResults")); + assert(rules_textview != NULL); + pv->rules_text = gtk_text_buffer_new(NULL); + gtk_text_view_set_buffer(rules_textview, pv->rules_text); + table = gtk_text_buffer_get_tag_table(pv->rules_text); + gtk_text_buffer_create_tag(pv->rules_text, "summary", "family", "monospace", "weight", "bold", NULL); + tag = gtk_text_buffer_create_tag(pv->rules_text, "line-number", + "family", "monospace", "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); + g_signal_connect(G_OBJECT(tag), "event", G_CALLBACK(policy_view_on_line_event), pv); + g_signal_connect(rules_textview, "motion-notify-event", G_CALLBACK(policy_view_on_rules_motion), NULL); + gtk_text_buffer_create_tag(pv->rules_text, "rule", "family", "monospace", NULL); +} + +policy_view_t *policy_view_create(toplevel_t * top) +{ + GtkWidget *w; + GtkTextView *policy_textview; + policy_view_t *pv; + if ((pv = calloc(1, sizeof(*pv))) == NULL) { + return NULL; + } + pv->top = top; + pv->xml = glade_xml_new(toplevel_get_glade_xml(top), "PolicyWindow", NULL); + pv->window = GTK_WINDOW(glade_xml_get_widget(pv->xml, "PolicyWindow")); + assert(pv->window != NULL); + gtk_window_set_transient_for(pv->window, toplevel_get_window(top)); + pv->notebook = GTK_NOTEBOOK(glade_xml_get_widget(pv->xml, "PolicyWindowNotebook")); + assert(pv->notebook != NULL); + + pv->stype_check = GTK_TOGGLE_BUTTON(glade_xml_get_widget(pv->xml, "PolicyWindowSTypeCheck")); + pv->ttype_check = GTK_TOGGLE_BUTTON(glade_xml_get_widget(pv->xml, "PolicyWindowTTypeCheck")); + pv->class_check = GTK_TOGGLE_BUTTON(glade_xml_get_widget(pv->xml, "PolicyWindowClassCheck")); + assert(pv->stype_check != NULL && pv->ttype_check != NULL && pv->class_check != NULL); + g_signal_connect(pv->stype_check, "toggled", G_CALLBACK(policy_view_on_stype_toggle), pv); + g_signal_connect(pv->ttype_check, "toggled", G_CALLBACK(policy_view_on_ttype_toggle), pv); + g_signal_connect(pv->class_check, "toggled", G_CALLBACK(policy_view_on_class_toggle), pv); + + pv->stype_combo = GTK_COMBO_BOX_ENTRY(glade_xml_get_widget(pv->xml, "PolicyWindowSTypeCombo")); + pv->ttype_combo = GTK_COMBO_BOX_ENTRY(glade_xml_get_widget(pv->xml, "PolicyWindowTTypeCombo")); + pv->class_combo = GTK_COMBO_BOX_ENTRY(glade_xml_get_widget(pv->xml, "PolicyWindowClassCombo")); + assert(pv->stype_combo != NULL && pv->ttype_combo != NULL && pv->class_combo != NULL); + pv->type_model = gtk_list_store_new(1, G_TYPE_STRING); + pv->class_model = gtk_list_store_new(1, G_TYPE_STRING); + gtk_combo_box_set_model(GTK_COMBO_BOX(pv->stype_combo), GTK_TREE_MODEL(pv->type_model)); + gtk_combo_box_set_model(GTK_COMBO_BOX(pv->ttype_combo), GTK_TREE_MODEL(pv->type_model)); + gtk_combo_box_set_model(GTK_COMBO_BOX(pv->class_combo), GTK_TREE_MODEL(pv->class_model)); + gtk_combo_box_entry_set_text_column(pv->stype_combo, 0); + gtk_combo_box_entry_set_text_column(pv->ttype_combo, 0); + gtk_combo_box_entry_set_text_column(pv->class_combo, 0); + + pv->stype_direct = GTK_TOGGLE_BUTTON(glade_xml_get_widget(pv->xml, "PolicyWindowSTypeDirectCheck")); + pv->ttype_direct = GTK_TOGGLE_BUTTON(glade_xml_get_widget(pv->xml, "PolicyWindowTTypeDirectCheck")); + assert(pv->stype_direct != NULL && pv->ttype_direct != NULL); + + policy_view_create_rules_buffer(pv); + + policy_textview = GTK_TEXT_VIEW(glade_xml_get_widget(pv->xml, "PolicyWindowPolicyText")); + assert(policy_textview != NULL); + pv->policy_text = gtk_text_buffer_new(NULL); + gtk_text_view_set_buffer(policy_textview, pv->policy_text); + + /* set up signal handlers for the widgets */ + + w = glade_xml_get_widget(pv->xml, "PolicyWindowFindTERulesButton"); + assert(w != NULL); + g_signal_connect(w, "clicked", G_CALLBACK(policy_view_on_find_terules_click), pv); + + w = glade_xml_get_widget(pv->xml, "PolicyWindowCloseButton"); + assert(w != NULL); + g_signal_connect(w, "clicked", G_CALLBACK(policy_view_close), pv); + g_signal_connect(pv->window, "delete_event", G_CALLBACK(policy_view_on_delete_event), NULL); + + policy_view_update(pv, NULL); + return pv; +} + +void policy_view_destroy(policy_view_t ** pv) +{ + if (pv != NULL && *pv != NULL) { + apol_vector_destroy(&(*pv)->type_list); + apol_vector_destroy(&(*pv)->class_list); + free(*pv); + *pv = NULL; + } +} + +/** + * If the currently loaded policy is a source policy, then load its + * contents into the policy text buffer. Otherwise let the user know + * that the policy is binary. + * + * @param pv Policy view's policy source tab to update. + * @param path Path to the currently loaded policy, or NULL if no + * policy is loaded. + */ +static void policy_view_load_policy_source(policy_view_t * pv, apol_policy_path_t * path) +{ + apol_policy_t *policy = toplevel_get_policy(pv->top); + const char *primary_path; + if (path == NULL) { + gtk_text_buffer_set_text(pv->policy_text, "No policy has been loaded.", -1); + return; + } + primary_path = apol_policy_path_get_primary(path); + if (!qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SOURCE)) { + GString *string = g_string_new(""); + g_string_printf(string, "Policy file %s is not a source policy.", primary_path); + gtk_text_buffer_set_text(pv->policy_text, string->str, -1); + g_string_free(string, TRUE); + } else { + /* load the policy by mmap()ing the file */ + struct stat statbuf; + int fd; + if (pv->policy_text_mmap != NULL) { + munmap(pv->policy_text_mmap, pv->policy_text_len); + } + + pv->policy_text_mmap = NULL; + pv->policy_text_len = 0; + + if ((fd = open(primary_path, O_RDONLY)) < 0) { + toplevel_ERR(pv->top, "Could not open %s for reading.", primary_path); + return; + } + if (fstat(fd, &statbuf) < 0) { + close(fd); + toplevel_ERR(pv->top, "Could not stat %s.", primary_path); + return; + } + + pv->policy_text_len = statbuf.st_size; + if ((pv->policy_text_mmap = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) { + close(fd); + pv->policy_text_mmap = NULL; + toplevel_ERR(pv->top, "Could not mmap %s.", primary_path); + return; + } + close(fd); + gtk_text_buffer_set_text(pv->policy_text, pv->policy_text_mmap, pv->policy_text_len); + } +} + +/** + * If a policy is currently loaded then set the rule search combo box + * menus to that policy's components. Otherwies clear the combo box + * menus. + * + * @param pv Policy view's rule search boxes to modify. + */ +static void policy_view_populate_combo_boxes(policy_view_t * pv) +{ + apol_policy_t *policy = toplevel_get_policy(pv->top); + gtk_list_store_clear(pv->type_model); + gtk_list_store_clear(pv->class_model); + apol_vector_destroy(&pv->type_list); + apol_vector_destroy(&pv->class_list); + pv->type_list = apol_vector_create(NULL); + pv->class_list = apol_vector_create(NULL); + if (policy != NULL) { + qpol_policy_t *qp = apol_policy_get_qpol(policy); + size_t i; + const qpol_type_t *type; + const qpol_class_t *obj_class; + const char *s; + GtkTreeIter iter; + apol_vector_t *v; + apol_type_get_by_query(policy, NULL, &v); + for (i = 0; i < apol_vector_get_size(v); i++) { + type = apol_vector_get_element(v, i); + qpol_type_get_name(qp, type, &s); + apol_vector_append(pv->type_list, (void *)s); + } + apol_vector_destroy(&v); + apol_vector_sort(pv->type_list, apol_str_strcmp, NULL); + for (i = 0; i < apol_vector_get_size(pv->type_list); i++) { + s = apol_vector_get_element(pv->type_list, i); +#ifdef GTK_2_8 + gtk_list_store_insert_with_values(pv->type_model, &iter, i, 0, s, -1); +#else + gtk_list_store_insert(pv->type_model, &iter, i); + gtk_list_store_set(pv->type_model, &iter, 0, s, -1); +#endif + } + apol_class_get_by_query(policy, NULL, &v); + for (i = 0; i < apol_vector_get_size(v); i++) { + obj_class = apol_vector_get_element(v, i); + qpol_class_get_name(qp, obj_class, &s); + apol_vector_append(pv->class_list, (void *)s); + } + apol_vector_destroy(&v); + apol_vector_sort(pv->class_list, apol_str_strcmp, NULL); + for (i = 0; i < apol_vector_get_size(pv->class_list); i++) { + s = apol_vector_get_element(pv->class_list, i); +#ifdef GTK_2_8 + gtk_list_store_insert_with_values(pv->class_model, &iter, i, 0, s, -1); +#else + gtk_list_store_insert(pv->class_model, &iter, i); + gtk_list_store_set(pv->class_model, &iter, 0, s, -1); +#endif + } + } +} + +void policy_view_update(policy_view_t * pv, apol_policy_path_t * path) +{ + GtkTextIter start, end; + policy_view_load_policy_source(pv, path); + policy_view_populate_combo_boxes(pv); + gtk_text_buffer_get_start_iter(pv->rules_text, &start); + gtk_text_buffer_get_end_iter(pv->rules_text, &end); + gtk_text_buffer_delete(pv->rules_text, &start, &end); + +} + +void policy_view_find_terules(policy_view_t * pv, seaudit_message_t * message) +{ + seaudit_message_type_e type = SEAUDIT_MESSAGE_TYPE_INVALID; + void *data = NULL; + const char *stype = "", *ttype = "", *obj_class = ""; + size_t i; + assert(pv->type_list != NULL); + assert(pv->class_list != NULL); + if (message != NULL) { + data = seaudit_message_get_data(message, &type); + } + if (type == SEAUDIT_MESSAGE_TYPE_AVC) { + seaudit_avc_message_t *avc = data; + if ((stype = seaudit_avc_message_get_source_type(avc)) == NULL) { + stype = ""; + } + if ((ttype = seaudit_avc_message_get_target_type(avc)) == NULL) { + ttype = ""; + } + if ((obj_class = seaudit_avc_message_get_object_class(avc)) == NULL) { + obj_class = ""; + } + } + if (strcmp(stype, "") == 0 || apol_vector_get_index(pv->type_list, stype, apol_str_strcmp, NULL, &i) < 0) { + gtk_combo_box_set_active(GTK_COMBO_BOX(pv->stype_combo), -1); + gtk_toggle_button_set_active(pv->stype_check, FALSE); + } else { + gtk_combo_box_set_active(GTK_COMBO_BOX(pv->stype_combo), i); + gtk_toggle_button_set_active(pv->stype_check, TRUE); + } + if (strcmp(ttype, "") == 0 || apol_vector_get_index(pv->type_list, ttype, apol_str_strcmp, NULL, &i) < 0) { + gtk_combo_box_set_active(GTK_COMBO_BOX(pv->ttype_combo), -1); + gtk_toggle_button_set_active(pv->ttype_check, FALSE); + } else { + gtk_combo_box_set_active(GTK_COMBO_BOX(pv->ttype_combo), i); + gtk_toggle_button_set_active(pv->ttype_check, TRUE); + } + if (strcmp(obj_class, "") == 0 || apol_vector_get_index(pv->class_list, obj_class, apol_str_strcmp, NULL, &i) < 0) { + gtk_combo_box_set_active(GTK_COMBO_BOX(pv->class_combo), -1); + gtk_toggle_button_set_active(pv->class_check, FALSE); + } else { + gtk_combo_box_set_active(GTK_COMBO_BOX(pv->class_combo), i); + gtk_toggle_button_set_active(pv->class_check, TRUE); + } + gtk_notebook_set_current_page(pv->notebook, 0); + gtk_widget_show(GTK_WIDGET(pv->window)); +} diff --git a/seaudit/policy_view.h b/seaudit/policy_view.h new file mode 100644 index 0000000..17b23ed --- /dev/null +++ b/seaudit/policy_view.h @@ -0,0 +1,77 @@ +/** + * @file + * Declaration of viewer for the currently loaded policy. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2003-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef POLICY_VIEW_H +#define POLICY_VIEW_H + +#include "toplevel.h" + +#include <seaudit/message.h> + +typedef struct policy_view policy_view_t; + +/** + * Create a new policy view object. This is used to display the + * policy's content and to search for TE rules. + * + * @param top Toplevel object that will control the newly opened + * policy view. + * + * @return An initialized policy view object, or NULL upon error. The + * caller must call policy_view_destroy() upon the returned value. + */ +policy_view_t *policy_view_create(toplevel_t * top); + +/** + * Destroy the policy view object. This does nothing if the pointer + * is set to NULL. + * + * @param pv Reference to a policy view object. Afterwards the + * pointer will be set to NULL. + */ +void policy_view_destroy(policy_view_t ** pv); + +/** + * (Re)synchronize the policy displayed in the viewer with the one + * actually loaded. If there is no policy loaded then clear the + * viewer's contents. + * + * @param pv Policy view to update. + * @param path Path to the policy, or NULL if no policy is loaded. + */ +void policy_view_update(policy_view_t * pv, apol_policy_path_t * path); + +/** + * (Re)open the policy view window to allow the user to search for TE + * rules in the currently opened policy. If message is not NULL then + * set the query's initial parameters to the message's source type, + * target type, and object class. + * + * @param pv Policy view object. Note that a policy must already + * exist and policy_view_update() must be first called. + * @param message If non-NULL, the initial parameters for query. + */ +void policy_view_find_terules(policy_view_t * pv, seaudit_message_t * message); + +#endif diff --git a/seaudit/preferences.c b/seaudit/preferences.c new file mode 100644 index 0000000..5e65385 --- /dev/null +++ b/seaudit/preferences.c @@ -0,0 +1,585 @@ +/** + * @file + * Implementation of the storage class preferences_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 program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "preferences.h" + +#include <apol/util.h> +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +/** default frequency, in milliseconds, to poll log file for changes */ +#define DEFAULT_LOG_UPDATE_INTERVAL 1000 + +/** maximum number of recent log files and recent policy files to remember */ +#define MAX_RECENT_ENTRIES 5 + +/** name of the user's seaudit personal preferences file */ +#define USER_SEAUDIT_CONF ".seaudit" + +/** name of the system seaudit preference file */ +#define SYSTEM_SEAUDIT_CONF "dot_seaudit" + +struct visible_field +{ + preference_field_e id; + const char *field; + int visible; +}; + +static const struct visible_field default_visible_fields[] = { + {HOST_FIELD, "host_field", 1}, + {MESSAGE_FIELD, "msg_field", 1}, + {DATE_FIELD, "date_field", 1}, + {SUSER_FIELD, "src_usr_field", 0}, + {SROLE_FIELD, "src_role_field", 0}, + {STYPE_FIELD, "src_type_field", 1}, + {SMLS_LVL_FIELD, "src_mls_lvl_field", 0}, + {SMLS_CLR_FIELD, "src_mls_clr_field", 0}, + {TUSER_FIELD, "tgt_usr_field", 0}, + {TROLE_FIELD, "tgt_role_field", 0}, + {TTYPE_FIELD, "tgt_type_field", 1}, + {TMLS_LVL_FIELD, "tgt_mls_lvl_field", 0}, + {TMLS_CLR_FIELD, "tgt_mls_clr_field", 0}, + {OBJCLASS_FIELD, "obj_class_field", 1}, + {PERM_FIELD, "perm_field", 1}, + {EXECUTABLE_FIELD, "exe_field", 1}, + {COMMAND_FIELD, "comm_field", 1}, + {NAME_FIELD, "name_field", 0}, + {PID_FIELD, "pid_field", 0}, + {INODE_FIELD, "inode_field", 0}, + {PATH_FIELD, "path_field", 0}, + {OTHER_FIELD, "other_field", 1} +}; + +static const size_t num_visible_fields = sizeof(default_visible_fields) / sizeof(default_visible_fields[0]); + +struct preferences +{ + /** path to default system log file */ + char *log; + /** path to default policy */ + apol_policy_path_t *policy; + /** default path when writing reports */ + char *report; + /** default path to the stylesheet, used during report writing */ + char *stylesheet; + /** vector of paths (strings) to recently opened log files */ + apol_vector_t *recent_log_files; + /** vector of apol_policy_path_t objects to recently opened + policies */ + apol_vector_t *recent_policy_files; + /** non-zero if seaudit should poll the log file for changes */ + int real_time_log; + /** frequency, in milliesconds, to poll log file */ + int real_time_interval; + struct visible_field *fields; +}; + +void preferences_apol_policy_path_free(void *elem) +{ + apol_policy_path_t *path = elem; + apol_policy_path_destroy(&path); +} + +/** + * Parse the old-style recent policies list (a ':' separated list of + * paths) into the recent_policy_files field. + */ +static int preferences_parse_old_recent_files(preferences_t * prefs, const char *s) +{ + apol_vector_t *v = NULL; + size_t i; + char *base; + apol_policy_path_t *path; + int error = 0; + + if ((v = apol_str_split(s, ":")) == NULL) { + error = errno; + goto cleanup; + } + for (i = 0; i < apol_vector_get_size(v); i++) { + base = apol_vector_get_element(v, i); + if ((path = apol_policy_path_create(APOL_POLICY_PATH_TYPE_MONOLITHIC, base, NULL)) == NULL || + apol_vector_append(prefs->recent_policy_files, path) < 0) { + error = errno; + apol_policy_path_destroy(&path); + goto cleanup; + } + } + + cleanup: + apol_vector_destroy(&v); + if (error != 0) { + errno = error; + return -1; + } + return 0; +} + +/** + * Parse the new recent policy files, which now spans across multiple + * lines. + */ +static int preferences_parse_new_recent_files(preferences_t * prefs, FILE * f, int num_files) +{ + int count; + for (count = 0; count < num_files; count++) { + char *var_name, *value = NULL; + apol_policy_path_t *p = NULL; + if (asprintf(&var_name, "RECENT_POLICY_PATH_%d", count) < 0) { + return -1; + } + value = apol_config_get_var(var_name, f); + free(var_name); + if (value == NULL || + (p = apol_policy_path_create_from_string(value)) == NULL || + apol_vector_append(prefs->recent_policy_files, p) < 0) { + free(value); + apol_policy_path_destroy(&p); + return -1; + } + free(value); + } + return 0; +} + +preferences_t *preferences_create(void) +{ + preferences_t *prefs = NULL; + FILE *file = NULL; + char *path = NULL, *value; + apol_vector_t *v = NULL; + size_t i, j; + int error = 0; + + if ((prefs = calloc(1, sizeof(*prefs))) == NULL || + (prefs->log = strdup("")) == NULL || + (prefs->report = strdup("")) == NULL || + (prefs->stylesheet = strdup("")) == NULL || + (prefs->recent_log_files = apol_vector_create(free)) == NULL || + (prefs->recent_policy_files = apol_vector_create(preferences_apol_policy_path_free)) == NULL || + (prefs->fields = calloc(num_visible_fields, sizeof(struct visible_field))) == NULL) { + error = errno; + goto cleanup; + } + prefs->real_time_interval = DEFAULT_LOG_UPDATE_INTERVAL; + memcpy(prefs->fields, default_visible_fields, num_visible_fields * sizeof(struct visible_field)); + path = apol_file_find_user_config(USER_SEAUDIT_CONF); + if (!path) { + if ((path = apol_file_find_path(SYSTEM_SEAUDIT_CONF)) == NULL) { + return prefs; + } + } + if ((file = fopen(path, "r")) == NULL) { + error = errno; + goto cleanup; + } + if ((value = apol_config_get_var("DEFAULT_LOG_FILE", file)) != NULL) { + free(prefs->log); + prefs->log = value; + } + if ((value = apol_config_get_var("DEFAULT_POLICY_FILE", file)) != NULL) { + apol_policy_path_destroy(&prefs->policy); + if (apol_policy_path_create(APOL_POLICY_PATH_TYPE_MONOLITHIC, value, NULL) == NULL) { + error = errno; + free(value); + goto cleanup; + } + free(value); + } + if ((value = apol_config_get_var("DEFAULT_POLICY_PATH", file)) != NULL) { + apol_policy_path_destroy(&prefs->policy); + if ((prefs->policy = apol_policy_path_create_from_string(value)) == NULL) { + error = errno; + free(value); + goto cleanup; + } + free(value); + } + if ((value = apol_config_get_var("DEFAULT_REPORT_CONFIG_FILE", file)) != NULL) { + free(prefs->report); + prefs->report = value; + } + if ((value = apol_config_get_var("DEFAULT_REPORT_CSS_FILE", file)) != NULL) { + free(prefs->stylesheet); + prefs->stylesheet = value; + } + if ((value = apol_config_get_var("RECENT_LOG_FILES", file)) == NULL || (v = apol_str_split(value, ":")) == NULL) { + error = errno; + free(value); + goto cleanup; + } + free(value); + apol_vector_destroy(&prefs->recent_log_files); + prefs->recent_log_files = v; + + /* test if there exists the new recent list that contains + * module filenames */ + if ((value = apol_config_get_var("RECENT_POLICY_PATH_FILES", file)) != NULL) { + if (preferences_parse_new_recent_files(prefs, file, atoi(value)) < 0) { + error = errno; + free(value); + goto cleanup; + } + } else { + /* use older style that could only handle monolithic policies */ + if ((value = apol_config_get_var("RECENT_POLICY_FILES", file)) == NULL + || preferences_parse_old_recent_files(prefs, value) < 0) { + error = errno; + free(value); + goto cleanup; + } + } + free(value); + + if ((value = apol_config_get_var("LOG_COLUMNS_HIDDEN", file)) == NULL || (v = apol_str_split(value, ":")) == NULL) { + error = errno; + goto cleanup; + } + for (j = 0; j < num_visible_fields; j++) { + prefs->fields[j].visible = 1; + } + for (i = 0; i < apol_vector_get_size(v); i++) { + char *s = apol_vector_get_element(v, i); + for (j = 0; j < num_visible_fields; j++) { + if (strcmp(s, prefs->fields[j].field) == 0) { + prefs->fields[j].visible = 0; + break; + } + } + } + free(value); + apol_vector_destroy(&v); + value = apol_config_get_var("REAL_TIME_LOG_MONITORING", file); + if (value != NULL && value[0] != '0') { + prefs->real_time_log = 1; + } + free(value); + value = apol_config_get_var("REAL_TIME_LOG_UPDATE_INTERVAL", file); + if (value != NULL) { + prefs->real_time_interval = atoi(value); + } + free(value); + cleanup: + free(path); + if (file != NULL) { + fclose(file); + } + if (error != 0) { + preferences_destroy(&prefs); + errno = error; + return NULL; + } + return prefs; +} + +void preferences_destroy(preferences_t ** prefs) +{ + if (prefs != NULL && *prefs != NULL) { + free((*prefs)->log); + apol_policy_path_destroy(&(*prefs)->policy); + free((*prefs)->report); + free((*prefs)->stylesheet); + apol_vector_destroy(&(*prefs)->recent_log_files); + apol_vector_destroy(&(*prefs)->recent_policy_files); + free((*prefs)->fields); + free(*prefs); + *prefs = NULL; + } +} + +int preferences_write_to_conf_file(preferences_t * prefs) +{ + FILE *file = NULL; + char *home, *conf_file = NULL, *value; + apol_vector_t *hidden_fields = NULL; + size_t i; + int retval = 0, error = 0; + + /* we need to open ~/.seaudit */ + home = getenv("HOME"); + if (!home) { + error = EBADRQC; + goto cleanup; + } + if (asprintf(&conf_file, "%s/%s", home, USER_SEAUDIT_CONF) < 0) { + error = errno; + goto cleanup; + } + + if ((file = fopen(conf_file, "w")) == NULL) { + error = errno; + goto cleanup; + } + + fprintf(file, "# configuration file for seaudit - an audit log tool for Security Enhanced Linux.\n"); + fprintf(file, "# this file is auto-generated\n\n"); + + if (strcmp(prefs->log, "") != 0) { + fprintf(file, "DEFAULT_LOG_FILE %s\n", prefs->log); + } + if (prefs->policy != NULL) { + value = apol_policy_path_to_string(prefs->policy); + if (value == NULL) { + error = errno; + goto cleanup; + } + fprintf(file, "DEFAULT_POLICY_PATH %s\n", value); + free(value); + } + if (strcmp(prefs->report, "") != 0) { + fprintf(file, "DEFAULT_REPORT_CONFIG_FILE %s\n", prefs->report); + } + if (strcmp(prefs->stylesheet, "") != 0) { + fprintf(file, "DEFAULT_REPORT_CSS_FILE %s\n", prefs->stylesheet); + } + if ((value = apol_str_join(prefs->recent_log_files, ":")) == NULL) { + error = errno; + goto cleanup; + } + fprintf(file, "RECENT_LOG_FILES %s\n", value); + free(value); + + fprintf(file, "RECENT_POLICY_PATH_FILES %zd\n", apol_vector_get_size(prefs->recent_policy_files)); + for (i = 0; i < apol_vector_get_size(prefs->recent_policy_files); i++) { + apol_policy_path_t *p = apol_vector_get_element(prefs->recent_policy_files, i); + if ((value = apol_policy_path_to_string(p)) == NULL) { + error = errno; + goto cleanup; + } + fprintf(file, "RECENT_POLICY_PATH_%zd %s\n", i, value); + free(value); + } + + if ((hidden_fields = apol_vector_create(NULL)) == NULL) { + error = errno; + goto cleanup; + } + for (i = 0; i < num_visible_fields; i++) { + if (!prefs->fields[i].visible && apol_vector_append(hidden_fields, (char *)prefs->fields[i].field) < 0) { + error = errno; + goto cleanup; + } + } + if ((value = apol_str_join(hidden_fields, ":")) == NULL) { + error = errno; + goto cleanup; + } + fprintf(file, "LOG_COLUMNS_HIDDEN %s\n", value); + free(value); + fprintf(file, "REAL_TIME_LOG_MONITORING %d\n", prefs->real_time_log); + fprintf(file, "REAL_TIME_LOG_UPDATE_INTERVAL %d\n", prefs->real_time_interval); + retval = 0; + cleanup: + free(conf_file); + apol_vector_destroy(&hidden_fields); + if (file != NULL) { + fclose(file); + } + errno = error; + return retval; +} + +int preferences_is_column_visible(preferences_t * prefs, preference_field_e id) +{ + size_t i; + for (i = 0; i < num_visible_fields; i++) { + if (prefs->fields[i].id == id) { + return prefs->fields[i].visible; + } + } + assert(0); + return -1; +} + +void preferences_set_column_visible(preferences_t * prefs, preference_field_e id, int visible) +{ + size_t i; + for (i = 0; i < num_visible_fields; i++) { + if (prefs->fields[i].id == id) { + prefs->fields[i].visible = visible; + return; + } + } + assert(0); +} + +int preferences_set_log(preferences_t * prefs, const char *log) +{ + char *s; + if ((s = strdup(log)) == NULL) { + return -1; + } + free(prefs->log); + prefs->log = s; + return 0; +} + +const char *preferences_get_log(preferences_t * prefs) +{ + return prefs->log; +} + +int preferences_set_policy(preferences_t * prefs, const apol_policy_path_t * policy) +{ + apol_policy_path_t *new_policy; + if ((new_policy = apol_policy_path_create_from_policy_path(policy)) == NULL) { + return -1; + } + apol_policy_path_destroy(&prefs->policy); + prefs->policy = new_policy; + return 0; +} + +const apol_policy_path_t *preferences_get_policy(preferences_t * prefs) +{ + return prefs->policy; +} + +int preferences_set_report(preferences_t * prefs, const char *report) +{ + char *s; + if ((s = strdup(report)) == NULL) { + return -1; + } + free(prefs->report); + prefs->report = s; + return 0; +} + +const char *preferences_get_report(preferences_t * prefs) +{ + return prefs->report; +} + +int preferences_set_stylesheet(preferences_t * prefs, const char *stylesheet) +{ + char *s; + if ((s = strdup(stylesheet)) == NULL) { + return -1; + } + free(prefs->stylesheet); + prefs->stylesheet = s; + return 0; +} + +const char *preferences_get_stylesheet(preferences_t * prefs) +{ + return prefs->stylesheet; +} + +void preferences_set_real_time_at_startup(preferences_t * prefs, int startup) +{ + prefs->real_time_log = startup; +} + +int preferences_get_real_time_at_startup(preferences_t * prefs) +{ + return prefs->real_time_log; +} + +void preferences_set_real_time_interval(preferences_t * prefs, int interval) +{ + if (interval <= 0) { + prefs->real_time_interval = 0; + } else { + prefs->real_time_interval = interval; + } +} + +int preferences_get_real_time_interval(preferences_t * prefs) +{ + return prefs->real_time_interval; +} + +/** + * Add an entry to a vector, discarding the oldest entry if the vector + * size is too large. + */ +static int prefs_add_recent_vector(apol_vector_t * v, const char *entry) +{ + size_t i; + char *s; + if (apol_vector_get_index(v, (void *)entry, apol_str_strcmp, NULL, &i) == 0) { + return 0; + } + if ((s = strdup(entry)) == NULL || apol_vector_append(v, s) < 0) { + int error = errno; + free(s); + errno = error; + return -1; + } + if (apol_vector_get_size(v) >= MAX_RECENT_ENTRIES) { + s = apol_vector_get_element(v, 0); + free(s); + return apol_vector_remove(v, 0); + } + return 0; +} + +int preferences_add_recent_log(preferences_t * prefs, const char *log) +{ + return prefs_add_recent_vector(prefs->recent_log_files, log); +} + +apol_vector_t *preferences_get_recent_logs(preferences_t * prefs) +{ + return prefs->recent_log_files; +} + +static int preferences_policy_path_compare(const void *a, const void *b, void *data __attribute__ ((unused))) +{ + return apol_policy_path_compare((const apol_policy_path_t *)a, (const apol_policy_path_t *)b); +} + +int preferences_add_recent_policy(preferences_t * prefs, const apol_policy_path_t * policy) +{ + size_t i; + apol_policy_path_t *p = NULL; + if (apol_vector_get_index(prefs->recent_policy_files, policy, preferences_policy_path_compare, NULL, &i) == 0) { + return 0; + } + if ((p = apol_policy_path_create_from_policy_path(policy)) == NULL || apol_vector_append(prefs->recent_policy_files, p) < 0) { + int error = errno; + apol_policy_path_destroy(&p); + errno = error; + return -1; + } + if (apol_vector_get_size(prefs->recent_policy_files) >= MAX_RECENT_ENTRIES) { + p = apol_vector_get_element(prefs->recent_policy_files, 0); + apol_policy_path_destroy(&p); + return apol_vector_remove(prefs->recent_policy_files, 0); + } + return 0; +} + +apol_vector_t *preferences_get_recent_policies(preferences_t * prefs) +{ + return prefs->recent_policy_files; +} diff --git a/seaudit/preferences.h b/seaudit/preferences.h new file mode 100644 index 0000000..8891943 --- /dev/null +++ b/seaudit/preferences.h @@ -0,0 +1,274 @@ +/** + * @file + * Declaration of the current user's preferences for the seaudit + * application. + * + * @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 program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PREFERENCES_H +#define PREFERENCES_H + +#include <apol/policy-path.h> +#include <apol/vector.h> + +typedef struct preferences preferences_t; + +/* n.b.: OTHER_FIELD must be the last entry in this enumeration, for + message_view stops processing after that token */ +typedef enum preference_field +{ + HOST_FIELD, MESSAGE_FIELD, DATE_FIELD, + SUSER_FIELD, SROLE_FIELD, STYPE_FIELD, SMLS_LVL_FIELD, SMLS_CLR_FIELD, + TUSER_FIELD, TROLE_FIELD, TTYPE_FIELD, TMLS_LVL_FIELD, TMLS_CLR_FIELD, + OBJCLASS_FIELD, PERM_FIELD, + EXECUTABLE_FIELD, COMMAND_FIELD, NAME_FIELD, + PID_FIELD, INODE_FIELD, PATH_FIELD, OTHER_FIELD +} preference_field_e; + +/** + * Allocate and return a preferences object. This function will first + * initialize the object using the user's configuration file. If that + * is not readable then the system-wide configuration is attempted. + * It is not an error if both files are not available. + * + * @return An initialized preferences object, or NULL upon error. The + * caller must call preferences_destroy() afterwards. + */ +preferences_t *preferences_create(void); + +/** + * Destroy a preferences object, and all memory associated with it. + * Does nothing if the pointer is already NULL. + * + * @param prefs Reference to a preferences object to destroy. This + * will be set to NULL afterwards. + */ +void preferences_destroy(preferences_t ** prefs); + +/** + * Write the preferences object to the user's configuration file, + * overwriting any existing file. + * + * @param prefs Preference object to write. + * + * @return 0 if successfully written, < 0 upon error. + */ +int preferences_write_to_conf_file(preferences_t * prefs); + +/** + * Return the visibility of the column with the given preference id. + * + * @param prefs Preference object to query. + * @param id Preferences column identifier. + * + * @return Non-zero if the column is set to be visible, zero if not. + */ +int preferences_is_column_visible(preferences_t * prefs, preference_field_e id); + +/** + * Set the visibility of a column with the given preference id. Note + * that this will <b>not</b> update any message_view_t. + * + * @param prefs Preference object to query. + * @param id Preferences column identifier. + * @param visible If non-zero then set column visible, zero to hide. + * + * @see message_view_update_visible_columns needs to be called if + * column visibilities are changed. + */ +void preferences_set_column_visible(preferences_t * prefs, preference_field_e id, int visible); + +/** + * Set the filename for the preferred audit log file. Unless + * overridden by the command line, this log file will be opened when + * seaudit is launched. + * + * @param prefs Preference object to modify. + * @param log Path to the log file. The string will be duplicated. + * + * @return 0 on success, < 0 on error. + */ +int preferences_set_log(preferences_t * prefs, const char *log); + +/** + * Get the filename for the preferred log file from the preferences + * object. + * + * @param prefs Preference object to query. + * + * @return Filename for the log file, or an empty string if none set. + * Do not modify this string. + */ +const char *preferences_get_log(preferences_t * prefs); + +/** + * Set the path for the preferred policy. Unless overridden by the + * command line, this policy will be opened when seaudit is launched. + * + * @param prefs Preference object to modify. + * @param policy Path to the policy file. The policy path object will + * be duplicated. + * + * @return 0 on success, < 0 on error. + */ +int preferences_set_policy(preferences_t * prefs, const apol_policy_path_t * policy); + +/** + * Get the policy path object for the preferred policy from the + * preferences object. + * + * @param prefs Preference object to query. + * + * @return Policy path object for the policy, or NULL if none set. Do + * not modify this object. + */ +const apol_policy_path_t *preferences_get_policy(preferences_t * prefs); + +/** + * Set the default report filename. + * + * @param prefs Preference object to modify. + * @param report Path to the report. The string will be duplicated. + * + * @return 0 on success, < 0 on error. + */ +int preferences_set_report(preferences_t * prefs, const char *report); + +/** + * Get the default report filename. + * + * @param prefs Preference object to query. + * + * @return Filename for the report, or an empty string if none set. + * Do not modify this string. + */ +const char *preferences_get_report(preferences_t * prefs); + +/** + * Set the default stylesheet filename. + * + * @param prefs Preference object to modify. + * @param stylesheet Path to the stylesheet. The string will be + * duplicated. + * + * @return 0 on success, < 0 on error. + */ +int preferences_set_stylesheet(preferences_t * prefs, const char *stylesheet); + +/** + * Get the default stylesheet filename. + * + * @param prefs Preference object to query. + * + * @return Filename for the stylesheet, or an empty string if none + * set. Do not modify this string. + */ +const char *preferences_get_stylesheet(preferences_t * prefs); + +/** + * Set the default real-time setting for opened log files. If startup + * is non-zero, then the real-time monitor will be enabled for new log + * files. + * + * @param prefs Preferences object to modify. + * @param startup If non-zero, then enable real-time by default. + */ +void preferences_set_real_time_at_startup(preferences_t * prefs, int startup); + +/** + * Get the default value for real-time monitoring. + * + * @param prefs Preference object to query. + * + * @return Non-zero if opened logs should be monitored. + */ +int preferences_get_real_time_at_startup(preferences_t * prefs); + +/** + * Set the time interval (in milliseconds) for polling the log file + * during real-time monitoring. + * + * @param prefs Preferences object to modify. + * @param interval Polling interval in milliseconds. + */ +void preferences_set_real_time_interval(preferences_t * prefs, int interval); + +/** + * Get the time interval (in milliseconds) when performing real-time + * monitoring. + * + * @param prefs Preference object to query. + * + * @return Time interval in milliseconds. + */ +int preferences_get_real_time_interval(preferences_t * prefs); + +/** + * Add a filename to the recently opened log files list. If the name + * is already in the list then do nothing. Otherwise append the name + * to the end of the list. If the list grows too large then remove + * the oldest entry. + * + * @param prefs Preference object to modify. + * @param log Path to the most recently opened log. The string will + * be duplicated. + * + * @return 0 on success, < 0 on error. + */ +int preferences_add_recent_log(preferences_t * prefs, const char *log); + +/** + * Return a vector of recently loaded log files (type char *), with + * the oldest file first. Note that the vector may be empty. + * + * @param prefs Preferences object to query. + * + * @return Vector of paths. Treat this vector as const. + */ +apol_vector_t *preferences_get_recent_logs(preferences_t * prefs); + +/** + * Add a policy path to the recently opened policy files list. If the + * name is already in the list then do nothing. Otherwise append the + * name to the end of the list. If the list grows too large then + * remove the oldest entry. + * + * @param prefs Preference object to modify. + * @param policy Path to the most recently opened policy. The path + * will be duplicated. + * + * @return 0 on success, < 0 on error. + */ +int preferences_add_recent_policy(preferences_t * prefs, const apol_policy_path_t * policy); + +/** + * Return a vector of recently loaded policy files (type + * apol_policy_path_t *), with the oldest file first. Note that the + * vector may be empty. + * + * @param prefs Preferences object to query. + * + * @return Vector of paths. Treat this vector as const. + */ +apol_vector_t *preferences_get_recent_policies(preferences_t * prefs); + +#endif diff --git a/seaudit/preferences_view.c b/seaudit/preferences_view.c new file mode 100644 index 0000000..7ac5ed3 --- /dev/null +++ b/seaudit/preferences_view.c @@ -0,0 +1,310 @@ +/** + * @file + * Implementation of preferences editor. + * + * @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 program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "open_policy_window.h" +#include "preferences_view.h" +#include "utilgui.h" +#include <assert.h> +#include <string.h> +#include <glade/glade.h> + +struct pref_view +{ + GladeXML *xml; + toplevel_t *top; + preferences_t *prefs; + GtkDialog *dialog; + const char *current_log; + const apol_policy_path_t *current_policy; + apol_policy_path_t *policy_path; +}; + +struct pref_entry +{ + const char *entry_name, *browse_name; + const char *(*accessor) (preferences_t *); + int (*modifier) (preferences_t *, const char *); + const char *title; + /* next field is for callbacks to the browse button */ + struct pref_view *pv; +}; + +static struct pref_entry pref_entry_data[] = { + {"PrefsViewLogEntry", "PrefsViewLogBrowseButton", preferences_get_log, preferences_set_log, "Select Default Log"}, + {"PrefsViewConfigEntry", "PrefsViewConfigBrowseButton", preferences_get_report, preferences_set_report, + "Select Report Configuration File"}, + {"PrefsViewStylesheetEntry", "PrefsViewStylesheetBrowseButton", preferences_get_stylesheet, preferences_set_stylesheet, + "Select HTML Report Style File"} +}; +static const size_t num_entries = sizeof(pref_entry_data) / sizeof(pref_entry_data[0]); + +struct pref_toggle +{ + const char *widget_name; + preference_field_e preference_field; +}; + +static const struct pref_toggle pref_toggle_map[] = { + {"HostCheck", HOST_FIELD}, + {"MessageCheck", MESSAGE_FIELD}, + {"DateCheck", DATE_FIELD}, + {"SourceUserCheck", SUSER_FIELD}, + {"SourceRoleCheck", SROLE_FIELD}, + {"SourceTypeCheck", STYPE_FIELD}, + {"SourceMLSLVLCheck", SMLS_LVL_FIELD}, + {"SourceMLSCLRCheck", SMLS_CLR_FIELD}, + {"TargetUserCheck", TUSER_FIELD}, + {"TargetRoleCheck", TROLE_FIELD}, + {"TargetTypeCheck", TTYPE_FIELD}, + {"TargetMLSLVLCheck", TMLS_LVL_FIELD}, + {"TargetMLSCLRCheck", TMLS_CLR_FIELD}, + {"ObjectClassCheck", OBJCLASS_FIELD}, + {"PermissionCheck", PERM_FIELD}, + {"ExecutableCheck", EXECUTABLE_FIELD}, + {"CommandCheck", COMMAND_FIELD}, + {"NameCheck", NAME_FIELD}, + {"PIDCheck", PID_FIELD}, + {"InodeCheck", INODE_FIELD}, + {"PathCheck", PATH_FIELD}, + {"OtherCheck", OTHER_FIELD} +}; +static const size_t num_toggles = sizeof(pref_toggle_map) / sizeof(pref_toggle_map[0]); + +static void preferences_view_on_browse_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data) +{ + const struct pref_entry *pe = (const struct pref_entry *)user_data; + struct pref_view *pv = pe->pv; + GtkEntry *entry = GTK_ENTRY(glade_xml_get_widget(pv->xml, pe->entry_name)); + const char *current_path = gtk_entry_get_text(entry); + GtkWindow *parent = GTK_WINDOW(pv->dialog); + const char *title = pe->title; + apol_vector_t *new_paths = util_open_file(parent, title, current_path, 0); + if (new_paths != NULL) { + gtk_entry_set_text(entry, apol_vector_get_element(new_paths, 0)); + apol_vector_destroy(&new_paths); + } +} + +static void preferences_view_on_log_current_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data) +{ + struct pref_view *pv = (struct pref_view *)user_data; + GtkEntry *entry = GTK_ENTRY(glade_xml_get_widget(pv->xml, "PrefsViewLogEntry")); + assert(entry != NULL); + if (pv->current_log == NULL) { + gtk_entry_set_text(entry, ""); + } else { + gtk_entry_set_text(entry, pv->current_log); + } +} + +static void preferences_view_on_policy_browse_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data) +{ + struct pref_view *pv = (struct pref_view *)user_data; + GtkEntry *entry = GTK_ENTRY(glade_xml_get_widget(pv->xml, "PrefsViewPolicyEntry")); + assert(entry != NULL); + apol_policy_path_t *new_path; + + open_policy_window_run(pv->top, pv->policy_path, &new_path); + if (new_path != NULL) { + apol_policy_path_destroy(&pv->policy_path); + pv->policy_path = new_path; + char *path_string = util_policy_path_to_string(pv->policy_path); + gtk_entry_set_text(entry, path_string); + free(path_string); + } +} + +static void preferences_view_on_policy_current_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data) +{ + struct pref_view *pv = (struct pref_view *)user_data; + GtkEntry *entry = GTK_ENTRY(glade_xml_get_widget(pv->xml, "PrefsViewPolicyEntry")); + assert(entry != NULL); + apol_policy_path_destroy(&pv->policy_path); + if (pv->current_policy != NULL) { + pv->policy_path = apol_policy_path_create_from_policy_path(pv->current_policy); + char *path_string = util_policy_path_to_string(pv->policy_path); + gtk_entry_set_text(entry, path_string); + free(path_string); + } else { + gtk_entry_set_text(entry, ""); + } +} + +static void preferences_view_init_widgets(struct pref_view *pv) +{ + GtkWidget *w; + size_t i; + + w = glade_xml_get_widget(pv->xml, "PreferencesWindow"); + assert(w != NULL); + pv->dialog = GTK_DIALOG(w); + gtk_window_set_transient_for(GTK_WINDOW(pv->dialog), toplevel_get_window(pv->top)); + + for (i = 0; i < num_entries; i++) { + struct pref_entry *pe = pref_entry_data + i; + w = glade_xml_get_widget(pv->xml, pe->browse_name); + assert(w != NULL); + pe->pv = pv; + g_signal_connect(w, "clicked", G_CALLBACK(preferences_view_on_browse_click), pe); + } + + w = glade_xml_get_widget(pv->xml, "PrefsViewLogCurrentButton"); + assert(w != NULL); + if (pv->current_log == NULL) { + gtk_widget_set_sensitive(w, FALSE); + } + g_signal_connect(w, "clicked", G_CALLBACK(preferences_view_on_log_current_click), pv); + + w = glade_xml_get_widget(pv->xml, "PrefsViewPolicyModifyButton"); + assert(w != NULL); + g_signal_connect(w, "clicked", G_CALLBACK(preferences_view_on_policy_browse_click), pv); + w = glade_xml_get_widget(pv->xml, "PrefsViewPolicyCurrentButton"); + assert(w != NULL); + if (pv->current_policy == NULL) { + gtk_widget_set_sensitive(w, FALSE); + } + g_signal_connect(w, "clicked", G_CALLBACK(preferences_view_on_policy_current_click), pv); +} + +/** + * Copy values from preferences object to dialog widgets. + */ +static void preferences_view_init_values(struct pref_view *pv) +{ + GtkWidget *w; + const char *current_value; + const apol_policy_path_t *current_path; + char *s; + size_t i; + + for (i = 0; i < num_entries; i++) { + const struct pref_entry *pe = pref_entry_data + i; + w = glade_xml_get_widget(pv->xml, pe->entry_name); + assert(w != NULL); + current_value = pe->accessor(pv->prefs); + gtk_entry_set_text(GTK_ENTRY(w), current_value); + } + if ((current_path = preferences_get_policy(pv->prefs)) != NULL) { + pv->policy_path = apol_policy_path_create_from_policy_path(current_path); + w = glade_xml_get_widget(pv->xml, "PrefsViewPolicyEntry"); + char *path_string = util_policy_path_to_string(pv->policy_path); + assert(w != NULL); + gtk_entry_set_text(GTK_ENTRY(w), path_string); + free(path_string); + } + for (i = 0; i < num_toggles; i++) { + int visible; + w = glade_xml_get_widget(pv->xml, pref_toggle_map[i].widget_name); + assert(w != NULL); + visible = preferences_is_column_visible(pv->prefs, pref_toggle_map[i].preference_field); + if (visible) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), TRUE); + } else { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), FALSE); + } + } + w = glade_xml_get_widget(pv->xml, "PrefsViewIntervalEntry"); + assert(w != NULL); + if (asprintf(&s, "%d", preferences_get_real_time_interval(pv->prefs)) >= 0) { + gtk_entry_set_text(GTK_ENTRY(w), s); + free(s); + } else { + gtk_entry_set_text(GTK_ENTRY(w), ""); + } + w = glade_xml_get_widget(pv->xml, "RealTimeCheck"); + assert(w != NULL); + if (preferences_get_real_time_at_startup(pv->prefs)) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), TRUE); + } else { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), FALSE); + } +} + +/** + * Copy values from dialog widget to the preferences object. + */ +static void preferences_view_get_from_dialog(struct pref_view *pv) +{ + GtkWidget *w; + const gchar *entry; + size_t i; + + for (i = 0; i < num_entries; i++) { + const struct pref_entry *pe = pref_entry_data + i; + w = glade_xml_get_widget(pv->xml, pe->entry_name); + entry = gtk_entry_get_text(GTK_ENTRY(w)); + pe->modifier(pv->prefs, entry); + } + preferences_set_policy(pv->prefs, pv->policy_path); + for (i = 0; i < num_toggles; i++) { + gboolean active; + w = glade_xml_get_widget(pv->xml, pref_toggle_map[i].widget_name); + active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); + if (active) { + preferences_set_column_visible(pv->prefs, pref_toggle_map[i].preference_field, 1); + } else { + preferences_set_column_visible(pv->prefs, pref_toggle_map[i].preference_field, 0); + } + } + w = glade_xml_get_widget(pv->xml, "PrefsViewIntervalEntry"); + entry = gtk_entry_get_text(GTK_ENTRY(w)); + if (strcmp(entry, "") == 0) { + entry = "0"; + } + preferences_set_real_time_interval(pv->prefs, atoi(entry)); + w = glade_xml_get_widget(pv->xml, "RealTimeCheck"); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) { + preferences_set_real_time_at_startup(pv->prefs, 1); + } else { + preferences_set_real_time_at_startup(pv->prefs, 0); + } +} + +int preferences_view_run(toplevel_t * top, const char *current_log, const apol_policy_path_t * current_policy) +{ + struct pref_view pv; + gint response; + + memset(&pv, 0, sizeof(pv)); + pv.top = top; + pv.xml = glade_xml_new(toplevel_get_glade_xml(top), "PreferencesWindow", NULL); + pv.prefs = toplevel_get_prefs(top); + pv.current_log = current_log; + pv.current_policy = current_policy; + + preferences_view_init_widgets(&pv); + preferences_view_init_values(&pv); + + response = gtk_dialog_run(pv.dialog); + if (response != GTK_RESPONSE_OK) { + gtk_widget_destroy(GTK_WIDGET(pv.dialog)); + return 0; + } + preferences_view_get_from_dialog(&pv); + gtk_widget_destroy(GTK_WIDGET(pv.dialog)); + return 1; +} diff --git a/seaudit/preferences_view.h b/seaudit/preferences_view.h new file mode 100644 index 0000000..d36aa3c --- /dev/null +++ b/seaudit/preferences_view.h @@ -0,0 +1,44 @@ +/** + * @file + * Declaration of preferences editor. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2003-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PREFERENCES_VIEW_H +#define PREFERENCES_VIEW_H + +#include "toplevel.h" +#include <gtk/gtk.h> + +/** + * Display a dialog from which the user may edit his preferences. + * + * @param top Toplevel object containing preferences to modify + * @param current_log Path to the currently loaded log file, or NULL + * if none loaded. + * @param current_policy Path to the currently loaded policy, or NULL + * if none loaded. + * + * @return Non-zero if preferences changed, zero if not. + */ +int preferences_view_run(toplevel_t * top, const char *current_log, const apol_policy_path_t * current_policy); + +#endif diff --git a/seaudit/progress.c b/seaudit/progress.c new file mode 100644 index 0000000..01b01fb --- /dev/null +++ b/seaudit/progress.c @@ -0,0 +1,200 @@ +/** + * @file + * Routines to show a progress dialog, indicating that the + * application is doing something. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2006-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "progress.h" +#include "utilgui.h" + +#include <gtk/gtk.h> +#include <glib.h> +#include <glib/gprintf.h> + +struct progress +{ + toplevel_t *top; + GtkWidget *progress; + GtkWidget *label1, *label2; + char *s; + int done; + GCond *cond; + GMutex *mutex; +}; + +progress_t *progress_create(toplevel_t * top) +{ + progress_t *p; + GtkWidget *vbox; + + if ((p = calloc(1, sizeof(*p))) == NULL) { + return NULL; + } + p->top = top; + p->progress = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_modal(GTK_WINDOW(p->progress), TRUE); + gtk_window_set_transient_for(GTK_WINDOW(p->progress), toplevel_get_window(top)); + gtk_window_set_default_size(GTK_WINDOW(p->progress), 300, 100); + vbox = gtk_vbox_new(FALSE, 2); + gtk_container_add(GTK_CONTAINER(p->progress), vbox); + p->label1 = gtk_label_new(NULL); + gtk_container_add(GTK_CONTAINER(vbox), p->label1); + p->label2 = gtk_label_new(NULL); + gtk_container_add(GTK_CONTAINER(vbox), p->label2); + gtk_widget_show(p->label1); + gtk_widget_show(p->label2); + gtk_widget_show(vbox); + util_cursor_wait(p->progress); + p->cond = g_cond_new(); + p->mutex = g_mutex_new(); + return p; +} + +void progress_destroy(progress_t ** progress) +{ + if (progress != NULL && *progress != NULL) { + free((*progress)->s); + g_cond_free((*progress)->cond); + g_mutex_free((*progress)->mutex); + free(*progress); + *progress = NULL; + } +} + +void progress_show(progress_t * progress, const char *title) +{ + gtk_label_set_text(GTK_LABEL(progress->label1), title); + gtk_label_set_text(GTK_LABEL(progress->label2), ""); + gtk_widget_show(progress->progress); + gtk_window_deiconify(GTK_WINDOW(progress->progress)); + gtk_window_set_title(GTK_WINDOW(progress->progress), title); + progress->done = 0; +} + +void progress_hide(progress_t * progress) +{ + gtk_widget_hide(progress->progress); +} + +int progress_wait(progress_t * progress) +{ + GTimeVal wait_time = { 0, 50000 }; + g_mutex_lock(progress->mutex); + while (!progress->done) { + g_cond_timed_wait(progress->cond, progress->mutex, &wait_time); + if (progress->s != NULL) { + gtk_label_set_text(GTK_LABEL(progress->label2), progress->s); + free(progress->s); + progress->s = NULL; + } + while (gtk_events_pending()) + gtk_main_iteration(); + } + g_mutex_unlock(progress->mutex); + if (progress->done < 0) { + toplevel_ERR(progress->top, GTK_LABEL(progress->label2)->label); + return progress->done; + } else if (progress->done > 1) { + toplevel_WARN(progress->top, GTK_LABEL(progress->label2)->label); + return progress->done - 1; + } else { + progress->done = 0; + return 0; + } +} + +void progress_done(progress_t * progress) +{ + g_mutex_lock(progress->mutex); + progress->done = 1; + g_cond_signal(progress->cond); + g_mutex_unlock(progress->mutex); +} + +void progress_warn(progress_t * progress, char *reason, ...) +{ + gchar *s; + va_list ap; + g_mutex_lock(progress->mutex); + if (reason != NULL) { + va_start(ap, reason); + g_vasprintf(&s, reason, ap); + free(progress->s); + progress->s = s; + va_end(ap); + } + progress->done = 2; + g_cond_signal(progress->cond); + g_mutex_unlock(progress->mutex); +} + +void progress_abort(progress_t * progress, char *reason, ...) +{ + gchar *s; + va_list ap; + g_mutex_lock(progress->mutex); + if (reason != NULL) { + va_start(ap, reason); + g_vasprintf(&s, reason, ap); + free(progress->s); + progress->s = s; + va_end(ap); + } + progress->done = -1; + g_cond_signal(progress->cond); + g_mutex_unlock(progress->mutex); +} + +static void progress_update_label(progress_t * progress, const char *fmt, va_list va_args) +{ + gchar *s = NULL; + g_vasprintf(&s, fmt, va_args); + g_mutex_lock(progress->mutex); + free(progress->s); + progress->s = s; + g_cond_signal(progress->cond); + g_mutex_unlock(progress->mutex); +} + +void progress_update(progress_t * progress, char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + progress_update_label(progress, fmt, ap); + va_end(ap); +} + +void progress_seaudit_handle_func(void *arg, const seaudit_log_t * log __attribute__ ((unused)), int level + __attribute__ ((unused)), const char *fmt, va_list va_args) +{ + progress_t *progress = arg; + progress_update_label(progress, fmt, va_args); +} + +void progress_apol_handle_func(void *varg, const apol_policy_t * p __attribute__ ((unused)), int level + __attribute__ ((unused)), const char *fmt, va_list argp) +{ + progress_t *progress = varg; + progress_update_label(progress, fmt, argp); +} diff --git a/seaudit/progress.h b/seaudit/progress.h new file mode 100644 index 0000000..5c6646f --- /dev/null +++ b/seaudit/progress.h @@ -0,0 +1,139 @@ +/** + * @file + * Header for showing progress dialogs. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2006-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef PROGRESS_H +#define PROGRESS_H + +typedef struct progress progress_t; + +#include "toplevel.h" + +#include <apol/policy.h> +#include <seaudit/log.h> + +/** + * Allocate and return a new progress dialog object. + * + * @param top Toplevel object that will control the progress object. + * + * @return An initialized progress object, or NULL upon error. The + * caller is responsible for calling progress_destroy() afterwards. + */ +progress_t *progress_create(toplevel_t * top); + +/** + * Destroy a progress dialog. Does nothing if the pointer is already + * NULL. + * + * @param prefs Reference to a progress object to destroy. This will + * be set to NULL afterwards. + */ +void progress_destroy(progress_t ** progress); + +/** + * Display a progress dialog. + * + * @param progress Progress dialog to show. + * @param title Title for the progress window. + */ +void progress_show(progress_t * progress, const char *title); + +/** + * Hide the progress dialog. Note that this does not actually destroy + * the object. + * + * @param progress Progress dialog to hide. + */ +void progress_hide(progress_t * progress); + +/* the rest of these are for multi-threaded progress dialog */ + +/** + * Block the current thread until the progress dialog receives a done + * signal via progress_done() or progress_abort(). The dialog will + * periodically awake and update the user interface, based upon + * message received by its handle implementations. + * + * @param progress Progress object to wait against. + * + * @return 0 if the progress object got a progress_done(), < 0 if + * progress_abort(). + */ +int progress_wait(progress_t * progress); + +/** + * Signal to a progress object that this thread is ending + * successfully. This will cause all threads waiting upon the + * progress object to resume. + * + * @param progress Progress object to signal completion. + */ +void progress_done(progress_t * progress); + +/** + * Signal to a progress object that this thread completed with + * warnings. This will cause all threads waiting upon the progress + * object to resume. + * + * @param progress Progress object to signal completion. + * @param reason Explanation for warning, or NULL to use most recently + * written message as the reason. + */ +void progress_warn(progress_t * progress, char *reason, ...) __attribute__ ((format(printf, 2, 3))); + +/** + * Signal to a progress object that this thread is aborting. This + * will cause all threads waiting upon the progress object to resume. + * + * @param progress Progress object to signal completion. + * @param reason Explanation for abort, or NULL to abort for no + * reason. The most recently written message will be used as the + * reason. + */ +void progress_abort(progress_t * progress, char *reason, ...) __attribute__ ((format(printf, 2, 3))); + +/** + * Have the progress dialog show a message upon its next refresh. + * + * @param progress Progress object to update. + * @param fmt Format for string to display. + */ +void progress_update(progress_t * progress, char *fmt, ...) __attribute__ ((format(printf, 2, 3))); + +/** + * Implementation of libseaudit's message callback function. This + * will route messages generated by libseaudit to the progress + * dialog's display. To use this, pass the progress_t object as + * seaudit_log_create()'s callback_arg parameter. + */ +void progress_seaudit_handle_func(void *arg, const seaudit_log_t * log, int level, const char *fmt, va_list va_args); + +/** + * Implementation of a libapol message callback function. This will + * route messages generated by libapol to the progress dialog's + * display. To use this, pass the progress_t object as + * apol_policy_open()'s varg parameter. + */ +void progress_apol_handle_func(void *varg, const apol_policy_t * p, int level, const char *fmt, va_list argp); + +#endif diff --git a/seaudit/report_window.c b/seaudit/report_window.c new file mode 100644 index 0000000..d7213b5 --- /dev/null +++ b/seaudit/report_window.c @@ -0,0 +1,261 @@ +/** + * @file + * Run the dialog that generates reports. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "report_window.h" +#include "utilgui.h" +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <glade/glade.h> +#include <seaudit/report.h> + +struct report_window +{ + GladeXML *xml; + GtkDialog *dialog; + GtkRadioButton *all_messages_radio, *text_radio; + GtkToggleButton *malformed_toggle, *use_stylesheet_toggle; + GtkWidget *stylesheet_label, *stylesheet_browse, *config_browse; + GtkEntry *stylesheet_entry, *config_entry; + char *filename; + message_view_t *current_view; + seaudit_log_t *log; + int result; + progress_t *progress; +}; + +static void report_window_on_all_messages_toggle(GtkToggleButton * toggle, gpointer user_data) +{ + gboolean sens = gtk_toggle_button_get_active(toggle); + struct report_window *rw = (struct report_window *)user_data; + gtk_widget_set_sensitive(GTK_WIDGET(rw->malformed_toggle), sens); +} + +static void report_window_on_use_stylesheet_toggle(GtkToggleButton * toggle, gpointer user_data) +{ + gboolean sens = gtk_toggle_button_get_active(toggle); + struct report_window *rw = (struct report_window *)user_data; + gtk_widget_set_sensitive(rw->stylesheet_label, sens); + gtk_widget_set_sensitive(GTK_WIDGET(rw->stylesheet_entry), sens); + gtk_widget_set_sensitive(rw->stylesheet_browse, sens); +} + +static void report_window_on_output_format_toggle(GtkToggleButton * toggle, gpointer user_data) +{ + gboolean sens = gtk_toggle_button_get_active(toggle); + struct report_window *rw = (struct report_window *)user_data; + gtk_widget_set_sensitive(GTK_WIDGET(rw->use_stylesheet_toggle), !sens); + if (sens == TRUE) { + gtk_widget_set_sensitive(rw->stylesheet_label, FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(rw->stylesheet_entry), FALSE); + gtk_widget_set_sensitive(rw->stylesheet_browse, FALSE); + } else { + report_window_on_use_stylesheet_toggle(rw->use_stylesheet_toggle, rw); + } +} + +static void report_window_browse(GtkEntry * entry, GtkWindow * parent, const char *title) +{ + const char *current_path = gtk_entry_get_text(entry); + apol_vector_t *new_paths = util_open_file(parent, title, current_path, 0); + if (new_paths != NULL) { + gtk_entry_set_text(entry, apol_vector_get_element(new_paths, 0)); + apol_vector_destroy(&new_paths); + } +} + +static void report_window_on_stylesheet_browse_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data) +{ + struct report_window *rw = (struct report_window *)user_data; + report_window_browse(rw->stylesheet_entry, GTK_WINDOW(rw->dialog), "Select Style Sheet"); +} + +static void report_window_on_config_browse_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data) +{ + struct report_window *rw = (struct report_window *)user_data; + report_window_browse(rw->config_entry, GTK_WINDOW(rw->dialog), "Select Report Configuration"); +} + +/** + * Set up report window struct's widget pointers. + */ +static void report_window_init_dialog(struct report_window *rw, toplevel_t * top) +{ + rw->dialog = GTK_DIALOG(glade_xml_get_widget(rw->xml, "ReportWindow")); + assert(rw->dialog != NULL); + gtk_window_set_transient_for(GTK_WINDOW(rw->dialog), toplevel_get_window(top)); + + rw->all_messages_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(rw->xml, "ReportWindowAllMessagesRadio")); + rw->malformed_toggle = GTK_TOGGLE_BUTTON(glade_xml_get_widget(rw->xml, "ReportWindowMalformedCheck")); + assert(rw->all_messages_radio != NULL && rw->malformed_toggle != NULL); + + rw->text_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(rw->xml, "ReportWindowTextRadio")); + rw->use_stylesheet_toggle = GTK_TOGGLE_BUTTON(glade_xml_get_widget(rw->xml, "ReportWindowUseStylesheetCheck")); + assert(rw->text_radio != NULL && rw->use_stylesheet_toggle != NULL); + + rw->stylesheet_label = glade_xml_get_widget(rw->xml, "ReportWindowStylesheetLabel"); + rw->stylesheet_entry = GTK_ENTRY(glade_xml_get_widget(rw->xml, "ReportWindowStylesheetEntry")); + rw->stylesheet_browse = glade_xml_get_widget(rw->xml, "ReportWindowStylesheetBrowse"); + assert(rw->stylesheet_label != NULL && rw->stylesheet_entry && rw->stylesheet_browse); + + rw->config_entry = GTK_ENTRY(glade_xml_get_widget(rw->xml, "ReportWindowConfigEntry")); + rw->config_browse = glade_xml_get_widget(rw->xml, "ReportWindowConfigBrowse"); + assert(rw->config_entry != NULL && rw->config_browse != NULL); + + /* set up signal handlers */ + g_signal_connect(rw->all_messages_radio, "toggled", G_CALLBACK(report_window_on_all_messages_toggle), rw); + g_signal_connect(rw->text_radio, "toggled", G_CALLBACK(report_window_on_output_format_toggle), rw); + g_signal_connect(rw->use_stylesheet_toggle, "toggled", G_CALLBACK(report_window_on_use_stylesheet_toggle), rw); + g_signal_connect(rw->stylesheet_browse, "clicked", G_CALLBACK(report_window_on_stylesheet_browse_click), rw); + g_signal_connect(rw->config_browse, "clicked", G_CALLBACK(report_window_on_config_browse_click), rw); + +} + +/** + * The first time the report window is shown, populate its entry boxes + * with values from the user's preferences. On subsequent times + * remember the user's entries. + */ +static void report_window_copy_prefs(struct report_window *rw, toplevel_t * top) +{ + static int report_window_initialized = 0; + if (!report_window_initialized) { + preferences_t *prefs = toplevel_get_prefs(top); + gtk_entry_set_text(rw->stylesheet_entry, preferences_get_stylesheet(prefs)); + gtk_entry_set_text(rw->config_entry, preferences_get_report(prefs)); + } + report_window_initialized = 1; +} + +static gpointer report_window_create_report_runner(gpointer data) +{ + struct report_window *rw = (struct report_window *)data; + seaudit_model_t *model = NULL; + seaudit_report_t *report = NULL; + seaudit_report_format_e format = SEAUDIT_REPORT_FORMAT_TEXT; + int do_malformed = 0, do_stylesheet = 0; + const char *config_name = NULL, *stylesheet_name = NULL; + + rw->result = -1; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rw->all_messages_radio))) { + model = seaudit_model_create("All Messages", rw->log); + if (gtk_toggle_button_get_active(rw->malformed_toggle)) { + do_malformed = 1; + } + } else { + seaudit_model_t *view_model = message_view_get_model(rw->current_view); + model = seaudit_model_create_from_model(view_model); + } + if (model == NULL) { + progress_abort(rw->progress, "%s", strerror(errno)); + goto cleanup; + } + if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rw->text_radio))) { + format = SEAUDIT_REPORT_FORMAT_HTML; + } + if (gtk_toggle_button_get_active(rw->use_stylesheet_toggle)) { + do_stylesheet = 1; + } + stylesheet_name = gtk_entry_get_text(rw->stylesheet_entry); + if (strcmp(stylesheet_name, "") == 0) { + stylesheet_name = NULL; + } + config_name = gtk_entry_get_text(rw->config_entry); + if (strcmp(config_name, "") == 0) { + config_name = NULL; + } + + if ((report = seaudit_report_create(model)) == NULL) { + progress_abort(rw->progress, "%s", strerror(errno)); + goto cleanup; + } + if (seaudit_report_set_format(rw->log, report, format) < 0 || + seaudit_report_set_configuration(rw->log, report, config_name) < 0 || + seaudit_report_set_stylesheet(rw->log, report, stylesheet_name, do_stylesheet) < 0 || + seaudit_report_set_malformed(rw->log, report, do_malformed) < 0) { + goto cleanup; + } + progress_update(rw->progress, "Writing"); + if (seaudit_report_write(rw->log, report, rw->filename) < 0) { + goto cleanup; + } + rw->result = 0; + cleanup: + seaudit_report_destroy(&report); + seaudit_model_destroy(&model); + if (rw->result == 0) { + progress_done(rw->progress); + } else { + progress_abort(rw->progress, NULL); + } + return NULL; +} + +void report_window_run(toplevel_t * top, message_view_t * view) +{ + struct report_window rw; + /** keey track of most recently used report filename */ + static char *filename = NULL; + + memset(&rw, 0, sizeof(rw)); + rw.xml = glade_xml_new(toplevel_get_glade_xml(top), "ReportWindow", NULL); + report_window_init_dialog(&rw, top); + report_window_copy_prefs(&rw, top); + + rw.current_view = view; + rw.log = toplevel_get_log(top); + rw.progress = toplevel_get_progress(top); + rw.filename = filename; + do { + gint response = gtk_dialog_run(rw.dialog); + if (response != GTK_RESPONSE_OK) { + break; + } + if ((filename = util_save_file(GTK_WINDOW(rw.dialog), "Save Report to File", rw.filename)) == NULL) { + continue; + } + g_free(rw.filename); + rw.filename = filename; + util_cursor_wait(GTK_WIDGET(rw.dialog)); + progress_show(rw.progress, "Creating Report"); + g_thread_create(report_window_create_report_runner, &rw, FALSE, NULL); + progress_wait(rw.progress); + progress_hide(rw.progress); + /* Reset the cursor if the save failed. upon success, + * the window will be destroyed anyways, so don't + * bother resetting the cursor. + * + * (Real reason: util_cursor_clear() resets the cursor + * as an idle callback -- but by the time it triggers, + * the window will be destroyed by then.) + */ + if (rw.result == 0) { + break; + } + util_cursor_clear(GTK_WIDGET(rw.dialog)); + } while (1); + gtk_widget_destroy(GTK_WIDGET(rw.dialog)); +} diff --git a/seaudit/report_window.h b/seaudit/report_window.h new file mode 100644 index 0000000..ff9fcb7 --- /dev/null +++ b/seaudit/report_window.h @@ -0,0 +1,41 @@ +/** + * @file + * Dialog that generates reports from all messages or only those in + * the current view. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef REPORT_WINDOW_H +#define REPORT_WINDOW_H + +#include "toplevel.h" +#include "message_view.h" + +/** + * Display and run a dialog that allows the user to generate a report. + * + * @param top Toplevel containing preferences and log file for report + * writer. + * @param view Current message view. + */ +void report_window_run(toplevel_t * top, message_view_t * view); + +#endif diff --git a/seaudit/seaudit-report-group.conf b/seaudit/seaudit-report-group.conf new file mode 100644 index 0000000..3b0664c --- /dev/null +++ b/seaudit/seaudit-report-group.conf @@ -0,0 +1,3 @@ +# This is the logfile group configuration file for Logwatch +LogFile = messages + diff --git a/seaudit/seaudit-report-service.conf b/seaudit/seaudit-report-service.conf new file mode 100644 index 0000000..30efcde --- /dev/null +++ b/seaudit/seaudit-report-service.conf @@ -0,0 +1,5 @@ +# This is the service filter configuration file for Logwatch +Title = "seaudit-report" + +# Which logfile group... +LogFile = seaudit-report-group diff --git a/seaudit/seaudit-report-service.in b/seaudit/seaudit-report-service.in new file mode 100644 index 0000000..d923589 --- /dev/null +++ b/seaudit/seaudit-report-service.in @@ -0,0 +1,24 @@ +#!/bin/sh +# shell script to run seaudit-report on STDIN +# + +SEAUDITREPORT=@bindir@ +OPTS="--stdin --malformed" + +echo "Date Range: $LOGWATCH_DATE_RANGE" +echo "Detail Level: $LOGWATCH_DETAIL_LEVEL" +echo "Temp Dir: $LOGWATCH_TEMP_DIR" +echo "Debug Level: $LOGWATCH_DEBUG" + +# execute the program with the specified options +${SEAUDITREPORT} ${OPTS} + +# program failed +if [ $? -ne 0 ]; then + RC=$? + echo >&2 "Failed while executing seaudit-report.\n" + exit $RC +fi + +# All done, exit ok +exit 0 diff --git a/seaudit/seaudit-report.c b/seaudit/seaudit-report.c new file mode 100644 index 0000000..af3c6fb --- /dev/null +++ b/seaudit/seaudit-report.c @@ -0,0 +1,246 @@ +/** + * @file + * Command line tool for processing SELinux audit logs and generating + * a concise report containing standard information as well as + * customized information using seaudit views. Reports are rendered + * in either HTML or plain text. Future support will provide + * rendering into XML. The HTML report can be formatted by providing + * an alternate stylesheet file or by configuring the default + * stylesheet. This tool also provides the option for including + * malformed strings within the report. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2004-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include <seaudit/log.h> +#include <seaudit/parse.h> +#include <seaudit/report.h> + +#include <apol/vector.h> + +#include <errno.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define COPYRIGHT_INFO "Copyright (C) 2004-2007 Tresys Technology, LLC" + +enum opts +{ + OPT_HTML = 256, OPT_STYLESHEET +}; + +static struct option const longopts[] = { + {"html", no_argument, NULL, OPT_HTML}, + {"malformed", no_argument, NULL, 'm'}, + {"output", required_argument, NULL, 'o'}, + {"stylesheet", required_argument, NULL, OPT_STYLESHEET}, + {"stdin", no_argument, NULL, 's'}, + {"config", required_argument, NULL, 'c'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {NULL, 0, NULL, 0} +}; + +/** + * Vector of seaudit_log_t, corresponding to each of the log files to + * process. + */ +static apol_vector_t *logs = NULL; + +/** + * Error reporting log handler. + */ +static seaudit_log_t *first_log = NULL; + +/** + * Model that incorporates all of the logs within the logs vector. + */ +static seaudit_model_t *model = NULL; + +/** + * Report object for the above model. + */ +static seaudit_report_t *report = NULL; + +/** + * Destination file for the seaudit report, or NULL to write to + * standard output. + */ +static char *outfile = NULL; + +static void seaudit_report_info_usage(const char *program_name, int brief) +{ + printf("Usage: %s [OPTIONS] LOGFILE ...\n\n", program_name); + if (brief) { + printf("\tTry %s --help for more help.\n\n", program_name); + return; + } + printf("Generate a customized SELinux log report.\n\n"); + printf(" -s, --stdin read log data from standard input\n"); + printf(" -m, --malformed include malformed log messages\n"); + printf(" -o FILE, --output=FILE output to FILE\n"); + printf(" --config=FILE read configuration from FILE\n"); + printf(" --html set output format to HTML\n"); + printf(" --stylesheet=FILE HTML style sheet for formatting HTML report\n"); + printf(" (ignored if --html is not given)\n"); + printf(" -h, --help print this help text and exit\n"); + printf(" -V, --version print version information and exit\n"); + printf("\n"); + printf("Default style sheet is at %s.\n", APOL_INSTALL_DIR); +} + +static void parse_command_line_args(int argc, char **argv) +{ + int optc, i; + int do_malformed = 0, do_style = 0, read_stdin = 0; + seaudit_report_format_e format = SEAUDIT_REPORT_FORMAT_TEXT; + char *configfile = NULL, *stylesheet = NULL; + + /* get option arguments */ + while ((optc = getopt_long(argc, argv, "smo:c:hV", longopts, NULL)) != -1) { + switch (optc) { + case 's': /* read LOGFILES from standard input */ + read_stdin = 1; + break; + case 'm': /* include malformed messages */ + do_malformed = 1; + break; + case 'o': /* output file name */ + outfile = optarg; + break; + case 'c': /* Alternate config file path */ + configfile = optarg; + break; + case OPT_HTML: /* Set the output to format to html */ + format = SEAUDIT_REPORT_FORMAT_HTML; + do_style = 1; + break; + case OPT_STYLESHEET: /* HTML stylesheet file path */ + stylesheet = optarg; + do_style = 1; + break; + case 'h': + /* display help */ + seaudit_report_info_usage(argv[0], 0); + exit(0); + case 'V': + /* display version */ + printf("seaudit-report %s\n%s\n", VERSION, COPYRIGHT_INFO); + exit(0); + default: + /* display usage and handle error */ + seaudit_report_info_usage(argv[0], 1); + exit(-1); + } + } + + /* Throw warning if a stylesheet was specified, but the --html + * option was not. */ + if (stylesheet != NULL && format != SEAUDIT_REPORT_FORMAT_HTML) { + fprintf(stderr, "Warning: The --html option was not specified.\n"); + exit(-1); + } + + if (!read_stdin && optind >= argc) { + /* display usage and handle error */ + seaudit_report_info_usage(argv[0], 1); + exit(-1); + } + + if ((model = seaudit_model_create("seaudit-report", NULL)) == NULL) { + exit(-1); + } + if ((first_log = seaudit_log_create(NULL, NULL)) == NULL || seaudit_model_append_log(model, first_log) < 0) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + exit(-1); + } + if ((logs = apol_vector_create(NULL)) == NULL || apol_vector_append(logs, first_log) < 0) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + exit(-1); + } + if (read_stdin) { + /* Ensure that logfiles were not specified in addition + * to the standard-in option */ + if (optind < argc) { + fprintf(stderr, "WARNING: %s\n", "Command line filename(s) will be ignored. Reading from stdin."); + } + if (seaudit_log_parse(first_log, stdin) < 0) { + exit(-1); + } + } else { + /* Parse given filenames */ + FILE *f; + seaudit_log_t *l; + if ((f = fopen(argv[optind], "r")) == NULL) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + exit(-1); + } + if (seaudit_log_parse(first_log, f) < 0) { + exit(-1); + } + fclose(f); + for (i = optind + 1; i < argc; i++) { + if ((l = seaudit_log_create(NULL, NULL)) == NULL || seaudit_model_append_log(model, l) < 0) { + exit(-1); + } + if (apol_vector_append(logs, l) < 0) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + exit(-1); + } + if ((f = fopen(argv[i], "r")) == NULL) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + exit(-1); + } + if (seaudit_log_parse(l, f) < 0) { + exit(-1); + } + fclose(f); + } + } + + if ((report = seaudit_report_create(model)) == NULL || + seaudit_report_set_format(first_log, report, format) < 0 || + seaudit_report_set_configuration(first_log, report, configfile) < 0 || + seaudit_report_set_stylesheet(first_log, report, stylesheet, do_style) < 0 || + seaudit_report_set_malformed(first_log, report, do_malformed) < 0) { + exit(-1); + } +} + +int main(int argc, char **argv) +{ + size_t i; + parse_command_line_args(argc, argv); + if (seaudit_report_write(first_log, report, outfile) < 0) { + return -1; + } + seaudit_report_destroy(&report); + seaudit_model_destroy(&model); + for (i = 0; i < apol_vector_get_size(logs); i++) { + seaudit_log_t *l = apol_vector_get_element(logs, i); + seaudit_log_destroy(&l); + } + apol_vector_destroy(&logs); + return 0; +} diff --git a/seaudit/seaudit-report.conf b/seaudit/seaudit-report.conf new file mode 100644 index 0000000..fb36c24 --- /dev/null +++ b/seaudit/seaudit-report.conf @@ -0,0 +1,62 @@ +<?xml version="1.0" ?> +<!-- comment + seaudit-report.conf + + This conf file is used to configure information presented in + reports generated by the seaudit-report tool. + + The XML-based configuration file is laid out as follows: + Report Configuration + Standard Section Definitions + Custom Section Definitions + SEAudit View Definitions + + The STANDARD SECTION definitions define a set of predefined tags + that the tool will look for when creating the report. The tool + will consider each of these tags as a standard section for the + report. To exclude a standard section within the report, simply + remove the appropriate standard-section tag. The predefined + standard-section tags may use any of the following identifiers: + + 'Statistics': displays general statistics for the log. + 'PolicyLoads': displays all load policy messages. + 'EnforcementToggles': displays all enforcement toggle messages. + 'PolicyBooleans': displays all policy boolean messages. + 'AllowListing': displays all allow messages. + 'DenyListing': displays all denied messages. + + All of the above predefined tags require the attribute 'id' to + be specified or an error will be returned. The 'title' attribute + is optional. + + The CUSTOM SECTION definitions are used to create customized + sections within the report through the use of saved seaudit + view files. SEAudit views files can be created using the seaudit + GUI tool or by manually creating the file(s) with the correct + format. View tags should be provided as children within the + custom-section tag and a valid pathname is required for the + tags' 'file' attribute. An example of a custom-section tag can + be: + <custom-section title="Critical Errors"> + <view file="/home/sec_admin/seaudit-report/views/critical.vw"> + </view> + </custom-section> + + The 'title' attribute is optional for the custom-section tag. + + NOTE: The tool will display the reports' sections in the order + in which the tags are defined within the config file. So for + instance, inserting the custom-section tag to be the first defined + tag within the config file, will display the custom-section results + before all other results in the report. See the default settings + below for further information. +--> + +<seaudit-report title="SEAudit Log Report"> + <standard-section id ="Statistics" title="Log Statistics"></standard-section> + <standard-section id ="PolicyLoads" title="Policy Loads"></standard-section> + <standard-section id ="EnforcementToggles" title="Enforcement mode toggles"></standard-section> + <standard-section id ="PolicyBooleans" title="Policy boolean changes"></standard-section> + <standard-section id ="AllowListing" title="Allow Listing"></standard-section> + <standard-section id ="DenyListing" title="Deny Listing"></standard-section> +</seaudit-report> diff --git a/seaudit/seaudit-report.css b/seaudit/seaudit-report.css new file mode 100644 index 0000000..4780a2d --- /dev/null +++ b/seaudit/seaudit-report.css @@ -0,0 +1,178 @@ +# seaudit-report.css +# +# This is a default stylesheet template used to format an HTML report +# generated by the seaudit-report tool. +# +# There are two ways of configuring this style sheet: +# +# 1. External Style Sheet: +# Specify an external stylesheet to link to the HTML report using a +# <link> tag, as follows: +# <link rel="stylesheet" type="text/css" href="mystyle.css"> +# The seaudit-report tool will insert the <link> tag you define +# within the <head> section of the generated HTML report. +# +# 2. Internal Style Sheet: +# Specify internal style tags for the HTML report using the <style> +# tag. An example can be: +# <style type="text/css"> +# body {background-color: red} +# p {margin-left: 20px} +# </style> +# The seaudit-report tool will insert the <style> tag you define +# within the head section of the generated HTML report. +# +# The following is a list of defined HTML tags and their class selectors +# that can be used: +# +# HTML Tag Class Selector(s) +# -------- ----------------- +# <h1> report_title +# +# <h2> standard_section_title, custom_section_title +# +# <font> message_count_label, stats_label, message_date, +# host_name, syscall_timestamp, avc_type, +# src_context, tgt_context, obj_class +# +# <b> report_date, message_count, stats_count +# +# See the default (internal) style sheet format below for an example.s + +body +{ + font-size: 82%; + color:#000000; + background-color:white; + margin:0px; +} + +h1.report_title +{ + margin-top:0px; + margin-bottom:5px; + font-size:110%; + padding-top:0px; + padding-bottom:1px; + padding-left:4px; + color:#ffffff; + text-align:left; + background-color:#808080; +} + +h2.standard_section_title +{ + margin-top:0px; + margin-bottom:5px; + font-size:100%; + padding-top:0px; + padding-bottom:1px; + padding-left:0px; + color:black; + background-color:transparent; +} + +h2.custom_section_title +{ + margin-top:0px; + margin-bottom:5px; + font-size:100%; + padding-top:0px; + padding-bottom:1px; + padding-left:0px; + color:black; + background-color:transparent; +} + +font.message_count_label +{ +color: #000000; +background-color:transparent; +} + +b.message_count +{ +color: #000000; +background-color:transparent; +} + +font.stats_label +{ +color: #000000; +background-color:transparent; +} + +b.stats_count +{ +color: #000000; +background-color:transparent; +} + +b.report_date +{ +color: #000000; +background-color:transparent; +} + +font.message_date +{ +color: black; +background-color:transparent; +position:relative +} + +font.host_name +{ +color: #000000; +background-color:transparent; +} + +font.syscall_timestamp +{ +color: #000000; +background-color:transparent; +} + +font.avc_deny +{ +color:red; +background-color:transparent; +} + +font.avc_grant +{ +color:green; +background-color:transparent; +} + +font.exe +{ +color: #000000; +background-color:transparent; +} + +font.path +{ +color: blue; +background-color:transparent; +} + +font.src_context +{ +color:black; +background-color:transparent; +font-weight: bold +} + +font.tgt_context +{ +color:black; +background-color:transparent; +font-weight: bold +} + +font.obj_class +{ +color: #000000; +background-color:transparent; +}
\ No newline at end of file diff --git a/seaudit/seaudit-small.png b/seaudit/seaudit-small.png Binary files differnew file mode 100644 index 0000000..4cced9b --- /dev/null +++ b/seaudit/seaudit-small.png diff --git a/seaudit/seaudit.c b/seaudit/seaudit.c new file mode 100644 index 0000000..ff542a9 --- /dev/null +++ b/seaudit/seaudit.c @@ -0,0 +1,418 @@ +/** + * @file + * Main driver for the seaudit application. This file also + * implements the main class seaudit_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 program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "seaudit.h" +#include "toplevel.h" + +#include <apol/util.h> +#include <seaudit/model.h> +#include <seaudit/parse.h> +#include <seaudit/util.h> + +#include <errno.h> +#include <getopt.h> +#include <stdlib.h> +#include <string.h> +#include <glade/glade.h> +#include <glib.h> +#include <gtk/gtk.h> + +struct seaudit +{ + preferences_t *prefs; + apol_policy_t *policy; + apol_policy_path_t *policy_path; + seaudit_log_t *log; + FILE *file; + char *log_path; + size_t num_log_messages; + const struct tm *first, *last; + toplevel_t *top; +}; + +static struct option const opts[] = { + {"log", required_argument, NULL, 'l'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {NULL, 0, NULL, 0} +}; + +preferences_t *seaudit_get_prefs(seaudit_t * s) +{ + return s->prefs; +} + +void seaudit_set_policy(seaudit_t * s, apol_policy_t * policy, apol_policy_path_t * path) +{ + if (policy != NULL) { + if (preferences_add_recent_policy(s->prefs, path) < 0) { + toplevel_ERR(s->top, "%s", strerror(errno)); + apol_policy_destroy(&policy); + return; + } + apol_policy_destroy(&s->policy); + s->policy = policy; + if (path != s->policy_path) { + apol_policy_path_destroy(&s->policy_path); + } + s->policy_path = path; + } else { + apol_policy_destroy(&s->policy); + apol_policy_path_destroy(&s->policy_path); + } +} + +apol_policy_t *seaudit_get_policy(seaudit_t * s) +{ + return s->policy; +} + +apol_policy_path_t *seaudit_get_policy_path(seaudit_t * s) +{ + return s->policy_path; +} + +void seaudit_set_log(seaudit_t * s, seaudit_log_t * log, FILE * f, const char *filename) +{ + if (s->file != NULL) { + fclose(s->file); + s->file = NULL; + } + if (log != NULL) { + seaudit_model_t *model = NULL; + apol_vector_t *messages = NULL; + char *t = NULL; + if ((model = seaudit_model_create(NULL, log)) == NULL || + (messages = seaudit_model_get_messages(log, model)) == NULL || + (t = strdup(filename)) == NULL || preferences_add_recent_log(s->prefs, filename) < 0) { + toplevel_ERR(s->top, "%s", strerror(errno)); + seaudit_log_destroy(&log); + seaudit_model_destroy(&model); + apol_vector_destroy(&messages); + free(t); + return; + } + /* do it in this order, for filename could be pointing to + * s->log_path */ + seaudit_log_destroy(&s->log); + s->log = log; + s->file = f; + free(s->log_path); + s->log_path = t; + s->num_log_messages = apol_vector_get_size(messages); + if (s->num_log_messages == 0) { + s->first = s->last = NULL; + } else { + seaudit_message_t *message = apol_vector_get_element(messages, 0); + s->first = seaudit_message_get_time(message); + message = apol_vector_get_element(messages, s->num_log_messages - 1); + s->last = seaudit_message_get_time(message); + } + seaudit_model_destroy(&model); + apol_vector_destroy(&messages); + } else { + seaudit_log_destroy(&s->log); + free(s->log_path); + s->log_path = NULL; + s->num_log_messages = 0; + s->first = s->last = NULL; + } +} + +int seaudit_parse_log(seaudit_t * s) +{ + return seaudit_log_parse(s->log, s->file); +} + +seaudit_log_t *seaudit_get_log(seaudit_t * s) +{ + return s->log; +} + +char *seaudit_get_log_path(seaudit_t * s) +{ + return s->log_path; +} + +apol_vector_t *seaudit_get_log_users(seaudit_t * s) +{ + if (s->log == NULL) { + return NULL; + } else { + return seaudit_log_get_users(s->log); + } +} + +apol_vector_t *seaudit_get_log_roles(seaudit_t * s) +{ + if (s->log == NULL) { + return NULL; + } else { + return seaudit_log_get_roles(s->log); + } +} + +apol_vector_t *seaudit_get_log_types(seaudit_t * s) +{ + if (s->log == NULL) { + return NULL; + } else { + return seaudit_log_get_types(s->log); + } +} + +apol_vector_t *seaudit_get_log_mls_lvl(seaudit_t * s) +{ + if (s->log == NULL) { + return NULL; + } else { + return seaudit_log_get_mls_lvl(s->log); + } +} + +apol_vector_t *seaudit_get_log_mls_clr(seaudit_t * s) +{ + if (s->log == NULL) { + return NULL; + } else { + return seaudit_log_get_mls_clr(s->log); + } +} + +apol_vector_t *seaudit_get_log_classes(seaudit_t * s) +{ + if (s->log == NULL) { + return NULL; + } else { + return seaudit_log_get_classes(s->log); + } +} + +size_t seaudit_get_num_log_messages(seaudit_t * s) +{ + return s->num_log_messages; +} + +const struct tm *seaudit_get_log_first(seaudit_t * s) +{ + return s->first; +} + +const struct tm *seaudit_get_log_last(seaudit_t * s) +{ + return s->last; +} + +static seaudit_t *seaudit_create(preferences_t * prefs) +{ + seaudit_t *s = calloc(1, sizeof(*s)); + if (s != NULL) { + s->prefs = prefs; + } + return s; +} + +static void seaudit_destroy(seaudit_t ** s) +{ + if (s != NULL && *s != NULL) { + apol_policy_destroy(&(*s)->policy); + seaudit_log_destroy(&(*s)->log); + if ((*s)->file != NULL) { + fclose((*s)->file); + } + preferences_destroy(&(*s)->prefs); + toplevel_destroy(&(*s)->top); + free((*s)->policy_path); + free((*s)->log_path); + free(*s); + *s = NULL; + } +} + +static void print_version_info(void) +{ + printf("seaudit %s\n%s\n", VERSION, COPYRIGHT_INFO); +} + +static void print_usage_info(const char *program_name, int brief) +{ + printf("Usage: %s [OPTIONS] [POLICY ...]\n\n", program_name); + if (brief) { + printf("\tTry %s --help for more help.\n\n", program_name); + return; + } + printf("Audit Log analysis tool for Security Enhanced Linux.\n\n"); + printf(" -l FILE, --log=FILE open the log FILE\n"); + printf(" -h, --help print this help text and exit\n"); + printf(" -V, --version print version information and exit\n\n"); +} + +static void seaudit_parse_command_line(seaudit_t * seaudit, int argc, char **argv, const char **log, apol_policy_path_t ** policy) +{ + int optc; + *log = NULL; + *policy = NULL; + apol_policy_path_type_e path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC; + char *primary_path = NULL; + apol_vector_t *modules = NULL; + while ((optc = getopt_long(argc, argv, "l:hV", opts, NULL)) != -1) { + switch (optc) { + case 'l': + { + *log = optarg; + break; + } + case 'h': + { + print_usage_info(argv[0], 0); + seaudit_destroy(&seaudit); + exit(EXIT_SUCCESS); + } + case 'V': + { + print_version_info(); + seaudit_destroy(&seaudit); + exit(EXIT_SUCCESS); + } + default: + { + /* unrecognized argument give full usage */ + print_usage_info(argv[0], 1); + seaudit_destroy(&seaudit); + exit(EXIT_FAILURE); + } + } + } + if (optind < argc) { /* modules */ + if ((modules = apol_vector_create(NULL)) == NULL) { + ERR(NULL, "%s", strerror(ENOMEM)); + seaudit_destroy(&seaudit); + exit(EXIT_FAILURE); + } + path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC; + primary_path = argv[optind++]; + while (argc - optind) { + if (apol_vector_append(modules, argv[optind])) { + ERR(NULL, "%s", strerror(ENOMEM)); + seaudit_destroy(&seaudit); + exit(EXIT_FAILURE); + } + path_type = APOL_POLICY_PATH_TYPE_MODULAR; + optind++; + } + } + if (*log == NULL) { + *log = preferences_get_log(seaudit->prefs); + } + if (primary_path != NULL && strcmp(primary_path, "") != 0) { + if (apol_file_is_policy_path_list(primary_path)) { + if ((*policy = apol_policy_path_create_from_file(primary_path)) == NULL) { + ERR(NULL, "%s", "invalid policy list"); + seaudit_destroy(&seaudit); + exit(EXIT_FAILURE); + } + } else { + if ((*policy = apol_policy_path_create(path_type, primary_path, modules)) == NULL) { + ERR(NULL, "%s", strerror(ENOMEM)); + seaudit_destroy(&seaudit); + exit(EXIT_FAILURE); + } + } + } else { + const apol_policy_path_t *path = preferences_get_policy(seaudit->prefs); + if (path != NULL && (*policy = apol_policy_path_create_from_policy_path(path)) == NULL) { + ERR(NULL, "%s", strerror(ENOMEM)); + seaudit_destroy(&seaudit); + exit(EXIT_FAILURE); + } + } + apol_vector_destroy(&modules); +} + +/* + * We don't want to do the heavy work of loading and displaying the + * log and policy before the main loop has started because it will + * freeze the gui for too long. To solve this, the function is called + * from an idle callback set-up in main. + */ +struct delay_file_data +{ + toplevel_t *top; + const char *log_filename; + apol_policy_path_t *policy_path; +}; + +static gboolean delayed_main(gpointer data) +{ + struct delay_file_data *dfd = (struct delay_file_data *)data; + if (dfd->log_filename != NULL && strcmp(dfd->log_filename, "") != 0) { + toplevel_open_log(dfd->top, dfd->log_filename); + } + if (dfd->policy_path != NULL) { + toplevel_open_policy(dfd->top, dfd->policy_path); + } + return FALSE; +} + +int main(int argc, char **argv) +{ + preferences_t *prefs; + seaudit_t *app; + const char *log; + apol_policy_path_t *policy; + struct delay_file_data file_data; + + gtk_init(&argc, &argv); + glade_init(); + if (!g_thread_supported()) + g_thread_init(NULL); + if ((prefs = preferences_create()) == NULL) { + ERR(NULL, "%s", strerror(ENOMEM)); + exit(EXIT_FAILURE); + } + if ((app = seaudit_create(prefs)) == NULL) { + ERR(NULL, "%s", strerror(ENOMEM)); + exit(EXIT_FAILURE); + } + seaudit_parse_command_line(app, argc, argv, &log, &policy); + if ((app->top = toplevel_create(app)) == NULL) { + ERR(NULL, "%s", strerror(ENOMEM)); + seaudit_destroy(&app); + exit(EXIT_FAILURE); + } + file_data.top = app->top; + file_data.log_filename = log; + file_data.policy_path = policy; + g_idle_add(&delayed_main, &file_data); + gtk_main(); + if (preferences_write_to_conf_file(app->prefs) < 0) { + ERR(NULL, "%s", strerror(ENOMEM)); + } + seaudit_destroy(&app); + exit(EXIT_SUCCESS); +} diff --git a/seaudit/seaudit.glade b/seaudit/seaudit.glade new file mode 100644 index 0000000..95da87e --- /dev/null +++ b/seaudit/seaudit.glade @@ -0,0 +1,7713 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> +<requires lib="gnome"/> + +<widget class="GtkDialog" id="PreferencesWindow"> + <property name="title" translatable="yes">seaudit Preferences</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">True</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">True</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <property name="has_separator">True</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="PrefsViewCancelButton"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-6</property> + <accessibility> + <atkproperty name="AtkObject::accessible_name" translatable="yes">Close</atkproperty> + </accessibility> + </widget> + </child> + + <child> + <widget class="GtkButton" id="PrefsViewOKButton"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkFrame" id="frame1"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkVBox" id="vbox39"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkTable" id="table2"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">4</property> + <property name="homogeneous">False</property> + <property name="row_spacing">4</property> + <property name="column_spacing">10</property> + + <child> + <widget class="GtkLabel" id="label7"> + <property name="visible">True</property> + <property name="label" translatable="yes">Policy:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="PrefsViewLogBrowseButton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment3"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image3"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label8"> + <property name="visible">True</property> + <property name="label" translatable="yes">Browse</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="PrefsViewLogEntry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="PrefsViewLogCurrentButton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Use Current</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="label" translatable="yes">Log:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="PrefsViewPolicyModifyButton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment4"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox5"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image4"> + <property name="visible">True</property> + <property name="stock">gtk-edit</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label9"> + <property name="visible">True</property> + <property name="label" translatable="yes">Choose...</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="PrefsViewPolicyEntry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">False</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="PrefsViewPolicyCurrentButton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Use Current</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table31"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">4</property> + <property name="column_spacing">10</property> + + <child> + <widget class="GtkLabel" id="label13"> + <property name="visible">True</property> + <property name="label" translatable="yes">Report Config File:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label14"> + <property name="visible">True</property> + <property name="label" translatable="yes">Report Style Sheet:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="PrefsViewStylesheetEntry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="PrefsViewConfigBrowseButton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment5"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox6"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="label" translatable="yes">Browse</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="PrefsViewStylesheetBrowseButton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment6"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox7"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image6"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="label" translatable="yes">Browse</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="PrefsViewConfigEntry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Default Files</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame2"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkTable" id="table3"> + <property name="border_width">10</property> + <property name="visible">True</property> + <property name="n_rows">5</property> + <property name="n_columns">5</property> + <property name="homogeneous">False</property> + <property name="row_spacing">2</property> + <property name="column_spacing">18</property> + + <child> + <widget class="GtkCheckButton" id="SourceTypeCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Source Type</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="SourceRoleCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Source Role</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="SourceUserCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Source User</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="SourceMLSLVLCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Source MLS Level</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="SourceMLSCLRCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Source MLS Clearance</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="DateCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Date</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="MessageCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Message</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="HostCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Hostname</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="TargetUserCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Target User</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="TargetRoleCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Target Role</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="TargetTypeCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Target Type</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="TargetMLSLVLCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Target MLS Level</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="TargetMLSCLRCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Target MLS Clearance</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="ObjectClassCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Object Class</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="PermissionCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Permission</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="ExecutableCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Executable</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="PIDCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">PID</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">4</property> + <property name="right_attach">5</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="InodeCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Inode</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">4</property> + <property name="right_attach">5</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="PathCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Path</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">4</property> + <property name="right_attach">5</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="OtherCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Other</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">4</property> + <property name="right_attach">5</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="NameCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Name</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="CommandCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Command</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label11"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Columns to Display</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame3"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkTable" id="table4"> + <property name="border_width">10</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">1</property> + <property name="homogeneous">False</property> + <property name="row_spacing">2</property> + <property name="column_spacing">18</property> + + <child> + <widget class="GtkHBox" id="hbox8"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkLabel" id="label15"> + <property name="visible">True</property> + <property name="label" translatable="yes">Log update interval (in milliseconds):</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="PrefsViewIntervalEntry"> + <property name="width_request">53</property> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Time interval for updating the log in real-time mode</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="RealTimeCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Enable real-time monitoring of newly opened log files</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label12"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Real-time Monitoring</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="PolicyWindow"> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK</property> + <property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property> + <property name="title" translatable="yes">Find TE Rules</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="default_width">800</property> + <property name="default_height">600</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">True</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkNotebook" id="PolicyWindowNotebook"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="show_tabs">True</property> + <property name="show_border">True</property> + <property name="tab_pos">GTK_POS_TOP</property> + <property name="scrollable">False</property> + <property name="enable_popup">False</property> + + <child> + <widget class="GtkAlignment" id="alignment2"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkVBox" id="vbox2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="border_width">10</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">41</property> + + <child> + <widget class="GtkVBox" id="vbox3"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkCheckButton" id="PolicyWindowSTypeCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Source type regular expression</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkComboBoxEntry" id="PolicyWindowSTypeCombo"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="add_tearoffs">False</property> + <property name="has_frame">True</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="PolicyWindowSTypeDirectCheck"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Only show direct matches</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkCheckButton" id="PolicyWindowTTypeCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Target type regular expression</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkComboBoxEntry" id="PolicyWindowTTypeCombo"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="add_tearoffs">False</property> + <property name="has_frame">True</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="PolicyWindowTTypeDirectCheck"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Only show direct matches</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox5"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkCheckButton" id="PolicyWindowClassCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Object class</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkComboBoxEntry" id="PolicyWindowClassCombo"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="add_tearoffs">False</property> + <property name="has_frame">True</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox6"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkButton" id="PolicyWindowFindTERulesButton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <accelerator key="Return" modifiers="0" signal="clicked"/> + + <child> + <widget class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="stock">gtk-find</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label8"> + <property name="visible">True</property> + <property name="label" translatable="yes">Find TE Rules</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="PolicyWindowCloseButton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="PolicyWindowTERulesResults"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK</property> + <property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property> + <property name="editable">False</property> + <property name="overwrite">False</property> + <property name="accepts_tab">True</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_NONE</property> + <property name="cursor_visible">True</property> + <property name="pixels_above_lines">0</property> + <property name="pixels_below_lines">0</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">0</property> + <property name="right_margin">0</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="PolicyWindowFindTERulesTab"> + <property name="visible">True</property> + <property name="label" translatable="yes">Find TE Rules</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="PolicyWindowPolicyText"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">False</property> + <property name="overwrite">False</property> + <property name="accepts_tab">True</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_NONE</property> + <property name="cursor_visible">True</property> + <property name="pixels_above_lines">0</property> + <property name="pixels_below_lines">0</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">0</property> + <property name="right_margin">0</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + </widget> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="PolicyWindowPolicyTextTab"> + <property name="visible">True</property> + <property name="label" translatable="yes">Policy Source</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkStatusbar" id="statusbar1"> + <property name="visible">True</property> + <property name="has_resize_grip">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="TopLevel"> + <property name="title" translatable="yes">seaudit</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="default_width">950</property> + <property name="default_height">650</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">True</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <signal name="destroy" handler="toplevel_on_destroy" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 16:53:05 GMT"/> + + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkMenuBar" id="menubar1"> + <property name="visible">True</property> + <property name="pack_direction">GTK_PACK_DIRECTION_LTR</property> + <property name="child_pack_direction">GTK_PACK_DIRECTION_LTR</property> + + <child> + <widget class="GtkMenuItem" id="FileMenu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_File</property> + <property name="use_underline">True</property> + + <child> + <widget class="GtkMenu" id="FileMenu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="OpenLog"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Open a log file</property> + <property name="label" translatable="yes">Open _Log</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_open_log_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:23:31 GMT"/> + <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1458"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="OpenRecentLog"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Open a log from the recent files list</property> + <property name="label" translatable="yes">Open Recent Log</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator3"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="OpenPolicy"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Open a policy</property> + <property name="label" translatable="yes">Open _Policy</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_open_policy_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:23:18 GMT"/> + <accelerator key="P" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1459"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="OpenRecentPolicy"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Open a policy from the recent files list</property> + <property name="label" translatable="yes">Open Recent Policy</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separatormenuitem1"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="Preferences"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Edit startup and display preferences</property> + <property name="label" translatable="yes">Preferences</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_preferences_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:22:57 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1460"> + <property name="visible">True</property> + <property name="stock">gtk-preferences</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator4"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="Quit"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Quit seaudit</property> + <property name="label" translatable="yes">_Quit</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_quit_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:24:49 GMT"/> + <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1461"> + <property name="visible">True</property> + <property name="stock">gtk-quit</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="ViewMenu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_View</property> + <property name="use_underline">True</property> + + <child> + <widget class="GtkMenu" id="ViewMenu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="NewView"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Create a new default view</property> + <property name="label" translatable="yes">_New View</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_new_view_activate" object="TopLevel" last_modification_time="Tue, 05 Dec 2006 20:38:59 GMT"/> + <accelerator key="N" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1462"> + <property name="visible">True</property> + <property name="stock">gtk-new</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="OpenView"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Open an existing view</property> + <property name="label" translatable="yes">_Open View...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_open_view_activate" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 15:48:22 GMT"/> + <accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1463"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="SaveView"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Save the current view</property> + <property name="label" translatable="yes">_Save View</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_save_view_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:34:20 GMT"/> + <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1464"> + <property name="visible">True</property> + <property name="stock">gtk-save</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="SaveViewAs"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Save the current view as a new file</property> + <property name="label" translatable="yes">S_ave View As...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_save_viewas_activate" object="TopLevel" last_modification_time="Tue, 05 Dec 2006 20:40:24 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1465"> + <property name="visible">True</property> + <property name="stock">gtk-save-as</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator5"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="ModifyView"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Modify the current view</property> + <property name="label" translatable="yes">_Modify View</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_modify_view_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:35:27 GMT"/> + <accelerator key="M" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1466"> + <property name="visible">True</property> + <property name="stock">gtk-convert</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator7"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="ExportAll"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Export to a file all messages in the current view</property> + <property name="label" translatable="yes">_Export Messages...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_export_all_messages_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:37:54 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="ExportSelected"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Export to a file selected messages</property> + <property name="label" translatable="yes">E_xport Selected Messages...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_export_selected_messages_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:37:16 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator8"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="ViewMessage"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">View all fields of the selected message</property> + <property name="label" translatable="yes">_View Selected Message</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_view_entire_message_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:39:51 GMT"/> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="SearchMenu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Search</property> + <property name="use_underline">True</property> + + <child> + <widget class="GtkMenu" id="SearchMenu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="FindTERules"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Find TE rules in the loaded policy</property> + <property name="label" translatable="yes">_Find TE Rules...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_find_terules_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 16:30:21 GMT"/> + <accelerator key="F" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1467"> + <property name="visible">True</property> + <property name="stock">gtk-find</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="ToolsMenu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Tools</property> + <property name="use_underline">True</property> + + <child> + <widget class="GtkMenu" id="ToolsMenu_menu"> + + <child> + <widget class="GtkMenuItem" id="CreateReport"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Create a report from audit messages</property> + <property name="label" translatable="yes">_Create Report...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_create_report_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 16:30:21 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator10"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkCheckMenuItem" id="MonitorLog"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Enable or disable real-time monitoring of log file</property> + <property name="label" translatable="yes">_Monitor Log</property> + <property name="use_underline">True</property> + <property name="active">False</property> + <signal name="activate" handler="toplevel_on_monitor_log_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 16:35:09 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="ClearView"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Clear all messages from the current view</property> + <property name="label" translatable="yes">C_lear View</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_clear_view_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 16:30:21 GMT"/> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="HelpMenu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Help</property> + <property name="use_underline">True</property> + + <child> + <widget class="GtkMenu" id="HelpMenu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="Help"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Help</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_help_activate" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 15:44:08 GMT"/> + <accelerator key="H" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1468"> + <property name="visible">True</property> + <property name="stock">gtk-help</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator9"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="About"> + <property name="visible">True</property> + <property name="label" translatable="yes">_About seaudit</property> + <property name="use_underline">True</property> + <signal name="activate" handler="toplevel_on_about_seaudit_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 16:02:03 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1469"> + <property name="visible">True</property> + <property name="stock">gtk-about</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkButton" id="FindTERulesButton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Find TE rules in the loaded policy</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <signal name="clicked" handler="toplevel_on_find_terules_click" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 15:48:56 GMT"/> + + <child> + <widget class="GtkAlignment" id="alignment54"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox69"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1488"> + <property name="visible">True</property> + <property name="stock">gtk-find</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label207"> + <property name="visible">True</property> + <property name="label" translatable="yes">Find TE Rules</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="ModifyViewButton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Modify the current view</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <signal name="clicked" handler="toplevel_on_modify_view_click" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 15:48:51 GMT"/> + + <child> + <widget class="GtkAlignment" id="alignment55"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox70"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1489"> + <property name="visible">True</property> + <property name="stock">gtk-convert</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label208"> + <property name="visible">True</property> + <property name="label" translatable="yes">Modify View</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="MonitorLogButton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Toggle the monitor log feature</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <signal name="clicked" handler="toplevel_on_monitor_log_click" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 15:48:44 GMT"/> + + <child> + <widget class="GtkAlignment" id="alignment56"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox71"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1490"> + <property name="visible">True</property> + <property name="stock">gtk-refresh</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label209"> + <property name="visible">True</property> + <property name="label" translatable="yes">Monitor Log</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="ClearViewButton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Clear messages in the current view</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <signal name="clicked" handler="toplevel_on_clear_view_click" object="TopLevel" last_modification_time="Thu, 05 Jul 2007 21:07:02 GMT"/> + + <child> + <widget class="GtkAlignment" id="alignment57"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox72"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1491"> + <property name="visible">True</property> + <property name="stock">gtk-clear</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label210"> + <property name="visible">True</property> + <property name="label" translatable="yes">Clear View</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="NotebookVBox"> + <property name="border_width">1</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox5"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="PolicyVersionLabel"> + <property name="visible">True</property> + <property name="label" translatable="yes">Policy: No Policy</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_END</property> + <property name="width_chars">28</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">20</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="LogNumLabel"> + <property name="visible">True</property> + <property name="label" translatable="yes">Log Messages: No log</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.519999980927</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_END</property> + <property name="width_chars">24</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="LogDateLabel"> + <property name="visible">True</property> + <property name="label" translatable="yes">Dates: No log</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_END</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="MonitorLogLabel"> + <property name="visible">True</property> + <property name="label" translatable="yes">Monitor Status: <span foreground="red">OFF</span></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">18</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">20</property> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="ReportWindow"> + <property name="title" translatable="yes">Create Report</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">True</property> + <property name="default_width">760</property> + <property name="default_height">240</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">True</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <property name="has_separator">True</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area2"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="ReportWindowClose"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-7</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="ReportWindowCreate"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-5</property> + + <child> + <widget class="GtkAlignment" id="alignment26"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox44"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1474"> + <property name="visible">True</property> + <property name="stock">gtk-new</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label129"> + <property name="visible">True</property> + <property name="label">Create Report</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox36"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkFrame" id="frame27"> + <property name="border_width">8</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + + <child> + <widget class="GtkAlignment" id="alignment21"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">4</property> + <property name="right_padding">4</property> + + <child> + <widget class="GtkVBox" id="vbox14"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkVBox" id="vbox18"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="ReportWindowAllMessagesRadio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Messages from entire audit log</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="ReportWindowViewMessagesRadio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Messages from current view +(Does not preserve sort order.)</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">ReportWindowAllMessagesRadio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="ReportWindowMalformedCheck"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Include malformed messages</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label122"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Input</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame28"> + <property name="border_width">8</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + + <child> + <widget class="GtkAlignment" id="alignment22"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">4</property> + <property name="right_padding">4</property> + + <child> + <widget class="GtkVBox" id="vbox15"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkVBox" id="vbox16"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="ReportWindowTextRadio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Plain Text</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="ReportWindowHTMLRadio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">HTML</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">ReportWindowTextRadio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox17"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkCheckButton" id="ReportWindowUseStylesheetCheck"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Use HTML style sheet</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox42"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">7</property> + + <child> + <widget class="GtkLabel" id="ReportWindowStylesheetLabel"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="label" translatable="yes"> Style sheet file:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="ReportWindowStylesheetEntry"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="ReportWindowStylesheetBrowse"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment25"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox43"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1473"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label128"> + <property name="visible">True</property> + <property name="label" translatable="yes">Browse</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox39"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">7</property> + + <child> + <widget class="GtkLabel" id="label123"> + <property name="visible">True</property> + <property name="label" translatable="yes">Report config file:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="ReportWindowConfigEntry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="ReportWindowConfigBrowse"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment24"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox41"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1472"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label126"> + <property name="visible">True</property> + <property name="label" translatable="yes">Browse</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label124"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Output</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="ModifyViewWindow"> + <property name="title" translatable="yes">Modify View</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">True</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">True</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <property name="has_separator">True</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox3"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area3"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="button48"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="button49"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-apply</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-10</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="button56"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox19"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="hbox46"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkLabel" id="label131"> + <property name="visible">True</property> + <property name="label" translatable="yes">View name:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="ModifyViewNameEntry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame29"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkHBox" id="hbox47"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkComboBox" id="ModifyViewVisibleCombo"> + <property name="visible">True</property> + <property name="items" translatable="yes">Show +Hide</property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label132"> + <property name="visible">True</property> + <property name="label" translatable="yes">messages that match</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="ModifyViewMatchCombo"> + <property name="visible">True</property> + <property name="items" translatable="yes">all filters +any filter</property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label133"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Match</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame30"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkHBox" id="hbox48"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow4"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="ModifyViewFilterView"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">False</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVButtonBox" id="vbuttonbox2"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_START</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkButton" id="ModifyViewAddButton"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-add</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="ModifyViewEditButton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-edit</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="ModifyViewRemoveButton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-remove</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="ModifyViewImportButton"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment28"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox49"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1476"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label134"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Import</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkButton" id="ModifyViewExportButton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment29"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox50"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1477"> + <property name="visible">True</property> + <property name="stock">gtk-save</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label135"> + <property name="visible">True</property> + <property name="label" translatable="yes">E_xport</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label136"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Filters</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="FilterWindow"> + <property name="title" translatable="yes">Edit Filter</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">True</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">True</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <property name="has_separator">True</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area4"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="closebutton1"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-7</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox20"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkFrame" id="frame31"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkVBox" id="vbox21"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="hbox51"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkLabel" id="label138"> + <property name="visible">True</property> + <property name="label" translatable="yes">Filter name:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewNameEntry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"> </property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox52"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkLabel" id="label139"> + <property name="visible">True</property> + <property name="label" translatable="yes">Filter match:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="FilterViewMatchCombo"> + <property name="visible">True</property> + <property name="items" translatable="yes">All Criteria +Any Criterion</property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkNotebook" id="notebook1"> + <property name="border_width">4</property> + <property name="width_request">349</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="show_tabs">True</property> + <property name="show_border">True</property> + <property name="tab_pos">GTK_POS_TOP</property> + <property name="scrollable">False</property> + <property name="enable_popup">False</property> + + <child> + <widget class="GtkVBox" id="vbox22"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkFrame" id="frame32"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkTable" id="table17"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="n_rows">5</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">4</property> + <property name="column_spacing">4</property> + + <child> + <widget class="GtkEntry" id="FilterViewSUserEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Source user(s) to filter, comma separated</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewSRoleEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Source role(s) to filter, comma separated</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewSTypeEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Source type(s) to filter, comma separated</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewSMLSLVLEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Source MLS Level(s) to filter, comma separated</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewSMLSCLREntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Source MLS Clearance(s) to filter, comma separated</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="FilterViewSRoleButton"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Select source role(s)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes"> Role: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="FilterViewSUserButton"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Select source user(s)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes"> User: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="FilterViewSTypeButton"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Select source type(s)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes"> Type: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="FilterViewSMLSLVLButton"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Select source MLS Level(s)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes"> MLS Level: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="FilterViewSMLSCLRButton"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Select source MLS Clearance(s)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes"> MLS Clearance: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label140"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Source Context</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame33"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkTable" id="table18"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="n_rows">5</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">4</property> + <property name="column_spacing">4</property> + + <child> + <widget class="GtkButton" id="FilterViewTTypeButton"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Select target type(s)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes"> Type: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="FilterViewTUserButton"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Select target user(s)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes"> User: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="FilterViewTRoleButton"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Select target role(s)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes"> Role: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="FilterViewTMLSLVLButton"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Select target MLS Level(s)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes"> MLS Level: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="FilterViewTMLSCLRButton"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Select target MLS Clearance(s)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes"> MLS Clearance: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewTTypeEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Target type(s) to filter, comma separated</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewTUserEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Target user(s) to filter, comma separated</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewTRoleEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Target role(s) to filter, comma separated</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewTMLSLVLEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Target MLS Level(s) to filter, comma separated</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewTMLSCLREntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Target MLS Clearance(s) to filter, comma separated</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="y_options"></property> + </packing> + </child> + + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label141"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Target Context</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame34"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkHBox" id="hbox53"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkButton" id="FilterViewClassButton"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Select object class(es)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes"> Class: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewClassEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Object class(es) to filter, comma separated</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label142"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Object Class</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox6"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_START</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkButton" id="FilterViewContextClearButton"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment38"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox58"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1480"> + <property name="visible">True</property> + <property name="stock">gtk-clear</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label175"> + <property name="visible">True</property> + <property name="label" translatable="yes">Clear Tab</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label144"> + <property name="visible">True</property> + <property name="label" translatable="yes">Context</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox23"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkFrame" id="frame35"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkTable" id="table19"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">4</property> + <property name="column_spacing">4</property> + + <child> + <widget class="GtkLabel" id="label145"> + <property name="visible">True</property> + <property name="label" translatable="yes">IP Address:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label146"> + <property name="visible">True</property> + <property name="label" translatable="yes">Port:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label147"> + <property name="visible">True</property> + <property name="label" translatable="yes">Interface:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewIPAddrEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">IP Address to filter (match as a glob expression)</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewPortEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Port number to match (any of port, source, dest, fport or lport)</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewNetIfEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Network interface to match (exact string match)</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label148"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Networking</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame36"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkTable" id="table20"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="n_rows">5</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">4</property> + <property name="column_spacing">4</property> + + <child> + <widget class="GtkLabel" id="label149"> + <property name="visible">True</property> + <property name="label" translatable="yes">Executable:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewExeEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Name of executable (match as a glob expression)</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewPathEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Path of target file (match as a glob expression)</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label150"> + <property name="visible">True</property> + <property name="label" translatable="yes">Path:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label151"> + <property name="visible">True</property> + <property name="label" translatable="yes">Hostname:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewHostEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Host system that generated audit message (match as a glob expression)</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label152"> + <property name="visible">True</property> + <property name="label" translatable="yes">Command:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="FilterViewCommEntry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Name of command (match as a glob expression)</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label153"> + <property name="visible">True</property> + <property name="label" translatable="yes">Message Type:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="FilterViewMessageCombo"> + <property name="visible">True</property> + <property name="items" translatable="yes">All Messages +Only AVC Denied +Only AVC Granted</property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label154"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Other</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox7"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_START</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkButton" id="FilterViewOtherClearButton"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment31"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox55"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1479"> + <property name="visible">True</property> + <property name="stock">gtk-clear</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label155"> + <property name="visible">True</property> + <property name="label" translatable="yes">Clear Tab</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label156"> + <property name="visible">True</property> + <property name="label" translatable="yes">Other</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox24"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkRadioButton" id="FilterViewDateNoneRadio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Do not match date and time</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="FilterViewDateBeforeRadio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Match messages before Start</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">FilterViewDateNoneRadio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="FilterViewDateAfterRadio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Match messages after Start</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">FilterViewDateNoneRadio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkAlignment" id="alignment41"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">20</property> + <property name="right_padding">20</property> + + <child> + <widget class="GtkFrame" id="FilterViewDateStartFrame"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkAlignment" id="alignment42"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">4</property> + <property name="right_padding">4</property> + + <child> + <widget class="GtkVBox" id="vbox29"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkTable" id="table26"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="homogeneous">True</property> + <property name="row_spacing">0</property> + <property name="column_spacing">4</property> + + <child> + <widget class="GtkLabel" id="label183"> + <property name="visible">True</property> + <property name="label" translatable="yes">Month:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label184"> + <property name="visible">True</property> + <property name="label" translatable="yes">Day:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="FilterViewDateStartDaySpin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 1 31 1 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="FilterViewDateStartMonthCombo"> + <property name="visible">True</property> + <property name="items" translatable="yes">Jan +Feb +Mar +Apr +May +Jun +Jul +Aug +Sep +Oct +Nov +Dec</property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table27"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">0</property> + <property name="column_spacing">4</property> + + <child> + <widget class="GtkLabel" id="label186"> + <property name="visible">True</property> + <property name="label" translatable="yes">Hour:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label187"> + <property name="visible">True</property> + <property name="label" translatable="yes">Minute:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label188"> + <property name="visible">True</property> + <property name="label" translatable="yes">Second:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="FilterViewDateStartHourSpin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0 0 23 1 10 10</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="FilterViewDateStartMinuteSpin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0 0 59 1 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="FilterViewDateStartSecondSpin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0 0 59 1 10 10</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label190"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Start</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="FilterViewDateBetweenRadio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Match messages between Start and End</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">FilterViewDateNoneRadio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkAlignment" id="alignment44"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">20</property> + <property name="right_padding">20</property> + + <child> + <widget class="GtkFrame" id="FilterViewDateEndFrame"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkAlignment" id="alignment45"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">4</property> + <property name="right_padding">4</property> + + <child> + <widget class="GtkVBox" id="vbox30"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkTable" id="table28"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="homogeneous">True</property> + <property name="row_spacing">0</property> + <property name="column_spacing">4</property> + + <child> + <widget class="GtkLabel" id="label191"> + <property name="visible">True</property> + <property name="label" translatable="yes">Month:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label192"> + <property name="visible">True</property> + <property name="label" translatable="yes">Day:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="FilterViewDateEndDaySpin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 1 31 1 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="FilterViewDateEndMonthCombo"> + <property name="visible">True</property> + <property name="items" translatable="yes">Jan +Feb +Mar +Apr +May +Jun +Jul +Aug +Sep +Oct +Nov +Dec</property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table29"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">0</property> + <property name="column_spacing">4</property> + + <child> + <widget class="GtkLabel" id="label193"> + <property name="visible">True</property> + <property name="label" translatable="yes">Hour:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label194"> + <property name="visible">True</property> + <property name="label" translatable="yes">Minute:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label195"> + <property name="visible">True</property> + <property name="label" translatable="yes">Second:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="FilterViewDateEndHourSpin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0 0 23 1 10 10</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="FilterViewDateEndMinuteSpin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0 0 59 1 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="FilterViewDateEndSecondSpin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">0 0 59 1 10 10</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label196"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>End</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label173"> + <property name="visible">True</property> + <property name="label" translatable="yes">Date</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox27"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow5"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="FilterViewDescView"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="overwrite">False</property> + <property name="accepts_tab">True</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_WORD</property> + <property name="cursor_visible">True</property> + <property name="pixels_above_lines">0</property> + <property name="pixels_below_lines">0</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">0</property> + <property name="right_margin">0</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label174"> + <property name="visible">True</property> + <property name="label" translatable="yes">Notes</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="PolicyComponentListsWindow"> + <property name="visible">True</property> + <property name="title" translatable="yes">Policy Components</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">True</property> + <property name="default_width">600</property> + <property name="default_height">450</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">True</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <property name="has_separator">True</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox5"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area5"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="closebutton2"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-7</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox31"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">10</property> + + <child> + <widget class="GtkVBox" id="vbox37"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label200"> + <property name="visible">True</property> + <property name="label" translatable="yes">Select items from:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_END</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkAlignment" id="alignment49"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">10</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkVBox" id="vbox38"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="PolicyCompLogRadio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Log</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="PolicyCompPolicyRadio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Policy</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">PolicyCompLogRadio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="PolicyCompBothRadio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Log and Policy</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">PolicyCompLogRadio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox59"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkFrame" id="frame50"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkVBox" id="vbox35"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow7"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="PolicyCompIncView"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Unselected Items</property> + <property name="can_focus">True</property> + <property name="events">GDK_ENTER_NOTIFY_MASK</property> + <property name="headers_visible">False</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox9"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_SPREAD</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkButton" id="PolicyCompIncSelectButton"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Select All</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="PolicyCompIncUnselectButton"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Unselect All</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label199"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Included Items</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkAlignment" id="alignment47"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">0.20000000298</property> + <property name="top_padding">0</property> + <property name="bottom_padding">50</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkVButtonBox" id="vbuttonbox3"> + <property name="width_request">85</property> + <property name="height_request">56</property> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_SPREAD</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkButton" id="PolicyCompToExcButton"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Add to selected items list</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment48"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox64"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1482"> + <property name="visible">True</property> + <property name="stock">gtk-go-forward</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label202"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkButton" id="PolicyCompToIncButton"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkImage" id="image1483"> + <property name="visible">True</property> + <property name="stock">gtk-go-back</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame52"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkVBox" id="vbox36"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow8"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="PolicyCompExcView"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Unselected Items</property> + <property name="can_focus">True</property> + <property name="events">GDK_ENTER_NOTIFY_MASK</property> + <property name="headers_visible">False</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox10"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_SPREAD</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkButton" id="PolicyCompExcSelectButton"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Select All</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="PolicyCompExcUnselectButton"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Unselect All</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label201"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Excluded Items</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="PolicyOpenWindow"> + <property name="title" translatable="yes">Open Policy</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">True</property> + <property name="default_width">340</property> + <property name="default_height">360</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">True</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <property name="has_separator">True</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area6"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="cancel button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="ok button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">10</property> + + <child> + <widget class="GtkVBox" id="vbox.1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Policy Type:</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_END</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkAlignment" id="alignment.1.2"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">10</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkVBox" id="vbox.1.2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="monolithic radio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Monolithic policy</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="modular radio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Modular policy</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">monolithic radio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox.2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="main filename label"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Policy Filename:</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_END</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox.2.2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkEntry" id="base entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="base browse"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment.2.2.1"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox.2.2.1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image.2.2.1.1"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label.2.2.1.1"> + <property name="visible">True</property> + <property name="label" translatable="yes">Browse</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox.3"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow.3"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="module view"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">False</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVButtonBox" id="vbuttonbox.3"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_START</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkButton" id="module add button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-add</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="module remove button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-remove</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="module list import button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment50"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox65"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1484"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label203"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Import</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkButton" id="module list export button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment51"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox66"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1485"> + <property name="visible">True</property> + <property name="stock">gtk-save</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label204"> + <property name="visible">True</property> + <property name="label" translatable="yes">E_xport</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/seaudit/seaudit.gladep b/seaudit/seaudit.gladep new file mode 100644 index 0000000..5b8f438 --- /dev/null +++ b/seaudit/seaudit.gladep @@ -0,0 +1,7 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd"> + +<glade-project> + <name>seaudit</name> + <program_name>seaudit</program_name> +</glade-project> diff --git a/seaudit/seaudit.h b/seaudit/seaudit.h new file mode 100644 index 0000000..34be02b --- /dev/null +++ b/seaudit/seaudit.h @@ -0,0 +1,231 @@ +/** + * @file + * Declaration of the main driver class for seaudit. + * + * @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 program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SEAUDIT_H +#define SEAUDIT_H + +#include "preferences.h" +#include <apol/policy.h> +#include <apol/policy-path.h> +#include <seaudit/log.h> +#include <stdio.h> +#include <time.h> + +typedef struct seaudit seaudit_t; + +#define COPYRIGHT_INFO "Copyright (c) 2003-2007 Tresys Technology, LLC" + +/** + * Retrieve the preferences object associated with the seaudit object. + * + * @param s seaudit object to query. + * + * @return Pointer to a preferences object. Do not free() this pointer. + */ +preferences_t *seaudit_get_prefs(seaudit_t * s); + +/** + * Set the currently loaded policy for seaudit. This will also update + * the preferences object's recently loaded policies. + * + * @param s seaudit object to modify. + * @param policy New policy file for seaudit. If NULL then seaudit + * has no policy opened. Afterwards seaudit takes ownership of the + * policy. + * @param path If policy is not NULL, then add this path to the most + * recently used policy files. This function takes ownership of the + * path. + */ +void seaudit_set_policy(seaudit_t * s, apol_policy_t * policy, apol_policy_path_t * path); + +/** + * Retrieve the currently loaded policy. + * + * @param s seaudit object to query. + * + * @return Pointer to an apol policy, or NULL if none loaded. Treat + * this as a const pointer. + */ +apol_policy_t *seaudit_get_policy(seaudit_t * s); + +/** + * Return the path to the currently loaded policy. If the current + * policy is modular then this returns the base policy's path. + * + * @param s seaudit object to query. + * + * @return Path of policy, or NULL if none loaded. Treat this as a + * const pointer. + */ +apol_policy_path_t *seaudit_get_policy_path(seaudit_t * s); + +/** + * Set the currently loaded log for seaudit. This will also update + * the preferences object's recently loaded files. + * + * @param s seaudit object to modify. + * @param log New log file for seaudit. If NULL then seaudit has no + * log files opened. Afterwards seaudit takes ownership of the log. + * @param f File handler that was used to open the log. Afterwards + * seaudit takes ownership of this handler. + * @param filename If log is not NULL, then add this filename to the + * most recently used files. + */ +void seaudit_set_log(seaudit_t * s, seaudit_log_t * log, FILE * f, const char *filename); + +/** + * Command seaudit to (re)parse its log file. + * + * @param s seaudit object containing the log. + * + * @return 0 if log parsed cleanly, < 0 upon errors, or > 0 if there + * were warnings. + */ +int seaudit_parse_log(seaudit_t * s); + +/** + * Retrieve the currently loaded log file. + * + * @param s seaudit object to query. + * + * @return Pointer to a libseaudit log, or NULL if none loaded. Treat + * this as a const pointer. + */ +seaudit_log_t *seaudit_get_log(seaudit_t * s); + +/** + * Return the path to the currently loaded log file. + * + * @param s seaudit object to query. + * + * @return Path of log file, or NULL if none loaded. Treat this as a + * const pointer. + */ +char *seaudit_get_log_path(seaudit_t * s); + +/** + * Return a vector of strings corresponding to all users found within + * currently opened log files. The vector will be sorted + * alphabetically. + * + * @param s seaudit object to query. + * + * @return Vector of sorted users, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *seaudit_get_log_users(seaudit_t * s); + +/** + * Return a vector of strings corresponding to all roles found within + * currently opened log files. The vector will be sorted + * alphabetically. + * + * @param s seaudit object to query. + * + * @return Vector of sorted roles, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *seaudit_get_log_roles(seaudit_t * s); + +/** + * Return a vector of strings corresponding to all types found within + * currently opened log files. The vector will be sorted + * alphabetically. + * + * @param s seaudit object to query. + * + * @return Vector of sorted types, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *seaudit_get_log_types(seaudit_t * s); + +/** + * Return a vector of strings corresponding to all mls levels + * found within currently opened log files. The vector will be sorted + * alphabetically. + * + * @param s seaudit object to query. + * + * @return Vector of sorted types, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *seaudit_get_log_mls_lvl(seaudit_t * s); + +/** + * Return a vector of strings corresponding to all mls clearance + * found within currently opened log files. The vector will be sorted + * alphabetically. + * + * @param s seaudit object to query. + * + * @return Vector of sorted types, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *seaudit_get_log_mls_clr(seaudit_t * s); + +/** + * Return a vector of strings corresponding to all object classes + * found within currently opened log file. The vector will be sorted + * alphabetically. + * + * @param s seaudit object to query. + * + * @return Vector of sorted classes, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *seaudit_get_log_classes(seaudit_t * s); + +/** + * Return the number of messages in the current log. + * + * @param s seaudit object to query. + * + * @return Number of log messages, or 0 if no log is opened. + */ +size_t seaudit_get_num_log_messages(seaudit_t * s); + +/** + * Return the time stamp for the first message in the currently opened + * log. + * + * @param s seaudit object to query. + * + * @return Time of the first log message, or NULL if no log is opened. + * Treat this as a const pointer. + */ +const struct tm *seaudit_get_log_first(seaudit_t * s); + +/** + * Return the time stamp for the last message in the currently opened + * log. + * + * @param s seaudit object to query. + * + * @return Time of the last log message, or NULL if no log is opened. + * Treat this as a const pointer. + */ +const struct tm *seaudit_get_log_last(seaudit_t * s); + +#endif diff --git a/seaudit/seaudit.png b/seaudit/seaudit.png Binary files differnew file mode 100644 index 0000000..8ed09e2 --- /dev/null +++ b/seaudit/seaudit.png diff --git a/seaudit/seaudit.xcf b/seaudit/seaudit.xcf Binary files differnew file mode 100644 index 0000000..ada98bb --- /dev/null +++ b/seaudit/seaudit.xcf diff --git a/seaudit/seaudit_help.txt b/seaudit/seaudit_help.txt new file mode 100644 index 0000000..3959f02 --- /dev/null +++ b/seaudit/seaudit_help.txt @@ -0,0 +1,293 @@ +Audit Log Analysis Tool for Security Enhanced Linux + + +Overview: +--------- +This file contains basic help information for using seaudit, an audit +log analysis tool for Security Enhanced Linux (SELinux) audit +messages. + +The tool does not need to be installed on an SELinux system; it will +work on any Linux machine. The tool parses a given syslog and +extracts all load policy messages, AVC messages, and change of Boolean +messages from conditional policies. + +The tool has the following main functions: + 1) Browse and sort SELinux audit messages. + 2) Filter an audit log based on fields in the messages. + 3) Search the policy based on data from a given audit message. + 4) Export SELinux audit messages to a file. + 5) Generate reports in HTML or plain text format from an entire log + or an seaudit view. + + +Log and Policy Files: +--------------------- +The program provides you with the option of opening either a source, +monolithic binary, or modular policy file. If a policy is not +specified at the command line, seaudit will attempt to use the default +policy location, as specified during configuration time (e.g., +./configure --with-default-policy). + +Note that seaudit does not require an opened policy; in this case the +user will not be able to use the search policy features of the tool. +Only one policy and one audit log can be open at a time, so if another +one is opened the current one will be closed. + +When opening a log file the user may get the warning "Warning! One or +more invalid messages found in audit log." This means that one or +more of the SELinux audit messages either was missing a standard +message field (e.g., time, hostname, or access type) or: + + 1) A message had an unrecognized time stamp, + 2) An AVC message did not contain permissions, + 3) An AVC message was not labeled as "denied" or "granted", + 4) A load policy message was not in the correct form, such as + missing a line or a data field, or + 5) A Boolean message did not contain a list of Booleans. + +The seaudit program will still attempt to display the remaining data +from the SELinux audit message in question along with all the other +SELinux messages in the log, but only if one of the following +sub-strings is found within the message: + + "avc:" - an access denied or granted message, + "security:" - a load policy message, or + "committed booleans" - a change in one or more Boolean states. + +All other messages will be ignored. + + +Menus: +------ +Use the FILE menu to load a different audit log or a policy. The file +menu also allows the user to change preferences including default log, +default policy, which columns to present when viewing audit logs, and +whether seaudit should enable real-time log monitoring upon start-up. +All of these settings will be saved and reloaded each time seaudit is +started. + +The VIEW menu allows the user to display multiple views of a log. A +default view is created automatically when an audit log is first +opened. Additional views can be created by selecting View->New View. +A view has its own set of filters that limits which messages are +shown. Use 'Save View' and 'Save View As...' menu items to save to +file the current view's settings. 'Export Messages' writes to a file +the messages within the current view; 'Export Selected Messages' +writes only those that are currently selected. 'View Selected +Message' will open a new window that shows all of the fields for the +selected log message or messages. + +Use the SEARCH menu to find type enforcement rules within the policy. + +The TOOLS menu presents seaudit's advanced features. The first +option, 'Create Report...', is used to create report files in HTML or +plain text format using an entire audit log or an seaudit view. +'Monitor Log' enables and disables seaudit's real-time monitoring +feature. + +Right-click on an audit message within a view to display a pop-up menu +that allows the user to: + - View the entire message within a separate text box, + - Find TE Rules within the policy using the message, or + - Export selected messages to a file. + + +Sorting: +-------- +By default the messages within a view are sorted in the order they +appear within the log file, typically chronologically. To sort by a +particular field click on the column heading. The only column that +cannot be used for sorting is the 'Other' column. Only one level of +sorting can be performed. The file KNOWN-BUGS describes a particular +instance where the sort order may be misleading. + + +Log Monitoring: +--------------- +Selecting 'Monitor Log' from the Tools Menu or clicking on the 'Toggle +Monitor' button turns on and off the real-time log monitoring feature. +When this feature is on, seaudit checks for new messages at a regular +interval, per second by default. This interval can be configured from +the Preferences dialog. As new messages are added to the currently +loaded log file, each view will be updated according to its filters +and sorting criterion. + + +Finding TE Rules: +----------------- +The 'Find TE Rules' button opens a new dialog box that contains two +tabs. In the first tab, the user enters search criteria similar to +those in apol's TE Rules query. If the user had right-clicked an +audit message and selected the second option, the search criteria will +be filled in automatically based on that message. For each entry, the +user may enter a regular expression; he may also choose a entry from +the drop-down box. + +The 'Only show direct matches' checkbox alters the meaning of the +search. By default the search returns rules that have either the +provided type or any of the type's attributes in the appropriate +field. If this checkbox is enabled then the search will only find +that type; it ignores the type's attributes. + +Click on 'Find TE Rules' button to perform the search and return a +list of matching rules. If the currently opened policy file is +capable of showing line numbers, the displayed rules will contain +hyperlinks to the appropriate line in the Policy Source tab. + +The second tab, 'Policy Source', provides a convenient display of the +text of the policy source file and is only available when opening a +source policy. If a modular policy was opened, then this tab only +shows the base policy's source. + +The seaudit program provides limited searching. More thorough policy +searches and analyses may be conducted through the companion tool, +apol. + + +Log Views: +---------- +The 'Modify View' button opens a dialog box that lets the user modify +the list of filters for the current view. Filters are used to select +either messages to show or to hide; in addition messages can match +either any filter or all filters. + + +Modifying Filters Within A View: +-------------------------------- +To add a new filter, first select the view for which the filter is +needed by clicking on the corresponding tab, then click on the 'Modify +View' button, and then 'Add'. Within this new dialog, edit the +various properties of a filter such as its name, description, source +context, target context, object type, etc. + +Use the 'Context' tab to enter values for part or all of the source +and target context, as well as the object class. Either enter the +values manually with a comma between entries or click on the button +(e.g., Types) and to open another dialog that has a list of all valid +entries. This list can be populated by values from the log, the +policy, or both the log and policy, by selecting the appropriate radio +button. + +Use the 'Other' tab to filter by networking criteria (i.e., IP +address, port and/or interface) and other miscellaneous fields. Many +of these fields accept either an exact match or a glob expression (see +Globbing Expressions below); the text entries' tool tips specify how +matching is performed. + +The filter criteria are saved automatically when this dialog is +closed. + + +Globbing Expressions: +--------------------- +Use glob expressions to construct more flexible search filters by +allowing for pattern expansion instead of just static strings. There +are several different methods of glob syntax that are supported by +seaudit. + +(1) Wildcard Matching + +String containing the characters '?' and '*' are said to contain +wildcard characters. While, both are considered wildcards they allow +for different functionality. + + (a) The '?' character matches any character. + + example: ?at matches the strings aat, bat, cat, etc. + + (b) The '*' matches any string. + + example: sys* matches the strings system, sysadmin, etc. + +(2) Character Classes + +Character classes are used when one desires to find certain +characters, at a certain position within a string. The '[' character +is used to begin a character class and the ']' character is used to +end the class. The characters in the string contained between the two +brackets comprise the character class, which can NOT be empty. + + example: e[abz]x matches the strings eax, ebx, ezx + +(3) Ranges + +Ranges are an extension of character classes which allow one to allow +for finding a certain sequential set of characters at any point in the +string. The '-' character is used to indicate a range of characters, +where the character to the left of the '-' is the beginning and the +character to the right of the '-' is the end. Multiple ranges can be +used within the same character class. + + example: a[b-e]f matches the strings abf, acf, adf, aef + example: 1[2-36-8]9 matches the strings 129, 139, 169, 179, 189 + +(4) Complementation + +Complementation allows for searching using the complement of any given +character class or range. The character '!' must be the first +character after '[' when one desires to use a complementation. When +using complementations the complement of the string enclosed in the +brackets after the '!' character is used. + + example: a[!b-y]z matches all three-character strings starting + with a followed by any character not occurring between b + and y (inclusive), and ending in z + + example: a[!c-ik-y]z matches all three-character string starting + with a followed by any character not occurring between c + and i (inclusive) or between k and y (inclusive), and + ending in z + + +*** CAUTION *** + +The seaudit program intersperses the use of regular expressions versus +glob expressions. For example, 'Edit Filter' uses tool tips to +specify what type of matching is permitted. The 'Find TE Rules' +dialog allows regular expressions, not glob expressions. +Additionally, note that all characters used in glob expressions are +case sensitive. + + +Status Bar: +----------- +At the bottom of seaudit is a status bar. In the left corner it +displays the approximate version of the policy loaded along with the +policy type. In the middle it displays the number of log messages in +the current view and the total number of SELinux messages in the audit +log. The next label shows the span of the dates in the audit log and +the right-most label shows the status of the real-time log monitor. + + +Creating Reports: +----------------- +From the Tools menu the user can create report files in HTML or plain +text format using an entire audit log or only those messages present +in the current view. Select the 'Create Report' menu item to display +a dialog for making configurations to the report and then save the +report to a file. + +Choose which messages to report using the input frame. Messages may +come from the entire audit log file or only those in the current view. +If choosing the entire log, one may also include malformed messages +within the report. See the previous 'Log and Policy Files' heading +for what makes up a malformed message in seaudit. + +Choose the type to report, either plain text or HTML, in the output +frame. If selecting an HTML file, an HTML style sheet may also be +included into the report. A report configuration file specifies the +type and order of messages to report. If the style sheet or the +configuration file is not specified, seaudit will use the appropriate +system default files; the default files may be changed from the +Preferences dialog. + +The seaudit report configuration file may be configured to affect +information presented in reports; it is required for report +generation. From this file, one can configure various sections for +the report, as well as create custom sections in the report through +the use of saved seaudit view files. Review the default +seaudit-report.conf file that comes packaged with the SETools +distribution for more information. This file can be located in the +shared data directory where seaudit was installed, typically +/usr/local/share/setools-<version>. diff --git a/seaudit/toplevel.c b/seaudit/toplevel.c new file mode 100644 index 0000000..d901a99 --- /dev/null +++ b/seaudit/toplevel.c @@ -0,0 +1,1179 @@ +/** + * @file + * Implementation for the main toplevel window. + * + * @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 program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "message_view.h" +#include "open_policy_window.h" +#include "policy_view.h" +#include "preferences_view.h" +#include "report_window.h" +#include "toplevel.h" +#include "utilgui.h" + +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <apol/util.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gtk/gtk.h> +#include <glade/glade.h> +#include <seaudit/parse.h> + +struct toplevel +{ + seaudit_t *s; + policy_view_t *pv; + progress_t *progress; + /** vector of message_view_t that are in the toplevel's notebook */ + apol_vector_t *views; + GladeXML *xml; + /** filename for glade file */ + char *xml_filename; + /** toplevel window widget */ + GtkWindow *w; + GtkNotebook *notebook; + /** non-zero if the log file should be polled for changes */ + int do_monitor_log; + /** event id for the monitor callback */ + guint monitor_id; + /** serial number for models created, such that new models + * will be named Untitled <number> */ + int next_model_number; + /** filename for most recently opened view */ + char *view_filename; +}; + +/** + * Given a view, return its index within the toplevel notebook pages. + * + * @param top Toplevel containing the notebook. + * @param view View to look up. + * + * @return Index of the view (zero-indexed), or -1 if not found. + */ +static gint toplevel_notebook_find_view(toplevel_t * top, message_view_t * view) +{ + gint num_pages = gtk_notebook_get_n_pages(top->notebook); + while (num_pages >= 1) { + GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, num_pages - 1); + GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child); + message_view_t *v = g_object_get_data(G_OBJECT(tab), "view-object"); + if (v == view) { + return num_pages - 1; + } + num_pages--; + } + return -1; +} + +/** + * Return the view on the page that is currently raised, or NULL if + * there are no views. + */ +static message_view_t *toplevel_get_current_view(toplevel_t * top) +{ + gint current = gtk_notebook_get_current_page(top->notebook); + if (current >= 0) { + GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, current); + GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child); + return g_object_get_data(G_OBJECT(tab), "view-object"); + } + return NULL; +} + +static void toplevel_on_notebook_switch_page(GtkNotebook * notebook __attribute__ ((unused)), GtkNotebookPage * page + __attribute__ ((unused)), guint pagenum __attribute__ ((unused)), toplevel_t * top) +{ + toplevel_update_selection_menu_item(top); + toplevel_update_status_bar(top); +} + +/** + * Callback invoked when a tab close button is clicked. + */ +static void toplevel_on_tab_close(GtkButton * button, toplevel_t * top) +{ + /* disallow the close if this is the last tab */ + if (top->views == NULL || apol_vector_get_size(top->views) <= 1) { + return; + } else { + message_view_t *view = g_object_get_data(G_OBJECT(button), "view-object"); + gint idx = toplevel_notebook_find_view(top, view); + size_t i; + assert(idx >= 0); + gtk_notebook_remove_page(top->notebook, idx); + apol_vector_get_index(top->views, view, NULL, NULL, &i); + message_view_destroy(&view); + apol_vector_remove(top->views, i); + } +} + +/** + * Create a new view associated with the given model, then create a + * tab to place that view. The newly created tab will then be raised. + * + * @param top Toplevel containing notebook to which add the view and tab. + * @param model Model from which to create a view. + * @param filename Initial filename for the view. + */ +static void toplevel_add_new_view(toplevel_t * top, seaudit_model_t * model, const char *filename) +{ + message_view_t *view; + GtkWidget *tab, *button, *label, *image; + gint idx; + if ((view = message_view_create(top, model, filename)) == NULL) { + return; + } + if (apol_vector_append(top->views, view) < 0) { + toplevel_ERR(top, "%s", strerror(errno)); + message_view_destroy(&view); + return; + } + tab = gtk_hbox_new(FALSE, 5); + g_object_set_data(G_OBJECT(tab), "view-object", view); + button = gtk_button_new(); + g_object_set_data(G_OBJECT(button), "view-object", view); + image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); + gtk_container_add(GTK_CONTAINER(button), image); + gtk_widget_set_size_request(image, 8, 8); + g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(toplevel_on_tab_close), top); + label = gtk_label_new(seaudit_model_get_name(model)); + g_object_set_data(G_OBJECT(tab), "label", label); + gtk_box_pack_start(GTK_BOX(tab), label, TRUE, TRUE, 5); + gtk_box_pack_end(GTK_BOX(tab), button, FALSE, FALSE, 5); + gtk_widget_show(label); + gtk_widget_show(button); + gtk_widget_show(image); + idx = gtk_notebook_append_page(top->notebook, message_view_get_view(view), tab); + gtk_notebook_set_current_page(top->notebook, idx); +} + +/** + * Create a new model for the currently loaded log file (which could + * be NULL), then create a view that watches that model. + */ +static void toplevel_add_new_model(toplevel_t * top) +{ + seaudit_log_t *log = seaudit_get_log(top->s); + char *model_name = NULL; + seaudit_model_t *model = NULL; + if (asprintf(&model_name, "Untitled %d", top->next_model_number) < 0) { + toplevel_ERR(top, "%s", strerror(errno)); + return; + } + model = seaudit_model_create(model_name, log); + free(model_name); + if (model == NULL) { + toplevel_ERR(top, "%s", strerror(errno)); + return; + } else { + top->next_model_number++; + toplevel_add_new_view(top, model, NULL); + } +} + +/** + * Callback whenever an item from the recent logs submenu is activated. + */ +static void toplevel_on_open_recent_log_activate(GtkWidget * widget, gpointer user_data) +{ + GtkWidget *label = gtk_bin_get_child(GTK_BIN(widget)); + const char *path = gtk_label_get_text(GTK_LABEL(label)); + toplevel_t *top = (toplevel_t *) user_data; + toplevel_open_log(top, path); +} + +/** + * Update the entries within recent logs submenu to match those in the + * preferences object. + */ +static void toplevel_set_recent_logs_submenu(toplevel_t * top) +{ + GtkMenuItem *recent = GTK_MENU_ITEM(glade_xml_get_widget(top->xml, "OpenRecentLog")); + apol_vector_t *paths = preferences_get_recent_logs(toplevel_get_prefs(top)); + GtkWidget *submenu, *submenu_item; + size_t i; + + gtk_menu_item_remove_submenu(recent); + submenu = gtk_menu_new(); + for (i = 0; i < apol_vector_get_size(paths); i++) { + char *path = (char *)apol_vector_get_element(paths, i); + submenu_item = gtk_menu_item_new_with_label(path); + gtk_menu_shell_prepend(GTK_MENU_SHELL(submenu), submenu_item); + gtk_widget_show(submenu_item); + g_signal_connect(G_OBJECT(submenu_item), "activate", G_CALLBACK(toplevel_on_open_recent_log_activate), top); + } + gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), submenu); +} + +/** + * Callback whenever an item from the recent policies submenu is + * activated. + */ +static void toplevel_on_open_recent_policy_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + apol_policy_path_t *path = g_object_get_data(G_OBJECT(menuitem), "path"); + toplevel_t *top = (toplevel_t *) user_data; + apol_policy_path_t *dup_path = apol_policy_path_create_from_policy_path(path); + if (dup_path == NULL) { + toplevel_ERR(top, "%s", strerror(errno)); + return; + } + toplevel_open_policy(top, dup_path); +} + +/** + * Update the entries within recent policies submenu to match those in + * the preferences object. + */ +static void toplevel_set_recent_policies_submenu(toplevel_t * top) +{ + GtkMenuItem *recent = GTK_MENU_ITEM(glade_xml_get_widget(top->xml, "OpenRecentPolicy")); + apol_vector_t *paths = preferences_get_recent_policies(toplevel_get_prefs(top)); + GtkWidget *submenu, *submenu_item; + size_t i; + + GtkTooltipsData *tips_data = gtk_tooltips_data_get(GTK_WIDGET(recent)); + assert(tips_data != NULL); + GtkTooltips *tooltips = tips_data->tooltips; + + gtk_menu_item_remove_submenu(recent); + submenu = gtk_menu_new(); + for (i = 0; i < apol_vector_get_size(paths); i++) { + apol_policy_path_t *path = apol_vector_get_element(paths, i); + char *menu_label = NULL; + const char *primary_path = apol_policy_path_get_primary(path); + GString *tip = g_string_new(NULL); + if ((menu_label = util_policy_path_to_string(path)) == NULL) { + toplevel_ERR(top, "%s", strerror(errno)); + g_string_free(tip, TRUE); + break; + } + submenu_item = gtk_menu_item_new_with_label(menu_label); + free(menu_label); + if (apol_policy_path_get_type(path) == APOL_POLICY_PATH_TYPE_MONOLITHIC) { + g_string_append_printf(tip, "monolithic policy: %s", primary_path); + } else { + char *s = NULL; + const apol_vector_t *modules = apol_policy_path_get_modules(path); + size_t num_modules = apol_vector_get_size(modules); + g_string_append_printf(tip, "base policy: %s", primary_path); + if (num_modules > 0) { + if ((s = apol_str_join(modules, "\n ")) == NULL) { + toplevel_ERR(top, "%s", strerror(errno)); + break; + } + g_string_append_printf(tip, "\n %s", s); + free(s); + } + } + gtk_tooltips_set_tip(tooltips, GTK_WIDGET(submenu_item), tip->str, ""); + g_string_free(tip, TRUE); + g_object_set_data(G_OBJECT(submenu_item), "path", path); + gtk_menu_shell_prepend(GTK_MENU_SHELL(submenu), submenu_item); + gtk_widget_show(submenu_item); + g_signal_connect(G_OBJECT(submenu_item), "activate", G_CALLBACK(toplevel_on_open_recent_policy_activate), top); + } + gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), submenu); +} + +/** + * Enable/disable all items (menus and buttons) that depend upon if a + * log is loaded. + * + * @param top Toplevel object containing menu items. + * @param TRUE to enable items, FALSE to disable. + */ +static void toplevel_enable_log_items(toplevel_t * top, gboolean sens) +{ + static const char *items[] = { + "NewView", "OpenView", "SaveView", "SaveViewAs", "ModifyView", + "ExportAll", "ExportSelected", "ViewMessage", + "CreateReport", "MonitorLog", "ClearView", + "ModifyViewButton", "MonitorLogButton", "ClearViewButton", + NULL + }; + size_t i; + const char *s; + for (i = 0, s = items[0]; s != NULL; s = items[++i]) { + GtkWidget *w = glade_xml_get_widget(top->xml, s); + assert(w != NULL); + gtk_widget_set_sensitive(w, sens); + } +} + +/** + * Enable/disable all items (menus and buttons) that depend upon if a + * policy is loaded. + * + * @param top Toplevel object containing widgets. + * @param TRUE to enable items, FALSE to disable. + */ +static void toplevel_enable_policy_items(toplevel_t * top, gboolean sens) +{ + static const char *items[] = { + "FindTERules", "FindTERulesButton", + NULL + }; + size_t i; + const char *s; + for (i = 0, s = items[0]; s != NULL; s = items[++i]) { + GtkWidget *w = glade_xml_get_widget(top->xml, s); + assert(w != NULL); + gtk_widget_set_sensitive(w, sens); + } +} + +/** + * Update the toplevel's title bar to list the log and policy files + * opened. + * + * @param top Toplevel to modify. + */ +static void toplevel_update_title_bar(toplevel_t * top) +{ + char *log_path = seaudit_get_log_path(top->s); + apol_policy_path_t *policy_path = seaudit_get_policy_path(top->s); + char *policy_type_str = "Policy"; + const char *primary_path; + char *s; + + if (log_path == NULL) { + log_path = "No Log"; + } + if (policy_path == NULL) { + primary_path = "No Policy"; + } else { + if (apol_policy_path_get_type(policy_path) == APOL_POLICY_PATH_TYPE_MODULAR) { + policy_type_str = "Base"; + } + primary_path = apol_policy_path_get_primary(policy_path); + } + if (asprintf(&s, "seaudit - [Log file: %s] [%s file: %s]", log_path, policy_type_str, primary_path) < 0) { + toplevel_ERR(top, "%s", strerror(errno)); + return; + } + gtk_window_set_title(top->w, s); + free(s); +} + +/** + * Initialize the application icons for the program. These icons are + * the ones shown by the window manager within title bars and pagers. + * The last icon listed in the array will be displayed in the About + * dialog. + * + * @param top Toplevel whose icon to set. All child windows will + * inherit these icons. + */ +static void init_icons(toplevel_t * top) +{ + static const char *icon_names[] = { "seaudit-small.png", "seaudit.png" }; + GdkPixbuf *icon; + char *path; + GList *icon_list = NULL; + size_t i; + for (i = 0; i < sizeof(icon_names) / sizeof(icon_names[0]); i++) { + if ((path = apol_file_find_path(icon_names[i])) == NULL) { + continue; + } + icon = gdk_pixbuf_new_from_file(path, NULL); + free(path); + if (icon == NULL) { + continue; + } + icon_list = g_list_append(icon_list, icon); + } + gtk_window_set_default_icon_list(icon_list); + gtk_window_set_icon_list(top->w, icon_list); +} + +static void message_view_free(void *elem) +{ + message_view_t *view = elem; + message_view_destroy(&view); +} + +toplevel_t *toplevel_create(seaudit_t * s) +{ + toplevel_t *top; + GtkWidget *vbox; + int error = 0; + + if ((top = calloc(1, sizeof(*top))) == NULL || (top->views = apol_vector_create(message_view_free)) == NULL) { + error = errno; + goto cleanup; + } + top->s = s; + top->next_model_number = 1; + + if ((top->xml_filename = apol_file_find_path("seaudit.glade")) == NULL || + (top->xml = glade_xml_new(top->xml_filename, "TopLevel", NULL)) == NULL) { + fprintf(stderr, "Could not open seaudit.glade.\n"); + error = EIO; + goto cleanup; + } + top->w = GTK_WINDOW(glade_xml_get_widget(top->xml, "TopLevel")); + g_object_set_data(G_OBJECT(top->w), "toplevel", top); + init_icons(top); + top->notebook = GTK_NOTEBOOK(gtk_notebook_new()); + g_signal_connect_after(G_OBJECT(top->notebook), "switch-page", G_CALLBACK(toplevel_on_notebook_switch_page), top); + vbox = glade_xml_get_widget(top->xml, "NotebookVBox"); + gtk_container_add(GTK_CONTAINER(vbox), GTK_WIDGET(top->notebook)); + gtk_widget_show(GTK_WIDGET(top->notebook)); + gtk_widget_show(GTK_WIDGET(top->w)); + toplevel_set_recent_logs_submenu(top); + toplevel_set_recent_policies_submenu(top); + + glade_xml_signal_autoconnect(top->xml); + + /* create initial blank tab for the notebook */ + toplevel_add_new_model(top); + + /* initialize sub-windows, now that glade XML file has been + * read */ + if ((top->pv = policy_view_create(top)) == NULL || (top->progress = progress_create(top)) == NULL) { + error = errno; + goto cleanup; + } + cleanup: + if (error != 0) { + toplevel_destroy(&top); + errno = error; + return NULL; + } + return top; +} + +void toplevel_destroy(toplevel_t ** top) +{ + if (top != NULL && *top != NULL) { + if ((*top)->monitor_id > 0) { + g_source_remove((*top)->monitor_id); + } + policy_view_destroy(&(*top)->pv); + apol_vector_destroy(&(*top)->views); + free((*top)->xml_filename); + g_free((*top)->view_filename); + progress_destroy(&(*top)->progress); + if ((*top)->w != NULL) { + gtk_widget_destroy(GTK_WIDGET((*top)->w)); + } + free(*top); + *top = NULL; + } +} + +struct log_run_datum +{ + toplevel_t *top; + FILE *file; + const char *filename; + seaudit_log_t *log; + int result; +}; + +/** + * Update the seaudit log, then refresh all views as necessary. Note + * that this only works in a single-threaded environment; otherwise + * there are two possible race conditions: + * - monitor is disabled while this function is being executed + * - a new log file is loaded while the function is being executed + * + * But what happens if this function is scheduled and then a new log + * is opened? In toplevel_open_log(), do_monitor_log is temporarily + * disabled because that function is threaded. It is then re-enabled + * afterwards. + * + * To make this function fully thread-safe requires making this entire + * function synchronized, and then employ locking every time + * do_monitor_log and monitor_id are set. + */ +static gboolean toplevel_monitor_log_timer(gpointer data) +{ + toplevel_t *top = (toplevel_t *) data; + if (top->do_monitor_log) { + int retval; + gint i = gtk_notebook_get_n_pages(top->notebook) - 1; + uint delay; + retval = seaudit_parse_log(top->s); + if (retval < 0) { + GtkCheckMenuItem *w; + toplevel_ERR(top, "Error while monitoring log: %s", strerror(errno)); + w = GTK_CHECK_MENU_ITEM(glade_xml_get_widget(top->xml, "MonitorLog")); + top->monitor_id = 0; + gtk_check_menu_item_set_active(w, 0); + return FALSE; + } + while (i >= 0) { + GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, i); + GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child); + message_view_t *v = g_object_get_data(G_OBJECT(tab), "view-object"); + message_view_update_rows(v); + i--; + } + + /* reschedule another timer callback */ + delay = preferences_get_real_time_interval(toplevel_get_prefs(top)); + top->monitor_id = g_timeout_add(delay, toplevel_monitor_log_timer, top); + } else { + top->monitor_id = 0; + } + return FALSE; +} + +/** + * Enable or disable the log monitoring feature. While enabled, the + * log file will be periodically polled; new lines will be parsed and + * inserted into the seaudit log object. All models and their views + * will then be notified of the changes. + * + * @param top Toplevel object whose widgets to update. + */ +static void toplevel_monitor_log(toplevel_t * top) +{ + GtkLabel *label = GTK_LABEL(glade_xml_get_widget(top->xml, "MonitorLogLabel")); + assert(label != NULL); + if (top->do_monitor_log) { + gtk_label_set_markup(label, "Monitor Status: <span foreground=\"green\">ON</span>"); + if (top->monitor_id == 0) { + uint delay = preferences_get_real_time_interval(toplevel_get_prefs(top)); + top->monitor_id = g_timeout_add(delay, toplevel_monitor_log_timer, top); + } + } else { + if (top->monitor_id > 0) { + g_source_remove(top->monitor_id); + top->monitor_id = 0; + } + gtk_label_set_markup(label, "Monitor Status: <span foreground=\"red\">OFF</span>"); + } +} + +/** + * Thread that loads and parses a log file. It will write to + * progress_seaudit_handle_func() its status during the load. Note + * that the file handle is not closed upon completion; it is left open + * so that subsequent calls to seaudit_log_parse(), such as + * forreal-time monitoring. + * + * @param data Pointer to a struct log_run_datum, for control + * information. + */ +static gpointer toplevel_open_log_runner(gpointer data) +{ + struct log_run_datum *run = (struct log_run_datum *)data; + progress_update(run->top->progress, "Parsing %s", run->filename); + if ((run->file = fopen(run->filename, "r")) == NULL) { + progress_update(run->top->progress, "Could not open %s for reading.", run->filename); + run->result = -1; + goto cleanup; + } + if ((run->log = seaudit_log_create(progress_seaudit_handle_func, run->top->progress)) == NULL) { + progress_update(run->top->progress, "%s", strerror(errno)); + run->result = -1; + goto cleanup; + } + run->result = seaudit_log_parse(run->log, run->file); + cleanup: + if (run->result < 0) { + if (run->file != NULL) { + fclose(run->file); + } + run->file = NULL; + seaudit_log_destroy(&run->log); + progress_abort(run->top->progress, NULL); + } else if (run->result > 0) { + progress_warn(run->top->progress, NULL); + } else { + progress_done(run->top->progress); + } + return NULL; +} + +/** + * Destroy all views and their notebook tabs. + */ +static void toplevel_destroy_views(toplevel_t * top) +{ + gint num_pages = gtk_notebook_get_n_pages(top->notebook); + while (num_pages >= 1) { + message_view_t *view = apol_vector_get_element(top->views, num_pages - 1); + gtk_notebook_remove_page(top->notebook, num_pages - 1); + message_view_destroy(&view); + apol_vector_remove(top->views, num_pages - 1); + num_pages--; + } +} + +void toplevel_open_log(toplevel_t * top, const char *filename) +{ + struct log_run_datum run = { top, NULL, filename, NULL, 0 }; + int was_monitor_running; + GtkCheckMenuItem *w; + + /* disable monitoring during the threaded part of this code */ + was_monitor_running = top->do_monitor_log; + top->do_monitor_log = 0; + toplevel_monitor_log(top); + + util_cursor_wait(GTK_WIDGET(top->w)); + progress_show(top->progress, "Opening Log"); + g_thread_create(toplevel_open_log_runner, &run, FALSE, NULL); + progress_wait(top->progress); + progress_hide(top->progress); + util_cursor_clear(GTK_WIDGET(top->w)); + + if (run.result < 0) { + top->do_monitor_log = was_monitor_running; + toplevel_monitor_log(top); + return; + } + + toplevel_destroy_views(top); + top->next_model_number = 1; + seaudit_set_log(top->s, run.log, run.file, filename); + toplevel_set_recent_logs_submenu(top); + toplevel_enable_log_items(top, TRUE); + toplevel_add_new_model(top); + toplevel_update_title_bar(top); + toplevel_update_status_bar(top); + toplevel_update_selection_menu_item(top); + top->do_monitor_log = preferences_get_real_time_at_startup(toplevel_get_prefs(top)); + + w = GTK_CHECK_MENU_ITEM(glade_xml_get_widget(top->xml, "MonitorLog")); + + gtk_check_menu_item_set_active(w, top->do_monitor_log); + /* call this again because the check item could have already + * been active, thus its handler would not run */ + toplevel_monitor_log(top); +} + +struct policy_run_datum +{ + toplevel_t *top; + apol_policy_path_t *path; + apol_policy_t *policy; + int result; +}; + +/** + * Thread that loads and parses a policy file. It will write to + * progress_seaudit_handle_func() its status during the load. + * + * @param data Pointer to a struct policy_run_datum, for control + * information. + */ +static gpointer toplevel_open_policy_runner(gpointer data) +{ + struct policy_run_datum *run = (struct policy_run_datum *)data; + progress_update(run->top->progress, "Opening policy."); + run->policy = + apol_policy_create_from_policy_path(run->path, QPOL_POLICY_OPTION_NO_NEVERALLOWS, progress_apol_handle_func, + run->top->progress); + if (run->policy == NULL) { + run->result = -1; + progress_abort(run->top->progress, NULL); + return NULL; + } + run->result = 0; + progress_done(run->top->progress); + return NULL; +} + +int toplevel_open_policy(toplevel_t * top, apol_policy_path_t * path) +{ + struct policy_run_datum run = { top, path, NULL, 0 }; + + util_cursor_wait(GTK_WIDGET(top->w)); + progress_show(top->progress, apol_policy_path_get_primary(path)); + g_thread_create(toplevel_open_policy_runner, &run, FALSE, NULL); + progress_wait(top->progress); + progress_hide(top->progress); + util_cursor_clear(GTK_WIDGET(top->w)); + if (run.result < 0) { + apol_policy_path_destroy(&path); + return run.result; + } + seaudit_set_policy(top->s, run.policy, path); + toplevel_set_recent_policies_submenu(top); + toplevel_enable_policy_items(top, TRUE); + toplevel_update_title_bar(top); + toplevel_update_status_bar(top); + policy_view_update(top->pv, path); + return 0; +} + +void toplevel_update_status_bar(toplevel_t * top) +{ + apol_policy_t *policy = seaudit_get_policy(top->s); + GtkLabel *policy_version = (GtkLabel *) glade_xml_get_widget(top->xml, "PolicyVersionLabel"); + GtkLabel *log_num = (GtkLabel *) glade_xml_get_widget(top->xml, "LogNumLabel"); + GtkLabel *log_dates = (GtkLabel *) glade_xml_get_widget(top->xml, "LogDateLabel"); + seaudit_log_t *log = toplevel_get_log(top); + + if (policy == NULL) { + gtk_label_set_text(policy_version, "Policy: No policy"); + } else { + char *policy_str = apol_policy_get_version_type_mls_str(policy); + if (policy_str == NULL) { + toplevel_ERR(top, "%s", strerror(errno)); + } else { + char *s; + if (asprintf(&s, "Policy: %s", policy_str) < 0) { + toplevel_ERR(top, "%s", strerror(errno)); + } else { + gtk_label_set_text(policy_version, s); + free(s); + } + free(policy_str); + } + } + + if (log == NULL) { + gtk_label_set_text(log_num, "Log Messages: No log"); + gtk_label_set_text(log_dates, "Dates: No log"); + } else { + message_view_t *view = toplevel_get_current_view(top); + size_t num_messages = seaudit_get_num_log_messages(top->s); + size_t num_view_messages; + const struct tm *first = seaudit_get_log_first(top->s); + const struct tm *last = seaudit_get_log_last(top->s); + assert(view != NULL); + num_view_messages = message_view_get_num_log_messages(view); + char *s, t1[256], t2[256]; + if (asprintf(&s, "Log Messages: %zd/%zd", num_view_messages, num_messages) < 0) { + toplevel_ERR(top, "%s", strerror(errno)); + } else { + gtk_label_set_text(log_num, s); + free(s); + } + if (first == NULL || last == NULL) { + gtk_label_set_text(log_dates, "Dates: No messages"); + } else { + strftime(t1, 256, "%b %d %H:%M:%S", first); + strftime(t2, 256, "%b %d %H:%M:%S", last); + if (asprintf(&s, "Dates: %s - %s", t1, t2) < 0) { + toplevel_ERR(top, "%s", strerror(errno)); + } else { + gtk_label_set_text(log_dates, s); + free(s); + } + } + } +} + +void toplevel_update_tabs(toplevel_t * top) +{ + gint i = gtk_notebook_get_n_pages(top->notebook) - 1; + while (i >= 0) { + GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, i); + GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child); + GtkWidget *label = g_object_get_data(G_OBJECT(tab), "label"); + message_view_t *v = g_object_get_data(G_OBJECT(tab), "view-object"); + seaudit_model_t *model = message_view_get_model(v); + const char *name = seaudit_model_get_name(model); + gtk_label_set_text(GTK_LABEL(label), name); + i--; + } +} + +void toplevel_update_selection_menu_item(toplevel_t * top) +{ + static const char *items[] = { + "ExportSelected", "ViewMessage", + NULL + }; + message_view_t *view = toplevel_get_current_view(top); + gboolean sens = FALSE; + size_t i; + const char *s; + if (view != NULL) { + sens = message_view_is_message_selected(view); + } + for (i = 0, s = items[0]; s != NULL; s = items[++i]) { + GtkWidget *w = glade_xml_get_widget(top->xml, s); + assert(s != NULL); + gtk_widget_set_sensitive(w, sens); + } +} + +preferences_t *toplevel_get_prefs(toplevel_t * top) +{ + return seaudit_get_prefs(top->s); +} + +seaudit_log_t *toplevel_get_log(toplevel_t * top) +{ + return seaudit_get_log(top->s); +} + +apol_vector_t *toplevel_get_log_users(toplevel_t * top) +{ + return seaudit_get_log_users(top->s); +} + +apol_vector_t *toplevel_get_log_roles(toplevel_t * top) +{ + return seaudit_get_log_roles(top->s); +} + +apol_vector_t *toplevel_get_log_types(toplevel_t * top) +{ + return seaudit_get_log_types(top->s); +} + +apol_vector_t *toplevel_get_log_mls_lvl(toplevel_t * top) +{ + return seaudit_get_log_mls_lvl(top->s); +} + +apol_vector_t *toplevel_get_log_mls_clr(toplevel_t * top) +{ + return seaudit_get_log_mls_clr(top->s); +} + +apol_vector_t *toplevel_get_log_classes(toplevel_t * top) +{ + return seaudit_get_log_classes(top->s); +} + +apol_policy_t *toplevel_get_policy(toplevel_t * top) +{ + return seaudit_get_policy(top->s); +} + +char *toplevel_get_glade_xml(toplevel_t * top) +{ + return top->xml_filename; +} + +progress_t *toplevel_get_progress(toplevel_t * top) +{ + return top->progress; +} + +GtkWindow *toplevel_get_window(toplevel_t * top) +{ + return top->w; +} + +void toplevel_find_terules(toplevel_t * top, seaudit_message_t * message) +{ + policy_view_find_terules(top->pv, message); +} + +/** + * Pop-up a dialog with a line of text and wait for the user to + * dismiss the dialog. + * + * @param top Toplevel window; this message dialog will be centered + * upon it. + * @param msg_type Type of message being displayed. + * @param fmt Format string to print, using syntax of printf(3). + */ +static void toplevel_message(toplevel_t * top, GtkMessageType msg_type, const char *fmt, va_list ap) +{ + GtkWidget *dialog; + char *msg; + if (vasprintf(&msg, fmt, ap) < 0) { + ERR(NULL, "%s", strerror(errno)); + return; + } + dialog = gtk_message_dialog_new(top->w, GTK_DIALOG_DESTROY_WITH_PARENT, msg_type, GTK_BUTTONS_CLOSE, msg); + free(msg); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +void toplevel_ERR(toplevel_t * top, const char *format, ...) +{ + va_list(ap); + va_start(ap, format); + toplevel_message(top, GTK_MESSAGE_ERROR, format, ap); + va_end(ap); +} + +void toplevel_WARN(toplevel_t * top, const char *format, ...) +{ + va_list(ap); + va_start(ap, format); + toplevel_message(top, GTK_MESSAGE_WARNING, format, ap); + va_end(ap); +} + +/************* below are callbacks for the toplevel menu items *************/ + +void toplevel_on_destroy(gpointer user_data, GtkObject * object __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + top->w = NULL; + gtk_main_quit(); +} + +void toplevel_on_open_log_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + apol_vector_t *paths = util_open_file(top->w, "Open Log", seaudit_get_log_path(top->s), 0); + if (paths != NULL) { + toplevel_open_log(top, apol_vector_get_element(paths, 0)); + apol_vector_destroy(&paths); + } +} + +void toplevel_on_open_policy_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + open_policy_window_run(top, seaudit_get_policy_path(top->s), NULL); +} + +void toplevel_on_preferences_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + if (preferences_view_run(top, seaudit_get_log_path(top->s), seaudit_get_policy_path(top->s))) { + size_t i; + for (i = 0; i < apol_vector_get_size(top->views); i++) { + message_view_t *v = apol_vector_get_element(top->views, i); + message_view_update_visible_columns(v); + } + } +} + +void toplevel_on_quit_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + top->w = NULL; + gtk_main_quit(); +} + +void toplevel_on_new_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + toplevel_add_new_model(top); +} + +void toplevel_on_open_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + apol_vector_t *paths = util_open_file(top->w, "Open View", top->view_filename, 0); + seaudit_model_t *model = NULL; + if (paths == NULL) { + return; + } + free(top->view_filename); + top->view_filename = strdup(apol_vector_get_element(paths, 0)); + apol_vector_destroy(&paths); + if (top->view_filename == NULL || + (model = seaudit_model_create_from_file(top->view_filename)) == NULL || + seaudit_model_append_log(model, seaudit_get_log(top->s)) < 0) { + toplevel_ERR(top, "Error opening view: %s", strerror(errno)); + seaudit_model_destroy(&model); + } else { + toplevel_add_new_view(top, model, top->view_filename); + } +} + +void toplevel_on_save_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + message_view_t *view = toplevel_get_current_view(top); + assert(view != NULL); + message_view_save(view); +} + +void toplevel_on_save_viewas_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + message_view_t *view = toplevel_get_current_view(top); + assert(view != NULL); + message_view_saveas(view); +} + +void toplevel_on_modify_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + message_view_t *view = toplevel_get_current_view(top); + assert(view != NULL); + message_view_modify(view); +} + +void toplevel_on_export_all_messages_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + message_view_t *view = toplevel_get_current_view(top); + assert(view != NULL); + message_view_export_all_messages(view); +} + +void toplevel_on_export_selected_messages_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + message_view_t *view = toplevel_get_current_view(top); + assert(view != NULL); + message_view_export_selected_messages(view); +} + +void toplevel_on_view_entire_message_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + message_view_t *view = toplevel_get_current_view(top); + assert(view != NULL); + message_view_entire_message(view); +} + +void toplevel_on_find_terules_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + toplevel_find_terules(top, NULL); +} + +void toplevel_on_create_report_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + message_view_t *view = toplevel_get_current_view(top); + assert(view != NULL); + report_window_run(top, view); +} + +void toplevel_on_monitor_log_activate(gpointer user_data, GtkMenuItem * widget) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) { + top->do_monitor_log = 1; + } else { + top->do_monitor_log = 0; + } + toplevel_monitor_log(top); +} + +void toplevel_on_clear_view_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + message_view_t *view = toplevel_get_current_view(top); + assert(view != NULL); + message_view_clear(view); +} + +void toplevel_on_help_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + GtkWidget *window; + GtkWidget *scroll; + GtkWidget *text_view; + GtkTextBuffer *buffer; + char *help_text = NULL; + size_t len; + int rt; + char *dir; + + window = gtk_dialog_new_with_buttons("seaudit Help", + GTK_WINDOW(top->w), + GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); + gtk_dialog_set_default_response(GTK_DIALOG(window), GTK_RESPONSE_CLOSE); + g_signal_connect_swapped(window, "response", G_CALLBACK(gtk_widget_destroy), window); + scroll = gtk_scrolled_window_new(NULL, NULL); + text_view = gtk_text_view_new(); + gtk_window_set_default_size(GTK_WINDOW(window), 520, 300); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->vbox), scroll); + gtk_container_add(GTK_CONTAINER(scroll), text_view); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_view), GTK_WRAP_NONE); + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view)); + dir = apol_file_find_path("seaudit_help.txt"); + if (!dir) { + toplevel_ERR(top, "Cannot find help file."); + return; + } + rt = apol_file_read_to_buffer(dir, &help_text, &len); + free(dir); + if (rt != 0) { + free(help_text); + return; + } + gtk_text_buffer_set_text(buffer, help_text, len); + gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view), FALSE); + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT); + gtk_widget_show(text_view); + gtk_widget_show(scroll); + gtk_widget_show(window); +} + +void toplevel_on_about_seaudit_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); +#ifdef GTK_2_8 + gtk_show_about_dialog(top->w, + "comments", "Audit Log Analysis Tool for Security Enhanced Linux", + "copyright", COPYRIGHT_INFO, + "name", "seaudit", "version", VERSION, "website", "http://oss.tresys.com/projects/setools", NULL); +#else + GtkWidget *w = gtk_message_dialog_new(top->w, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + "%s %s\n%s\n%s\n%s", + "seaudit", VERSION, + "Audit Log Analysis Tool for Security Enhanced Linux", + COPYRIGHT_INFO, + "http://oss.tresys.com/projects/setools"); + gtk_dialog_run(GTK_DIALOG(w)); + gtk_widget_destroy(w); +#endif +} + +void toplevel_on_find_terules_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event + __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + toplevel_find_terules(top, NULL); +} + +void toplevel_on_modify_view_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event + __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + message_view_t *view = toplevel_get_current_view(top); + assert(view != NULL); + message_view_modify(view); +} + +void toplevel_on_monitor_log_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event + __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + GtkCheckMenuItem *w = GTK_CHECK_MENU_ITEM(glade_xml_get_widget(top->xml, "MonitorLog")); + gboolean old_state; + assert(w != NULL); + old_state = gtk_check_menu_item_get_active(w); + gtk_check_menu_item_set_active(w, !old_state); +} + +void toplevel_on_clear_view_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event + __attribute__ ((unused))) +{ + toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel"); + message_view_t *view = toplevel_get_current_view(top); + assert(view != NULL); + message_view_clear(view); +} diff --git a/seaudit/toplevel.h b/seaudit/toplevel.h new file mode 100644 index 0000000..448c8ad --- /dev/null +++ b/seaudit/toplevel.h @@ -0,0 +1,263 @@ +/** + * @file + * Declaration of the main toplevel window for seaudit. + * + * @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 program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef TOPLEVEL_H +#define TOPLEVEL_H + +typedef struct toplevel toplevel_t; + +#include "progress.h" +#include "seaudit.h" +#include <apol/policy-path.h> +#include <gtk/gtk.h> +#include <seaudit/message.h> + +/** + * Allocate and return an instance of the toplevel window object. + * This will create the window, set up the menus and icons, create an + * empty notebook, then display the window. + * + * @param s Main seaudit object that will control the toplevel. + * + * @return An initialized toplevel object, or NULL upon error. The + * caller must call toplevel_destroy() afterwards. + */ +toplevel_t *toplevel_create(seaudit_t * s); + +/** + * Destroy the toplevel window. This function will recursively + * destroy all other windows. This does nothing if the pointer is set + * to NULL. + * + * @param top Reference to a toplevel object. Afterwards the pointer + * will be set to NULL. + */ +void toplevel_destroy(toplevel_t ** top); + +/** + * Open a log file, destroying any existing logs and views first. + * Afterwards, create a new view for the log. + * + * @param top Toplevel object, used for UI control. + * @param filename Name of the log to open. + */ +void toplevel_open_log(toplevel_t * top, const char *filename); + +/** + * Open a policy file, destroying any existing policies upon success. + * + * @param top Toplevel object, used for UI control. + * @param path Path to the policy to open. This function takes + * ownership of this object. + * + * @return 0 on successful open, < 0 on error. + */ +int toplevel_open_policy(toplevel_t * top, apol_policy_path_t * path); + +/** + * Update the status bar to show the current policy, number of log + * messages in the current view, range of messages in current view, + * and monitor status. + * + * @param top Toplevel whose status bar to update. + */ +void toplevel_update_status_bar(toplevel_t * top); + +/** + * Update the menu items whenever a message is selected/deselected. + * Certain commands are legal only when one or more messages are + * selected. + * + * @param top Toplevel whose menu to update. + */ +void toplevel_update_selection_menu_item(toplevel_t * top); + +/** + * Update the tab names for all views. + * + * @param top Toplevel whose notebook tabs to update. + */ +void toplevel_update_tabs(toplevel_t * top); + +/** + * Return the current preferences object for the toplevel object. + * + * @param top Toplevel containing preferences. + * + * @return Pointer to a preferences object. Do not free() this pointer. + */ +preferences_t *toplevel_get_prefs(toplevel_t * top); + +/** + * Return a seaudit_log_t object used for error reporting by + * libseaudit. + * + * @param top Toplevel containing seaudit log object. + * + * @return libseaudit reporting object, or NULL if no log exists yet. + * Treat this as a const pointer. + */ +seaudit_log_t *toplevel_get_log(toplevel_t * top); + +/** + * Return a vector of strings corresponding to all users found within + * the current log file. The vector will be sorted alphabetically. + * + * @param top Toplevel containing seaudit log object. + * + * @return Vector of sorted users, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *toplevel_get_log_users(toplevel_t * top); + +/** + * Return a vector of strings corresponding to all roles found within + * the current log file. The vector will be sorted alphabetically. + * + * @param top Toplevel containing seaudit log object. + * + * @return Vector of sorted roles, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *toplevel_get_log_roles(toplevel_t * top); + +/** + * Return a vector of strings corresponding to all types found within + * the current log file. The vector will be sorted alphabetically. + * + * @param top Toplevel containing seaudit log object. + * + * @return Vector of sorted types, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *toplevel_get_log_types(toplevel_t * top); + +/** + * Return a vector of strings corresponding to all mls + * levels found within the current log file. + * The vector will be sorted alphabetically. + * + * @param top Toplevel containing seaudit log object. + * + * @return Vector of sorted types, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *toplevel_get_log_mls_lvl(toplevel_t * top); + +/** + * Return a vector of strings corresponding to all mls + * clearance found within the current log file. + * The vector will be sorted alphabetically. + * + * @param top Toplevel containing seaudit log object. + * + * @return Vector of sorted types, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *toplevel_get_log_mls_clr(toplevel_t * top); + +/** + * Return a vector of strings corresponding to all object classes + * found within the current log file. The vector will be sorted + * alphabetically. + * + * @param top Toplevel containing seaudit log object. + * + * @return Vector of sorted classes, or NULL if no log is loaded. The + * caller must call apol_vector_destroy() upon the return value. + */ +apol_vector_t *toplevel_get_log_classes(toplevel_t * top); + +/** + * Return the currently loaded policy. + * + * @param top Toplevel containing policy. + * + * @return Current policy, or NULL if no policy is loaded yet. Treat + * this as a const pointer. + */ +apol_policy_t *toplevel_get_policy(toplevel_t * top); + +/** + * Return the filename containing seaudit's glade file. + * + * @param top Toplevel containing glade XML declarations. + * + * @return Name of the glade file. Do not modify this string. + */ +char *toplevel_get_glade_xml(toplevel_t * top); + +/** + * Return the progress object, so that sub-windows may also show the + * threaded progress object. + * + * @param top Toplevel containing progress object. + * + * @return Progress object. Do not free() this pointer. + */ +progress_t *toplevel_get_progress(toplevel_t * top); + +/** + * Return the main application window. Sub-windows should be set + * transient to this window. + * + * @param top Toplevel containing main window. + * + * @return Main window. + */ +GtkWindow *toplevel_get_window(toplevel_t * top); + +/** + * (Re)open a dialog that allows the user to search for TE rules in + * the currently opened policy. If message is not NULL then set the + * query's initial parameters to the message's source type, target + * type, and object class. + * + * @param top Toplevel containing policy. + * @param message If non-NULL, the initial parameters for query. + */ +void toplevel_find_terules(toplevel_t * top, seaudit_message_t * message); + +/** + * Pop-up an error dialog with a line of text and wait for the user to + * dismiss the dialog. + * + * @param top Toplevel window; this message dialog will be centered + * upon it. + * @param format Format string to print, using syntax of printf(3). + */ +void toplevel_ERR(toplevel_t * top, const char *format, ...) __attribute__ ((format(printf, 2, 3))); + +/** + * Pop-up a warning dialog with a line of text and wait for the user + * to dismiss the dialog. + * + * @param top Toplevel window; this message dialog will be centered + * upon it. + * @param format Format string to print, using syntax of printf(3). + */ +void toplevel_WARN(toplevel_t * top, const char *format, ...) __attribute__ ((format(printf, 2, 3))); + +#endif diff --git a/seaudit/utilgui.c b/seaudit/utilgui.c new file mode 100644 index 0000000..22028e1 --- /dev/null +++ b/seaudit/utilgui.c @@ -0,0 +1,134 @@ +/** + * @file + * Miscellaneous helper functions for GTK+ applications. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2003-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "utilgui.h" +#include <string.h> + +void util_message(GtkWindow * parent, GtkMessageType msg_type, const char *msg) +{ + GtkWidget *dialog; + dialog = gtk_message_dialog_new(parent, GTK_DIALOG_DESTROY_WITH_PARENT, msg_type, GTK_BUTTONS_CLOSE, msg); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +void util_cursor_wait(GtkWidget * widget) +{ + GdkCursor *cursor; + if (widget->window != NULL) { + cursor = gdk_cursor_new(GDK_WATCH); + gdk_window_set_cursor(widget->window, cursor); + gdk_cursor_unref(cursor); + } +} + +/** + * WARNING: this is sort of a hack + * + * If we reset the pointer at the end of a callback, it gets reset too + * soon (i.e. before all of the pending events have been processed. To + * avoid this, this function is put in an idle handler by + * util_clear_cursor(). + */ +static gboolean pointer_reset(gpointer data) +{ + gdk_window_set_cursor(GTK_WIDGET(data)->window, NULL); + return FALSE; +} + +void util_cursor_clear(GtkWidget * widget) +{ + g_idle_add(&pointer_reset, widget); +} + +apol_vector_t *util_open_file(GtkWindow * parent, const char *title, const char *init_path, gboolean multiple) +{ + GtkWidget *dialog = gtk_file_chooser_dialog_new(title, parent, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); + apol_vector_t *paths = NULL; + if (init_path != NULL) { + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), init_path); + } + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), multiple); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + GSList *files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); + GSList *f; + paths = apol_vector_create(g_free); + for (f = files; f != NULL; f = f->next) { + apol_vector_append(paths, f->data); + } + g_slist_free(files); + } + gtk_widget_destroy(dialog); + return paths; +} + +char *util_save_file(GtkWindow * parent, const char *title, const char *init_path) +{ + GtkWidget *dialog = gtk_file_chooser_dialog_new(title, parent, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); + char *path = NULL; +#ifdef GTK_2_8 + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); +#endif + if (init_path != NULL) { + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), init_path); + } else { + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled"); + } + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + } + gtk_widget_destroy(dialog); + return path; +} + +char *util_policy_path_to_string(const apol_policy_path_t * path) +{ + char *s; + const char *primary_path = apol_policy_path_get_primary(path); + if (apol_policy_path_get_type(path) == APOL_POLICY_PATH_TYPE_MONOLITHIC) { + return strdup(primary_path); + } else { + const apol_vector_t *modules = apol_policy_path_get_modules(path); + size_t num_modules = apol_vector_get_size(modules); + if (asprintf(&s, "%s + %zd module%s", primary_path, num_modules, num_modules == 1 ? "" : "s") < 0) { + return NULL; + } + return s; + } +} + +const gchar *util_combo_box_get_active_text(GtkComboBox * w) +{ +#ifdef GTK_2_8 + return gtk_combo_box_get_active_text(w); +#else + return gtk_entry_get_text(GTK_ENTRY(GTK_BIN(w)->child)); +#endif +} diff --git a/seaudit/utilgui.h b/seaudit/utilgui.h new file mode 100644 index 0000000..52365f4 --- /dev/null +++ b/seaudit/utilgui.h @@ -0,0 +1,106 @@ +/** + * @file + * Miscellaneous helper functions for GTK+ applications. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2003-2007 Tresys Technology, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef UTILGUI_H +#define UTILGUI_H + +#include <apol/policy-path.h> +#include <gtk/gtk.h> + +/** + * Pop-up a dialog with a line of text and wait for the user to + * dismiss the dialog. + * + * @param parent Parent window; this message dialog will be centered + * upon the parent. + * @param msg_type Type of message being displayed. + * @param msg Text of message to display. + */ +void util_message(GtkWindow * parent, GtkMessageType msg_type, const char *msg); +/** + * Set the cursor over a widget to the watch cursor. + * + * @param widget Widget whose cursor to set. + */ +void util_cursor_wait(GtkWidget * widget); + +/** + * Clear the cursor over a widget, setting it to the default arrow. + * + * @param widget Widget whose cursor to set. + */ +void util_cursor_clear(GtkWidget * widget); + +/** + * Allow the user select one or more existing files. Run the dialog + * and return a vector of selected filenames. + * + * @param parent Parent window; this dialog will be centered upon the + * parent. + * @param title Name of the dialog. + * @param init_path If not NULL, the default filename. + * @param multiple If true, allow the user to select multiple files. + * Otherwise only one file at a time may be chosen. + * + * @return Vector of filenames selected, or NULL if none were + * selected. The caller must call apol_vector_destroy() upon the + * returned value. + */ +apol_vector_t *util_open_file(GtkWindow * parent, const char *title, const char *init_path, gboolean multiple); + +/** + * Allow the user select an existing file or enter a new file for + * writing. Run the dialog and return the selected filename. + * + * @param parent Parent window; this dialog will be centered upon the + * parent. + * @param title Name of the dialog. + * @param init_path If not NULL, the default filename. + * + * @return Name of the file selected, or NULL if no file was selected. + * The caller must free the returned value with g_free(). + */ +char *util_save_file(GtkWindow * parent, const char *title, const char *init_path); + +/** + * Given a policy path, return a newly allocated string that briefly + * describes the path. This string is suitable for showing to the + * user. + * + * @param path Policy path to describe. + * + * @return String describing the path, or NULL upon error. The caller + * must free the string afterwards. + */ +char *util_policy_path_to_string(const apol_policy_path_t * path); + +/** + * Get the active text from a GtkComboBox. + * + * Whereas GTK 2.6 has gtk_combo_box_get_active_text(), GTK 2.4 + * (another supported platform) does not. + */ +const gchar *util_combo_box_get_active_text(GtkComboBox * w); + +#endif |