/** * @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 #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 #include #include #include #include #include #include #include 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 */ 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: ON"); 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: OFF"); } } /** * 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, "%s", 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); }