/** * @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 #include "filter_view.h" #include "policy_components_view.h" #include #include #include #include #include #include #include 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); }