sympl-filesystem-security 6.32 KB
Newer Older
Paul Cammish's avatar
Paul Cammish committed
1
2
3
4
#!/bin/bash
# Fairly simple bash script to enforce filesystem permissions for sensitive
# directories used by Sympl.
#
5
# Copyright 2019-2020, Paul Cammish <sympl@kelduum.net>
Paul Cammish's avatar
Paul Cammish committed
6
# Licensed under GPL3+
Paul Cammish's avatar
Paul Cammish committed
7
8
9
10


set -e

11
if [ -f /etc/sympl/do-not-secure ] || [ -f /etc/sympl/disable-filesystem-security ] ; then exit 0; fi
Paul Cammish's avatar
Paul Cammish committed
12

13
14
15
16
17
18
if [ "x$1" == "x--verbose" ]; then
  VERBOSE='-ls'
else
  VERBOSE=''
fi

Paul Cammish's avatar
Paul Cammish committed
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
function secure_domain_dir()
{

  domain="$1"

  if [ ! -d "${domain}" ]; then

    echo "E: ${domain} doesnt exist"
    exit 1

  fi

  if [ -d ${domain}/public ]; then

    # Determine uid for public from config/public-user or default to 33 (www-data)

    if [ -f "${domain}/config/public-user" ]; then
      public_uid="$( cat "${domain}/config/public-user" | sed 's|#.*||' | head -n 1 | grep . )"
      if id -u $uid > /dev/null 2&>1 ; then
        public_uid="$( id -u $public_uid )"
      else
        public_uid=33
      fi
    else
      public_uid=33
    fi

    # Determine gid for public from config/public-group or default to 33 (www-data)

    if [ -f "${domain}/config/public-group" ]; then
      public_gid="$( cat "${domain}/config/public-group" | sed 's|#.*||' | head -n 1 | grep . )"
Paul Cammish's avatar
Paul Cammish committed
50
51
      if getent group $public_gid > /dev/null 2>&1 ; then
        public_gid="$( getent group $public_gid | cut -d ':' -f 3 )"
Paul Cammish's avatar
Paul Cammish committed
52
53
54
55
56
57
58
59
      else
        public_gid=33
      fi
    else
      public_gid=33
    fi


Paul Cammish's avatar
Paul Cammish committed
60
    # Add sympl to the public group if it's >= 1000 and not already in it
Paul Cammish's avatar
Paul Cammish committed
61

Paul Cammish's avatar
Paul Cammish committed
62
    if [ "$public_gid" -ge "1000" ] && [ "$(id -Gn sympl | tr ' ' '\n' | grep -c "^$( getent group $public_gid | cut -d ':' -f 1 )$" )" == "0" ]; then
Paul Cammish's avatar
Paul Cammish committed
63
64
65
66
67
      # sympl is not in the $public_gid group, adding
      usermod -a -G $public_gid sympl
    fi


Paul Cammish's avatar
Paul Cammish committed
68
    # Enforce permissions for /srv/example.org/public, /php_sessions, /php_tmp
Paul Cammish's avatar
Paul Cammish committed
69
    #   but exclude changing any permissions inside public/cgi-bin
Paul Cammish's avatar
Paul Cammish committed
70

Paul Cammish's avatar
Paul Cammish committed
71
72
    find "${domain}/public" ! -path "${domain}/public/cgi-bin/*" \( -type f -o -type d \) \( ! -uid ${public_uid} -o ! -gid ${public_gid} \) $VERBOSE -exec chown ${public_uid}:${public_gid} {} \;
    find "${domain}/public" ! -path "${domain}/public/cgi-bin/*" \( -type f ! -perm 664 $VERBOSE -exec chmod 664 {} \; -o -type d ! -perm 2775 $VERBOSE -exec chmod 2775 {} \; \)
Paul Cammish's avatar
Paul Cammish committed
73
74
75

    if [ -d "${domain}/php_sessions" ]; then

76
77
      find "${domain}/php_sessions" \( -type f -o -type d \) \( ! -uid ${public_uid} -o ! -gid ${public_gid} \) $VERBOSE -exec chown ${public_uid}:${public_gid} {} \;
      find "${domain}/php_sessions" \( -type f ! -perm 664 $VERBOSE -exec chmod 664 {} \; -o -type d ! -perm 2775 $VERBOSE -exec chmod 2775 {} \; \)
Paul Cammish's avatar
Paul Cammish committed
78
79
80
81
82

    fi

    if [ -d "${domain}/php_tmp" ]; then

83
84
      find "${domain}/php_tmp" \( -type f -o -type d \) \( ! -uid ${public_uid} -o ! -gid ${public_gid} \) $VERBOSE -exec chown ${public_uid}:${public_gid} {} \;
      find "${domain}/php_tmp" \( -type f ! -perm 664 $VERBOSE -exec chmod 664 {} \; -o -type d ! -perm 2775 $VERBOSE -exec chmod 2775 {} \; \)
Paul Cammish's avatar
Paul Cammish committed
85
86

    fi
Paul Cammish's avatar
Paul Cammish committed
87
88


Paul Cammish's avatar
Paul Cammish committed
89
    # Lock down the public/htdocs/stats directory, if it exists and contains webalizer html
Paul Cammish's avatar
Paul Cammish committed
90
91
    # By default this is left unprotected, and includes IP addresses which are classified
    #   under GDPR as personally identifiable
92

Paul Cammish's avatar
Paul Cammish committed
93
94
    if [ ! -f "${domain}/public/htdocs/stats/.htaccess" ] && [ -f "${domain}/public/htdocs/stats/index.html" ]; then
      if [ $( grep -c 'webalizer' "${domain}/public/htdocs/stats/index.html" ) != 0 ]; then
Paul Cammish's avatar
Paul Cammish committed
95
96
97
98
        echo "# Prevent unauthorized access to stats and enforce HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
99
100
101
102
AuthType Basic
AuthName \"Access Restricted\"
AuthUserFile ${domain}/config/stats-htaccess
Require valid-user" > "${domain}/public/htdocs/stats/.htaccess"
Paul Cammish's avatar
Paul Cammish committed
103
      fi
Paul Cammish's avatar
Paul Cammish committed
104
    fi
105

Paul Cammish's avatar
Paul Cammish committed
106
  fi
107

Paul Cammish's avatar
Paul Cammish committed
108
  # Enforce permissions for /srv/example.com/config - exim requires directory traversal (+x) as steps through to the target.
Paul Cammish's avatar
Paul Cammish committed
109
110
111

  if [ -d ${domain}/config ]; then

112
    find "${domain}/config" ! -name 'stats-htaccess' \( -type f -o -type d \) \( ! -user sympl -o ! -group sympl \) ! -path '*ssl/sets*' $VERBOSE -exec chown sympl:sympl {} \;
Paul Cammish's avatar
Paul Cammish committed
113

114
    if [ -d "${domain}/config/ssl/sets" ]; then
115
      find "${domain}/config/ssl/sets" \( ! -user sympl -o ! -group ssl-cert \) $VERBOSE -exec chown sympl:ssl-cert {} \;
116
    fi
Paul Cammish's avatar
Paul Cammish committed
117

118
119
120
121
    find "${domain}/config" \( -type f ! -perm 660 $VERBOSE -exec chmod 660 {} \; \) -o \( -type d ! -perm 2771 $VERBOSE -exec chmod 2771 {} \; \)

    if [ -f "${domain}/config/stats-htaccess" ]; then
      find "${domain}/config/stats-htaccess" \( ! -user sympl -o ! -group www-data \) $VERBOSE -exec chown sympl:www-data {} \;
Paul Cammish's avatar
Paul Cammish committed
122
      find "${domain}/config/stats-htaccess" ! -perm 660 $VERBOSE -exec chmod 660 {} \;
123
    fi
Paul Cammish's avatar
Paul Cammish committed
124
125
126
127
128
129
130
131
132

  fi

}

# Enforce permissions on /var/backups

if [ -d /var/backups ]; then

133
  find "/var/backups" ! -type l \( ! -user sympl -o ! -group sympl \) $VERBOSE -exec chown sympl:sympl {} \;
Paul Cammish's avatar
Paul Cammish committed
134

135
  find "/var/backups" ! -type l \( -type f ! -perm 660 $VERBOSE -exec chmod 660 {} \; -o -type d ! -perm 770 $VERBOSE -exec chmod 770 {} \; \)
Paul Cammish's avatar
Paul Cammish committed
136
137
138
139
140
141
142

fi

# Enforce permisions on /etc/sympl

if [ -d /etc/sympl ]; then

Paul Cammish's avatar
Paul Cammish committed
143
144
145
146
147
  # Make (almost) everything owned by sympl:sympl
  find "/etc/sympl" ! -type l \
    ! -path '*/test.d/*' \
    ! -path '*/firewall/local.d/*' \
    \( ! -user sympl -o ! -group sympl \) \
Paul Cammish's avatar
Paul Cammish committed
148
    $VERBOSE -exec chown sympl:sympl {} \;
Paul Cammish's avatar
Paul Cammish committed
149
150
151
152
153
154
155
156
157
158

  # Make (almost) everything read-only for others
  find "/etc/sympl" ! -type l \
    ! -path '*/test.d/*' \
    ! -path '*/firewall/local.d/*' \
    ! -path '*/backup.d/post-backup.d/*' \
    ! -path '*/backup.d/pre-backup.d/*' \
    \( -type f ! -perm 664 $VERBOSE -exec chmod 664 {} \; \
    -o -type d ! -perm 775 $VERBOSE -exec chmod 775 {} \; \)

159
160
161
162
163
164
  if [ -d /etc/sympl/backup.d/post-backup.d ] || [ -d /etc/sympl/backup.d/pre-backup.d ]; then
    # Make sure theres at least something executable in the backup pre/post scripts
    if [ $(find "/etc/sympl/backup.d/" -type f \( -path '*/backup.d/post-backup.d/*' -o -path '*/backup.d/pre-backup.d/*' \) -name '*-*' -executable | wc -l) == 0 ]; then
      chmod +x /etc/sympl/backup.d/post-backup.d/* 2&> /dev/null || true
      chmod +x /etc/sympl/backup.d/pre-backup.d/*  2&> /dev/null || true
    fi
Paul Cammish's avatar
Paul Cammish committed
165
  fi
Paul Cammish's avatar
Paul Cammish committed
166
167
168
169

fi

for domain in $( find /srv -maxdepth 1 -mindepth 1 ! -type l -type d -print | grep -v '^/srv/\.' | grep '\.' ); do
170
  if [ ! -f ${domain}/config/do-not-secure ] || [ -f /etc/sympl/disable-filesystem-security ] ; then
Paul Cammish's avatar
Paul Cammish committed
171
172
173
174
175
    secure_domain_dir ${domain}
  fi
done

exit 0