#!/usr/bin/python3 -O """ This is graphical frontend to msec. """ import os import sys import string import getopt import signal import traceback import queue from textwrap import wrap from threading import Thread import time # PyGTK import warnings warnings.filterwarnings('error', module='gtk') try: from gi.repository import GLib from gi.repository import GdkPixbuf from gi.repository import Gtk import gi from gi.repository import GObject from gi.repository import Pango except Warning as e: print("ERROR: %s" % e) print("Exiting..") sys.exit(1) warnings.resetwarnings() # config import config # helper tools import tools # version try: from version import version except: version = "development version" # libmsec from libmsec import MSEC, PERMS, Log import logging # localization import gettext try: gettext.install("msec") except IOError: _ = str # text strings LEVEL_SECURITY_TEXT=_("""Choose security level This application allows you to configure your system security. If you wish to activate it, choose the appropriate security level: """) # level descriptions level_descriptions = { "standard": _("""This profile configures a reasonably safe set of security features. It is the suggested level for Desktop. If unsure which profile to use, use this one."""), "netbook": _("""This profile is focused on netbooks, laptops or low-end devices, which are only accessed by local users and run on batteries."""), "secure": _("""This profile is configured to provide maximum security, even at the cost of limiting the remote access to the system. This level is suggested for security-concerned systems and servers. """), "fileserver": _("""This profile is targeted on local network servers, which do not receive accesses from unauthorized Internet users."""), "webserver": _("""This profile is provided for servers which are intended to be accessed by unauthorized Internet users."""), "audit_daily": _("""This profile is intended for the users who do not rely on msec to change system settings, and use it for periodic checks only. It configures all periodic checks to run once a day."""), "audit_weekly": _("""This profile is similar to the 'audit_daily' profile, but it runs all checks weekly."""), } # level order. Levels will appear in this order, the unspecified levels will appear last level_order = ["standard", "netbook", "fileserver", "webserver", "secure", "audit_daily", "audit_weekly"] # description for level without description DEFAULT_LEVEL_DESCRIPTION="\n".join(wrap(_("""Custom security level."""), 80)) SYSTEM_SECURITY_TEXT=_("""System security options These options control the local security configuration, such as the login restrictions, password configurations, integration with other security tools, and default file creation permissions. """) NETWORK_SECURITY_TEXT=_("""Network security options These options define the network security against remote threats, unauthorized accesses, and breakin attempts. """) PERIODIC_SECURITY_TEXT=_("""Periodic security checks These options configure the security checks that should be executed periodically. """) EXCEPTIONS_TEXT=_("""Exceptions Here you can configure the allowed exceptions for msec periodic security checks. For each supported test, you may add as many exceptions as you want for each check. Note that each exception is parsed as a regexp.""") PERMISSIONS_SECURITY_TEXT=_("""File permissions These options allow to fine-tune system permissions for important files and directories. The following permissions are checked periodically, and any change to the owner, group, or current permission is reported. The permissions can be enforced, automatically changing them to the specified values when a change is detected. """) SAVE_SETTINGS_TEXT=_("""Save and apply new configuration?""") # gui-related settings DEFAULT_SPACING=5 BANNER="msec.png" class BackgroundRunner(Thread): # background task runner def __init__(self, finish, program): Thread.__init__(self) """Runs a program in background.""" self.program = program self.finish = finish def run(self): """Installs tomoyo policy""" print("Running %s" % self.program) try: res = os.system(self.program) self.finish.put(res) except: print("Aborted: %s" % sys.exc_info()[1]) self.finish.put(-1) class MsecGui: """Msec GUI""" # common columns (COLUMN_LEVEL, COLUMN_LEVEL_DESCR, COLUMN_LEVEL_CURRENT) = list(range(3)) (COLUMN_OPTION, COLUMN_DESCR, COLUMN_VALUE, COLUMN_CUSTOM) = list(range(4)) (COLUMN_PATH, COLUMN_USER, COLUMN_GROUP, COLUMN_PERM, COLUMN_FORCE, COLUMN_ACL) = list(range(6)) (COLUMN_EXCEPTION, COLUMN_EXCEPTION_VALUE, COLUMN_POS) = list(range(3)) def __init__(self, log, msec, perms, msecconfig, permconfig, exceptions, embed=None): """Initializes gui""" self.log = log self.msec = msec self.perms = perms # current configuration self.msecconfig = msecconfig self.permconfig = permconfig self.exceptions = exceptions # pre-defined standard configurations self.msec_defaults = {} self.perm_defaults = {} levels = config.list_available_levels(log, '') for z in levels: try: self.msec_defaults[z] = config.load_defaults(log, z) except: self.log.error(_("Unable to load configuration for level '%s'") % z) traceback.print_exc() continue try: self.perm_defaults[z] = config.load_default_perms(log, z) except: self.log.error(_("Unable to load permissions for level '%s'") % z) traceback.print_exc() continue # pre-load documentation for all possible options self.descriptions = {} for option in config.SETTINGS: # get documentation for item config.find_doc(msec, option, cached=self.descriptions) # loading the current config self.reload_config() if embed: # embedding in MCC self.window = Gtk.Plug.new(embed) else: # running standalone self.window = Gtk.Window() self.window.set_default_size(640, 440) self.window.connect('delete-event', self.quit) # are we enforcing a level self.enforced_level = None self.enforcing_level = False main_vbox = Gtk.VBox(homogeneous=False, spacing=5) self.window.add(main_vbox) # menu menubar = Gtk.MenuBar() main_vbox.pack_start(menubar, False, False, 0) menus = [ (_("_File"), [ (_("_Save configuration"), self.ok), # (None, None), # (_("_Import configuration"), None), # (_("_Export configuration"), None), # (None, None), (_("_Quit"), self.quit), ]), (_("_Help"), [ (_("_Help"), None), (_("_About"), None), ]), ] # building menus for topmenu, items in menus: # file menu filemenu = Gtk.MenuItem(label=topmenu, use_underline=True) menubar.add(filemenu) menu = Gtk.Menu() filemenu.set_submenu(menu) group = None for submenu, callback in items: menuitem = Gtk.MenuItem(label=submenu, use_underline=True) #menuitem = Gtk.MenuItem(submenu) if callback: menuitem.connect('activate', callback) else: menuitem.set_sensitive(False) menu.add(menuitem) # show logo banner = Gtk.HBox(homogeneous=False, spacing=10) try: # logo image = Gtk.Image() pixbuf = GdkPixbuf.Pixbuf.new_from_file("%s/%s" % (config.MSEC_DIR, BANNER)) image.set_from_pixbuf(pixbuf) banner.pack_start(image, False, False, 0) label = Gtk.Label(label=_("MSEC: System Security and Audit")) label.modify_font(Pango.FontDescription("13")) banner.pack_start(label, False, False, 0) main_vbox.pack_start(banner, False, False, 0) except: print("Banner %s Not found" % ("%s/%s" % (config.MSEC_DIR, BANNER))) # creating main UI self.main_notebook = Gtk.Notebook() main_vbox.pack_start(self.main_notebook, True, True, 0) # creating tabs self.notebook = Gtk.Notebook() self.main_notebook.append_page(self.create_summary_ui(), Gtk.Label(label=_("Overview"))) self.main_notebook.append_page(self.notebook, Gtk.Label(label=_("Security settings"))) # data to change the values self.current_options_view = {} # checkboxes callbacks self.checkboxes_callbacks = {} # tabs to create in the intrerface tabs = [ (1, self.level_security_page, _("Basic security")), (2, self.system_security_page, _("System security")), (3, self.network_security_page, _("Network security")), (4, self.periodic_security_page, _("Periodic checks")), (5, self.exceptions_page, _("Exceptions")), (6, self.permissions_security_page, _("Permissions")), ] for id, callback, label in tabs: self.notebook.append_page(callback(id), Gtk.Label(label=label)) # are we enabled? self.toggle_level(self.base_level) # pending signals self.signals = queue.Queue() GLib.timeout_add(500, self.check_signals) self.window.show_all() def level_changed(self, treeview, path, col, model): """Switches to a new security level""" iter = model.get_iter(path) level = model.get_value(iter, self.COLUMN_LEVEL) print("Switching to %s" % level) self.toggle_level(level, force=True) def check_signals(self): """Checks for received signals""" if not self.signals.empty(): s = self.signals.get() if s == signal.SIGTERM: self.quit(self.window) GLib.timeout_add(500, self.check_signals) def check_for_changes(self, curconfig, curperms): """Checks for changes in configuration. Returns number of configuration changes, the description of changes, and results of msec dry run""" # apply config and preview changes self.log.start_buffer() self.msec.apply(curconfig) self.msec.commit(False) messages = self.log.get_buffer() # check for changed options num_changes = 0 changes = [] for name, type, oldconf, curconf in [ (_("MSEC option changes"), _("option"), self.oldconfig, curconfig), (_("System permissions changes"), _("permission check"), self.oldperms, curperms), ]: # check for changes opt_changes = [] opt_adds = [] opt_dels = [] # changed options curchanges = "" opt_changes = [opt for opt in oldconf if (curconf.get(opt) != oldconf.get(opt) and curconf.get(opt) != None and curconf.get(opt) != None)] if len(opt_changes) > 0: curchanges += "\n\t" + "\n\t".join([_("changed %s %s (%s -> %s)") % (type, param, oldconf.get(param), curconf.get(param)) for param in opt_changes]) num_changes += len(opt_changes) # new options opt_adds = [opt for opt in curconf.list_options() if (opt not in oldconf and curconf.get(opt))] if len(opt_adds) > 0: curchanges += "\n\t" + "\n\t".join([_("added %s %s (%s)") % (type, param, curconf.get(param)) for param in opt_adds]) num_changes += len(opt_adds) # removed options opt_dels = [opt for opt in oldconf if ((opt not in curconf.list_options() or curconf.get(opt) == None) and oldconf.get(opt))] if len(opt_dels) > 0: curchanges += "\n\t" + "\n\t".join([_("removed %s %s") % (type, param) for param in opt_dels]) num_changes += len(opt_dels) # adding labels if curchanges == "": curchanges = _("no changes") # store the current changes changes.append((name, curchanges)) # return what we found return num_changes, changes, messages def ok(self, widget, ask_ignore=False): """Ok button""" curconfig = self.msecconfig curperms = self.permconfig # creating preview window if ask_ignore: dialog = Gtk.Dialog(_("Saving changes.."), self.window, Gtk.DialogFlags.MODAL, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, _("Ignore and quit"), Gtk.ResponseType.REJECT, Gtk.STOCK_OK, Gtk.ResponseType.OK) ) else: dialog = Gtk.Dialog(_("Saving changes.."), self.window, Gtk.DialogFlags.MODAL, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK) ) dialog.set_default_size(640, 300) dialog.set_default_response(Gtk.ResponseType.OK) label = Gtk.Label(label=SAVE_SETTINGS_TEXT) dialog.vbox.set_spacing(DEFAULT_SPACING) dialog.vbox.pack_start(label, False, False, padding=DEFAULT_SPACING) dialog.set_resizable(False) # detailed information exp_vbox = Gtk.VBox() # scrolledwindow sw = Gtk.ScrolledWindow() sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) exp_vbox.pack_start(sw, True, True, DEFAULT_SPACING) vbox = Gtk.VBox() exp_vbox.set_size_request(640, 280) sw.add_with_viewport(vbox) # were there changes in configuration? num_changes, allchanges, messages = self.check_for_changes(curconfig, curperms) # TODO: FIX for name, changes in allchanges: label = Gtk.Label(label=_('%s: %s\n') % (name, changes)) label.set_use_markup(True) label.set_property("xalign", 0.0) vbox.pack_start(label, False, False, padding=DEFAULT_SPACING) # see if there were any changes to system files for msg in messages['info']: if msg.find(config.MODIFICATIONS_FOUND) != -1 or msg.find(config.MODIFICATIONS_NOT_FOUND) != -1: label = Gtk.Label(label=_("MSEC test run results: %s") % msg) label.set_line_wrap(True) label.set_use_markup(True) label.set_property("xalign", 0.0) vbox.pack_start(label, False, False, padding=DEFAULT_SPACING) break # adding specific messages advanced = Gtk.Expander(label=_("Details")) vbox_advanced = Gtk.VBox() advanced.add(vbox_advanced) vbox.pack_start(advanced, False, False, padding=DEFAULT_SPACING) for cat in ['info', 'critical', 'error', 'warn', 'debug']: msgs = messages[cat] expander = Gtk.Expander(label=_('MSEC messages (%s): %d') % (cat, len(msgs))) textview = Gtk.TextView() textview.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) textview.set_editable(False) expander.add(textview) count = 1 for msg in msgs: buffer = textview.get_buffer() end = buffer.get_end_iter() buffer.insert(end, "%d: %s\n" % (count, msg)) count += 1 vbox_advanced.pack_start(expander, False, False, padding=DEFAULT_SPACING) # hide all information in an expander expander = Gtk.Expander(label=_("Details (%d changes)..") % num_changes) expander.add(exp_vbox) dialog.vbox.pack_start(expander, False, False, padding=DEFAULT_SPACING) dialog.show_all() response = dialog.run() if response != Gtk.ResponseType.OK: dialog.destroy() return response dialog.destroy() # new base level self.msecconfig.set("BASE_LEVEL", self.base_level) levelconf = config.load_defaults(log, self.base_level) standard_permconf = config.load_default_perms(log, self.base_level) # saving the configuration self.msecconfig.save(levelconf) self.msec.apply(self.msecconfig) self.msec.commit(True) # saving permissions self.permconfig.save(standard_permconf) self.reload_config() return response def reload_config(self): """Reloads config files""" # msecconfig self.msecconfig.reset() self.msecconfig.load() config.merge_with_baselevel(log, self.msecconfig, self.msecconfig.get_base_level(), config.load_defaults, root='') # permconfig self.permconfig.reset() self.permconfig.load() config.merge_with_baselevel(log, self.permconfig, self.msecconfig.get_base_level(), config.load_default_perms, root='') # exceptions self.exceptions.reset() self.exceptions.load() # saving old config self.oldconfig = {} for opt in self.msecconfig.list_options(): self.oldconfig[opt] = self.msecconfig.get(opt) # permissions self.oldperms = {} for opt in self.permconfig.list_options(): self.oldperms[opt] = self.permconfig.get(opt) # what level are we? level = self.msecconfig.get("BASE_LEVEL") if not level: self.log.info(_("No base msec level specified, using '%s'") % config.STANDARD_LEVEL) self.base_level = config.STANDARD_LEVEL else: self.log.info(_("Detected base msec level '%s'") % level) self.base_level = level def create_treeview(self, options): """Creates a treeview from given list of options""" sw = Gtk.ScrolledWindow() sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) # list of options lstore = Gtk.ListStore( GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_INT) # treeview treeview = Gtk.TreeView(model=lstore) treeview.set_rules_hint(True) treeview.set_search_column(self.COLUMN_DESCR) treeview.connect('row-activated', self.option_changed, lstore) # configuring columns # column for option names renderer = Gtk.CellRendererText() renderer.set_property('width', 200) column = Gtk.TreeViewColumn(_('Security Option'), renderer, text=self.COLUMN_OPTION, weight=self.COLUMN_CUSTOM) column.set_sort_column_id(self.COLUMN_OPTION) column.set_resizable(True) column.set_expand(True) treeview.append_column(column) # column for descriptions renderer = Gtk.CellRendererText() renderer.set_property('wrap-width', 400) renderer.set_property('wrap-mode', Pango.WrapMode.WORD_CHAR) column = Gtk.TreeViewColumn(_('Description'), renderer, text=self.COLUMN_DESCR, weight=self.COLUMN_CUSTOM) treeview.append_column(column) column.set_expand(True) #treeview.append_column(column) # column for values column = Gtk.TreeViewColumn(_('Value'), Gtk.CellRendererText(), text=self.COLUMN_VALUE, weight=self.COLUMN_CUSTOM) column.set_sort_column_id(self.COLUMN_VALUE) treeview.append_column(column) sw.add(treeview) for option in options: # retreiving option description if option not in config.SETTINGS: # invalid option self.log.error(_("Invalid option '%s'!") % option) continue # getting level settings, callback and valid params callback, params = config.SETTINGS[option] # now for the value value = self.msecconfig.get(option) # check for disabled options if not value: value = config.OPTION_DISABLED # description doc = config.find_doc(self.msec, option, self.descriptions) # was it changed? if yes, change description to italic if self.option_is_changed(option, value): custom = Pango.Weight.BOLD else: custom = Pango.Weight.NORMAL # building the option iter = lstore.append() lstore.set(iter, self.COLUMN_OPTION, option, self.COLUMN_DESCR, doc, self.COLUMN_VALUE, value, self.COLUMN_CUSTOM, custom, ) return sw, lstore def option_is_changed(self, option, value, level=None): """Checks if the option is different from one specified by base level""" if not level: level = self.base_level conf = self.msec_defaults[level] if conf.get(option) != value: # it was changed return True else: return False def create_summary_ui(self): """Builds the security summary UI""" vbox = Gtk.VBox(homogeneous=False, spacing=20) table = Gtk.Table(n_rows=4, n_columns=4, homogeneous=False) def create_security_item(table, row, text, icon=None): # show logo banner = Gtk.HBox(homogeneous=False, spacing=10) if icon: try: # logo image = Gtk.Image() pixbuf = GdkPixbuf.Pixbuf.new_from_file(icon) image.set_from_pixbuf(pixbuf) banner.pack_start(image, False, False, 0) table.attach(banner, 0, 1, row, row+1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0) except: print("Unable to load icon %s: %s" % (icon, sys.exc_info()[1])) label = Gtk.Label(label=text) label.set_property("xalign", 0.0) label.modify_font(Pango.FontDescription("12")) label.set_property("xalign", 0.0) label.set_property("yalign", 0.5) table.attach(label, 1, 2, row, row + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0) row = 0 # firewall create_security_item(table, row, _("Firewall"), "/usr/share/mcc/themes/default/firewall-mdk.png") firewall_status = tools.find_firewall_info(log) label = Gtk.Label(label=firewall_status) label.set_property("xalign", 0.0) label.set_property("yalign", 0.5) table.attach(label, 2, 3, row, row + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0) button = Gtk.Button(label=_("Configure")) button.connect('clicked', self.run_configure_app, tools.FIREWALL_CMD) table.attach(button, 3, 4, row, row + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0) vbox.pack_start(table, False, False, 0) row += 1 # updates create_security_item(table, row, _("Updates"), "/usr/share/mcc/themes/default/MageiaUpdate.png") updates = tools.get_updates_status(log) label = Gtk.Label(label=updates) label.set_property("xalign", 0.0) label.set_property("yalign", 0.5) table.attach(label, 2, 3, row, row + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0) button = Gtk.Button(label=_("Update now")) button.connect('clicked', self.run_configure_app, tools.UPDATE_CMD) table.attach(button, 3, 4, row, row + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0) row += 1 # security create_security_item(table, row, _("Security"), "/usr/share/mcc/themes/default/security-mdk.png") baselevel = self.msecconfig.get("BASE_LEVEL") if baselevel == config.NONE_LEVEL: msec_status = [_("Msec is disabled")] else: msec_status = [] msec_status.append(_("Msec is enabled")) msec_status.append(_("Base security level: '%s'") % baselevel) # find out custom settings custom_count = 0 base_config = self.msec_defaults[baselevel] for o in self.msecconfig.list_options(): if self.msecconfig.get(o) != base_config.get(o): custom_count += 1 if custom_count > 0: msec_status.append(_("Custom settings: %d") % custom_count) label = Gtk.Label(label="\n".join(msec_status)) label.set_property("xalign", 0.0) label.set_property("yalign", 0.5) table.attach(label, 2, 3, row, row + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0) button = Gtk.Button(label=_("Configure")) button.connect('clicked', lambda x: self.main_notebook.set_current_page(1)) table.attach(button, 3, 4, row, row + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0) row += 1 # msec reports label = Gtk.Label(label=_("Periodic checks")) label.set_property("xalign", 0.0) label.set_property("yalign", 0.5) label.modify_font(Pango.FontDescription("11")) table.attach(label, 2, 3, row, row + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0) row += 1 for check, logfile, updated_n, updated in tools.periodic_check_status(log): if not updated: updated = _("Never") label = Gtk.Label(label=_("Check: %s. Last run: %s") % (check, updated)) label.set_property("xalign", 0.0) table.attach(label, 2, 3, row, row + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0) h = Gtk.HBox() button = Gtk.Button(label=_("Show results")) if updated_n: button.connect('clicked', self.show_test_results, logfile) else: button.set_sensitive(False) h.pack_start(button, False, False, 0) button = Gtk.Button(label=_("Run now")) button.connect('clicked', self.run_periodic_check, check) h.pack_start(button, False, False, 0) table.attach(h, 3, 4, row, row + 1, Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, 0, 0, 0) row += 1 return vbox def process_events(self): """Process pending gtk events""" while Gtk.events_pending(): Gtk.main_iteration() def show_test_results(self, widget, logfile): """Shows results of last periodic check""" # first, try to read the file data = [] try: with open(logfile, "r") as fd: data = fd.readlines() except: data = [_("Unable to read log file: %s") % sys.exc_info()[1]] dialog = Gtk.Dialog(_("Periodic check results"), self.window, 0, (Gtk.STOCK_OK, Gtk.ResponseType.OK)) dialog.set_size_request(640, 280) view = Gtk.TextView() buffer = view.get_buffer() buffer.create_tag("monospace", family="monospace", editable=False) iter = buffer.get_iter_at_offset(0) for l in data: buffer.insert_with_tags_by_name(iter, l, "monospace") sw = Gtk.ScrolledWindow() sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) sw.add(view) dialog.vbox.pack_start(sw, True, True, 0) dialog.show_all() ret = dialog.run() dialog.destroy() if ret != Gtk.ResponseType.YES: return pass def run_periodic_check(self, widget, check): """Shows results for the test""" dialog = Gtk.MessageDialog( parent=self.window, flags=0, type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.YES_NO) dialog.set_markup(_("Do you want to run the %s periodic check? Please note that it could take a considerable time to finish.") % check) dialog.show_all() ret = dialog.run() dialog.destroy() if ret != Gtk.ResponseType.YES: return # progress bar progress = Gtk.Window() progress.set_title(_("Please wait, running checks...")) progress.set_transient_for(self.window) progress.set_modal(True) progress.connect('delete-event', lambda *w: None) vbox = Gtk.VBox(spacing=10) progress.add(vbox) progressbar = Gtk.ProgressBar() progressbar.set_text(_("Please wait, running checks...")) vbox.pack_start(progressbar, True, True, 0) label = Gtk.Label(_("Please wait, this might take a few minutes.")) vbox.pack_start(label, True, True, 0) # show window progress.show_all() self.process_events() # queue to signal that job is finished q = queue.Queue() if check == "manual": program = "/usr/share/msec/security.sh" else: program = "/etc/cron.%s/msec" % check installer = BackgroundRunner(finish=q, program=program) installer.start() while 1: self.process_events() if not q.empty(): result = q.get() break else: progressbar.pulse() time.sleep(0.5) progress.destroy() if result == 0: text = _("Periodic check was executed successfully!") type = Gtk.MessageType.INFO else: text = _("An error occurred while running periodic check.") type = Gtk.MessageType.ERROR # policy was initialized dialog = Gtk.MessageDialog( parent=self.window, flags=0, type=type, message_format=text, buttons=Gtk.ButtonsType.OK ) dialog.show_all() dialog.run() dialog.destroy() def run_configure_app(self, widget, cmd): """Runs application-specific configuration""" os.system(cmd) self.reload_summary() def reload_summary(self): """Reloads summary tab""" pass def level_security_page(self, id): """Builds the basic security page""" vbox = Gtk.VBox(homogeneous=False) entry = Gtk.Label(label=LEVEL_SECURITY_TEXT) entry.set_use_markup(True) vbox.pack_start(entry, False, False, 0) # none self.msec_enabled = Gtk.CheckButton(label=_("Enable MSEC tool")) if self.base_level != config.NONE_LEVEL: self.msec_enabled.set_active(True) self.msec_enabled.connect('clicked', self.enable_disable_msec) vbox.pack_start(self.msec_enabled, False, False, 0) # security levels self.levels_frame = Gtk.Frame.new(_("Select the base security level")) levels_vbox = Gtk.VBox(homogeneous=False) self.levels_frame.add(levels_vbox) # create the security level selection screen sw = Gtk.ScrolledWindow() sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) # list of levels lstore = Gtk.ListStore( GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_INT) # treeview treeview = Gtk.TreeView(model=lstore) treeview.set_rules_hint(True) treeview.set_search_column(self.COLUMN_LEVEL_DESCR) treeview.connect('row-activated', self.level_changed, lstore) # columns # column for level names renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn(_('Level name'), renderer, text=self.COLUMN_OPTION, weight=self.COLUMN_LEVEL_CURRENT) column.set_sort_column_id(self.COLUMN_LEVEL) column.set_resizable(True) column.set_expand(False) treeview.append_column(column) # column for descriptions renderer = Gtk.CellRendererText() renderer.set_property('wrap-width', 600) renderer.set_property('wrap-mode', Pango.WrapMode.WORD_CHAR) column = Gtk.TreeViewColumn(_('Description'), renderer, text=self.COLUMN_DESCR, weight=self.COLUMN_LEVEL_CURRENT) treeview.append_column(column) column.set_expand(True) #treeview.append_column(column) sw.add(treeview) # first, add levels from level_order levels = [] for level in level_order: if level in self.msec_defaults: levels.append(level) # then, add all other levels for level in self.msec_defaults: if level not in levels: levels.append(level) # now build the gui for level in levels: # skip NONE level, as it disables msec if level == "none": continue if level in level_descriptions: descr = level_descriptions[level] else: descr = DEFAULT_LEVEL_DESCRIPTION # TODO: mark current level as bold iter = lstore.append() if self.base_level == level: weight = Pango.Weight.BOLD else: weight = Pango.Weight.NORMAL lstore.set(iter, self.COLUMN_LEVEL, level, self.COLUMN_LEVEL_DESCR, descr, self.COLUMN_LEVEL_CURRENT, weight) levels_vbox.pack_start(sw, True, True, 0) vbox.pack_start(self.levels_frame, True, True, 0) # save the list of levels self.level_list = lstore # putting levels to vbox # notifications by email hbox = Gtk.HBox() self.notify_mail = Gtk.CheckButton(label=_("Send security alerts by email to:")) if self.msecconfig.get("MAIL_WARN") == "yes": self.notify_mail.set_active(True) hbox.pack_start(self.notify_mail, False, False, 0) # email address self.email_entry = Gtk.Entry() email = self.msecconfig.get("MAIL_USER") if not email: email = "" self.email_entry.set_text(email) self.email_entry.connect('changed', self.change_email) hbox.pack_start(self.email_entry, False, False, 5) vbox.pack_start(hbox, False, False, 0) # updating the mail address/checkbox relationship self.notify_mail.connect('clicked', self.notify_mail_changed, self.email_entry) self.checkboxes_callbacks["MAIL_WARN"] = (self.notify_mail_changed, self.notify_mail, hbox) self.notify_mail_changed(self.notify_mail, hbox) # notifications on desktop self.notify_desktop = Gtk.CheckButton(label=_("Display security alerts on desktop")) if self.msecconfig.get("NOTIFY_WARN") == "yes": self.notify_desktop.set_active(True) self.notify_desktop.connect('clicked', self.notify_changed, None) vbox.pack_start(self.notify_desktop, False, False, 0) self.checkboxes_callbacks["NOTIFY_WARN"] = (self.notify_changed, self.notify_desktop, None) return vbox def change_email(self, widget): """Email address was changed""" email = widget.get_text() self.msecconfig.set("MAIL_USER", email) def notify_mail_changed(self, widget, param): """Changes to mail notifications""" status = widget.get_active() if status: self.msecconfig.set("MAIL_WARN", "yes") param.set_sensitive(True) else: if self.msecconfig.get("MAIL_WARN"): self.msecconfig.set("MAIL_WARN", "no") param.set_sensitive(False) def notify_changed(self, widget, param): """Changes to mail notifications""" status = widget.get_active() if status: self.msecconfig.set("NOTIFY_WARN", "yes") else: self.msecconfig.set("NOTIFY_WARN", "no") def enable_disable_msec(self, widget): """Enables/disables msec tool""" newstatus = widget.get_active() if newstatus == False: self.toggle_level(config.NONE_LEVEL, force=True) else: # revert back to the selected level or switch to 'Standard' if none level = config.STANDARD_LEVEL iter = self.level_list.get_iter_first() while iter: list_level = self.level_list.get_value(iter, self.COLUMN_LEVEL) list_weight = self.level_list.get_value(iter, self.COLUMN_LEVEL_CURRENT) if list_weight == Pango.Weight.BOLD: # found previous level level = list_level break iter = self.level_list.iter_next(iter) self.toggle_level(level, force=True) def toggle_level(self, level, force=False): """Enables/disables graphical items for msec""" if level != config.NONE_LEVEL: enabled = True else: enabled = False # update notebook pages npages = self.notebook.get_n_pages() self.levels_frame.set_sensitive(enabled) for page in range(1, npages): curpage = self.notebook.get_nth_page(page) curpage.set_sensitive(enabled) label = self.notebook.get_tab_label(curpage) label.set_sensitive(enabled) if level == self.base_level: # Not changing anything return # updating the markup of new current level unless switching to 'None' level # in this case, we'll still use current level in case user decides to switch back later if level != config.NONE_LEVEL: iter = self.level_list.get_iter_first() while iter: list_level = self.level_list.get_value(iter, self.COLUMN_LEVEL) if list_level != level: # not current level, changing font weight self.level_list.set(iter, self.COLUMN_LEVEL_CURRENT, Pango.Weight.NORMAL) else: # updating current level self.level_list.set(iter, self.COLUMN_LEVEL_CURRENT, Pango.Weight.BOLD) iter = self.level_list.iter_next(iter) # what is the current level? defconfig = self.msec_defaults[level] for z in self.current_options_view: options, curconfig = self.current_options_view[z] iter = options.get_iter_first() # what options are we changing if curconfig.__class__ == config.MsecConfig: # main msec options while iter: option = options.get_value(iter, self.COLUMN_OPTION) curvalue = options.get_value(iter, self.COLUMN_VALUE) newvalue = defconfig.get(option) # changing option if force: if curvalue != newvalue: self.log.debug("%s: %s -> %s" % (option, curvalue, newvalue)) options.set(iter, self.COLUMN_VALUE, newvalue) # reset customization curconfig.set(option, newvalue) # set option as normal options.set(iter, self.COLUMN_CUSTOM, Pango.Weight.NORMAL) ## skip custom options #print "Base level: %s" % self.base_level #if self.option_is_changed(option, curvalue): # # custom option # print "Custom option detected: %s" % option iter = options.iter_next(iter) elif curconfig.__class__ == config.PermConfig: self.reset_permissions(None, options, level=level) pass else: #print curconfig.__class__ pass # checkboxes for option in self.checkboxes_callbacks: if force: func, widget, callback = self.checkboxes_callbacks[option] if defconfig.get(option) == "yes": widget.set_active(True) else: widget.set_active(False) self.msecconfig.set(option, defconfig.get(option)) func(widget, callback) # finally, change new base_level self.base_level = level def force_level(self, widget, level): """Defines a given security level""" if widget.get_active(): #self.base_level = level # update everything self.toggle_level(level, force=True) def system_security_page(self, id): """Builds the network security page""" vbox = Gtk.VBox(homogeneous=False) entry = Gtk.Label(label=SYSTEM_SECURITY_TEXT) entry.set_use_markup(True) vbox.pack_start(entry, False, False, 0) # system security options options_view, model = self.create_treeview(config.SETTINGS_SYSTEM) self.current_options_view[id] = (model, self.msecconfig) vbox.pack_start(options_view, True, True, 0) return vbox def network_security_page(self, id): """Builds the network security page""" vbox = Gtk.VBox(homogeneous=False) entry = Gtk.Label(label=NETWORK_SECURITY_TEXT) entry.set_use_markup(True) vbox.pack_start(entry, False, False, 0) # network security options options_view, model = self.create_treeview(config.SETTINGS_NETWORK) self.current_options_view[id] = (model, self.msecconfig) vbox.pack_start(options_view, True, True, 0) return vbox def periodic_security_page(self, id): """Builds the network security page""" vbox = Gtk.VBox(homogeneous=False) entry = Gtk.Label(label=PERIODIC_SECURITY_TEXT) entry.set_use_markup(True) vbox.pack_start(entry, False, False, 0) periodic_checks = self.msecconfig.get("CHECK_SECURITY") self.periodic_checks = Gtk.CheckButton(label=_("Enable periodic security checks")) if periodic_checks == "yes": self.periodic_checks.set_active(True) vbox.pack_start(self.periodic_checks, False, False, 0) # network security options options_view, model = self.create_treeview(config.SETTINGS_PERIODIC) vbox.pack_start(options_view, True, True, 0) # see if these tests are enabled self.periodic_checks.connect('clicked', self.periodic_tests, options_view) if periodic_checks == 'no': # disable all periodic tests options_view.set_sensitive(False) # save options self.current_options_view[id] = (model, self.msecconfig) # save the checkboxes self.checkboxes_callbacks["CHECK_SECURITY"] = (self.periodic_tests, self.periodic_checks, options_view) return vbox def periodic_tests(self, widget, options): '''Enables/disables periodic security tests.''' status = widget.get_active() if status: self.msecconfig.set("CHECK_SECURITY", "yes") options.set_sensitive(True) else: self.msecconfig.set("CHECK_SECURITY", "no") options.set_sensitive(False) def exceptions_page(self, id): """Builds the exceptions page""" vbox = Gtk.VBox(homogeneous=False) entry = Gtk.Label(label=EXCEPTIONS_TEXT) entry.set_use_markup(True) vbox.pack_start(entry, False, False, 0) sw = Gtk.ScrolledWindow() sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) # list of options lstore = Gtk.ListStore( GObject.TYPE_STRING, GObject.TYPE_STRING ) # treeview treeview = Gtk.TreeView(model=lstore) treeview.set_rules_hint(True) treeview.set_search_column(self.COLUMN_EXCEPTION) # TODO: fix treeview.connect('row-activated', self.exception_changed, lstore) # configuring columns # column for exception position column = Gtk.TreeViewColumn(_('Security check'), Gtk.CellRendererText(), text=self.COLUMN_EXCEPTION) column.set_sort_column_id(self.COLUMN_EXCEPTION) column.set_expand(True) treeview.append_column(column) # column for check exception column = Gtk.TreeViewColumn(_('Exception'), Gtk.CellRendererText(), text=self.COLUMN_EXCEPTION_VALUE) column.set_sort_column_id(self.COLUMN_EXCEPTION_VALUE) column.set_expand(True) treeview.append_column(column) sw.add(treeview) for option, value in self.exceptions.list_options(): # building the option iter = lstore.append() lstore.set(iter, self.COLUMN_EXCEPTION, option, self.COLUMN_EXCEPTION_VALUE, value, ) vbox.pack_start(sw, True, True, 0) self.current_options_view[id] = (lstore, self.exceptions) # buttons hbox hbox = Gtk.HBox(homogeneous=True, spacing=10) # add button = Gtk.Button(label=_("Add a rule")) button.connect('clicked', self.add_exception, lstore) hbox.pack_start(button, False, False, 0) # delete button = Gtk.Button(label=_("Delete")) button.connect('clicked', self.remove_exception, treeview) hbox.pack_start(button, False, False, 0) vbox.pack_start(hbox, False, False, 0) return vbox def permissions_security_page(self, id): """Builds the network security page""" vbox = Gtk.VBox(homogeneous=False) entry = Gtk.Label(label=PERMISSIONS_SECURITY_TEXT) entry.set_use_markup(True) vbox.pack_start(entry, False, False, 0) sw = Gtk.ScrolledWindow() sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) # list of options lstore = Gtk.ListStore( GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_BOOLEAN, GObject.TYPE_STRING) # treeview treeview = Gtk.TreeView(model=lstore) treeview.set_rules_hint(True) treeview.set_search_column(self.COLUMN_DESCR) # TODO: fix treeview.connect('row-activated', self.permission_changed, lstore) # configuring columns # column for path mask column = Gtk.TreeViewColumn(_('Path'), Gtk.CellRendererText(), text=self.COLUMN_PATH) column.set_sort_column_id(self.COLUMN_PATH) column.set_expand(True) treeview.append_column(column) # column for user column = Gtk.TreeViewColumn(_('User'), Gtk.CellRendererText(), text=self.COLUMN_USER) column.set_sort_column_id(self.COLUMN_USER) column.set_expand(True) treeview.append_column(column) # column for group column = Gtk.TreeViewColumn(_('Group'), Gtk.CellRendererText(), text=self.COLUMN_GROUP) column.set_sort_column_id(self.COLUMN_GROUP) column.set_expand(True) treeview.append_column(column) # column for permissions column = Gtk.TreeViewColumn(_('Permissions'), Gtk.CellRendererText(), text=self.COLUMN_PERM) column.set_sort_column_id(self.COLUMN_VALUE) column.set_expand(True) treeview.append_column(column) # column for force option renderer = Gtk.CellRendererToggle() renderer.connect('toggled', self.toggle_enforced, lstore) column = Gtk.TreeViewColumn(_('Enforce'), renderer, active=self.COLUMN_FORCE) column.set_sort_column_id(self.COLUMN_FORCE) column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) column.set_fixed_width(50) column.set_expand(True) treeview.append_column(column) # column for Acl column = Gtk.TreeViewColumn(_('Acl'), Gtk.CellRendererText(), text=self.COLUMN_ACL) column.set_sort_column_id(self.COLUMN_ACL) column.set_expand(True) treeview.append_column(column) sw.add(treeview) for file in self.permconfig.list_options(): user_s, group_s, perm_s, force, acl = self.permconfig.get(file) # convert to boolean if force: force = True else: force = False # building the option iter = lstore.append() lstore.set(iter, self.COLUMN_PATH, file, self.COLUMN_USER, user_s, self.COLUMN_GROUP, group_s, self.COLUMN_PERM, perm_s, self.COLUMN_FORCE, force, self.COLUMN_ACL, acl, ) vbox.pack_start(sw, True, True, 0) self.current_options_view[id] = (lstore, self.permconfig) # buttons hbox hbox = Gtk.HBox(homogeneous=True, spacing=10) # # up # button = Gtk.Button(_("Up")) # button.connect('clicked', self.move_rule_up, lstore) # hbox.pack_start(button, False, 0) # # down # button = Gtk.Button(_("Down")) # button.connect('clicked', self.move_rule_up, lstore) # hbox.pack_start(button, False, 0) # # default # button = Gtk.Button(_("Reset to default level permissions")) # button.connect('clicked', self.reset_permissions, lstore) # hbox.pack_start(button, False, 0) # add button = Gtk.Button(label=_("Add a rule")) button.connect('clicked', self.add_permission_check, lstore) hbox.pack_start(button, False, False, 0) # delete button = Gtk.Button(label=_("Delete")) button.connect('clicked', self.remove_permission_check, treeview) hbox.pack_start(button, False, False, 0) ## edit #button = Gtk.Button(_("Edit")) #button.connect('clicked', self.move_rule_up, lstore) #hbox.pack_start(button, False, 0) vbox.pack_start(hbox, False, False, 0) return vbox def reset_permissions(self, widget, model, level=None): """Reset permissions to default specified by level""" model.clear() self.permconfig.reset() if not level: defperms = self.perm_defaults[self.base_level] else: defperms = self.perm_defaults[level] for file in defperms.list_options(): user_s, group_s, perm_s, force_s, acls = defperms.get(file) # convert to boolean if force_s: force_val = True else: force_val = False # building the option iter = model.append() model.set(iter, self.COLUMN_PATH, file, self.COLUMN_USER, user_s, self.COLUMN_GROUP, group_s, self.COLUMN_PERM, perm_s, self.COLUMN_FORCE, force_val, self.COLUMN_ACL, acls, ) # changing back force value self.permconfig.set(file, (user_s, group_s, perm_s, force_s, acls)) def remove_exception(self, widget, treeview): """Removes an exception from list""" model, iter = treeview.get_selection().get_selected() if not iter: # nothing selected return pos, = model.get_path(iter) self.exceptions.remove(pos) model.remove(iter) # save exceptions self.exceptions.save() def remove_permission_check(self, widget, treeview): """Removes a permission check for file""" model, iter = treeview.get_selection().get_selected() if not iter: # nothing selected return file = model.get_value(iter, self.COLUMN_PATH) self.permconfig.remove(file) model.remove(iter) def toggle_enforced(self, cell, path, model): '''Toggles a forced permission on an item''' iter = model.get_iter((int(path),)) file = model.get_value(iter, self.COLUMN_PATH) fixed = model.get_value(iter, self.COLUMN_FORCE) user, group, perm, force, acl = self.permconfig.get(file) # do something with the value fixed = not fixed # set new value model.set(iter, self.COLUMN_FORCE, fixed) if fixed: force = "force" else: force = "" self.permconfig.set(file, (user, group, perm, force, acl)) def add_permission_check(self, widget, model): """Adds a permission check""" return self.permission_changed(None, None, None, model) def add_exception(self, widget, model): """Adds a new exception""" return self.exception_changed(None, None, None, model) def exception_changed(self, treeview, path, col, model): """Processes an exception change. If path is None, adds a new item.""" if path: iter = model.get_iter(path) exception_pos, = path module = model.get_value(iter, self.COLUMN_EXCEPTION) exception = model.get_value(iter, self.COLUMN_EXCEPTION_VALUE) title = _("Editing exception") else: exception_pos = -1 module = "" exception = "" title = _("Adding new exception") # asks for new parameter value dialog = Gtk.Dialog(title, self.window, 0, (Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)) label = Gtk.Label(label=_("Editing exception. Please select the correspondent msec check and exception value\n")) label.set_line_wrap(True) label.set_use_markup(True) dialog.vbox.pack_start(label, False, False, 0) # module hbox = Gtk.HBox() hbox.pack_start(Gtk.Label(_("Check: ")), True, True, 0) entry_module = Gtk.ComboBoxText() pos = 0 for item in config.CHECKS_WITH_EXCEPTIONS: entry_module.append_text(item) if item == module: entry_module.set_active(pos) pos += 1 if not module: entry_module.set_active(0) hbox.pack_start(entry_module, True, True, 0) dialog.vbox.pack_start(hbox, False, False, 0) # exception hbox = Gtk.HBox() hbox.pack_start(Gtk.Label(_("Exception: ")), True, True, 0) entry_exception = Gtk.Entry() entry_exception.set_text(exception) hbox.pack_start(entry_exception, True, True, 0) dialog.vbox.pack_start(hbox, False, False, 0) dialog.show_all() response = dialog.run() if response != Gtk.ResponseType.OK: dialog.destroy() return new_check = entry_module.get_active_text() new_exception = entry_exception.get_text() dialog.destroy() self.exceptions.set(exception_pos, (new_check, new_exception)) if not path: # adding new entry iter = model.append() model.set(iter, self.COLUMN_EXCEPTION, new_check) model.set(iter, self.COLUMN_EXCEPTION_VALUE, new_exception) # save exceptions self.exceptions.save() def permission_changed(self, treeview, path, col, model): """Processes a permission change. If path is None, adds a new item.""" if path: iter = model.get_iter(path) file = model.get_value(iter, self.COLUMN_PATH) user = model.get_value(iter, self.COLUMN_USER) group = model.get_value(iter, self.COLUMN_GROUP) perm = model.get_value(iter, self.COLUMN_PERM) force = model.get_value(iter, self.COLUMN_FORCE) acl = model.get_value(iter, self.COLUMN_ACL) title = _("Changing permissions for %s") % file else: file = "" user = "" group = "" perm = "" force = "" acl = "" title = _("Adding new permission check") if not force: force = "" else: force = "force" # asks for new parameter value dialog = Gtk.Dialog(title, self.window, 0, (Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)) label = Gtk.Label(label=_("Changing permissions on %s") % (file or _("new file"))) label.set_line_wrap(True) label.set_use_markup(True) dialog.vbox.pack_start(label, False, False, padding=5) # aligning entries sizegroup1 = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL) sizegroup2 = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL) if not path: # file hbox = Gtk.HBox() label = Gtk.Label(label=_("File: ")) hbox.pack_start(label, True, True, 0) entry_file = Gtk.Entry() entry_file.set_text(file) hbox.pack_start(entry_file, True, True, 0) sizegroup1.add_widget(label) sizegroup2.add_widget(entry_file) dialog.vbox.pack_start(hbox, False, False, 0) label = Gtk.Label(_("Please specify new file owner and permissions, or use 'current' to keep current settings.")) label.set_line_wrap(True) label.set_use_markup(True) dialog.vbox.pack_start(label, False, False, padding=5) # user hbox = Gtk.HBox() label = Gtk.Label(label=_("User: ")) hbox.pack_start(label, True, True, 0) entry_user = Gtk.Entry() entry_user.set_text(user) hbox.pack_start(entry_user, True, True, 0) sizegroup1.add_widget(label) sizegroup2.add_widget(entry_user) dialog.vbox.pack_start(hbox, False, False, 0) # group hbox = Gtk.HBox() label = Gtk.Label(label=_("Group: ")) hbox.pack_start(label, True, True, 0) entry_group = Gtk.Entry() entry_group.set_text(group) hbox.pack_start(entry_group, True, True, 0) sizegroup1.add_widget(label) sizegroup2.add_widget(entry_group) dialog.vbox.pack_start(hbox, False, False, 0) # perm hbox = Gtk.HBox() label = Gtk.Label(label=_("Permissions: ")) hbox.pack_start(label, True, True, 0) entry_perm = Gtk.Entry() entry_perm.set_text(perm) hbox.pack_start(entry_perm, True, True, 0) sizegroup1.add_widget(label) sizegroup2.add_widget(entry_perm) dialog.vbox.pack_start(hbox, False, False, 0) label = Gtk.Label(label=_("To enforce additional ACL (Access Control List) on file, specify them in the following format:\nuser1:acl,user2:acl\nRefer to 'man setfacl' for details.")) label.set_line_wrap(True) label.set_use_markup(True) dialog.vbox.pack_start(label, False, False, padding=5) # acl hbox = Gtk.HBox() label = Gtk.Label(label=_("ACL: ")) hbox.pack_start(label, True, True, 0) entry_acl = Gtk.Entry() entry_acl.set_text(acl) hbox.pack_start(entry_acl, True, True, 0) sizegroup1.add_widget(label) sizegroup2.add_widget(entry_acl) dialog.vbox.pack_start(hbox, False, False, 0) dialog.show_all() response = dialog.run() if response != Gtk.ResponseType.OK: dialog.destroy() return if not path: newfile = entry_file.get_text() else: newfile = file newuser = entry_user.get_text() newgroup = entry_group.get_text() newperm = entry_perm.get_text() newacl = entry_acl.get_text() dialog.destroy() # if acl is specified, the permissions will be enforced if newacl != "": force = "force" self.permconfig.set(newfile, (newuser, newgroup, newperm, force, newacl)) if not path: # adding new entry iter = model.append() model.set(iter, self.COLUMN_PATH, newfile) model.set(iter, self.COLUMN_USER, newuser) model.set(iter, self.COLUMN_GROUP, newgroup) model.set(iter, self.COLUMN_PERM, newperm) model.set(iter, self.COLUMN_FORCE, True if force == "force" else False) model.set(iter, self.COLUMN_ACL, newacl) def option_changed(self, treeview, path, col, model): """Processes an option change""" iter = model.get_iter(path) param = model.get_value(iter, self.COLUMN_OPTION) descr = model.get_value(iter, self.COLUMN_DESCR) value = model.get_value(iter, self.COLUMN_VALUE) # option is disabled? if not value: value = config.OPTION_DISABLED callback, params = config.SETTINGS[param] conf_def = self.msec_defaults[self.base_level] # Highlighting default options def_start="" def_end="" if self.base_level == config.STANDARD_LEVEL: def_start="" def_end="" elif self.base_level == config.SECURE_LEVEL: sec_start="" sec_end="" val_def = conf_def.get(param) # asks for new parameter value dialog = Gtk.Dialog(_("Select new value for %s") % (param), self.window, 0, (Gtk.STOCK_OK, Gtk.ResponseType.OK, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)) # option title label = Gtk.Label(label="%s\n" % param) label.set_use_markup(True) # description dialog.vbox.pack_start(label, True, True, 0) label = Gtk.Label(label=_("%s\n\n\tCurrent value:\t\t\t%s\n\t%sDefault level value:\t%s%s\n") % (descr, value, def_start, val_def, def_end,)) label.set_line_wrap(True) label.set_use_markup(True) dialog.vbox.pack_start(label, True, True, 0) dialog.vbox.pack_start(Gtk.HSeparator(), True, True, 0) # new value hbox = Gtk.HBox() hbox.pack_start(Gtk.Label(_("New value:")), True, True, 0) if '*' in params: # string parameter entry = Gtk.Entry() entry.set_text(value) else: # combobox parameter entry = Gtk.ComboBoxText() # add an item to disable a check if config.OPTION_DISABLED not in params: params.append(config.OPTION_DISABLED) for item in params: entry.append_text(item) if value not in params: entry.append_text(value) params.append(value) active = params.index(value) entry.set_active(active) hbox.pack_start(entry, True, True, 0) dialog.vbox.pack_start(hbox, True, True, 0) dialog.show_all() response = dialog.run() if response != Gtk.ResponseType.OK: dialog.destroy() return # process new parameter if '*' in params: newval = entry.get_text() else: newval = entry.get_active_text() dialog.destroy() # update options self.msecconfig.set(param, newval) # is it different from default? if yes, change description to italic doc = config.find_doc(self.msec, param, self.descriptions) if self.option_is_changed(param, newval): custom = Pango.Weight.BOLD else: custom = Pango.Weight.NORMAL model.set(iter, self.COLUMN_VALUE, newval) model.set(iter, self.COLUMN_DESCR, doc) model.set(iter, self.COLUMN_CUSTOM, custom) def signal_quit(self, s): """Quits via a signal""" self.signals.put(s) return True def quit(self, widget, event=None): """Quits the application""" num_changes, allchanges, messages = self.check_for_changes(self.msecconfig, self.permconfig) if num_changes == 0: Gtk.main_quit() return False else: ret = self.ok(widget, ask_ignore=True) if ret == Gtk.ResponseType.OK or ret == Gtk.ResponseType.REJECT: Gtk.main_quit() else: return True # {{{ usage def usage(): """Prints help message""" print("""Msec: Mandriva Security Center (%s). Arguments to msecgui: -h, --help displays this helpful message. -d enable debugging messages. -e, --embedded embed in MCC. """ % version) # }}} if __name__ == "__main__": log_level = logging.INFO PlugWindowID = None # parse command line try: opt, args = getopt.getopt(sys.argv[1:], 'hde:', ['help', 'debug', 'embedded=']) except getopt.error: usage() sys.exit(1) for o in opt: # help if o[0] == '-h' or o[0] == '--help': usage() sys.exit(0) # list elif o[0] == '-d' or o[0] == '--debug': log_level = logging.DEBUG elif o[0] == '-e' or o[0] == '--embedded': try: PlugWindowID = int(o[1]) except: print("Error: bad master window XID (%s)!" % o[1], file=sys.stderr) sys.exit(1) # configuring logging log = Log(interactive=True, log_syslog=False, log_file=True, log_level=log_level, log_path=config.SECURITYLOG) # loading initial config msec_config = config.MsecConfig(log, config=config.SECURITYCONF) # loading permissions config perm_conf = config.PermConfig(log, config=config.PERMCONF) # loading exceptions exceptions = config.ExceptionConfig(log, config=config.EXCEPTIONSCONF) # creating an msec instance msec = MSEC(log) perms = PERMS(log) log.info("Starting gui..") gui = MsecGui(log, msec, perms, msec_config, perm_conf, exceptions, embed=PlugWindowID) signal.signal(signal.SIGTERM, lambda s, f: gui.signal_quit(s)) Gtk.main()