ad82f27642c50b2d62c18135304bb61088b9fba5
   1#
   2#   sudo-journald.py
   3#   
   4#   Get number of sudo sessions for each user
   5#
   6
   7import re
   8from systemd import journal
   9
  10from logparse.formatting import *
  11from logparse.util import readlog
  12from logparse.config import prefs
  13from logparse.load_parsers import Parser
  14
  15class SudoCommand():
  16
  17    def __init__(self, msg):
  18        self.init_user, self.pwd, self.su, self.command = re.search(
  19                r"\s*(?P<init_user>\w*) : TTY=.* ; PWD=(?P<pwd>\S*) ;"
  20                " USER=(?P<su>\w*) ; COMMAND=(?P<command>\S*)", msg)\
  21                        .groupdict().values()
  22
  23class Sudo(Parser):
  24
  25    def __init__(self):
  26        super().__init__()
  27        self.name = "sudo"
  28        self.info = "Get number of sudo sessions for each user"
  29
  30    def parse_log(self):
  31
  32        logger.debug("Starting sudo section")
  33        section = Section("sudo")
  34
  35        if not (config.prefs.getboolean("sudo", "summary") 
  36                or config.prefs.getboolean("sudo", "list-users")):
  37            logger.warning("Both summary and list-users configuration options "
  38                "are set to false, so no output will be generated. "
  39                "Skipping this parser.")
  40            return None
  41
  42        j = journal.Reader()
  43        j.this_machine()
  44        j.log_level(journal.LOG_INFO)
  45        j.add_match(_COMM="sudo")
  46        j.seek_realtime(section.period.startdate)
  47        j.log_level(5)
  48        
  49        logger.debug("Searching for sudo commands")
  50
  51        messages = [entry["MESSAGE"] for entry in j if "MESSAGE" in entry]
  52
  53        commands_objects = []   # list of command objects
  54        init_users = {}         # keys are users, values are lists of commands
  55
  56        logger.debug("Parsing sudo log messages")
  57
  58        for msg in messages:
  59
  60            if "COMMAND=" in msg:
  61                try:
  62                    command_obj = SudoCommand(msg)
  63                except Exception as e:
  64                    logger.warning("Malformed sudo log message: {0}. "
  65                        "Error message: {1}".format(msg, str(e)))
  66                    continue
  67                if config.prefs.getboolean("sudo", "truncate-commands"):
  68                    command_obj.command = command_obj.command.split("/")[-1]
  69                commands_objects.append(command_obj)
  70                if not command_obj.init_user in init_users:
  71                    init_users[command_obj.init_user] = []
  72                init_users[command_obj.init_user].append(
  73                        command_obj.su + ": " + command_obj.command)
  74
  75        logger.debug("Generating output")
  76
  77        if len(commands_objects) == 0:
  78            logger.warning("No sudo commands found")
  79            return
  80
  81        if config.prefs.getboolean("sudo", "summary"):
  82
  83            summary_data = Data()
  84            summary_data.subtitle = plural("sudo session", len(commands_objects))
  85
  86            if all(cmd.su == commands_objects[0].su for cmd in commands_objects):
  87                # Only one superuser
  88                if len(set(cmd.init_user for cmd in commands_objects)) > 1:
  89                    # Multiple initiating users
  90                    summary_data.subtitle += " for superuser " \
  91                            + commands_objects[0].su
  92                    summary_data.items = ["{}: {}".format(cmd.init_user, cmd.command)
  93                            for cmd in commands_objects]
  94                else:
  95                    # Only one initiating user
  96                    summary_data.subtitle += " opened by " \
  97                        + commands_objects[0].init_user + " for " \
  98                        + commands_objects[0].su
  99                    summary_data.items = [cmd.command 
 100                            for cmd in commands_objects]
 101            else:
 102                # Multiple superusers
 103                if len(set(cmd.init_user for cmd in commands_objects)) > 1:
 104                    # Multiple initiating users
 105                    summary_data.subtitle += " for " + plural("superuser",
 106                            len(set(cmd.su for cmd in commands_objects)))
 107                    summary_data.items = ["{}→{}: {}".format(
 108                        cmd.init_user, cmd.su, cmd.command)
 109                        for cmd in commands_objects]
 110                else:
 111                    # Only one initiating user
 112                    summary_data.subtitle += " by " \
 113                            + commands_objects[0].init_user \
 114                            + " for " + plural("superuser",
 115                                    len(set(cmd.su
 116                                        for cmd in commands_objects)))
 117                    summary_data.items = ["{}: {}".format(
 118                        cmd.su, cmd.command) for cmd in commands_objects]
 119            summary_data.orderbyfreq()
 120            summary_data.truncl(config.prefs.getint("logparse", "maxcmd"))
 121            section.append_data(summary_data)
 122
 123        if config.prefs.getboolean("sudo", "list-users") \
 124                and len(set(cmd.init_user for cmd in commands_objects)) > 1:
 125            for user, user_commands in init_users.items():
 126                user_data = Data()
 127                user_data.subtitle = plural("sudo session",
 128                        len(user_commands)) + " for user " + user
 129                user_data.items = user_commands
 130                user_data.orderbyfreq()
 131                user_data.truncl(config.prefs.getint("logparse", "maxcmd"))
 132                section.append_data(user_data)
 133
 134        logger.info("Finished sudo section")
 135
 136        return section