logparse / parsers / sshd.pyon commit rename parsers, better journald integration (e1f7605)
   1"""
   2Find number of ssh logins and authorised users (uses /var/log/auth.log)
   3NOTE: This file is now deprecated in favour of the newer journald mechanism
   4used in sshd-journald.py. This parser is still functional but is slower and
   5has less features. Please switch over if possible.
   6"""
   7
   8import re
   9
  10from logparse.formatting import *
  11from logparse.util import readlog, resolve
  12from logparse import config
  13from logparse.load_parsers import Parser
  14
  15class Sshd(Parser):
  16
  17    def __init__(self):
  18        super().__init__()
  19        self.name = "sshd"
  20        self.info = "Find number of ssh logins and authorised users "
  21                "(uses /var/log/auth.log)"
  22        self.deprecated = True
  23        self.successor = "sshd_journald"
  24
  25    def parse_log(self):
  26
  27        logger.warning("NOTE: This sshd parser is now deprecated. "
  28            "Please use sshd-journald if possible.")
  29        logger.debug("Starting sshd section")
  30        section = Section("ssh")
  31
  32        logger.debug("Searching for matches in {0}".format(
  33            config.prefs.get("logs", "auth")))
  34        authlog = readlog(config.prefs.get("logs", "auth"))
  35        matches = re.findall('.*sshd.*Accepted publickey for .* from .*', 
  36                authlog)    # get all logins
  37        invalid_matches = re.findall(".*sshd.*Invalid user .* from .*", authlog)
  38        root_matches = re.findall("Disconnected from authenticating user root",
  39                authlog)
  40        logger.debug("Finished searching for logins")
  41        
  42        users = []  # list of users with format [username, number of logins] 
  43                    # for each item
  44        data = []
  45        num = len(matches)     # total number of logins
  46
  47        for match in matches:
  48
  49            # [('user', 'ip')]
  50            entry = re.search('^.*publickey\sfor\s(\w*)\sfrom\s(\S*)', match)
  51
  52            user = entry.group(1)
  53            ip = entry.group(2)
  54
  55            userhost = user + '@' + resolve(ip, 
  56                    fqdn=config.prefs.get("sshd", "sshd-resolve-domains"))
  57            users.append(userhost)
  58
  59        logger.debug("Parsed list of authorised users")
  60
  61        # Format authorised users
  62        auth_data = Data(subtitle=plural('login', num) + ' from', items=users)
  63        if (len(auth_data.items) == 1):
  64            # If only one user, do not display no of logins for this user
  65            logger.debug("Found {0} logins for user {1}".format(
  66        auth_data.orderbyfreq()
  67        auth_data.truncl(config.prefs.getint("logparse", "maxlist"))
  68        logger.debug("Found {0} logins for {1} users".format(
  69            len(matches), len(users)))
  70        section.append_data(auth_data)
  71
  72        # Format invalid users
  73        invalid_users = []
  74        for match in invalid_matches:
  75            # [('user', 'ip')]
  76            entry = re.search('^.*Invalid user (\S+) from (\S+).*', match)  
  77            try:
  78                user = entry.group(1)
  79                ip = entry.group(2)
  80            except:     # blank user field
  81                continue
  82
  83            userhost = user + '@' + ip
  84            invalid_users.append(userhost)
  85
  86        logger.debug("Parsed list of invalid users")
  87
  88        invalid_data = Data(subtitle=plural("attempted login", 
  89            len(invalid_matches)) + " from " 
  90            + plural("invalid user", len(invalid_users), print_quantity=False), 
  91            items=invalid_users)
  92        if (len(invalid_data.items) == 1):
  93            # If only one user, do not display no of logins for this user
  94            logger.debug("Found {0} login attempts for user {1}"
  95                .format(len(invalid_matches), invalid_data.items[0]))
  96            invalid_data.subtitle += ' ' + invalid_data.items[0]
  97        invalid_data.orderbyfreq()
  98        invalid_data.truncl(config.prefs.get("logparse", "maxlist"))
  99        logger.debug("Found {0} login attempts for invalid users"
 100            .format(len(invalid_matches)))
 101        section.append_data(invalid_data)
 102
 103        logger.debug("Found {0} attempted logins for root".
 104            format(str(len(root_matches))))
 105
 106        section.append_data(Data(subtitle=plural("attempted login", 
 107            str(len(root_matches))) + " for root"))
 108
 109        logger.info("Finished sshd section")
 110        return section