gc.sh: suppress darcs optimize output
[girocco.git] / jailsetup.sh
blob8faad71198a4833280f36b58afcd50bbc060aa4e
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 EOT
95 elif [ -z "$dbonly" ]; then
96 # Make sure an sshd entry is present
97 if ! grep -q '^sshd:' etc/passwd; then
98 echo "*** Error: chroot etc/passwd exists but lacks sshd entry." >&2
99 exit 1
103 if [ ! -s etc/group ]; then
104 cat >etc/group <<EOT
105 _repo:x:$("$getent" group "$cfg_owning_group" | cut -d : -f 3):$cfg_mirror_user
109 # Set up basic default Git configuration; if there isn't any already
110 mkdir -p etc/girocco
111 if [ ! -s etc/girocco/.gitconfig ]; then
112 cat >etc/girocco/.gitconfig <<EOT
113 [http]
114 lowSpeedLimit = 1
115 lowSpeedTime = 600
119 mkdir -p etc/sshkeys etc/sshcerts etc/sshactive
120 for ruser in $reserved_users; do
121 touch etc/sshkeys/$ruser
122 done
123 chgrp $cfg_owning_group etc etc/sshkeys etc/sshcerts etc/sshactive ||
124 echo "WARNING: Cannot chgrp $cfg_owning_group the etc directories"
125 chgrp $cfg_owning_group etc/passwd ||
126 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/passwd"
127 chgrp $cfg_owning_group etc/group ||
128 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/group"
129 chgrp $cfg_owning_group etc/girocco etc/girocco/.gitconfig ||
130 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/girocco"
131 chmod g+s etc etc/sshkeys etc/sshcerts etc/sshactive ||
132 echo "WARNING: Cannot chmod g+s the etc directories"
133 chmod g+w etc etc/sshkeys etc/sshcerts etc/sshactive ||
134 echo "WARNING: Cannot chmod g+w the etc directories"
135 chmod g+w etc/passwd etc/group ||
136 echo "WARNING: Cannot chmod g+w the etc/passwd and/or etc/group files"
137 chmod go-w etc/passwd etc/girocco etc/girocco/.gitconfig ||
138 echo "WARNING: Cannot chmod go-w etc/girocco and/or etc/girocco/.gitconfig"
139 chmod a-w etc/girocco ||
140 echo "WARNING: Cannot chmod a-w etc/girocco"
141 chmod -R g+w etc/sshkeys etc/sshcerts etc/sshactive 2>/dev/null ||
142 echo "WARNING: Cannot chmod g+w the sshkeys, sshcerts and/or sshactive files"
144 # Note time of last install
145 > etc/sshactive/_install
147 [ -z "$dbonly" ] || exit 0
149 # Make sure the system type is supported for chroot
150 sysname="$(uname -s | tr A-Z a-z || :)"
151 : ${sysname:=linux}
152 nosshdir=
153 # These equivalents may need to be expanded at some point
154 case "$sysname" in
155 *kfreebsd*)
156 sysname=linux;;
157 *darwin*)
158 sysname=darwin;;
159 *freebsd*)
160 sysname=freebsd;;
161 *linux*)
162 sysname=linux;;
163 esac
165 chrootsetup="$curdir/chrootsetup_$sysname.sh"
166 if ! [ -r "$chrootsetup" -a -s "$chrootsetup" ]; then
167 echo "*** Error: $chrootsetup not found" >&2
168 echo "*** Error: creating a chroot for a `uname -s` system is not supported" >&2
169 exit 1
172 # validate reporoot, chroot and jailreporoot before doing anything more
174 # validates the passed in dir if a second argument is not empty dir must NOT
175 # start with / otherwise it must. A trailing '/' is removed and any duplicated
176 # // are removed and a sole / or empty is disallowed.
177 make_valid_dir() {
178 _check="$(echo "$1" | tr -s /)"
179 _check="${_check%/}"
180 [ -z "$_check" -o "$_check" = "/" ] && return 1
181 if [ -z "$2" ]; then
182 # must start with '/'
183 case "$_check" in /*) :;; *) return 1; esac
184 else
185 # must NOT start with '/'
186 case "$_check" in /*) return 1; esac
188 echo "$_check"
191 if ! reporoot="$(make_valid_dir "$cfg_reporoot")"; then
192 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
193 echo "*** Error: MUST start with '/' and MUST NOT be '/'" >&2
194 exit 1
196 if ! chroot="$(make_valid_dir "$cfg_chroot")"; then
197 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
198 echo "*** Error: MUST start with '/' and MUST NOT be '/'" >&2
199 exit 1
201 if ! jailreporoot="$(make_valid_dir "$cfg_jailreporoot" 1)"; then
202 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
203 echo "*** Error: MUST NOT start with '/' and MUST NOT be ''" >&2
204 exit 1
207 # chroot MUST NOT be reporoot
208 if [ "$chroot" = "$reporoot" ]; then
209 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
210 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
211 echo "*** Error: reporoot and chroot MUST NOT be the same" >&2
212 exit 1
215 # chroot MUST NOT be a subdirectory of reporoot
216 case "$chroot" in "$reporoot"/*)
217 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
218 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
219 echo "*** Error: chroot MUST NOT be a subdirectory of reporoot" >&2
220 exit 1
221 esac
223 # chroot/jailreporoot MUST NOT be a subdirectory of reporoot
224 case "$chroot/$jailreporoot" in "$reporoot"/*)
225 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
226 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
227 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
228 echo "*** Error: chroot/jailreporoot MUST NOT be a subdirectory of reporoot" >&2
229 exit 1
230 esac
232 # reporoot MUST NOT be a subdirectory of chroot/jailreporoot
233 case "$reporoot" in "$chroot/$jailreporoot"/*)
234 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
235 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
236 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
237 echo "*** Error: reporoot MUST NOT be a subdirectory of chroot/jailreporoot" >&2
238 exit 1
239 esac
241 # Set the user and group on the top of the chroot before creating anything else
242 chown 0:0 "$chroot"
244 # When we create a fork, the alternates always have an absolute path.
245 # If reporoot is not --bind mounted at the same location in chroot we must
246 # create a suitable symlink so the absolute path alternates continue to work
247 # in the ssh chroot or else forks will be broken in there.
248 if [ "$reporoot" != "/$jailreporoot" ]; then
249 mkdirp="$(dirname "${reporoot#/}")"
250 [ "$mkdirp" = "." ] && mkdirp=
251 lnback=
252 [ -z "$mkdirp" ] || lnback="$(echo "$mkdirp/" | sed -e 's,[^/]*/,../,g')"
253 [ -z "$mkdirp" ] || mkdir -p "$chroot/$mkdirp"
254 (umask 0; ln -s -f -n "$lnback$jailreporoot" "$chroot$reporoot")
255 [ $? -eq 0 ] || exit 1
258 # First, setup basic platform-independent directory structure
259 mkdir -p bin dev etc lib sbin var/empty var/run "$jailreporoot"
260 chmod 0555 var/empty
261 rm -rf usr local
262 ln -s . usr
263 ln -s . local
265 # Now source the platform-specific script that is responsible for dev device
266 # setup, proc setup (if needed), lib64 setup (if needed) and basic library
267 # installation to make a chroot operational. Additionally it will define a
268 # pull_in_bin function that can be used to add executables and their library
269 # dependencies to the chroot and finally will install a suitable nc.openbsd
270 # compatible version of netcat that supports connections to unix sockets.
271 . "$chrootsetup"
273 # Now, bring in sshd, sh etc.
274 # The $chrootsetup script should have already provided a suitable nc.openbsd
275 install -p "$cfg_basedir/bin/git-shell-verify" bin/git-shell-verify.new
276 install -p "$cfg_basedir/bin/git-askpass-password" bin/git-askpass-password.new
277 perl -i -p \
278 -e 's|^#!.*|#!/bin/sh| if $. == 1;' \
279 -e 'close ARGV if eof;' \
280 bin/git-shell-verify.new bin/git-askpass-password.new
281 mv -f bin/git-askpass-password.new bin/git-askpass-password
282 mv -f bin/git-shell-verify.new bin/git-shell-verify
283 pull_in_bin "$cfg_basedir/bin/can_user_push" bin
284 pull_in_bin "$cfg_basedir/bin/list_packs" bin
285 pull_in_bin "${cfg_posix_sh_bin:-/bin/sh}" bin/sh
286 pull_in_bin /bin/chmod bin
287 pull_in_bin /bin/date bin
288 pull_in_bin /bin/mv bin
289 pull_in_bin /bin/rm bin
290 pull_in_bin /usr/bin/find bin
291 pull_in_bin /usr/bin/touch bin
292 pull_in_bin /usr/bin/xargs bin
293 pull_in_bin /usr/sbin/sshd sbin
295 # ...and the bits of git we need,
296 # being sure to use the configured git and its --exec-path to find the pieces
297 for i in git git-index-pack git-receive-pack git-shell git-update-server-info git-upload-archive \
298 git-upload-pack git-unpack-objects git-config git-for-each-ref git-rev-list; do
299 pull_in_bin "$var_git_exec_path/$i" bin git
300 done
302 # Note time of last jailsetup
303 > etc/sshactive/_jailsetup
305 # Update permissions on the database files
306 chown $cfg_cgi_user:$cfg_owning_group etc/passwd etc/group
307 chown -R $cfg_cgi_user:$cfg_owning_group etc/sshkeys etc/sshcerts etc/sshactive
308 chown $cfg_mirror_user:$cfg_owning_group etc etc/girocco etc/girocco/.gitconfig
310 # Set up basic sshd configuration:
311 if [ -n "$nosshdir" ]; then
312 rm -rf etc/ssh
313 ln -s . etc/ssh
314 [ ! -f /etc/moduli ] || { cp -p /etc/moduli etc/; chown 0:0 etc/moduli; }
315 else
316 [ ! -e etc/ssh -o -d etc/ssh ] || rm -rf etc/ssh
317 mkdir -p etc/ssh
318 [ ! -f /etc/ssh/moduli ] || { cp -p /etc/ssh/moduli etc/ssh/; chown 0:0 etc/ssh/moduli; }
320 mkdir -p var/run/sshd
321 if [ ! -s etc/ssh/sshd_config ]; then
322 cat >etc/ssh/sshd_config <<EOT
323 Protocol 2
324 Port $cfg_sshd_jail_port
325 UsePAM no
326 X11Forwarding no
327 AllowAgentForwarding no
328 AllowTcpForwarding no
329 PermitTunnel no
330 IgnoreUserKnownHosts yes
331 PrintLastLog no
332 PrintMotd no
333 UseDNS no
334 PermitRootLogin no
335 UsePrivilegeSeparation yes
337 HostKey /etc/ssh/ssh_host_rsa_key
339 if [ -z "$cfg_disable_dsa" ]; then
340 cat >>etc/ssh/sshd_config <<EOT
341 HostKey /etc/ssh/ssh_host_dsa_key
344 cat >>etc/ssh/sshd_config <<EOT
345 AuthorizedKeysFile /etc/sshkeys/%u
346 StrictModes no
348 # mob user:
349 PermitEmptyPasswords yes
350 ChallengeResponseAuthentication no
351 PasswordAuthentication yes
354 if [ ! -s etc/ssh/ssh_host_rsa_key ]; then
355 bits=2048
356 if [ "$cfg_rsakeylength" -gt "$bits" ] 2>/dev/null; then
357 bits="$cfg_rsakeylength"
359 yes | ssh-keygen -b "$bits" -t rsa -N "" -C Girocco -f etc/ssh/ssh_host_rsa_key
361 if [ -z "$cfg_disable_dsa" -a ! -s etc/ssh/ssh_host_dsa_key ]; then
362 # ssh-keygen can only create 1024 bit DSA keys
363 yes | ssh-keygen -b 1024 -t dsa -N "" -C Girocco -f etc/ssh/ssh_host_dsa_key
366 # Set the final permissions on the binaries and perform any final twiddling
367 chroot_update_permissions
369 # Change the owner of the sshd-related files
370 chown 0:0 etc/ssh/ssh_* etc/ssh/sshd_*
372 echo "--- Add to your boot scripts: mount --bind $reporoot $chroot/$jailreporoot"
373 echo "--- Add to your boot scripts: mount --bind /proc $chroot/proc"
374 echo "--- Add to your syslog configuration: listening on socket $chroot/dev/log"
375 echo "--- To restart a running jail's sshd: sudo kill -HUP \`cat $chroot/var/run/sshd.pid\`"