Project.pm: remove duplicate users from the project membership list
[girocco.git] / jailsetup.sh
blobcad77b8e6cc0053c2af31e07cd64287825f27eb8
1 #!/bin/sh
2 # The Girocco jail setup script
4 # If the first parameter is "dbonly", setup the database only
6 # We are designed to set up the chroot based on the output of
7 # `uname -s` by sourcing a suitable system-specific script.
8 # Unrecognized systems will generate an error. When using
9 # "dbonly" the setup of the chroot binaries is skipped so the
10 # output of `uname -s` does not matter in that case.
12 set -e
14 curdir="`pwd`"
15 srcdir="$curdir/src"
16 getent="$srcdir/getent"
17 . ./shlib.sh
19 dbonly=''
20 [ "$1" != "dbonly" ] || dbonly=1
22 reserved_users="root sshd _sshd mob nobody everyone $cfg_cgi_user $cfg_mirror_user"
24 # Require either sshd or _sshd user unless "dbonly"
25 sshd_user=sshd
26 if ! "$getent" passwd sshd >/dev/null && ! "$getent" passwd _sshd >/dev/null; then
27 if [ -n "$dbonly" ]; then
28 if [ ! -s etc/passwd ]; then
29 # Only complain on initial etc/passwd creation
30 echo "WARNING: no sshd or _sshd user, omitting entries from chroot etc/passwd"
32 sshd_user=
33 else
34 echo "*** Error: You do not have required sshd or _sshd user in system." >&2
35 exit 1
37 else
38 "$getent" passwd sshd >/dev/null || sshd_user=_sshd
41 # Verify we have all we need
42 if ! "$getent" passwd "$cfg_mirror_user" >/dev/null; then
43 echo "*** Error: You do not have \"$cfg_mirror_user\" user in system yet." >&2
44 exit 1
46 if ! "$getent" passwd "$cfg_cgi_user" >/dev/null; then
47 echo "*** Error: You do not have \"$cfg_cgi_user\" user in system yet." >&2
48 exit 1
50 if [ -n "$dbonly" -a -z "$cfg_owning_group" ]; then
51 cfg_owning_group="$("$getent" passwd "$cfg_mirror_user" | cut -d : -f 4)"
52 elif ! "$getent" group "$cfg_owning_group" >/dev/null; then
53 echo "*** Error: You do not have \"$cfg_owning_group\" group in system yet." >&2
54 exit 1
57 # One last paranoid check before we go writing all over everything
58 if [ -z "$cfg_chroot" -o "$cfg_chroot" = "/" ]; then
59 echo "*** Error: chroot location is not set or is invalid." >&2
60 echo "*** Error: perhaps you have an incorrect Config.pm?" >&2
61 exit 1
64 umask 022
65 mkdir -p "$cfg_chroot"
66 cd "$cfg_chroot"
67 chmod 755 "$cfg_chroot" ||
68 echo "WARNING: Cannot chmod $cfg_chroot"
70 # Set up basic user/group configuration; if there isn't any already
71 mobpass=''
72 [ -n "$cfg_mob" ] || mobpass='x'
73 mkdir -p etc
74 if [ ! -s etc/passwd ]; then
75 cat >etc/passwd <<EOT
76 root:x:0:0:system administrator:/var/empty:/bin/false
77 nobody:x:$("$getent" passwd nobody | cut -d : -f 3-4):unprivileged user:/var/empty:/bin/false
78 EOT
79 [ -z "$sshd_user" ] || cat >>etc/passwd <<EOT
80 sshd:x:$("$getent" passwd $sshd_user | cut -d : -f 3-4):privilege separation:/var/empty:/bin/false
81 _sshd:x:$("$getent" passwd $sshd_user | cut -d : -f 3-4):privilege separation:/var/empty:/bin/false
82 EOT
83 cat >>etc/passwd <<EOT
84 $cfg_cgi_user:x:$("$getent" passwd "$cfg_cgi_user" | cut -d : -f 3-5):/:/bin/true
85 $cfg_mirror_user:x:$("$getent" passwd "$cfg_mirror_user" | cut -d : -f 3-5):/:/bin/true
86 everyone:x:65537:$("$getent" group "$cfg_owning_group" | cut -d : -f 3):every user:/:/bin/false
87 mob:$mobpass:65538:$("$getent" group "$cfg_owning_group" | cut -d : -f 3):the mob:/:/bin/git-shell-verify
88 EOT
89 elif [ -z "$dbonly" ]; then
90 # Make sure an sshd entry is present
91 if ! grep -q '^sshd:' etc/passwd; then
92 echo "*** Error: chroot etc/passwd exists but lacks sshd entry." >&2
93 exit 1
97 if [ ! -s etc/group ]; then
98 cat >etc/group <<EOT
99 _repo:x:$("$getent" group "$cfg_owning_group" | cut -d : -f 3):$cfg_mirror_user
103 # Set up basic default Git configuration; if there isn't any already
104 mkdir -p etc/girocco
105 if [ ! -s etc/girocco/.gitconfig ]; then
106 cat >etc/girocco/.gitconfig <<EOT
107 [http]
108 lowSpeedLimit = 1
109 lowSpeedTime = 600
113 mkdir -p etc/sshkeys etc/sshcerts etc/sshactive
114 for ruser in $reserved_users; do
115 touch etc/sshkeys/$ruser
116 done
117 chgrp $cfg_owning_group etc etc/sshkeys etc/sshcerts etc/sshactive ||
118 echo "WARNING: Cannot chgrp $cfg_owning_group the etc directories"
119 chgrp $cfg_owning_group etc/passwd ||
120 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/passwd"
121 chgrp $cfg_owning_group etc/group ||
122 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/group"
123 chgrp $cfg_owning_group etc/girocco etc/girocco/.gitconfig ||
124 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/girocco"
125 chmod g+s etc etc/sshkeys etc/sshcerts etc/sshactive ||
126 echo "WARNING: Cannot chmod g+s the etc directories"
127 chmod g+w etc etc/sshkeys etc/sshcerts etc/sshactive ||
128 echo "WARNING: Cannot chmod g+w the etc directories"
129 chmod g+w etc/passwd etc/group ||
130 echo "WARNING: Cannot chmod g+w the etc/passwd and/or etc/group files"
131 chmod go-w etc/passwd etc/girocco etc/girocco/.gitconfig ||
132 echo "WARNING: Cannot chmod go-w etc/girocco and/or etc/girocco/.gitconfig"
133 chmod a-w etc/girocco ||
134 echo "WARNING: Cannot chmod a-w etc/girocco"
135 chmod -R g+w etc/sshkeys etc/sshcerts etc/sshactive 2>/dev/null ||
136 echo "WARNING: Cannot chmod g+w the sshkeys, sshcerts and/or sshactive files"
138 # Note time of last install
139 > etc/sshactive/_install
141 [ -z "$dbonly" ] || exit 0
143 # Make sure the system type is supported for chroot
144 sysname="$(uname -s | tr A-Z a-z || :)"
145 : ${sysname:=linux}
146 nosshdir=
147 # These equivalents may need to be expanded at some point
148 case "$sysname" in
149 *kfreebsd*)
150 sysname=linux;;
151 *darwin*)
152 sysname=darwin;;
153 *freebsd*)
154 sysname=freebsd;;
155 *linux*)
156 sysname=linux;;
157 esac
159 chrootsetup="$curdir/chrootsetup_$sysname.sh"
160 if ! [ -r "$chrootsetup" -a -s "$chrootsetup" ]; then
161 echo "*** Error: $chrootsetup not found" >&2
162 echo "*** Error: creating a chroot for a `uname -s` system is not supported" >&2
163 exit 1
166 # validate reporoot, chroot and jailreporoot before doing anything more
168 # validates the passed in dir if a second argument is not empty dir must NOT
169 # start with / otherwise it must. A trailing '/' is removed and any duplicated
170 # // are removed and a sole / or empty is disallowed.
171 make_valid_dir() {
172 _check="$(echo "$1" | tr -s /)"
173 _check="${_check%/}"
174 [ -z "$_check" -o "$_check" = "/" ] && return 1
175 if [ -z "$2" ]; then
176 # must start with '/'
177 case "$_check" in /*) :;; *) return 1; esac
178 else
179 # must NOT start with '/'
180 case "$_check" in /*) return 1; esac
182 echo "$_check"
185 if ! reporoot="$(make_valid_dir "$cfg_reporoot")"; then
186 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
187 echo "*** Error: MUST start with '/' and MUST NOT be '/'" >&2
188 exit 1
190 if ! chroot="$(make_valid_dir "$cfg_chroot")"; then
191 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
192 echo "*** Error: MUST start with '/' and MUST NOT be '/'" >&2
193 exit 1
195 if ! jailreporoot="$(make_valid_dir "$cfg_jailreporoot" 1)"; then
196 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
197 echo "*** Error: MUST NOT start with '/' and MUST NOT be ''" >&2
198 exit 1
201 # chroot MUST NOT be reporoot
202 if [ "$chroot" = "$reporoot" ]; then
203 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
204 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
205 echo "*** Error: reporoot and chroot MUST NOT be the same" >&2
206 exit 1
209 # chroot MUST NOT be a subdirectory of reporoot
210 case "$chroot" in "$reporoot"/*)
211 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
212 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
213 echo "*** Error: chroot MUST NOT be a subdirectory of reporoot" >&2
214 exit 1
215 esac
217 # chroot/jailreporoot MUST NOT be a subdirectory of reporoot
218 case "$chroot/$jailreporoot" in "$reporoot"/*)
219 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
220 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
221 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
222 echo "*** Error: chroot/jailreporoot MUST NOT be a subdirectory of reporoot" >&2
223 exit 1
224 esac
226 # reporoot MUST NOT be a subdirectory of chroot/jailreporoot
227 case "$reporoot" in "$chroot/$jailreporoot"/*)
228 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
229 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
230 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
231 echo "*** Error: reporoot MUST NOT be a subdirectory of chroot/jailreporoot" >&2
232 exit 1
233 esac
235 # Set the user and group on the top of the chroot before creating anything else
236 chown 0:0 "$chroot"
238 # When we create a fork, the alternates always have an absolute path.
239 # If reporoot is not --bind mounted at the same location in chroot we must
240 # create a suitable symlink so the absolute path alternates continue to work
241 # in the ssh chroot or else forks will be broken in there.
242 if [ "$reporoot" != "/$jailreporoot" ]; then
243 mkdirp="$(dirname "${reporoot#/}")"
244 [ "$mkdirp" = "." ] && mkdirp=
245 lnback=
246 [ -z "$mkdirp" ] || lnback="$(echo "$mkdirp/" | sed -e 's,[^/]*/,../,g')"
247 [ -z "$mkdirp" ] || mkdir -p "$chroot/$mkdirp"
248 (umask 0; ln -s -f -n "$lnback$jailreporoot" "$chroot$reporoot")
249 [ $? -eq 0 ] || exit 1
252 # First, setup basic platform-independent directory structure
253 mkdir -p bin dev etc lib sbin var/empty var/run "$jailreporoot"
254 chmod 0444 var/empty
255 rm -rf usr
256 ln -s . usr
258 # Now source the platform-specific script that is responsible for dev device
259 # setup, proc setup (if needed), lib64 setup (if needed) and basic library
260 # installation to make a chroot operational. Additionally it will define a
261 # pull_in_bin function that can be used to add executables and their library
262 # dependencies to the chroot and finally will install a suitable nc.openbsd
263 # compatible version of netcat that supports connections to unix sockets.
264 . "$chrootsetup"
266 # Now, bring in sshd, sh etc.
267 # The $chrootsetup script should have already provided a suitable nc.openbsd
268 install -p "$cfg_basedir/bin/git-shell-verify" bin
269 pull_in_bin "$cfg_basedir/bin/can_user_push" bin
270 pull_in_bin /bin/sh bin
271 pull_in_bin /bin/date bin
272 pull_in_bin /bin/mv bin
273 pull_in_bin /bin/rm bin
274 pull_in_bin /usr/sbin/sshd sbin
276 # ...and the bits of git we need,
277 # being sure to use the configured git and its --exec-path to find the pieces
278 git_exec_path="$("$cfg_git_bin" --exec-path)"
279 for i in git git-index-pack git-receive-pack git-shell git-update-server-info git-upload-archive \
280 git-upload-pack git-unpack-objects git-show-ref git-config git-for-each-ref git-rev-list; do
281 pull_in_bin "$git_exec_path/$i" bin git
282 done
284 # Note time of last jailsetup
285 > etc/sshactive/_jailsetup
287 # Update permissions on the database files
288 chown $cfg_cgi_user:$cfg_owning_group etc/passwd etc/group
289 chown -R $cfg_cgi_user:$cfg_owning_group etc/sshkeys etc/sshcerts etc/sshactive
290 chown $cfg_mirror_user:$cfg_owning_group etc etc/girocco etc/girocco/.gitconfig
292 # Set up basic sshd configuration:
293 if [ -n "$nosshdir" ]; then
294 rm -rf etc/ssh
295 ln -s . etc/ssh
296 [ ! -f /etc/moduli ] || { cp -p /etc/moduli etc/; chown 0:0 etc/moduli; }
297 else
298 [ ! -e etc/ssh -o -d etc/ssh ] || rm -rf etc/ssh
299 mkdir -p etc/ssh
300 [ ! -f /etc/ssh/moduli ] || { cp -p /etc/ssh/moduli etc/ssh/; chown 0:0 etc/ssh/moduli; }
302 mkdir -p var/run/sshd
303 if [ ! -s etc/ssh/sshd_config ]; then
304 cat >etc/ssh/sshd_config <<EOT
305 Protocol 2
306 Port $cfg_sshd_jail_port
307 UsePAM no
308 X11Forwarding no
309 AllowAgentForwarding no
310 AllowTcpForwarding no
311 PermitTunnel no
312 IgnoreUserKnownHosts yes
313 PrintLastLog no
314 PrintMotd no
315 UseDNS no
316 PermitRootLogin no
317 UsePrivilegeSeparation yes
319 HostKey /etc/ssh/ssh_host_rsa_key
321 if [ -z "$cfg_disable_dsa" ]; then
322 cat >>etc/ssh/sshd_config <<EOT
323 HostKey /etc/ssh/ssh_host_dsa_key
326 cat >>etc/ssh/sshd_config <<EOT
327 AuthorizedKeysFile /etc/sshkeys/%u
328 StrictModes no
330 # mob user:
331 PermitEmptyPasswords yes
332 ChallengeResponseAuthentication no
333 PasswordAuthentication yes
336 if [ ! -s etc/ssh/ssh_host_rsa_key ]; then
337 bits=2048
338 if [ "$cfg_rsakeylength" -gt "$bits" ] 2>/dev/null; then
339 bits="$cfg_rsakeylength"
341 yes | ssh-keygen -b "$bits" -t rsa -N "" -C Girocco -f etc/ssh/ssh_host_rsa_key
343 if [ -z "$cfg_disable_dsa" -a ! -s etc/ssh/ssh_host_dsa_key ]; then
344 # ssh-keygen can only create 1024 bit DSA keys
345 yes | ssh-keygen -b 1024 -t dsa -N "" -C Girocco -f etc/ssh/ssh_host_dsa_key
348 # Set the final permissions on the binaries and perform any final twiddling
349 chroot_update_permissions
351 # Change the owner of the sshd-related files
352 chown 0:0 etc/ssh/ssh_* etc/ssh/sshd_*
354 echo "--- Add to your boot scripts: mount --bind $reporoot $chroot/$jailreporoot"
355 echo "--- Add to your boot scripts: mount --bind /proc $chroot/proc"
356 echo "--- Add to your syslog configuration: listening on socket $chroot/dev/log"
357 echo "--- To restart a running jail's sshd: sudo kill -HUP \`cat $chroot/var/run/sshd.pid\`"