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