def email_alert(siginfo, to_addrs):
    smtp_host    = get_config('email','smtp_host')
    smtp_port    = get_config('email','smtp_port', int)
    from_address = get_config('email','from_address')

    from_user, from_domain = parse_email_addr(from_address)
    if from_user is None:
        from_user = "******"
    if from_domain is None:
        from_domain = get_hostname()
    from_address = '%s@%s' % (from_user, from_domain)

    log_debug("alert smtp=%s:%d  -> %s" % (smtp_host, smtp_port, ','.join(to_addrs)))

    siginfo.update_derived_template_substitutions()
    summary = siginfo.substitute(siginfo.summary())
    subject = '[%s] %s' % (get_config('email','subject'), summary)
    text = siginfo.format_text() + siginfo.format_details() 

    email_msg            = MIMEMultipart('alternative')
    email_msg['Subject'] = subject
    email_msg['From']    = from_address
    email_msg['To']      = ', '.join(to_addrs)
    email_msg['Date']    = formatdate()

    email_msg.attach(MIMEText(text))

    import smtplib
    try:
        smtp = smtplib.SMTP(smtp_host, smtp_port)
        smtp.sendmail(from_address, to_addrs, email_msg.as_string())
        smtp.quit()
    except smtplib.SMTPException, e:
        syslog.syslog(syslog.LOG_ERR, "email failed: %s" % e)
示例#2
0
    def get_socket_paths(self):
        self.audit_socket_paths = []

        audit_socket_path = get_config('audit','text_protocol_socket_path')
        self.audit_socket_paths.append(audit_socket_path)

        audit_socket_path = get_config('audit','binary_protocol_socket_path')
        self.audit_socket_paths.append(audit_socket_path)
    def get_socket_paths(self):
        self.audit_socket_paths = []

        audit_socket_path = get_config("audit", "text_protocol_socket_path")
        self.audit_socket_paths.append(audit_socket_path)

        audit_socket_path = get_config("audit", "binary_protocol_socket_path")
        self.audit_socket_paths.append(audit_socket_path)
    def __init__(self, username):
        RpcChannel.__init__(self, channel_type='sealert')
        GObject.GObject.__init__(self)
        self.connection_state.connect('changed', self.on_connection_state_change)

        self.connect_rpc_interface('SEAlert', self)
        self.connect_rpc_interface('SETroubleshootDatabaseNotify', self)

        self.pkg_version = get_config('general', 'pkg_version')
        self.rpc_version = get_config('general', 'rpc_version')
        self.username = username
        self.retry_connection_if_closed = False
        self.connection_retry = Retry(self.retry_connection, self.get_connection_retry_interval, notify_interval=1.0)
        self.report_connect_failure = True
        self.database_name = 'audit_listener'
示例#5
0
    def report_problem(self, siginfo):
        siginfo = super(AlertPluginReportReceiver, self).report_problem(siginfo)

        if email_recipients is not None:
            to_addrs = []
            for recipient in email_recipients.recipient_list:
                username = "******" % recipient.address
                action = siginfo.evaluate_filter_for_user(username, recipient.filter_type)
                if action != "ignore":
                    log_debug("Email: siginfo.sig=%s" % siginfo.sig)
                    to_addrs.append(recipient.address)

            if len(to_addrs):
                from setroubleshoot.email_alert import email_alert
                email_alert(siginfo, to_addrs)

        log_debug("sending alert to all clients")

        from setroubleshoot.html_util import html_to_text
        syslog.syslog(syslog.LOG_ERR, siginfo.summary() + _(" For complete SELinux messages run: sealert -l %s") % siginfo.local_id)
        for audit_record in siginfo.audit_event.records:
            if audit_record.record_type == 'AVC':
                pid = audit_record.fields["pid"]
                break
        if get_config('setroubleshootd_log', 'log_full_report', bool):
            systemd.journal.send(siginfo.format_text(), OBJECT_PID=pid)

        for u in siginfo.users:
            action = siginfo.evaluate_filter_for_user(u.username)
            if action == "ignore":
                return siginfo

        send_alert_notification(siginfo)
        return siginfo
示例#6
0
def make_database_filepath(name):
    database_dir = get_config('database', 'database_dir')
    # strip off extension if one was provided
    name = re.sub('\\.xml$', '', name)
    filename = name + '_database.xml'
    filepath = os.path.join(database_dir, filename)
    return filepath
示例#7
0
    def open(self, logfile_path=None):
        if logfile_path is not None:
            self.logfile_path = logfile_path
        log_debug('%s.open(%s)' % (self.__class__.__name__, self.logfile_path))
        try:
            stat_info = os.stat(self.logfile_path)
            self.file_size = stat_info[ST_SIZE]
            self.file = open(self.logfile_path)
            self.fileno = self.file.fileno()
        except EnvironmentError as e:
            syslog.syslog(syslog.LOG_ERR, '%s.open(): %s' % (self.__class__.__name__, e.strerror))
            self.errno = e.errno
            self.strerror = e.strerror
            raise e

        self.n_bytes_read = 0
        self.line_count = 0
        self.record_count = 0
        self.progress = 0.0
        self.cancelled = False
        self.emit('progress', self.progress)

        logfile_basename = os.path.basename(self.logfile_path)
        self.friendly_name = "file: %s" % (os.path.splitext(logfile_basename)[0])
        self.database = SETroubleshootDatabase(None, logfile_basename, friendly_name=self.friendly_name)

        self.record_reader = AuditRecordReader(AuditRecordReader.TEXT_FORMAT)
        self.record_receiver = AuditRecordReceiver()
        self.analyzer = Analyze()
        if not get_config('test', 'analyze', bool):
            self.report_receiver = PluginReportReceiver(self.database)
        else:
            self.report_receiver = TestPluginReportReceiver(self.database)

        return True
示例#8
0
def find_program(prog):
    if os.path.isabs(prog):
        return prog
    basename = os.path.basename(prog)
    search_path = get_config('fix_command', 'prog_search_path').split(':')
    for d in search_path:
        path = os.path.join(d, basename)
        if os.path.exists(path):
            return path
    return None
 def __init__(self, queue, report_receiver):
     # parent class constructor
     threading.Thread.__init__(self)
     self.queue = queue
     self.report_receiver = report_receiver
     self.record_receiver = AuditRecordReceiver()
     self.retry_interval = get_config("audit", "retry_interval", int)
     self.get_socket_paths()
     self.timeout_interval = 2
     self.has_audit_eoe = False
示例#10
0
    def __init__(self, filepath, name, friendly_name=None):
        self.filepath = filepath
        self.notify = None
        self.properties = SEDatabaseProperties(name, friendly_name, self.filepath)
        self.lock = threading.Lock()
        self.file_exists = False
        self.modified_count = 0
        self.auto_save_interval = 5   # auto save after this many seconds
        self.auto_save_threshold = 200  # auto save after this many changes
        self.auto_save_timer = None
        self.max_alerts = get_config('database', 'max_alerts', int)
        self.max_alert_age = None
        max_alert_age = get_config('database', 'max_alert_age')
        if max_alert_age is not None:
            max_alert_age = max_alert_age.strip()
            if max_alert_age:
                self.max_alert_age = parse_datetime_offset(max_alert_age)

        log_debug("created new database: name=%s, friendly_name=%s, filepath=%s" % (self.properties.name, self.properties.friendly_name, self.properties.filepath))

        self.load()
示例#11
0
def get_plugin_names(filter_glob=None):
    if filter_glob is None:
        filter_glob = '*'
    else:
        filter_glob = re.sub('.py$', '', filter_glob)

    plugin_dir = get_config('plugins', 'plugin_dir')
    plugin_names = []
    for p in glob.glob(os.path.join(plugin_dir, filter_glob + ".py")):
        p = os.path.basename(p)
        if p in ['__init__.py']:
            continue
        plugin_name = os.path.splitext(os.path.basename(p))[0]
        plugin_names.append(plugin_name)
    return plugin_names
示例#12
0
def load_plugins(filter_glob=None):
    plugin_dir = get_config('plugins', 'plugin_dir')
    plugin_base = os.path.basename(plugin_dir)
    plugins = []
    plugin_names = get_plugin_names(filter_glob)
    log_debug("load_plugins() names=%s" % plugin_names)

    # load the parent (e.g. the package containing the submodules), required for python 2.5 and above
    module_name = plugin_base
    plugin_name = '__init__'
    if module_name not in sys.modules:
        try:
            import imp
            mod_fp, mod_path, mod_description = imp.find_module(plugin_name, [plugin_dir])
            mod = imp.load_module(module_name, mod_fp, mod_path, mod_description)
        except Exception:
            syslog.syslog(syslog.LOG_ERR, "failed to initialize plugins in %s" % plugin_dir)
            return []

        if mod_fp:
            mod_fp.close()

    for plugin_name in plugin_names:
        module_name = "%s.%s" % (plugin_base, plugin_name)
        mod = sys.modules.get(module_name)
        if mod is not None:
            log_debug("load_plugins() %s previously imported" % module_name)
            plugins.append(mod.plugin())
            continue
        try:
            import imp
            mod_fp, mod_path, mod_description = imp.find_module(plugin_name, [plugin_dir])
            mod = imp.load_module(module_name, mod_fp, mod_path, mod_description)
            plugins.append(mod.plugin())
        except Exception:
            syslog.syslog(syslog.LOG_ERR, "failed to load %s plugin" % plugin_name)

        if mod_fp:
            mod_fp.close()

    plugins.sort(key=cmp_to_key(sort_plugins))
    return plugins
示例#13
0
def log_debug(*msg):
    global log_level
    if log_level == "unknown":
        log_level = get_config('sealert_log', 'level')
    if log_level == "debug":
        syslog.syslog(syslog.LOG_DEBUG, msg)
示例#14
0
# (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., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import gettext
from setroubleshoot.config import parse_config_setting, get_config

translation = gettext.translation(domain=get_config('general', 'i18n_text_domain'),
                                  localedir=get_config('general', 'i18n_locale_dir'),
                                  fallback=True)

try:
    _ = translation.ugettext  # Unicode version of gettext for Py2
except AttributeError:
    _ = translation.gettext  # Python3 (uses unicode by default)

from setroubleshoot.signature import *
from setroubleshoot.util import *

#import sys
import os.path
import re
示例#15
0
def log_init(section):
    global log_level
    log_level = log_levels.get(get_config(section, 'level').upper())
    if log_level is None:
        log_level = syslog.LOG_WARNING
示例#16
0
def launch_web_browser_on_url(url):
    web_browser_launcher = get_config('helper_apps', 'web_browser_launcher')
    os.spawnl(os.P_NOWAIT, web_browser_launcher, web_browser_launcher, url)
示例#17
0
#/usr/bin/env python

# Author: Thomas Liu <*****@*****.**>
import yum
import gettext
from setroubleshoot.config import parse_config_setting, get_config
gettext.install(domain    = get_config('general', 'i18n_text_domain'),
                localedir = get_config('general', 'i18n_locale_dir'))

installed = []
try:
    yb = yum.YumBase()
    yb.conf.cache = True
    installed = yb.rpmdb.searchNevra('selinux-policy')
    if installed:
        for pkg in sorted(installed):
            if pkg.name == 'selinux-policy':
                print _("current: %s ") % pkg.printVer()
    try:
        pl = yb.doPackageLists(patterns=['selinux-policy'])
    except yum.Errors.RepoError, msg:
        yb.conf.cache = False
        pl = yb.doPackageLists(patterns=['selinux-policy'])

    if pl.available:
        for pkg in sorted(pl.available):
            print _("newer: %s ") % pkg.printVer()
            

except yum.Errors.RepoError, msg:
    print "error: ", str(msg)
示例#18
0
    'XmlSerialize',
]

import sys
from types import *
import libxml2

import syslog
from setroubleshoot.config import get_config
from setroubleshoot.errcode import *
from setroubleshoot.util import *

#------------------------------------------------------------------------

i18n_encoding = get_config('general', 'i18n_encoding')

#------------------------------------------------------------------------

def validate_database_doc(doc):
    if doc is None:
        syslog.syslog(syslog.LOG_DEBUG, "validate_database_doc: doc is empty, validate fails")
        return False
    root_node = doc.getRootElement()
    if root_node is None:
        syslog.syslog(syslog.LOG_DEBUG, "validate_database_doc: root is empty, validate fails")
        return False
    version = root_node.prop('version')
    if version is None:
        syslog.syslog(syslog.LOG_DEBUG, "validate_database_doc: version is empty, validate fails")
        return False
示例#19
0
import gettext
#import errno as Errno
import os
#import pwd
import signal
import atexit
#from stat import *
import sys
import syslog
import systemd.journal
#import threading
#from types import *

from setroubleshoot.config import parse_config_setting, get_config

domain = get_config('general', 'i18n_text_domain')
localedir = get_config('general', 'i18n_locale_dir')
kwargs = {}
if sys.version_info < (3,):
    kwargs['unicode'] = True
gettext.install(domain=domain,
                localedir=localedir,
                **kwargs)

translation = gettext.translation(domain=domain,
                                  localedir=localedir,
                                  fallback=True)

try:
    _ = translation.ugettext  # This raises exception in Python3, succ. in Py2
except AttributeError:
示例#20
0
def get_default_port():
    default_port = get_config('connection','default_port', int)
    return default_port
示例#21
0
def get_socket_list_from_config(cfg_section):
    addr_string = get_config(cfg_section, 'address_list')
    socket_addresses = parse_socket_address_list(addr_string)
    return socket_addresses
示例#22
0
    rec += "<fix>"
    rec += se_plugin.fix_description
    rec += "</fix>\n"
    rec += "</setroubleshoot>"
    return rec


__all__ = [
    'RunFaultServer',
    'get_host_database',
    'send_alert_notification',
]
from setroubleshoot.config import get_config
import gettext

gettext.install(domain=get_config('general', 'i18n_text_domain'),
                localedir=get_config('general', 'i18n_locale_dir'),
                unicode=False,
                codeset=get_config('general', 'i18n_encoding'))

from setroubleshoot.util import *

se_plugins = {}
plugins = load_plugins()
for p in plugins:
    se_plugins[p.analysis_id.split(".")[1]] = p

fd = open("/usr/share/system-config-selinux/selinux.tbl")
booll = fd.readlines()
fd.close()
booldict = {}
示例#23
0
import atexit
#from stat import *
import syslog
import systemd.journal
#import threading
#from types import *

from setroubleshoot.access_control import ServerAccess
from setroubleshoot.analyze import (PluginReportReceiver,
                                    SETroubleshootDatabase,
                                    TestPluginReportReceiver,
                                    AnalyzeThread, 
                                    )                                
from setroubleshoot.avc_audit import *
from setroubleshoot.config import get_config
if get_config('general', 'use_auparse', bool):
    from setroubleshoot.avc_auparse import *
else:
    from setroubleshoot.avc_audit import AuditRecordReceiver
    
from setroubleshoot.errcode import (ProgramError,
                                    ERR_NOT_AUTHENTICATED, 
                                    ERR_USER_LOOKUP, 
                                    ERR_USER_PROHIBITED, 
                                    ERR_USER_PERMISSION, 
                                    ERR_FILE_OPEN, 
                                    ERR_DATABASE_NOT_FOUND, 
                                    )
                                    
from setroubleshoot.rpc import (RpcChannel,
                                ConnectionState, 
示例#24
0
def RunFaultServer(timeout=10):
    # FIXME
    audit2why.init()
    global host_database, analysis_queue, email_recipients

    signal.signal(signal.SIGHUP, sighandler)
    signal.signal(signal.SIGQUIT, sighandler)
    signal.signal(signal.SIGTERM, sighandler)
    signal.signal(signal.SIGALRM, sighandler)

    #interface_registry.dump_interfaces()

    try:
        # FIXME: should this be using our logging objects in log.py?
        # currently syslog is only used for putting an alert into
        # the syslog with it's id

        pkg_name = get_config('general','pkg_name')
        syslog.openlog(pkg_name)

        # Create an object responsible for sending notifications to clients
        client_notifier = ClientNotifier(connection_pool)

        # Create a database local to this host
        
        database_filename = get_config('database','filename')
        database_filepath = make_database_filepath(database_filename)
        assure_file_ownership_permissions(database_filepath, 0600, 'root', 'root')
        host_database = SETroubleshootDatabase(database_filepath, database_filename,
                                               friendly_name=_("Audit Listener"))
        host_database.set_notify(client_notifier)

        atexit.register(goodbye, host_database)

        deleted = False
        for i in host_database.sigs.signature_list:
            why, bools = audit2why.analyze(str(i.sig.scontext), str(i.sig.tcontext), str(i.sig.tclass), i.sig.access)
            if why == audit2why.ALLOW or why == audit2why.DONTAUDIT:
                if why == audit2why.ALLOW:
                    reason = "allowed"
                else:
                    reason = "dontaudit'd"
                syslog.syslog(syslog.LOG_ERR, "Deleting alert %s, it is %s in current policy" % (i.local_id, reason) )
                deleted = True
                host_database.delete_signature(i.sig)
        if deleted:
            host_database.save(prune=True)
        # Attach the local database to an object which will send alerts
        # specific to this host

        if not get_config('test', 'analyze', bool):
            alert_receiver = AlertPluginReportReceiver(host_database)
        else:
            alert_receiver = TestPluginReportReceiver(host_database)

        # Create a synchronized queue for analysis requests
        import Queue
        analysis_queue = Queue.Queue(0)

        # Create a thread to peform analysis, it takes AVC objects off
        # the analysis queue and runs the plugins against the
        # AVC. Analysis requests in the queue may arrive from a
        # variety of places; from the audit system, from a log file
        # scan, etc. The disposition of the analysis (e.g. where the
        # results of the analysis are to go) are included in the queued
        # object along with the data to analyze.

        analyze_thread = AnalyzeThread(analysis_queue)
        analyze_thread.setDaemon(True)
        analyze_thread.start()
    
        # Create a thread to receive messages from the audit system.
        # This is a time sensitive operation, the primary job of this
        # thread is to receive the audit message as quickly as
        # possible and return to listening on the audit socket. When
        # it receives a complete audit event it places it in the
        # analysis queue where another thread will process it
        # independently.

#        audit_socket_thread = AuditSocketReceiverThread(analysis_queue, alert_receiver)
#        audit_socket_thread.setDaemon(True)
#        audit_socket_thread.start()

        # Initialize the email recipient list
        from setroubleshoot.signature import SEEmailRecipientSet
        email_recipients = SEEmailRecipientSet()
        assure_file_ownership_permissions(email_recipients_filepath, 0600, 'root', 'root')
        try:
            email_recipients.parse_recipient_file(email_recipients_filepath)
        except ProgramError, e:
            if e.errno == ERR_FILE_OPEN:
                syslog.syslog(syslog.LOG_DEBUG, e.strerror)
            else:
                raise e

        # Create a server to listen for alert clients and then run.
        listen_addresses = get_socket_list_from_config('listen_for_client')
        for listen_address in listen_addresses:
            listening_server = ListeningServer(listen_address, SetroubleshootdClientConnectionHandler)
            listening_server.open()

        dbus.glib.init_threads()
        setroubleshootd_dbus = SetroubleshootdDBus(analysis_queue, alert_receiver, timeout)
        main_loop = gobject.MainLoop()
        main_loop.run()
 def init_privilege(self, privilege):
     cfg_names = [name.strip() for name in \
                  get_config('access', '%s_users' % privilege).split(',')]
     return cfg_names
示例#26
0
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import gettext
from math import pi
from subprocess import *
from gettext import ngettext as P_
from setroubleshoot.config import parse_config_setting, get_config

domain = get_config("general", "i18n_text_domain")
gettext.install(domain=domain, unicode=True, localedir=get_config("general", "i18n_locale_dir"))
translation = gettext.translation(domain, fallback=True)
_ = translation.ugettext
import sys, os
from xml.dom import minidom
from xmlrpclib import ProtocolError
import gtk, glib
import gtk.glade
from setroubleshoot.errcode import *
from setroubleshoot.signature import *
from setroubleshoot.util import *
from setroubleshoot.html_util import html_to_text
import re
import dbus
import slip.dbus.service
示例#27
0
def RunFaultServer(timeout=10):
    signal.alarm(timeout)
    sigalrm_handler = signal.signal(signal.SIGALRM, polling_failed_handler)
    # polling for /sys/fs/selinux/policy file
    while True:
        try:
            audit2why.init()
            signal.alarm(0)
            break
        # retry if init() failed to open /sys/fs/selinux/policy
        except ValueError as e:
            # The value error contains the following error message,
            # followed by strerror string (which can differ with localization)
            if "unable to open /sys/fs/selinux/policy" in str(e):
                continue
            raise e
        except SystemError as e:
            # As a result of a bug in audit2why.c, SystemError is raised instead of ValueError.
            # Python reports: "SystemError occurs as a direct cause of ValueError"
            # Error message of the ValueError is stored in __context__
            # TODO: remove this except clause when the bug in audti2why is fixed
            if "unable to open /sys/fs/selinux/policy" in str(getattr(e, "__context__", "")):
                continue
            raise e

    global host_database, analysis_queue, email_recipients

    signal.signal(signal.SIGALRM, sigalrm_handler)
    signal.signal(signal.SIGHUP, sighandler)

    #interface_registry.dump_interfaces()

    try:
        # FIXME: should this be using our logging objects in log.py?
        # currently syslog is only used for putting an alert into
        # the syslog with it's id

        pkg_name = get_config('general', 'pkg_name')
        syslog.openlog(pkg_name)

        # Create an object responsible for sending notifications to clients
        client_notifier = ClientNotifier(connection_pool)

        # Create a database local to this host

        database_filename = get_config('database', 'filename')
        database_filepath = make_database_filepath(database_filename)
        assure_file_ownership_permissions(database_filepath, 0o600, 'setroubleshoot')
        host_database = SETroubleshootDatabase(database_filepath, database_filename,
                                               friendly_name=_("Audit Listener"))
        host_database.set_notify(client_notifier)

        atexit.register(goodbye, host_database)

        deleted = False
        for i in host_database.sigs.signature_list:
            why, bools = audit2why.analyze(str(i.sig.scontext), str(i.sig.tcontext), str(i.sig.tclass), i.sig.access)
            if why == audit2why.ALLOW or why == audit2why.DONTAUDIT:
                if why == audit2why.ALLOW:
                    reason = "allowed"
                else:
                    reason = "dontaudit'd"
                syslog.syslog(syslog.LOG_ERR, "Deleting alert %s, it is %s in current policy" % (i.local_id, reason))
                deleted = True
                host_database.delete_signature(i.sig)
        if deleted:
            host_database.save(prune=True)
        # Attach the local database to an object which will send alerts
        # specific to this host

        if not get_config('test', 'analyze', bool):
            alert_receiver = AlertPluginReportReceiver(host_database)
        else:
            alert_receiver = TestPluginReportReceiver(host_database)

        # Create a synchronized queue for analysis requests
        import six.moves.queue
        analysis_queue = six.moves.queue.Queue(0)

        # Create a thread to peform analysis, it takes AVC objects off
        # the analysis queue and runs the plugins against the
        # AVC. Analysis requests in the queue may arrive from a
        # variety of places; from the audit system, from a log file
        # scan, etc. The disposition of the analysis (e.g. where the
        # results of the analysis are to go) are included in the queued
        # object along with the data to analyze.

        analyze_thread = AnalyzeThread(analysis_queue)
        analyze_thread.setDaemon(True)
        analyze_thread.start()

        # Create a thread to receive messages from the audit system.
        # This is a time sensitive operation, the primary job of this
        # thread is to receive the audit message as quickly as
        # possible and return to listening on the audit socket. When
        # it receives a complete audit event it places it in the
        # analysis queue where another thread will process it
        # independently.

#        audit_socket_thread = AuditSocketReceiverThread(analysis_queue, alert_receiver)
#        audit_socket_thread.setDaemon(True)
#        audit_socket_thread.start()

        # Initialize the email recipient list
        from setroubleshoot.signature import SEEmailRecipientSet
        email_recipients = SEEmailRecipientSet()
        assure_file_ownership_permissions(email_recipients_filepath, 0o600, 'setroubleshoot')
        try:
            email_recipients.parse_recipient_file(email_recipients_filepath)
        except ProgramError as e:
            if e.errno == ERR_FILE_OPEN:
                log_debug(e.strerror)
            else:
                raise e

        # Create a server to listen for alert clients and then run.
        listen_addresses = get_socket_list_from_config('listen_for_client')
        for listen_address in listen_addresses:
            listening_server = ListeningServer(listen_address, SetroubleshootdClientConnectionHandler)
            listening_server.open()

        dbus.glib.init_threads()
        setroubleshootd_dbus = SetroubleshootdDBus(analysis_queue, alert_receiver, timeout)
        main_loop = GLib.MainLoop()
        main_loop.run()

    except KeyboardInterrupt as e:
        log_debug("KeyboardInterrupt in RunFaultServer")

    except SystemExit as e:
        log_debug("raising SystemExit in RunFaultServer")

    except Exception as e:
        import traceback
        syslog_trace(traceback.format_exc())
        syslog.syslog(syslog.LOG_ERR, "exception %s: %s" % (e.__class__.__name__, str(e)))