project-disk-use: included binned use
[girocco.git] / jailsetup.sh
blobcceaa860e31e3792f173ebea5a795727ba2d8efa
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 -R g+w etc/sshkeys etc/sshcerts etc/sshactive 2>/dev/null ||
134 echo "WARNING: Cannot chmod g+w the sshkeys, sshcerts and/or sshactive files"
136 # Note time of last install
137 > etc/sshactive/_install
139 [ -z "$dbonly" ] || exit 0
141 # Make sure the system type is supported for chroot
142 sysname="$(uname -s | tr A-Z a-z || :)"
143 : ${sysname:=linux}
144 nosshdir=
145 # These equivalents may need to be expanded at some point
146 case "$sysname" in
147 *kfreebsd*)
148 sysname=linux;;
149 *darwin*)
150 sysname=darwin;;
151 *freebsd*)
152 sysname=freebsd;;
153 *linux*)
154 sysname=linux;;
155 esac
157 chrootsetup="$curdir/chrootsetup_$sysname.sh"
158 if ! [ -r "$chrootsetup" -a -s "$chrootsetup" ]; then
159 echo "*** Error: $chrootsetup not found" >&2
160 echo "*** Error: creating a chroot for a `uname -s` system is not supported" >&2
161 exit 1
164 # validate reporoot, chroot and jailreporoot before doing anything more
166 # validates the passed in dir if a second argument is not empty dir must NOT
167 # start with / otherwise it must. A trailing '/' is removed and any duplicated
168 # // are removed and a sole / or empty is disallowed.
169 make_valid_dir() {
170 _check="$(echo "$1" | tr -s /)"
171 _check="${_check%/}"
172 [ -z "$_check" -o "$_check" = "/" ] && return 1
173 if [ -z "$2" ]; then
174 # must start with '/'
175 case "$_check" in /*) :;; *) return 1; esac
176 else
177 # must NOT start with '/'
178 case "$_check" in /*) return 1; esac
180 echo "$_check"
183 if ! reporoot="$(make_valid_dir "$cfg_reporoot")"; then
184 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
185 echo "*** Error: MUST start with '/' and MUST NOT be '/'" >&2
186 exit 1
188 if ! chroot="$(make_valid_dir "$cfg_chroot")"; then
189 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
190 echo "*** Error: MUST start with '/' and MUST NOT be '/'" >&2
191 exit 1
193 if ! jailreporoot="$(make_valid_dir "$cfg_jailreporoot" 1)"; then
194 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
195 echo "*** Error: MUST NOT start with '/' and MUST NOT be ''" >&2
196 exit 1
199 # chroot MUST NOT be reporoot
200 if [ "$chroot" = "$reporoot" ]; then
201 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
202 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
203 echo "*** Error: reporoot and chroot MUST NOT be the same" >&2
204 exit 1
207 # chroot MUST NOT be a subdirectory of reporoot
208 case "$chroot" in "$reporoot"/*)
209 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
210 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
211 echo "*** Error: chroot MUST NOT be a subdirectory of reporoot" >&2
212 exit 1
213 esac
215 # chroot/jailreporoot MUST NOT be a subdirectory of reporoot
216 case "$chroot/$jailreporoot" in "$reporoot"/*)
217 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
218 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
219 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
220 echo "*** Error: chroot/jailreporoot MUST NOT be a subdirectory of reporoot" >&2
221 exit 1
222 esac
224 # reporoot MUST NOT be a subdirectory of chroot/jailreporoot
225 case "$reporoot" in "$chroot/$jailreporoot"/*)
226 echo "*** Error: invalid Config::reporoot: $cfg_reporoot" >&2
227 echo "*** Error: invalid Config::chroot: $cfg_chroot" >&2
228 echo "*** Error: invalid Config::jailreporoot: $cfg_jailreporoot" >&2
229 echo "*** Error: reporoot MUST NOT be a subdirectory of chroot/jailreporoot" >&2
230 exit 1
231 esac
233 # Set the user and group on the top of the chroot before creating anything else
234 chown 0:0 "$chroot"
236 # When we create a fork, the alternates always have an absolute path.
237 # If reporoot is not --bind mounted at the same location in chroot we must
238 # create a suitable symlink so the absolute path alternates continue to work
239 # in the ssh chroot or else forks will be broken in there.
240 if [ "$reporoot" != "/$jailreporoot" ]; then
241 mkdirp="$(dirname "${reporoot#/}")"
242 [ "$mkdirp" = "." ] && mkdirp=
243 lnback=
244 [ -z "$mkdirp" ] || lnback="$(echo "$mkdirp/" | sed -e 's,[^/]*/,../,g')"
245 [ -z "$mkdirp" ] || mkdir -p "$chroot/$mkdirp"
246 (umask 0; ln -s -f -n "$lnback$jailreporoot" "$chroot$reporoot")
247 [ $? -eq 0 ] || exit 1
250 # First, setup basic platform-independent directory structure
251 mkdir -p bin dev etc lib sbin var/empty var/run "$jailreporoot"
252 chmod 0444 var/empty
253 rm -rf usr
254 ln -s . usr
256 # Now source the platform-specific script that is responsible for dev device
257 # setup, proc setup (if needed), lib64 setup (if needed) and basic library
258 # installation to make a chroot operational. Additionally it will define a
259 # pull_in_bin function that can be used to add executables and their library
260 # dependencies to the chroot and finally will install a suitable nc.openbsd
261 # compatible version of netcat that supports connections to unix sockets.
262 . "$chrootsetup"
264 # Now, bring in sshd, sh etc.
265 # The $chrootsetup script should have already provided a suitable nc.openbsd
266 install -p "$cfg_basedir/bin/git-shell-verify" bin
267 pull_in_bin "$cfg_basedir/bin/can_user_push" bin
268 pull_in_bin /bin/sh bin
269 pull_in_bin /bin/date bin
270 pull_in_bin /bin/mv bin
271 pull_in_bin /bin/rm bin
272 pull_in_bin /usr/sbin/sshd sbin
274 # ...and the bits of git we need,
275 # being sure to use the configured git and its --exec-path to find the pieces
276 git_exec_path="$("$cfg_git_bin" --exec-path)"
277 for i in git git-index-pack git-receive-pack git-shell git-update-server-info git-upload-archive \
278 git-upload-pack git-unpack-objects git-show-ref git-config git-for-each-ref git-rev-list; do
279 pull_in_bin "$git_exec_path/$i" bin git
280 done
282 # Note time of last jailsetup
283 > etc/sshactive/_jailsetup
285 # Update permissions on the database files
286 chown $cfg_cgi_user:$cfg_owning_group etc/passwd etc/group
287 chown -R $cfg_cgi_user:$cfg_owning_group etc/sshkeys etc/sshcerts etc/sshactive
288 chown $cfg_mirror_user:$cfg_owning_group etc etc/girocco etc/girocco/.gitconfig
290 # Set up basic sshd configuration:
291 if [ -n "$nosshdir" ]; then
292 rm -rf etc/ssh
293 ln -s . etc/ssh
294 [ ! -f /etc/moduli ] || { cp -p /etc/moduli etc/; chown 0:0 etc/moduli; }
295 else
296 [ ! -e etc/ssh -o -d etc/ssh ] || rm -rf etc/ssh
297 mkdir -p etc/ssh
298 [ ! -f /etc/ssh/moduli ] || { cp -p /etc/ssh/moduli etc/ssh/; chown 0:0 etc/ssh/moduli; }
300 mkdir -p var/run/sshd
301 if [ ! -s etc/ssh/sshd_config ]; then
302 cat >etc/ssh/sshd_config <<EOT
303 Protocol 2
304 Port $cfg_sshd_jail_port
305 UsePAM no
306 X11Forwarding no
307 AllowAgentForwarding no
308 AllowTcpForwarding no
309 PermitTunnel no
310 IgnoreUserKnownHosts yes
311 PrintLastLog no
312 PrintMotd no
313 UseDNS no
314 PermitRootLogin no
315 UsePrivilegeSeparation yes
317 HostKey /etc/ssh/ssh_host_rsa_key
319 if [ -z "$cfg_disable_dsa" ]; then
320 cat >>etc/ssh/sshd_config <<EOT
321 HostKey /etc/ssh/ssh_host_dsa_key
324 cat >>etc/ssh/sshd_config <<EOT
325 AuthorizedKeysFile /etc/sshkeys/%u
326 StrictModes no
328 # mob user:
329 PermitEmptyPasswords yes
330 ChallengeResponseAuthentication no
331 PasswordAuthentication yes
334 if [ ! -s etc/ssh/ssh_host_rsa_key ]; then
335 bits=2048
336 if [ "$cfg_rsakeylength" -gt "$bits" ] 2>/dev/null; then
337 bits="$cfg_rsakeylength"
339 yes | ssh-keygen -b "$bits" -t rsa -N "" -C Girocco -f etc/ssh/ssh_host_rsa_key
341 if [ -z "$cfg_disable_dsa" -a ! -s etc/ssh/ssh_host_dsa_key ]; then
342 # ssh-keygen can only create 1024 bit DSA keys
343 yes | ssh-keygen -b 1024 -t dsa -N "" -C Girocco -f etc/ssh/ssh_host_dsa_key
346 # Set the final permissions on the binaries and perform any final twiddling
347 chroot_update_permissions
349 # Change the owner of the sshd-related files
350 chown 0:0 etc/ssh/ssh_* etc/ssh/sshd_*
352 echo "--- Add to your boot scripts: mount --bind $reporoot $chroot/$jailreporoot"
353 echo "--- Add to your boot scripts: mount --bind /proc $chroot/proc"
354 echo "--- Add to your syslog configuration: listening on socket $chroot/dev/log"
355 echo "--- To restart a running jail's sshd: sudo kill -HUP \`cat $chroot/var/run/sshd.pid\`"