~plumgrid-team/charms/trusty/plumgrid-director/trunk

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/contrib/hardening/host/checks/suid_sgid.py

  • Committer: bbaqar at plumgrid
  • Date: 2016-04-25 09:14:38 UTC
  • mfrom: (30.1.3 plumgrid-director)
  • Revision ID: bbaqar@plumgrid.com-20160425091438-4hk5s00dydf00jem
Merge: Liberty/Mitaka support

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2016 Canonical Limited.
 
2
#
 
3
# This file is part of charm-helpers.
 
4
#
 
5
# charm-helpers is free software: you can redistribute it and/or modify
 
6
# it under the terms of the GNU Lesser General Public License version 3 as
 
7
# published by the Free Software Foundation.
 
8
#
 
9
# charm-helpers is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU Lesser General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU Lesser General Public License
 
15
# along with charm-helpers.  If not, see <http://www.gnu.org/licenses/>.
 
16
 
 
17
import subprocess
 
18
 
 
19
from charmhelpers.core.hookenv import (
 
20
    log,
 
21
    INFO,
 
22
)
 
23
from charmhelpers.contrib.hardening.audits.file import NoSUIDSGIDAudit
 
24
from charmhelpers.contrib.hardening import utils
 
25
 
 
26
 
 
27
BLACKLIST = ['/usr/bin/rcp', '/usr/bin/rlogin', '/usr/bin/rsh',
 
28
             '/usr/libexec/openssh/ssh-keysign',
 
29
             '/usr/lib/openssh/ssh-keysign',
 
30
             '/sbin/netreport',
 
31
             '/usr/sbin/usernetctl',
 
32
             '/usr/sbin/userisdnctl',
 
33
             '/usr/sbin/pppd',
 
34
             '/usr/bin/lockfile',
 
35
             '/usr/bin/mail-lock',
 
36
             '/usr/bin/mail-unlock',
 
37
             '/usr/bin/mail-touchlock',
 
38
             '/usr/bin/dotlockfile',
 
39
             '/usr/bin/arping',
 
40
             '/usr/sbin/uuidd',
 
41
             '/usr/bin/mtr',
 
42
             '/usr/lib/evolution/camel-lock-helper-1.2',
 
43
             '/usr/lib/pt_chown',
 
44
             '/usr/lib/eject/dmcrypt-get-device',
 
45
             '/usr/lib/mc/cons.saver']
 
46
 
 
47
WHITELIST = ['/bin/mount', '/bin/ping', '/bin/su', '/bin/umount',
 
48
             '/sbin/pam_timestamp_check', '/sbin/unix_chkpwd', '/usr/bin/at',
 
49
             '/usr/bin/gpasswd', '/usr/bin/locate', '/usr/bin/newgrp',
 
50
             '/usr/bin/passwd', '/usr/bin/ssh-agent',
 
51
             '/usr/libexec/utempter/utempter', '/usr/sbin/lockdev',
 
52
             '/usr/sbin/sendmail.sendmail', '/usr/bin/expiry',
 
53
             '/bin/ping6', '/usr/bin/traceroute6.iputils',
 
54
             '/sbin/mount.nfs', '/sbin/umount.nfs',
 
55
             '/sbin/mount.nfs4', '/sbin/umount.nfs4',
 
56
             '/usr/bin/crontab',
 
57
             '/usr/bin/wall', '/usr/bin/write',
 
58
             '/usr/bin/screen',
 
59
             '/usr/bin/mlocate',
 
60
             '/usr/bin/chage', '/usr/bin/chfn', '/usr/bin/chsh',
 
61
             '/bin/fusermount',
 
62
             '/usr/bin/pkexec',
 
63
             '/usr/bin/sudo', '/usr/bin/sudoedit',
 
64
             '/usr/sbin/postdrop', '/usr/sbin/postqueue',
 
65
             '/usr/sbin/suexec',
 
66
             '/usr/lib/squid/ncsa_auth', '/usr/lib/squid/pam_auth',
 
67
             '/usr/kerberos/bin/ksu',
 
68
             '/usr/sbin/ccreds_validate',
 
69
             '/usr/bin/Xorg',
 
70
             '/usr/bin/X',
 
71
             '/usr/lib/dbus-1.0/dbus-daemon-launch-helper',
 
72
             '/usr/lib/vte/gnome-pty-helper',
 
73
             '/usr/lib/libvte9/gnome-pty-helper',
 
74
             '/usr/lib/libvte-2.90-9/gnome-pty-helper']
 
75
 
 
76
 
 
77
def get_audits():
 
78
    """Get OS hardening suid/sgid audits.
 
79
 
 
80
    :returns:  dictionary of audits
 
81
    """
 
82
    checks = []
 
83
    settings = utils.get_settings('os')
 
84
    if not settings['security']['suid_sgid_enforce']:
 
85
        log("Skipping suid/sgid hardening", level=INFO)
 
86
        return checks
 
87
 
 
88
    # Build the blacklist and whitelist of files for suid/sgid checks.
 
89
    # There are a total of 4 lists:
 
90
    #   1. the system blacklist
 
91
    #   2. the system whitelist
 
92
    #   3. the user blacklist
 
93
    #   4. the user whitelist
 
94
    #
 
95
    # The blacklist is the set of paths which should NOT have the suid/sgid bit
 
96
    # set and the whitelist is the set of paths which MAY have the suid/sgid
 
97
    # bit setl. The user whitelist/blacklist effectively override the system
 
98
    # whitelist/blacklist.
 
99
    u_b = settings['security']['suid_sgid_blacklist']
 
100
    u_w = settings['security']['suid_sgid_whitelist']
 
101
 
 
102
    blacklist = set(BLACKLIST) - set(u_w + u_b)
 
103
    whitelist = set(WHITELIST) - set(u_b + u_w)
 
104
 
 
105
    checks.append(NoSUIDSGIDAudit(blacklist))
 
106
 
 
107
    dry_run = settings['security']['suid_sgid_dry_run_on_unknown']
 
108
 
 
109
    if settings['security']['suid_sgid_remove_from_unknown'] or dry_run:
 
110
        # If the policy is a dry_run (e.g. complain only) or remove unknown
 
111
        # suid/sgid bits then find all of the paths which have the suid/sgid
 
112
        # bit set and then remove the whitelisted paths.
 
113
        root_path = settings['environment']['root_path']
 
114
        unknown_paths = find_paths_with_suid_sgid(root_path) - set(whitelist)
 
115
        checks.append(NoSUIDSGIDAudit(unknown_paths, unless=dry_run))
 
116
 
 
117
    return checks
 
118
 
 
119
 
 
120
def find_paths_with_suid_sgid(root_path):
 
121
    """Finds all paths/files which have an suid/sgid bit enabled.
 
122
 
 
123
    Starting with the root_path, this will recursively find all paths which
 
124
    have an suid or sgid bit set.
 
125
    """
 
126
    cmd = ['find', root_path, '-perm', '-4000', '-o', '-perm', '-2000',
 
127
           '-type', 'f', '!', '-path', '/proc/*', '-print']
 
128
 
 
129
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
130
    out, _ = p.communicate()
 
131
    return set(out.split('\n'))