commit 2ce7241c750e85a881e3b811f8c9805709cca8a3 Author: Jeremy Kindy kindyjd@wfu.edu Date: Wed Jan 27 15:42:52 2010 +0000
adding yum, sudo, selinux modules and configuration files
etc/modules.d/selinux.conf.in | 11 +++ etc/modules.d/sudo.conf.in | 11 +++ etc/modules.d/yum.conf.in | 11 +++ modules/selinux_mod.py | 114 ++++++++++++++++++++++++ modules/sudo_mod.py | 190 +++++++++++++++++++++++++++++++++++++++++ modules/yum_mod.py | 170 ++++++++++++++++++++++++++++++++++++ 6 files changed, 507 insertions(+), 0 deletions(-) --- diff --git a/etc/modules.d/selinux.conf.in b/etc/modules.d/selinux.conf.in new file mode 100644 index 0000000..9659438 --- /dev/null +++ b/etc/modules.d/selinux.conf.in @@ -0,0 +1,11 @@ +[module] +desc = SELinux Report +exec = %%MODULES_DIR%%/selinux_mod.py +files = /var/log/messages[.#] +enabled = yes +internal = yes +outhtml = yes +priority = 5 + +[conf] +enable_selinux = 1 diff --git a/etc/modules.d/sudo.conf.in b/etc/modules.d/sudo.conf.in new file mode 100644 index 0000000..4f01be1 --- /dev/null +++ b/etc/modules.d/sudo.conf.in @@ -0,0 +1,11 @@ +[module] +desc = Sudo Report +exec = %%MODULES_DIR%%/sudo_mod.py +files = /var/log/secure[.#] +enabled = yes +internal = yes +outhtml = yes +priority = 5 + +[conf] +enable_sudo = 1 diff --git a/etc/modules.d/yum.conf.in b/etc/modules.d/yum.conf.in new file mode 100644 index 0000000..13eeedb --- /dev/null +++ b/etc/modules.d/yum.conf.in @@ -0,0 +1,11 @@ +[module] +desc = Yum Report +exec = %%MODULES_DIR%%/yum_mod.py +files = /var/log/messages[.#] +enabled = yes +internal = yes +outhtml = yes +priority = 5 + +[conf] +enable_yum = 1 diff --git a/modules/selinux_mod.py b/modules/selinux_mod.py new file mode 100644 index 0000000..d603877 --- /dev/null +++ b/modules/selinux_mod.py @@ -0,0 +1,114 @@ +#!/usr/bin/python -tt +""" +Reports on selinux messages + +Jeremy Kindy (kindyjd at wfu.edu), Wake Forest University +""" + +import sys +import re + +## +# This is for testing purposes, so you can invoke this from the +# modules directory. See also the testing notes at the end of the +# file. +# +sys.path.insert(0, '../py/') +from epylog import Result, InternalModule + +class selinux_mod(InternalModule): + def __init__(self, opts, logger): + InternalModule.__init__(self) + self.logger = logger + self.logger.put(3, 'initializing selinux') + rc = re.compile + + self.ignore = 0 + self.preventing = 1 + + selinux_map = { + rc('.*setroubleshoot: SELinux is preventing'): self.selinux + } + + do_selinux = int(opts.get('enable_selinux', '1')) + + self.regex_map = {} + if do_selinux: self.regex_map.update(selinux_map) + + self.selinux_message_re = rc('setroubleshoot: (.*). For complete SELinux') + + self.selinux_title = '<font color="blue">SELinux Report</font>' + self.selinux_preventing_title = '<font color="blue">SELinux Prevention Report</font>' + + self.report_wrap = '<table border="0" width="100%%" rules="cols" cellpadding="2">%s</table>' + self.subreport_wrap = '<tr><th colspan="2" align="left"><h3>%s</h3></th></tr>\n%s' + + self.line_rep = '<tr%s><td valign="top" width="25%%">%s</td><td valign="top" width="75%%">%s</td></tr>\n' + + self.flip = ' bgcolor="#dddddd"' + + + ## + # Line-matching routines + # + def selinux(self, linemap): + action = self.preventing + self.logger.put(3, 'selinux invoked') + sys, msg, mult = self.get_smm(linemap) + + self.logger.put(3, 'test selinux %d' % mult) + message = self._get_selinux_message(msg) + self.logger.put(3, 'selinux message: %s' % message) + + restuple = self._mk_restuple(sys, action, message) + self.logger.put(3, 'selinux finished') + return {restuple: mult} + + ## + # Helpers + # + def _mk_restuple(self, sys, action, message): + return (action, message, sys) + + def _get_selinux_message(self, str): + message = 'unknown' + mo = self.selinux_message_re.search(str) + if mo: message = mo.group(1) + return message + + #### + # Finalize the report + def finalize(self, rs): + logger = self.logger + ## + # Prepare report + # + report = '' + rep = {} + + # (action, message) + for action in [self.preventing]: + rep[action] = '' + flipper = '' + for message in rs.get_distinct((action,)): + if flipper: flipper = '' + else: flipper = self.flip + service_rep = [] + + for system in rs.get_distinct((action, message,)): + service_rep.append(system) + + system_list = ', '.join(service_rep) + rep[action] += self.line_rep % (flipper, message, system_list) + + if rep[self.preventing]: + report += self.subreport_wrap % (self.selinux_preventing_title, rep[self.preventing]) + logger.put(3, 'selinux report: self.preventing added') + + report = self.report_wrap % report + return report + + +if __name__ == '__main__': + from epylog.helpers import ModuleTest + ModuleTest(selinux_mod, sys.argv) diff --git a/modules/sudo_mod.py b/modules/sudo_mod.py new file mode 100644 index 0000000..786e3bf --- /dev/null +++ b/modules/sudo_mod.py @@ -0,0 +1,190 @@ +#!/usr/bin/python -tt +""" +Reports on sudo usage by users. + +Jeremy Kindy (kindyjd at wfu.edu), Wake Forest University +""" + +import sys +import re + +## +# This is for testing purposes, so you can invoke this from the +# modules directory. See also the testing notes at the end of the +# file. +# +sys.path.insert(0, '../py/') +from epylog import Result, InternalModule + +class sudo_mod(InternalModule): + def __init__(self, opts, logger): + InternalModule.__init__(self) + self.logger = logger + self.logger.put(2, 'initializing sudo') + rc = re.compile + + self.ignore = 0 + self.open = 1 + self.not_allowed = 2 + + sudo_map = { + rc('.*sudo:\s+\S+\s:\sTTY'): self.sudo, + rc('.*sudo:'): self.sudo_na + } + + do_sudo = int(opts.get('enable_sudo', '1')) + + self.regex_map = {} + if do_sudo: self.regex_map.update(sudo_map) + + self.sudo_user_name_re = rc('sudo:\s*(\S*)') + self.sudo_as_user_re = rc('.*USER=(\S*)\s;\sCOMMAND') + self.sudo_command_name_re = rc('.*COMMAND=(.*)') + self.sudo_error_message_re = rc('sudo:\s*\S*\s+:\s+(.*)\s+;\s+TTY') + + + self.sudo_title = '<font color="blue">User Sudo Report</font>' + self.sudo_open_title = '<font color="blue">User Sudo Report</font>' + self.sudo_not_allowed_title = '<font color="red">Disallowed Sudo Commands</font>' + + self.report_wrap = '<table border="0" width="100%%" rules="cols" cellpadding="2">%s</table>' + self.subreport_wrap = '<tr><th colspan="5" align="left"><h3>%s</h3></th></tr>\n%s' + self.subreport_na_wrap = '<tr><th colspan="5" align="left"><h3>%s</h3></th></tr>\n%s' + + self.line_rep = '<tr%s><td valign="top" width="15%%">%s</td><td valign="top" width="45%%" colspan="2">%s</td><td width="25%%">%s</td><td width="15%%">%s</td></tr>\n' + self.line_rep_na = '<tr%s><td valign="top" width="15%%">%s</td><td valign="top" width="30%%">%s</td><td valign="top" width="15%%">%s</td><td width="25%%">%s</td><td width="15%%">%s</td></tr>\n' + + self.flip = ' bgcolor="#dddddd"' + + + ## + # Line-matching routines + # + def sudo(self, linemap): + action = self.open + self.logger.put(2, 'sudo invoked') + sys, msg, mult = self.get_smm(linemap) + + self.logger.put(3, 'test sudo %d' % mult) + user = self._get_sudo_user(msg) + self.logger.put(3, 'sudo user: %s' % user) + asuser = self._get_sudo_as_user(msg) + self.logger.put(3, 'sudo asuser: %s' % asuser) + command_name = self._get_sudo_command_name(msg) + self.logger.put(3, 'sudo command: %s' % command_name) + + restuple = self._mk_restuple(sys, action, user, asuser, command_name, None) + self.logger.put(2, 'sudo finished') + return {restuple: mult} + + def sudo_na(self, linemap): + action = self.not_allowed + self.logger.put(2, 'sudo_na invoked') + sys, msg, mult = self.get_smm(linemap) + + self.logger.put(3, 'test sudo %d' % mult) + user = self._get_sudo_user(msg) + self.logger.put(3, 'sudo user: %s' % user) + asuser = self._get_sudo_as_user(msg) + self.logger.put(3, 'sudo asuser: %s' % asuser) + command_name = self._get_sudo_command_name(msg) + self.logger.put(3, 'sudo command: %s' % command_name) + error_message = self._get_sudo_error_message(msg) + self.logger.put(3, 'sudo error_message: %s' % error_message) + + restuple = self._mk_restuple(sys, action, user, asuser, command_name, error_message) + self.logger.put(2, 'sudo finished') + return {restuple: mult} + + def sudo_ignore(self, linemap): + restuple = self._mk_restuple(None, self.ignore, None, None, None, None) + return {restuple: 1} + + ## + # HElpers + # + def _mk_restuple(self, sys, action, user=None, asuser=None, command_name=None, error_message=None): + return (action, user, command_name, asuser, error_message, sys) + #return (sys, action, user, asuser, command_name) + + def _get_sudo_user(self, str): + user = 'unknown' + mo = self.sudo_user_name_re.search(str) + if mo: user = mo.group(1) + return user + + def _get_sudo_as_user(self, str): + asuser = 'unknown' + mo = self.sudo_as_user_re.search(str) + if mo: asuser = mo.group(1) + return asuser + + def _get_sudo_error_message(self, str): + pass_attempts = 0 + mo = self.sudo_error_message_re.search(str) + if mo: pass_attempts = mo.group(1) + return pass_attempts + + def _get_sudo_command_name(self, str): + command_name = 'unknown' + mo = self.sudo_command_name_re.search(str) + if mo: command_name = mo.group(1) + return command_name + + #### + # Finalize the report + def finalize(self, rs): + logger = self.logger + ## + # Prepare report + # + report = '' + rep = {} + + # (action, user, command_name, system, error_message) + for action in [self.open, self.not_allowed]: + rep[action] = '' + flipper = '' + for user in rs.get_distinct((action,)): + #logger.put(2, 'sudo user: %s' % user) + if flipper: flipper = '' + else: flipper = self.flip + service_rep = [] + blank = 0 + for command_name in rs.get_distinct((action, user)): + for asuser in rs.get_distinct((action, user, command_name)): + for error_message in rs.get_distinct((action, user, command_name, asuser)): + mymap = rs.get_submap((action, user, command_name, asuser, error_message)) + #logger.put(2, 'sudo command_name: %s' % command_name) + key2s = [] + for key2 in mymap.keys(): + hostname = key2[0] + key2s.append('%s(%d)' % (hostname, mymap[key2])) + hostnames = ', '.join(key2s) + #logger.put(2, 'sudo hostnames: %s' % hostnames) + service_rep.append([command_name, hostnames, asuser, error_message]) + for svcrep in service_rep: + #logger.put(2, 'sudo svcrep: %s' % svcrep) + if blank: user = ' ' + else: blank = 1 + if (action == self.open): + rep[action] += self.line_rep % (flipper, user, svcrep[0], svcrep[1], svcrep[2]) + else: + rep[action] += self.line_rep_na % (flipper, user, svcrep[0], svcrep[3], svcrep[1], svcrep[2]) + + + if rep[self.open]: + report += self.subreport_wrap % (self.sudo_open_title, rep[self.open]) + logger.put(2, 'sudo report: self.open added') + + if rep[self.not_allowed]: + report += self.subreport_na_wrap % (self.sudo_not_allowed_title, rep[self.not_allowed]) + logger.put(2, 'sudo report: self.not_allowed added') + + report = self.report_wrap % report + return report + + +if __name__ == '__main__': + from epylog.helpers import ModuleTest + ModuleTest(sudo_mod, sys.argv) diff --git a/modules/yum_mod.py b/modules/yum_mod.py new file mode 100644 index 0000000..0ab5e9d --- /dev/null +++ b/modules/yum_mod.py @@ -0,0 +1,170 @@ +#!/usr/bin/python -tt +""" +Creates report of packages added via the RedHat yum command. + +Will not catch creations or deletions resulting from direct use of +the rpm command. + +Jeremy Kindy (kindyjd at wfu.edu), Wake Forest University +""" + +import sys +import re + +## +# This is for testing purposes, so you can invoke this from the +# modules directory. See also the testing notes at the end of the +# file. +# +sys.path.insert(0, '../py/') +from epylog import Result, InternalModule + +class yum_mod(InternalModule): + def __init__(self, opts, logger): + InternalModule.__init__(self) + self.logger = logger + rc = re.compile + + self.ignore = 0 + self.installed = 1 + self.updated = 2 + self.erased = 3 + + yum_map = { + rc('yum: Installed:'): self.pkg_installed, + rc('yum: Updated:'): self.pkg_updated, + rc('yum: Erased:'): self.pkg_erased + } + + do_yum = int(opts.get('enable_yum', '1')) + + self.regex_map = {} + if do_yum: self.regex_map.update(yum_map) + + self.name_re = rc('profile: [(.*)]') + self.installed_name_re = rc('Installed: (.*)') + self.updated_name_re = rc('Updated: (.*)') + self.erased_name_re = rc('Erased: (.*)') + + self.yum_title = '<font color="blue">Yum Changes Report</font>' + self.yum_installed_title = '<font color="blue">Packages Installed</font>' + self.yum_updated_title = '<font color="blue">Packages Updated</font>' + self.yum_erased_title = '<font color="blue">Packages Erased</font>' + + self.report_wrap = '<table border="0" width="100%%" rules="cols" cellpadding="2">%s</table>' + self.subreport_wrap = '<tr><th colspan="2" align="left"><h3>%s</h3></th></tr>\n%s' + + self.line_rep = '<tr%s><td valign="top" width="25%%">%s</td><td valign="top" width="75%%">%s</td></tr>\n' + + self.flip = ' bgcolor="#dddddd"' + + + ## + # Line-matching routines + # + def pkg_updated(self, linemap): + self.logger.put(3, 'entered pkg_updated...') + action = self.updated + sys, msg, mult = self.get_smm(linemap) + + self.logger.put(3, 'test yum %d' % mult) + name = self._get_updated_name(msg) + self.logger.put(3, 'name: %s' % name) + + restuple = self._mk_restuple(action, sys, name) + return {restuple: mult} + + def pkg_installed(self, linemap): + self.logger.put(3, 'entered pkg_installed...') + action = self.installed + sys, msg, mult = self.get_smm(linemap) + + self.logger.put(3, 'test yum %d' % mult) + name = self._get_installed_name(msg) + self.logger.put(3, 'name: %s' % name) + + restuple = self._mk_restuple(action, sys, name) + return {restuple: mult} + + def pkg_erased(self, linemap): + self.logger.put(3, 'entered pkg_erased...') + action = self.erased + sys, msg, mult = self.get_smm(linemap) + + self.logger.put(3, 'test yum %d' % mult) + name = self._get_erased_name(msg) + self.logger.put(3, 'name: %s' % name) + + restuple = self._mk_restuple(action, sys, name) + return {restuple: mult} + + + ## + # Helpers + # + def _mk_restuple(self, action, sys, name=None): + return (action, sys, name) + + def _get_name(self, str): + name = 'unknown' + mo = self.name_re.search(str) + if mo: name = mo.group(1) + return name + + def _get_installed_name(self, str): + name = 'unknown' + mo = self.installed_name_re.search(str) + if mo: name = mo.group(1) + return name + + def _get_updated_name(self, str): + name = 'unknown' + mo = self.updated_name_re.search(str) + if mo: name = mo.group(1) + return name + + def _get_erased_name(self, str): + name = 'unknown' + mo = self.erased_name_re.search(str) + if mo: name = mo.group(1) + return name + + def finalize(self, rs): + logger = self.logger + ## + # Prepare report + # + report = '' + rep = {} + # (action, sys, name) + for action in [self.updated, self.installed, self.erased]: + rep[action] = '' + flipper = '' + for system in rs.get_distinct((action,)): + self.logger.put(3, 'system: %s' % system) + if flipper: flipper = '' + else: flipper = self.flip + service_rep = [] + + for name in rs.get_distinct((action, system,)): + service_rep.append(name) + + user_list = ', '.join(service_rep) + rep[action] += self.line_rep % (flipper, system, user_list) + + if rep[self.installed]: + report += self.subreport_wrap % (self.yum_installed_title, rep[self.installed]) + + if rep[self.updated]: + report += self.subreport_wrap % (self.yum_updated_title, rep[self.updated]) + + if rep[self.erased]: + report += self.subreport_wrap % (self.yum_erased_title, rep[self.erased]) + + report = self.report_wrap % report + return report + + +if __name__ == '__main__': + from epylog.helpers import ModuleTest + ModuleTest(users_mod, sys.argv)