aboutsummaryrefslogtreecommitdiffstats
path: root/src/msec/plugins/network.py
blob: e33a51bea1807e0e9c98e40883b2800c1b9409e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/python3
"""Msec plugin for enforcing network security settings"""

# main plugin class name
PLUGIN = "network"

# configuration

import os
import re
import string
import stat
import sys

import config

import gettext
# localization
try:
    gettext.install('msec')
except IOError:
    _ = str

# list of config files

ATALLOW = '/etc/at.allow'
AUTOLOGIN = '/etc/sysconfig/autologin'
BASTILLENOLOGIN = '/etc/bastille-no-login'
CRON = '/etc/cron.d/msec'
CRONALLOW = '/etc/cron.allow'
FSTAB = '/etc/fstab'
GDM = '/etc/pam.d/gdm'
GDMCONF = '/etc/X11/gdm/custom.conf'
HALT = '/usr/bin/halt'
HOSTCONF = '/etc/host.conf'
HOSTSDENY = '/etc/hosts.deny'
INITTAB = '/etc/inittab'
ISSUE = '/etc/issue'
ISSUENET = '/etc/issue.net'
KDE = '/etc/pam.d/kde'
LILOCONF = '/etc/lilo.conf'
LOGINDEFS = '/etc/login.defs'
MENULST = '/boot/grub/menu.lst'
SHELLCONF = '/etc/security/shell'
MSECBIN = '/usr/sbin/msec'
MSECCRON = '/etc/cron.hourly/msec'
MSEC_XINIT = '/etc/X11/xinit.d/msec'
OPASSWD = '/etc/security/opasswd'
PASSWD = '/etc/pam.d/passwd'
POWEROFF = '/usr/bin/poweroff'
REBOOT = '/usr/bin/reboot'
SECURITYSH = '/usr/share/msec/security.sh'
SERVER = '/etc/security/msec/server'
SHADOW = '/etc/shadow'
SHUTDOWN = '/usr/bin/shutdown'
SHUTDOWNALLOW = '/etc/shutdown.allow'
SSHDCONFIG = '/etc/ssh/sshd_config'
STARTX = '/usr/bin/startx'
SYSCTLCONF = '/etc/sysctl.conf'
SYSLOGCONF = '/etc/syslog.conf'
XDM = '/etc/pam.d/xdm'
XSERVERS = '/etc/X11/xdm/Xservers'
EXPORT = '/root/.xauth/export'

# regexps
# X server
SECURETTY = '/etc/securetty'
STARTX_REGEXP = '(\s*serverargs=".*) -nolisten tcp(.*")'
XSERVERS_REGEXP = '(\s*[^#]+/usr/bin/X .*) -nolisten tcp(.*)'
GDMCONF_REGEXP = '(\s*command=.*/X.*?) -nolisten tcp(.*)$'
# ctrl-alt-del
CTRALTDEL_REGEXP = '^ca::ctrlaltdel:/sbin/shutdown.*'
# consolehelper
CONSOLE_HELPER = 'consolehelper'
# ssh PermitRootLogin
PERMIT_ROOT_LOGIN_REGEXP = '^\s*PermitRootLogin\s+(no|yes|without-password|forced-commands-only)'
# tcp_wrappers
ALL_REGEXP = '^ALL:ALL:DENY'
ALL_LOCAL_REGEXP = '^ALL:ALL EXCEPT 127\.0\.0\.1:DENY'
# sulogin
SULOGIN_REGEXP = '~~:S:wait:/sbin/sulogin'

def invert(param):
    """Returns inverse value for param. E.g., yes becomes no, and no becomes yes."""
    if param == "yes":
        return "no"
    else:
        return "yes"
class network:
    def __init__(self, log=None, configfiles=None, root=None):
        """This plugin is responsible for enforcing network security settings on the machine."""
        self.log = log
        self.configfiles = configfiles
        self.root = root

        # associate helper commands with files
        self.configfiles.add_config_assoc(INITTAB, '/sbin/telinit q')
        self.configfiles.add_config_assoc('/etc(?:/rc.d)?/init.d/(.+)', '[ -f /var/lock/subsys/@1 ] && @0 reload')
        self.configfiles.add_config_assoc(SYSCTLCONF, '/sbin/sysctl -e -p /etc/sysctl.conf')
        self.configfiles.add_config_assoc(SSHDCONFIG, '[ -f /var/lock/subsys/sshd ] && /etc/rc.d/init.d/sshd restart')
        self.configfiles.add_config_assoc(LILOCONF, '[ `/usr/sbin/detectloader` = LILO ] && /sbin/lilo')
        self.configfiles.add_config_assoc(SYSLOGCONF, '[ -f /var/lock/subsys/syslog ] && service syslog reload')
        self.configfiles.add_config_assoc('^/etc/issue$', '/usr/bin/killall mingetty')

        # security options
        config.SETTINGS['ACCEPT_BOGUS_ERROR_RESPONSES'] = ("network.accept_bogus_error_responses", ['yes', 'no'])
        config.SETTINGS['ACCEPT_BROADCASTED_ICMP_ECHO'] = ("network.accept_broadcasted_icmp_echo", ['yes', 'no'])
        config.SETTINGS['ACCEPT_ICMP_ECHO'] = ("network.accept_icmp_echo", ['yes', 'no'])
        config.SETTINGS['ALLOW_REMOTE_ROOT_LOGIN'] = ("network.allow_remote_root_login", ['yes', 'no', 'without-password'])
        config.SETTINGS['ENABLE_IP_SPOOFING_PROTECTION'] = ("network.enable_ip_spoofing_protection", ['yes', 'no'])
        config.SETTINGS['ENABLE_LOG_STRANGE_PACKETS'] = ("network.enable_log_strange_packets", ['yes', 'no'])

        # network settings
        for check in ["ACCEPT_BOGUS_ERROR_RESPONSES", "ACCEPT_BROADCASTED_ICMP_ECHO", "ACCEPT_ICMP_ECHO",
                    "ALLOW_REMOTE_ROOT_LOGIN", "ALLOW_X_CONNECTIONS", "ALLOW_XSERVER_TO_LISTEN",
                    "AUTHORIZE_SERVICES", "ENABLE_IP_SPOOFING_PROTECTION",
                    "ENABLE_LOG_STRANGE_PACKETS"]:
            config.SETTINGS_NETWORK.append(check)

    def allow_remote_root_login(self, arg):
        '''  Allow remote root login via sshd. If yes, login is allowed. If without-password, only public-key authentication logins are allowed. See sshd_config(5) man page for more information.'''
        sshd_config = self.configfiles.get_config_file(SSHDCONFIG)

        if not sshd_config.exists():
            return

        val = sshd_config.get_match(PERMIT_ROOT_LOGIN_REGEXP, '@1')

        if val != arg:
            if arg == "yes":
                self.log.info(_('Allowing remote root login'))
                sshd_config.exists() and sshd_config.replace_line_matching(PERMIT_ROOT_LOGIN_REGEXP,
                                                                           'PermitRootLogin yes', 1)
            elif arg == "no":
                self.log.info(_('Forbidding remote root login'))
                sshd_config.exists() and sshd_config.replace_line_matching(PERMIT_ROOT_LOGIN_REGEXP,
                                                                           'PermitRootLogin no', 1)
            elif arg == "without-password":
                self.log.info(_('Allowing remote root login only by passphrase'))
                sshd_config.exists() and sshd_config.replace_line_matching(PERMIT_ROOT_LOGIN_REGEXP,
                                                                           'PermitRootLogin without-password', 1)

    def set_zero_one_variable(self, file, variable, value, one_msg, zero_msg):
        ''' Helper function for enable_ip_spoofing_protection, accept_icmp_echo, accept_broadcasted_icmp_echo,
        # accept_bogus_error_responses and enable_log_strange_packets.'''
        f = self.configfiles.get_config_file(file)
        curvalue = f.get_shell_variable(variable)
        if value == "yes":
            value = "1"
        else:
            value = "0"
        if value != curvalue:
            if value == "1":
                self.log.info(one_msg)
                f.set_shell_variable(variable, 1)
            else:
                self.log.info(zero_msg)
                f.set_shell_variable(variable, 0)

    def enable_ip_spoofing_protection(self, arg, alert=1):
        '''  Enable IP spoofing protection.'''
        self.set_zero_one_variable(SYSCTLCONF, 'net.ipv4.conf.all.rp_filter', arg, 'Enabling ip spoofing protection', 'Disabling ip spoofing protection')

    def accept_icmp_echo(self, arg):
        ''' Accept ICMP echo.'''
        self.set_zero_one_variable(SYSCTLCONF, 'net.ipv4.icmp_echo_ignore_all', invert(arg), 'Ignoring icmp echo', 'Accepting icmp echo')

    def accept_broadcasted_icmp_echo(self, arg):
        ''' Accept broadcasted ICMP echo.'''
        self.set_zero_one_variable(SYSCTLCONF, 'net.ipv4.icmp_echo_ignore_broadcasts', invert(arg), 'Ignoring broadcasted icmp echo', 'Accepting broadcasted icmp echo')

    def accept_bogus_error_responses(self, arg):
        '''  Accept bogus IPv4 error messages.'''
        self.set_zero_one_variable(SYSCTLCONF, 'net.ipv4.icmp_ignore_bogus_error_responses', invert(arg), 'Ignoring bogus icmp error responses', 'Accepting bogus icmp error responses')

    def enable_log_strange_packets(self, arg):
        '''  Enable logging of strange network packets.'''
        self.set_zero_one_variable(SYSCTLCONF, 'net.ipv4.conf.all.log_martians', arg, 'Enabling logging of strange packets', 'Disabling logging of strange packets')