#!/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 = 'User Sudo Report'
self.sudo_open_title = 'User Sudo Report'
self.sudo_not_allowed_title = 'Disallowed Sudo Commands'
self.report_wrap = '
'
self.subreport_wrap = '%s |
\n%s'
self.subreport_na_wrap = '%s |
\n%s'
self.line_rep = '%s | %s | %s | %s |
\n'
self.line_rep_na = '%s | %s | %s | %s | %s |
\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)