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.
16 getent
="$srcdir/getent"
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"
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"
34 echo "*** Error: You do not have required sshd or _sshd user in system." >&2
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
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
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
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
65 mkdir
-p "$cfg_chroot"
67 chmod 755 "$cfg_chroot" ||
68 echo "WARNING: Cannot chmod $cfg_chroot"
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
76 [ -n "$cfg_mob" ] || mobpass
='x'
78 if [ ! -s etc
/passwd
]; then
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
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
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
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
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
103 if [ ! -s etc
/group
]; then
105 _repo:x:$("$getent" group "$cfg_owning_group" | cut -d : -f 3):$cfg_mirror_user
109 # Set up basic default Git configuration
110 # Initialize one if none exists or update critical variables for an existing one
113 if [ -e etc
/girocco
/.gitconfig
] && ! [ -f etc
/girocco
/.gitconfig
]; then
114 echo "*** Error: chroot etc/girocco/.gitconfig exists but is not a file." >&2
117 if [ -f etc
/girocco
/.gitconfig
]; then
119 x
="$(git config --file etc/girocco/.gitconfig --get "no--such--section.no such subsection.no--such--key
")" || gcerr
=$?
120 if [ $gcerr -gt 1 ]; then
121 echo "*** Error: chroot etc/girocco/.gitconfig exists but is corrupt." >&2
122 echo "*** Error: either remove it or edit it to correct the problem." >&2
126 if [ ! -s etc
/girocco
/.gitconfig
]; then
127 chmod u
+w etc
/girocco
129 cat >etc
/girocco
/.gitconfig
<<EOT
130 # Any values set here will take effect whenever Girocco runs a git command
134 # $1 => name, $2 => value, $3 => overwrite_flag
135 update_config_item
() {
138 _oldval
="$(git config --file etc/girocco/.gitconfig --get "$1")" || _existsnot
=1
139 if [ -z "$_existsnot" ]; then
140 [ -n "$3" ] ||
return 0
141 [ "$_oldval" != "$2" ] ||
return 0
143 [ -n "$didchmod" ] ||
{ chmod u
+w etc
/girocco
; didchmod
=1; }
144 git config
--file etc
/girocco
/.gitconfig
"$1" "$2"
145 if [ -n "$_existsnot" ]; then
146 echo "chroot: etc/girocco/.gitconfig: config $1: (created) \"$2\""
148 echo "chroot: etc/girocco/.gitconfig: config $1: \"$_oldval\" -> \"$2\""
151 if [ -n "$cfg_git_no_mmap" ]; then
152 update_config_item core.packedGitWindowSize
1m
1
154 update_config_item core.packedGitWindowSize
32m
1
156 if [ -n "$var_window_memory" ]; then
157 update_config_item pack.windowMemory
"$var_window_memory" 1
159 if [ -n "$cfg_jgit_compatible_bitmaps" ]; then
160 update_config_item pack.writeBitmapHashCache false
1
162 update_config_item pack.writeBitmapHashCache true
1
164 update_config_item http.lowSpeedLimit
1
165 update_config_item http.lowSpeedTime
600
166 [ -z "$didchmod" ] ||
chmod a-w etc
/girocco
168 mkdir
-p etc
/sshkeys etc
/sshcerts etc
/sshactive
169 for ruser
in $reserved_users; do
170 touch etc
/sshkeys
/$ruser
172 chgrp
$cfg_owning_group etc etc
/sshkeys etc
/sshcerts etc
/sshactive ||
173 echo "WARNING: Cannot chgrp $cfg_owning_group the etc directories"
174 chgrp
$cfg_owning_group etc
/passwd ||
175 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/passwd"
176 chgrp
$cfg_owning_group etc
/group ||
177 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/group"
178 chgrp
$cfg_owning_group etc
/girocco etc
/girocco
/.gitconfig ||
179 echo "WARNING: Cannot chgrp $cfg_owning_group $cfg_chroot/etc/girocco"
180 chmod g
+s etc etc
/sshkeys etc
/sshcerts etc
/sshactive ||
181 echo "WARNING: Cannot chmod g+s the etc directories"
182 chmod g
+w etc etc
/sshkeys etc
/sshcerts etc
/sshactive ||
183 echo "WARNING: Cannot chmod g+w the etc directories"
184 chmod g
+w etc
/passwd etc
/group ||
185 echo "WARNING: Cannot chmod g+w the etc/passwd and/or etc/group files"
186 chmod go-w etc
/passwd etc
/girocco etc
/girocco
/.gitconfig ||
187 echo "WARNING: Cannot chmod go-w etc/girocco and/or etc/girocco/.gitconfig"
188 chmod a-w etc
/girocco ||
189 echo "WARNING: Cannot chmod a-w etc/girocco"
190 chmod -R g
+w etc
/sshkeys etc
/sshcerts etc
/sshactive
2>/dev
/null ||
191 echo "WARNING: Cannot chmod g+w the sshkeys, sshcerts and/or sshactive files"
193 # Note time of last install
194 > etc
/sshactive
/_install
196 [ -z "$dbonly" ] ||
exit 0
198 # Make sure the system type is supported for chroot
199 sysname
="$(uname -s | tr A-Z a-z || :)"
202 # These equivalents may need to be expanded at some point
216 chrootsetup
="$curdir/chrootsetup_$sysname.sh"
217 if ! [ -r "$chrootsetup" -a -s "$chrootsetup" ]; then
218 echo "*** Error: $chrootsetup not found" >&2
219 echo "*** Error: creating a chroot for a `uname -s` system is not supported" >&2
223 # validate reporoot, chroot and jailreporoot before doing anything more
225 # validates the passed in dir if a second argument is not empty dir must NOT
226 # start with / otherwise it must. A trailing '/' is removed and any duplicated
227 # // are removed and a sole / or empty is disallowed.
229 _check
="$(echo "$1" | tr -s /)"
231 [ -z "$_check" -o "$_check" = "/" ] && return 1
233 # must start with '/'
234 case "$_check" in /*) :;; *) return 1; esac
236 # must NOT start with '/'
237 case "$_check" in /*) return 1; esac
242 if ! reporoot
="$(make_valid_dir "$cfg_reporoot")"; then
243 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
244 echo "*** Error: MUST start with '/' and MUST NOT be '/'" >&2
247 if ! chroot
="$(make_valid_dir "$cfg_chroot")"; then
248 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
249 echo "*** Error: MUST start with '/' and MUST NOT be '/'" >&2
252 if ! jailreporoot
="$(make_valid_dir "$cfg_jailreporoot" 1)"; then
253 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
254 echo "*** Error: MUST NOT start with '/' and MUST NOT be ''" >&2
258 # chroot MUST NOT be reporoot
259 if [ "$chroot" = "$reporoot" ]; then
260 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
261 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
262 echo "*** Error: reporoot and chroot MUST NOT be the same" >&2
266 # chroot MUST NOT be a subdirectory of reporoot
267 case "$chroot" in "$reporoot"/*)
268 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
269 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
270 echo "*** Error: chroot MUST NOT be a subdirectory of reporoot" >&2
274 # chroot/jailreporoot MUST NOT be a subdirectory of reporoot
275 case "$chroot/$jailreporoot" in "$reporoot"/*)
276 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
277 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
278 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
279 echo "*** Error: chroot/jailreporoot MUST NOT be a subdirectory of reporoot" >&2
283 # reporoot MUST NOT be a subdirectory of chroot/jailreporoot
284 case "$reporoot" in "$chroot/$jailreporoot"/*)
285 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
286 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
287 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
288 echo "*** Error: reporoot MUST NOT be a subdirectory of chroot/jailreporoot" >&2
292 # Set the user and group on the top of the chroot before creating anything else
295 # When we create a fork, the alternates always have an absolute path.
296 # If reporoot is not --bind mounted at the same location in chroot we must
297 # create a suitable symlink so the absolute path alternates continue to work
298 # in the ssh chroot or else forks will be broken in there.
299 if [ "$reporoot" != "/$jailreporoot" ]; then
300 mkdirp
="$(dirname "${reporoot#/}")"
301 [ "$mkdirp" = "." ] && mkdirp
=
303 [ -z "$mkdirp" ] || lnback
="$(echo "$mkdirp/" | sed -e 's,[^/]*/,../,g')"
304 [ -z "$mkdirp" ] || mkdir
-p "$chroot/$mkdirp"
305 (umask 0; ln -s -f -n "$lnback$jailreporoot" "$chroot$reporoot")
306 [ $?
-eq 0 ] ||
exit 1
309 # First, setup basic platform-independent directory structure
310 mkdir
-p bin dev etc lib sbin var
/empty var
/run
"$jailreporoot"
316 # Now source the platform-specific script that is responsible for dev device
317 # setup, proc setup (if needed), lib64 setup (if needed) and basic library
318 # installation to make a chroot operational. Additionally it will define a
319 # pull_in_bin function that can be used to add executables and their library
320 # dependencies to the chroot and finally will install a suitable nc.openbsd
321 # compatible version of netcat that supports connections to unix sockets.
324 # Now, bring in sshd, sh etc.
325 # The $chrootsetup script should have already provided a suitable nc.openbsd
326 install -p "$cfg_basedir/bin/git-shell-verify" bin
/git-shell-verify.new
327 install -p "$cfg_basedir/bin/git-askpass-password" bin
/git-askpass-password.new
329 -e 's|^#!.*|#!/bin/sh| if $. == 1;' \
330 -e 'close ARGV if eof;' \
331 bin
/git-shell-verify.new bin
/git-askpass-password.new
332 mv -f bin
/git-askpass-password.new bin
/git-askpass-password
333 mv -f bin
/git-shell-verify.new bin
/git-shell-verify
334 pull_in_bin
"$cfg_basedir/bin/can_user_push" bin
335 pull_in_bin
"$cfg_basedir/bin/list_packs" bin
336 pull_in_bin
"$var_sh_bin" bin
/sh
337 pull_in_bin
/bin
/chmod bin
338 pull_in_bin
/bin
/date bin
339 pull_in_bin
/bin
/mkdir bin
340 pull_in_bin
/bin
/mv bin
341 pull_in_bin
/bin
/rm bin
342 pull_in_bin
/bin
/sleep bin
343 pull_in_bin
/usr
/bin
/find bin
344 pull_in_bin
/usr
/bin
/touch bin
345 pull_in_bin
/usr
/bin
/wc bin
346 pull_in_bin
/usr
/bin
/xargs bin
347 pull_in_bin
/usr
/sbin
/sshd sbin
349 # ...and the bits of git we need,
350 # being sure to use the configured git and its --exec-path to find the pieces
351 for i
in git git-index-pack git-receive-pack git-shell git-update-server-info git-upload-archive \
352 git-upload-pack git-unpack-objects git-config git-for-each-ref git-rev-list
; do
353 pull_in_bin
"$var_git_exec_path/$i" bin git
356 # Note time of last jailsetup
357 > etc
/sshactive
/_jailsetup
359 # Update permissions on the database files
360 chown
$cfg_cgi_user:$cfg_owning_group etc
/passwd etc
/group
361 chown
-R $cfg_cgi_user:$cfg_owning_group etc
/sshkeys etc
/sshcerts etc
/sshactive
362 chown
$cfg_mirror_user:$cfg_owning_group etc etc
/girocco etc
/girocco
/.gitconfig
364 # Set up basic sshd configuration:
365 if [ -n "$nosshdir" ]; then
368 [ ! -f /etc
/moduli
] ||
{ cp -p /etc
/moduli etc
/; chown
0:0 etc
/moduli
; }
370 [ ! -e etc
/ssh -o -d etc
/ssh ] ||
rm -rf etc
/ssh
372 [ ! -f /etc
/ssh
/moduli
] ||
{ cp -p /etc
/ssh
/moduli etc
/ssh
/; chown
0:0 etc
/ssh
/moduli
; }
374 mkdir
-p var
/run
/sshd
375 if [ ! -s etc
/ssh
/sshd_config
]; then
376 cat >etc
/ssh
/sshd_config
<<EOT
378 Port $cfg_sshd_jail_port
381 AllowAgentForwarding no
382 AllowTcpForwarding no
384 IgnoreUserKnownHosts yes
389 UsePrivilegeSeparation yes
391 HostKey /etc/ssh/ssh_host_rsa_key
393 if [ -z "$cfg_disable_dsa" ]; then
394 cat >>etc
/ssh
/sshd_config
<<EOT
395 HostKey /etc/ssh/ssh_host_dsa_key
398 cat >>etc
/ssh
/sshd_config
<<EOT
399 AuthorizedKeysFile /etc/sshkeys/%u
403 PermitEmptyPasswords yes
404 ChallengeResponseAuthentication no
405 PasswordAuthentication yes
408 if [ ! -s etc
/ssh
/ssh_host_rsa_key
]; then
410 if [ "$cfg_rsakeylength" -gt "$bits" ] 2>/dev
/null
; then
411 bits
="$cfg_rsakeylength"
413 yes | ssh-keygen
-b "$bits" -t rsa
-N "" -C Girocco
-f etc
/ssh
/ssh_host_rsa_key
415 if [ -z "$cfg_disable_dsa" -a ! -s etc
/ssh
/ssh_host_dsa_key
]; then
416 # ssh-keygen can only create 1024 bit DSA keys
417 yes | ssh-keygen
-b 1024 -t dsa
-N "" -C Girocco
-f etc
/ssh
/ssh_host_dsa_key
420 # Set the final permissions on the binaries and perform any final twiddling
421 chroot_update_permissions
423 # Change the owner of the sshd-related files
424 chown
0:0 etc
/ssh
/ssh_
* etc
/ssh
/sshd_
*
426 echo "--- Add to your boot scripts: mount --bind $reporoot $chroot/$jailreporoot"
427 echo "--- Add to your boot scripts: mount --bind /proc $chroot/proc"
428 echo "--- Add to your syslog configuration: listening on socket $chroot/dev/log"
429 echo "--- To restart a running jail's sshd: sudo kill -HUP \`cat $chroot/var/run/sshd.pid\`"