gc.sh: remove_crud: nuke objects/??/tmp_obj_* files
[girocco.git] / jailsetup.sh
blobb0946fe045e094ebf50528546ae9d447e20240d1
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 git lock bundle 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 mkdir -p var/empty
71 chmod 0555 var/empty ||
72 echo "WARNING: Cannot chmod a=rx $cfg_chroot/var/empty"
74 # Set up basic user/group configuration; if there isn't any already
75 mobpass=''
76 [ -n "$cfg_mob" ] || mobpass='x'
77 mkdir -p etc
78 if [ ! -s etc/passwd ]; then
79 cat >etc/passwd <<EOT
80 root:x:0:0:system administrator:/var/empty:/bin/false
81 nobody:x:$("$getent" passwd nobody | cut -d : -f 3-4):unprivileged user:/var/empty:/bin/false
82 EOT
83 [ -z "$sshd_user" ] || cat >>etc/passwd <<EOT
84 sshd:x:$("$getent" passwd $sshd_user | cut -d : -f 3-4):privilege separation:/var/empty:/bin/false
85 _sshd:x:$("$getent" passwd $sshd_user | cut -d : -f 3-4):privilege separation:/var/empty:/bin/false
86 EOT
87 [ "$cfg_cgi_user" = "$cfg_mirror_user" ] || cat >>etc/passwd <<EOT
88 $cfg_cgi_user:x:$("$getent" passwd "$cfg_cgi_user" | cut -d : -f 3-5):/:/bin/true
89 EOT
90 cat >>etc/passwd <<EOT
91 $cfg_mirror_user:x:$("$getent" passwd "$cfg_mirror_user" | cut -d : -f 3-5):/:/bin/true
92 everyone:x:65537:$("$getent" group "$cfg_owning_group" | cut -d : -f 3):every user:/:/bin/false
93 mob:$mobpass:65538:$("$getent" group "$cfg_owning_group" | cut -d : -f 3):the mob:/:/bin/git-shell-verify
94 git::65539:$("$getent" passwd nobody | cut -d : -f 4):read-only access:/:/bin/git-shell-verify
95 EOT
96 elif [ -z "$dbonly" ]; then
97 # Make sure an sshd entry is present
98 if ! grep -q '^sshd:' etc/passwd; then
99 echo "*** Error: chroot etc/passwd exists but lacks sshd entry." >&2
100 exit 1
104 if [ ! -s etc/group ]; then
105 cat >etc/group <<EOT
106 _repo:x:$("$getent" group "$cfg_owning_group" | cut -d : -f 3):$cfg_mirror_user
110 # Set up basic default Git configuration
111 # Initialize one if none exists or update critical variables for an existing one
112 mkdir -p etc/girocco
113 didchmod=
114 if [ -e etc/girocco/.gitconfig ] && ! [ -f etc/girocco/.gitconfig ]; then
115 echo "*** Error: chroot etc/girocco/.gitconfig exists but is not a file." >&2
116 exit 1
118 if [ -f etc/girocco/.gitconfig ]; then
119 gcerr=0
120 x="$(git config --file etc/girocco/.gitconfig --get "no--such--section.no such subsection.no--such--key")" || gcerr=$?
121 if [ $gcerr -gt 1 ]; then
122 echo "*** Error: chroot etc/girocco/.gitconfig exists but is corrupt." >&2
123 echo "*** Error: either remove it or edit it to correct the problem." >&2
124 exit 1
127 if [ ! -s etc/girocco/.gitconfig ]; then
128 chmod u+w etc/girocco
129 didchmod=1
130 cat >etc/girocco/.gitconfig <<EOT
131 # Any values set here will take effect whenever Girocco runs a git command
135 # $1 => name, $2 => value, $3 => overwrite_flag
136 update_config_item() {
137 _existsnot=
138 _oldval=
139 _oldval="$(git config --file etc/girocco/.gitconfig --get "$1")" || _existsnot=1
140 if [ -z "$_existsnot" ]; then
141 [ -n "$3" ] || return 0
142 [ "$_oldval" != "$2" ] || return 0
144 [ -n "$didchmod" ] || { chmod u+w etc/girocco; didchmod=1; }
145 git config --file etc/girocco/.gitconfig "$1" "$2"
146 if [ -n "$_existsnot" ]; then
147 echo "chroot: etc/girocco/.gitconfig: config $1: (created) \"$2\""
148 else
149 echo "chroot: etc/girocco/.gitconfig: config $1: \"$_oldval\" -> \"$2\""
152 if [ -n "$cfg_git_no_mmap" ]; then
153 update_config_item core.packedGitWindowSize 1m 1
154 else
155 update_config_item core.packedGitWindowSize 32m 1
157 if [ -n "$var_window_memory" ]; then
158 update_config_item pack.windowMemory "$var_window_memory" 1
160 if [ -n "$cfg_jgit_compatible_bitmaps" ]; then
161 update_config_item pack.writeBitmapHashCache false 1
162 else
163 update_config_item pack.writeBitmapHashCache true 1
165 update_config_item http.lowSpeedLimit 1
166 update_config_item http.lowSpeedTime 600
167 update_config_item receive.maxInputSize "${cfg_max_receive_size:-0}" 1
168 [ -z "$didchmod" ] || chmod a-w etc/girocco
170 mkdir -p etc/sshkeys etc/sshcerts etc/sshactive
171 for ruser in $reserved_users; do
172 touch etc/sshkeys/$ruser
173 done
174 chgrp $cfg_owning_group etc etc/sshkeys etc/sshcerts etc/sshactive ||
175 echo "WARNING: Cannot chgrp $cfg_owning_group the etc directories"
176 chgrp $cfg_owning_group etc/passwd ||
177 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/passwd"
178 chgrp $cfg_owning_group etc/group ||
179 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/group"
180 chgrp $cfg_owning_group etc/girocco etc/girocco/.gitconfig ||
181 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/girocco"
182 chmod g+s etc etc/sshkeys etc/sshcerts etc/sshactive ||
183 echo "WARNING: Cannot chmod g+s the etc directories"
184 chmod g+w etc etc/sshkeys etc/sshcerts etc/sshactive ||
185 echo "WARNING: Cannot chmod g+w the etc directories"
186 chmod g+w etc/passwd etc/group ||
187 echo "WARNING: Cannot chmod g+w the etc/passwd and/or etc/group files"
188 chmod go-w etc/passwd etc/girocco etc/girocco/.gitconfig ||
189 echo "WARNING: Cannot chmod go-w etc/girocco and/or etc/girocco/.gitconfig"
190 chmod a-w etc/girocco ||
191 echo "WARNING: Cannot chmod a-w etc/girocco"
192 chmod -R g+w etc/sshkeys etc/sshcerts etc/sshactive 2>/dev/null ||
193 echo "WARNING: Cannot chmod g+w the sshkeys, sshcerts and/or sshactive files"
195 # Note time of last install
196 > etc/sshactive/_install
198 [ -z "$dbonly" ] || exit 0
200 # Make sure the system type is supported for chroot
201 sysname="$(uname -s | tr A-Z a-z || :)"
202 : ${sysname:=linux}
203 nosshdir=
204 # These equivalents may need to be expanded at some point
205 case "$sysname" in
206 *kfreebsd*)
207 sysname=linux;;
208 *darwin*)
209 sysname=darwin;;
210 *dragonfly*)
211 sysname=dragonfly;;
212 *freebsd*)
213 sysname=freebsd;;
214 *linux*)
215 sysname=linux;;
216 esac
218 chrootsetup="$curdir/chrootsetup_$sysname.sh"
219 if ! [ -r "$chrootsetup" -a -s "$chrootsetup" ]; then
220 echo "*** Error: $chrootsetup not found" >&2
221 echo "*** Error: creating a chroot for a `uname -s` system is not supported" >&2
222 exit 1
225 # validate reporoot, chroot and jailreporoot before doing anything more
227 # validates the passed in dir if a second argument is not empty dir must NOT
228 # start with / otherwise it must. A trailing '/' is removed and any duplicated
229 # // are removed and a sole / or empty is disallowed.
230 make_valid_dir() {
231 _check="$(echo "$1" | tr -s /)"
232 _check="${_check%/}"
233 [ -z "$_check" -o "$_check" = "/" ] && return 1
234 if [ -z "$2" ]; then
235 # must start with '/'
236 case "$_check" in /*) :;; *) return 1; esac
237 else
238 # must NOT start with '/'
239 case "$_check" in /*) return 1; esac
241 echo "$_check"
244 if ! reporoot="$(make_valid_dir "$cfg_reporoot")"; then
245 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
246 echo "*** Error: MUST start with '/' and MUST NOT be '/'" >&2
247 exit 1
249 if ! chroot="$(make_valid_dir "$cfg_chroot")"; then
250 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
251 echo "*** Error: MUST start with '/' and MUST NOT be '/'" >&2
252 exit 1
254 if ! jailreporoot="$(make_valid_dir "$cfg_jailreporoot" 1)"; then
255 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
256 echo "*** Error: MUST NOT start with '/' and MUST NOT be ''" >&2
257 exit 1
260 # chroot MUST NOT be reporoot
261 if [ "$chroot" = "$reporoot" ]; then
262 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
263 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
264 echo "*** Error: reporoot and chroot MUST NOT be the same" >&2
265 exit 1
268 # chroot MUST NOT be a subdirectory of reporoot
269 case "$chroot" in "$reporoot"/*)
270 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
271 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
272 echo "*** Error: chroot MUST NOT be a subdirectory of reporoot" >&2
273 exit 1
274 esac
276 # chroot/jailreporoot MUST NOT be a subdirectory of reporoot
277 case "$chroot/$jailreporoot" in "$reporoot"/*)
278 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
279 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
280 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
281 echo "*** Error: chroot/jailreporoot MUST NOT be a subdirectory of reporoot" >&2
282 exit 1
283 esac
285 # reporoot MUST NOT be a subdirectory of chroot/jailreporoot
286 case "$reporoot" in "$chroot/$jailreporoot"/*)
287 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
288 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
289 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
290 echo "*** Error: reporoot MUST NOT be a subdirectory of chroot/jailreporoot" >&2
291 exit 1
292 esac
294 # Set the user and group on the top of the chroot before creating anything else
295 chown 0:0 "$chroot"
297 # When we create a fork, the alternates always have an absolute path.
298 # If reporoot is not --bind mounted at the same location in chroot we must
299 # create a suitable symlink so the absolute path alternates continue to work
300 # in the ssh chroot or else forks will be broken in there.
301 if [ "$reporoot" != "/$jailreporoot" ]; then
302 mkdirp="$(dirname "${reporoot#/}")"
303 [ "$mkdirp" = "." ] && mkdirp=
304 lnback=
305 [ -z "$mkdirp" ] || lnback="$(echo "$mkdirp/" | sed -e 's,[^/]*/,../,g')"
306 [ -z "$mkdirp" ] || mkdir -p "$chroot/$mkdirp"
307 (umask 0; ln -s -f -n "$lnback$jailreporoot" "$chroot$reporoot")
308 [ $? -eq 0 ] || exit 1
311 # First, setup basic platform-independent directory structure
312 mkdir -p bin dev etc lib sbin var/empty var/run "$jailreporoot"
313 chmod 0555 var/empty
314 rm -rf usr local
315 ln -s . usr
316 ln -s . local
318 # Now source the platform-specific script that is responsible for dev device
319 # setup, proc setup (if needed), lib64 setup (if needed) and basic library
320 # installation to make a chroot operational. Additionally it will define a
321 # pull_in_bin function that can be used to add executables and their library
322 # dependencies to the chroot and finally will install a suitable nc.openbsd
323 # compatible version of netcat that supports connections to unix sockets.
324 . "$chrootsetup"
326 # Now, bring in sshd, sh etc.
327 # The $chrootsetup script should have already provided a suitable nc.openbsd
328 install -p "$cfg_basedir/bin/git-shell-verify" bin/git-shell-verify.new
329 install -p "$cfg_basedir/bin/git-askpass-password" bin/git-askpass-password.new
330 perl -i -p \
331 -e 's|^#!.*|#!/bin/sh| if $. == 1;' \
332 -e 'close ARGV if eof;' \
333 bin/git-shell-verify.new bin/git-askpass-password.new
334 mv -f bin/git-askpass-password.new bin/git-askpass-password
335 mv -f bin/git-shell-verify.new bin/git-shell-verify
336 pull_in_bin "$cfg_basedir/bin/can_user_push" bin
337 pull_in_bin "$cfg_basedir/bin/list_packs" bin
338 pull_in_bin "$var_sh_bin" bin/sh
339 pull_in_bin /bin/chmod bin
340 pull_in_bin /bin/date bin
341 pull_in_bin /bin/mkdir bin
342 pull_in_bin /bin/mv bin
343 pull_in_bin /bin/rm bin
344 pull_in_bin /bin/sleep bin
345 pull_in_bin /usr/bin/find bin
346 pull_in_bin /usr/bin/touch bin
347 pull_in_bin /usr/bin/wc bin
348 pull_in_bin /usr/bin/xargs bin
349 pull_in_bin /usr/sbin/sshd sbin
351 # ...and the bits of git we need,
352 # being sure to use the configured git and its --exec-path to find the pieces
353 for i in git git-index-pack git-receive-pack git-shell git-update-server-info git-upload-archive \
354 git-upload-pack git-unpack-objects git-config git-for-each-ref git-rev-list; do
355 pull_in_bin "$var_git_exec_path/$i" bin git
356 done
358 # ...and any extras identified by install.sh
359 if [ -n "$GIROCCO_CHROOT_EXTRA_INSTALLS" ]; then
360 for i in $GIROCCO_CHROOT_EXTRA_INSTALLS; do
361 pull_in_bin "$i" bin
362 done
365 # Note time of last jailsetup
366 > etc/sshactive/_jailsetup
368 # Update permissions on the database files
369 chown $cfg_cgi_user:$cfg_owning_group etc/passwd etc/group
370 chown -R $cfg_cgi_user:$cfg_owning_group etc/sshkeys etc/sshcerts etc/sshactive
371 chown $cfg_mirror_user:$cfg_owning_group etc etc/girocco etc/girocco/.gitconfig
373 # Set up basic sshd configuration:
374 if [ -n "$nosshdir" ]; then
375 rm -rf etc/ssh
376 ln -s . etc/ssh
377 [ ! -f /etc/moduli ] || { cp -p /etc/moduli etc/; chown 0:0 etc/moduli; }
378 else
379 [ ! -e etc/ssh -o -d etc/ssh ] || rm -rf etc/ssh
380 mkdir -p etc/ssh
381 [ ! -f /etc/ssh/moduli ] || { cp -p /etc/ssh/moduli etc/ssh/; chown 0:0 etc/ssh/moduli; }
383 mkdir -p var/run/sshd
384 if [ ! -s etc/ssh/sshd_config ]; then
385 cat >etc/ssh/sshd_config <<EOT
386 Protocol 2
387 Port $cfg_sshd_jail_port
388 UsePAM no
389 X11Forwarding no
390 AllowAgentForwarding no
391 AllowTcpForwarding no
392 PermitTunnel no
393 IgnoreUserKnownHosts yes
394 PrintLastLog no
395 PrintMotd no
396 UseDNS no
397 PermitRootLogin no
398 UsePrivilegeSeparation yes
400 HostKey /etc/ssh/ssh_host_rsa_key
402 if [ -z "$cfg_disable_dsa" ]; then
403 cat >>etc/ssh/sshd_config <<EOT
404 HostKey /etc/ssh/ssh_host_dsa_key
407 cat >>etc/ssh/sshd_config <<EOT
408 AuthorizedKeysFile /etc/sshkeys/%u
409 StrictModes no
411 # mob and git users:
412 PermitEmptyPasswords yes
413 ChallengeResponseAuthentication no
414 PasswordAuthentication yes
417 if [ ! -s etc/ssh/ssh_host_rsa_key ]; then
418 bits=2048
419 if [ "$cfg_rsakeylength" -gt "$bits" ] 2>/dev/null; then
420 bits="$cfg_rsakeylength"
422 yes | ssh-keygen -b "$bits" -t rsa -N "" -C Girocco -f etc/ssh/ssh_host_rsa_key
424 if [ -z "$cfg_disable_dsa" -a ! -s etc/ssh/ssh_host_dsa_key ]; then
425 # ssh-keygen can only create 1024 bit DSA keys
426 yes | ssh-keygen -b 1024 -t dsa -N "" -C Girocco -f etc/ssh/ssh_host_dsa_key
429 # Set the final permissions on the binaries and perform any final twiddling
430 chroot_update_permissions
432 # Change the owner of the sshd-related files
433 chown 0:0 etc/ssh/ssh_* etc/ssh/sshd_*
435 echo "--- Add to your boot scripts: mount --bind $reporoot $chroot/$jailreporoot"
436 echo "--- Add to your boot scripts: mount --bind /proc $chroot/proc"
437 echo "--- Add to your syslog configuration: listening on socket $chroot/dev/log"
438 echo "--- To restart a running jail's sshd: sudo kill -HUP \`cat $chroot/var/run/sshd.pid\`"