3 # (c) Copyright by Wolfgang Fuschlberger
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 # ( http://www.fsf.org/licenses/gpl.txt )
16 # first Release: 2004-07-30
17 # latest update: 2007-02-24
19 # The latest version of the script is available at
20 # http://www.fuschlberger.net/programs/ssh-scp-chroot-jail/
22 # Feedback is welcome!
24 # Thanks for Bugfixes / Enhancements to
25 # Michael Prokop <http://www.michael-prokop.at/chroot/>,
26 # Randy K., Randy D. and Jonathan Hunter.
30 # - enable scp and sftp in the chroot-jail
31 # - use one directory (default /home/jail/) as chroot for all users
32 # - create new accounts
33 # - move existing accounts to chroot
34 ################################################################################
36 # Check if we are called with username or update
39 echo "Error: Parameter missing. Did you forget the username?"
40 echo "-------------------------------------------------------------"
41 echo "Creating new chrooted account:"
42 echo "Usage: $0 username"
44 echo "or specify \$SHELL and path where the jail should be located:"
45 echo "Usage: $0 username [/path/to/chroot-shell [/path/to/jail]]"
46 echo "Default shell = /bin/chroot-shell"
47 echo "Default chroot-path = /home/jail"
48 echo "-------------------------------------------------------------"
49 echo "Updating files in the chroot-jail:"
50 echo "Usage: $0 update [/path/to/chroot-shell [/path/to/jail]]"
51 echo "-------------------------------------------------------------"
52 echo "To uninstall: # userdel \$USER"
53 echo " # rm -rf /home/jail"
54 echo " # rm -f /bin/chroot-shell"
55 echo " delete the User's line from /etc/sudoers"
60 if [ "$(whoami &2>/dev/null)" != "root" ] && [ "$(id -un &2>/dev/null)" != "root" ] ; then
63 Error: You must be root to run this script."
68 # Check existence of necessary files
69 echo "Checking distribution... "
70 if [ -f /etc/debian_version ];
71 then echo " Supported Distribution found"
72 echo " System is running Debian Linux"
74 elif [ -f /etc/SuSE-release ];
75 then echo " Supported Distribution found"
76 echo " System is running SuSE Linux"
78 elif [ -f /etc/fedora-release ];
79 then echo " Supported Distribution found"
80 echo " System is running Fedora Linux"
82 elif [ -f /etc/redhat-release ];
83 then echo " Supported Distribution found"
84 echo " System is running Red Hat Linux"
86 else echo -e " failed...........\nThis script works best on Debian, Red Hat, Fedora and SuSE Linux!\nLet's try it nevertheless....\nIf some program files cannot be found adjust the respective path in line 98\n"
90 # Specify the apps you want to copy to the jail
91 if [ "$DISTRO" = SUSE ]; then
92 APPS="/bin/bash /bin/cp /usr/bin/dircolors /bin/ls /bin/mkdir /bin/mv /bin/rm /bin/rmdir /bin/sh /bin/su /usr/bin/groups /usr/bin/id /usr/bin/netcat /usr/bin/rsync /usr/bin/ssh /usr/bin/scp /sbin/unix_chkpwd"
93 elif [ "$DISTRO" = FEDORA ]; then
94 APPS="/bin/bash /bin/cp /usr/bin/dircolors /bin/ls /bin/mkdir /bin/mv /bin/rm /bin/rmdir /bin/sh /bin/su /usr/bin/groups /usr/bin/id /usr/bin/nc /usr/bin/rsync /usr/bin/ssh /usr/bin/scp /sbin/unix_chkpwd"
95 elif [ "$DISTRO" = REDHAT ]; then
96 APPS="/bin/bash /bin/cp /usr/bin/dircolors /bin/ls /bin/mkdir /bin/mv /bin/rm /bin/rmdir /bin/sh /bin/su /usr/bin/groups /usr/bin/id /usr/bin/nc /usr/bin/rsync /usr/bin/ssh /usr/bin/scp /sbin/unix_chkpwd"
97 elif [ "$DISTRO" = DEBIAN ]; then
98 APPS="/bin/bash /bin/cp /usr/bin/dircolors /bin/ls /bin/mkdir /bin/mv /bin/rm /bin/rmdir /bin/sh /bin/su /usr/bin/groups /usr/bin/id /usr/bin/rsync /usr/bin/ssh /usr/bin/scp /sbin/unix_chkpwd"
100 APPS="/bin/bash /bin/cp /usr/bin/dircolors /bin/ls /bin/mkdir /bin/mv /bin/rm /bin/rmdir /bin/sh /bin/su /usr/bin/groups /usr/bin/id /usr/bin/rsync /usr/bin/ssh /usr/bin/scp /usr/sbin/unix_chkpwd"
103 # Check existence of necessary files
104 echo "Checking for which... "
105 if ( test -f /usr/bin/which ) || ( test -f /bin/which ) || ( test -f /sbin/which ) || ( test -f /usr/sbin/which );
109 Please install which-binary!
114 echo "Checking for chroot..."
115 if [ `which chroot` ];
120 Please install chroot-package/binary!
125 echo "Checking for sudo..."
126 if [ `which sudo` ]; then
132 Please install sudo-package/binary!
137 echo "Checking for dirname..."
138 if [ `which dirname` ]; then
144 Please install dirname-binary (to be found eg in the package coreutils)!
149 echo "Checking for awk..."
150 if [ `which awk` ]; then
157 Please install (g)awk-package/binary!
162 # get location of sftp-server binary from /etc/ssh/sshd_config
163 # check for existence of /etc/ssh/sshd_config and for
164 # (uncommented) line with sftp-server filename. If neither exists, just skip
165 # this step and continue without sftp-server
167 if (test ! -f /etc/ssh/sshd_config &> /dev/null); then
169 File /etc/ssh/sshd_config not found.
170 Not checking for path to sftp-server.
173 if !(grep -v "^#" /etc/ssh/sshd_config | grep -i sftp-server &> /dev/null); then
174 echo "Obviously no sftp-server is running on this system.
176 else SFTP_SERVER=$(grep -v "^#" /etc/ssh/sshd_config | grep -i sftp-server | awk '{ print $3}')
180 #if !(grep -v "^#" /etc/ssh/sshd_config | grep -i sftp-server /etc/ssh/sshd_config | awk '{ print $3}' &> /dev/null); then
181 APPS="$APPS $SFTP_SERVER"
183 # Get accountname to create
186 if ! [ -z "$2" ] ; then
189 SHELL=/bin/chroot-shell
192 if ! [ -z "$3" ] ; then
198 # Exit if user already exists
199 #id $CHROOT_USERNAME > /dev/null 2>&1 && { echo "User exists."; echo "Exiting."; exit 1; }
200 if ( id $CHROOT_USERNAME > /dev/null 2>&1 ) ; then {
202 -----------------------------
203 User $CHROOT_USERNAME exists.
205 Are you sure you want to modify the users home directory and lock him into the
208 Say only yes if you absolutely know what you are doing!"
209 read -p "(yes/no) -> " MODIFYUSER
210 if [ "$MODIFYUSER" != "yes" ]; then
212 Not entered yes. Exiting...."
220 # Create $SHELL (shell for jailed accounts)
221 if [ -f ${SHELL} ] ; then
223 -----------------------------
224 The file $SHELL exists.
225 Probably it was created by this script.
227 Are you sure you want to overwrite it?
228 (you want to say yes for example if you are running the script for the second
229 time when adding more than one account to the jail)"
230 read -p "(yes/no) -> " OVERWRITE
231 if [ "$OVERWRITE" != "yes" ]; then
233 Not entered yes. Exiting...."
237 echo "Creating $SHELL"
238 echo '#!/bin/sh' > $SHELL
239 echo "`which sudo` `which chroot` $JAILPATH /bin/su - \$USER" \"\$@\" >> $SHELL
243 # make common jail for everybody if inexistent
244 if [ ! -d ${JAILPATH} ] ; then
246 echo "Creating ${JAILPATH}"
250 # Create directories in jail that do not exist yet
251 JAILDIRS="dev etc etc/pam.d bin home sbin usr usr/bin usr/lib"
252 for directory in $JAILDIRS ; do
253 if [ ! -d "$JAILPATH/$directory" ] ; then
254 mkdir $JAILPATH/"$directory"
255 echo "Creating $JAILPATH/$directory"
260 # Comment in the following lines if your apache can't read the directories and
261 # uses the security contexts
262 # Fix security contexts so Apache can read files
263 #CHCON=$(`which chcon`)
264 #if [ -n "$CHCON" ] && [ -x $CHCON ]; then
265 # $CHCON -t home_root_t $JAILPATH/home
266 # $CHCON -t user_home_dir_t $JAILPATH/home/$CHROOT_USERNAME
269 # Creating necessary devices
270 [ -r $JAILPATH/dev/urandom ] || mknod $JAILPATH/dev/urandom c 1 9
271 [ -r $JAILPATH/dev/null ] || mknod -m 666 $JAILPATH/dev/null c 1 3
272 [ -r $JAILPATH/dev/zero ] || mknod -m 666 $JAILPATH/dev/zero c 1 5
273 [ -r $JAILPATH/dev/tty ] || mknod -m 666 $JAILPATH/dev/tty c 5 0
275 # if we only want to update the files in the jail
276 # skip the creation of the new account
277 if [ "$1" != "update" ]; then
279 # Modifiy /etc/sudoers to enable chroot-ing for users
280 # must be removed by hand if account is deleted
281 echo "Modifying /etc/sudoers"
282 echo "$CHROOT_USERNAME ALL=NOPASSWD: `which chroot`, /bin/su - $CHROOT_USERNAME" >> /etc/sudoers
284 # Define HomeDir for simple referencing
285 HOMEDIR="$JAILPATH/home/$CHROOT_USERNAME"
287 # Create new account, setting $SHELL to the above created script and
288 # $HOME to $JAILPATH/home/*
289 if [ "$CREATEUSER" != "yes" ] ; then echo "
290 Not creating new User account
291 Modifying User \"$CHROOT_USERNAME\"
292 Copying files in $CHROOT_USERNAME's \$HOME to \"$HOMEDIR\"
294 usermod -d "$HOMEDIR" -m -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
297 if [ "$CREATEUSER" = "yes" ] ; then {
298 echo "Adding User \"$CHROOT_USERNAME\" to system"
299 useradd -m -d "$HOMEDIR" -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
301 # Enter password for new account
302 if !(passwd $CHROOT_USERNAME);
303 then echo "Passwords are probably not the same, try again."
310 # Create /usr/bin/groups in the jail
311 echo "#!/bin/bash" > usr/bin/groups
312 echo "id -Gn" >> usr/bin/groups
313 chmod 755 usr/bin/groups
315 # Add users to etc/passwd
317 # check if file exists (ie we are not called for the first time)
318 # if yes skip root's entry and do not overwrite the file
319 if [ ! -f etc/passwd ] ; then
320 grep /etc/passwd -e "^root" > ${JAILPATH}/etc/passwd
322 if [ ! -f etc/group ] ; then
323 grep /etc/group -e "^root" > ${JAILPATH}/etc/group
324 # add the group for all users to etc/group (otherwise there is a nasty error
325 # message and probably because of that changing directories doesn't work with
327 grep /etc/group -e "^users" >> ${JAILPATH}/etc/group
330 # grep the username which was given to us from /etc/passwd and add it
331 # to ./etc/passwd replacing the $HOME with the directory as it will then
333 echo "Adding User $CHROOT_USERNAME to jail"
334 grep -e "^$CHROOT_USERNAME:" /etc/passwd | \
335 sed -e "s#$JAILPATH##" \
336 -e "s#$SHELL#/bin/bash#" >> ${JAILPATH}/etc/passwd
338 # if the system uses one account/one group we write the
339 # account's group to etc/group
340 grep -e "^$CHROOT_USERNAME:" /etc/group >> ${JAILPATH}/etc/group
342 # write the user's line from /etc/shadow to /home/jail/etc/shadow
343 grep -e "^$CHROOT_USERNAME:" /etc/shadow >> ${JAILPATH}/etc/shadow
344 chmod 600 ${JAILPATH}/etc/shadow
346 # endif for =! update
349 # Copy the apps and the related libs
350 echo "Copying necessary library-files to jail (may take some time)"
352 # The original code worked fine on RedHat 7.3, but did not on FC3.
353 # On FC3, when the 'ldd' is done, there is a 'linux-gate.so.1' that
354 # points to nothing (or a 90xb.....), and it also does not pick up
355 # some files that start with a '/'. To fix this, I am doing the ldd
356 # to a file called ldlist, then going back into the file and pulling
357 # out the libs that start with '/'
361 # The original code worked fine on 2.4 kernel systems. Kernel 2.6
362 # introduced an internal library called 'linux-gate.so.1'. This
363 # 'phantom' library caused non-critical errors to display during the
364 # copy since the file does not actually exist on the file system.
365 # To fix re-direct output of ldd to a file, parse the file and get
366 # library files that start with /
368 if [ -x ${HOME}/ldlist ]; then
369 mv ${HOME}/ldlist ${HOME}/ldlist.bak
371 if [ -x ${HOME}/lddlist2 ]; then
372 mv ${HOME}/lddlist2 ${HOME}/lddlist2.bak
377 # First of all, check that this application exists
379 # Check that the directory exists; create it if not.
380 app_path=`echo $app | sed -e 's#\(.\+\)/[^/]\+#\1#'`
381 if ! [ -d .$app_path ]; then
385 # If the files in the chroot are on the same file system as the
386 # original files you should be able to use hard links instead of
387 # copying the files, too. Symbolic links cannot be used, because the
388 # original files are outside the chroot.
391 # get list of necessary libraries
392 ldd $app >> ${HOME}/ldlist
396 # Clear out any old temporary file before we start
397 if [ -e ${HOME}/ldlist2 ]; then
400 for libs in `cat ${HOME}/ldlist`; do
401 frst_char="`echo $libs | cut -c1`"
402 if [ "$frst_char" = "/" ]; then
403 echo "$libs" >> ${HOME}/ldlist2
406 for lib in `cat ${HOME}/ldlist2`; do
407 mkdir -p .`dirname $lib` > /dev/null 2>&1
409 # If the files in the chroot are on the same file system as the original
410 # files you should be able to use hard links instead of copying the files,
411 # too. Symbolic links cannot be used, because the original files are
412 # outside the chroot.
417 # Now, cleanup the 2 files we created for the library list
419 /bin/rm -f ${HOME}/ldlist
420 /bin/rm -f ${HOME}/ldlist2
422 # Necessary files that are not listed by ldd.
424 # There might be errors because of files that do not exist but in the end it
425 # may work nevertheless (I added new file names at the end without deleting old
426 # ones for reasons of backward compatibility).
427 # So please test ssh/scp before reporting a bug.
428 if [ "$DISTRO" = SUSE ]; then
429 cp /lib/libnss_compat.so.2 /lib/libnss_files.so.2 /lib/libnss_dns.so.2 /lib/libxcrypt.so.1 ${JAILPATH}/lib/
430 elif [ "$DISTRO" = FEDORA ]; then
431 cp /lib/libnss_compat.so.2 /lib/libnsl.so.1 /lib/libnss_files.so.2 /lib/ld-linux.so.2 /lib/ld-ldb.so.3 /lib/ld-lsb.so.3 /lib/libnss_dns.so.2 /lib/libxcrypt.so.1 ${JAILPATH}/lib/
432 cp /lib/*.* ${JAILPATH}/lib/
433 cp /usr/lib/libcrack.so.2 ${JAILPATH}/usr/lib/
434 elif [ "$DISTRO" = REDHAT ]; then
435 cp /lib/libnss_compat.so.2 /lib/libnsl.so.1 /lib/libnss_files.so.2 /lib/ld-linux.so.2 /lib/ld-lsb.so.1 /lib/libnss_dns.so.2 /lib/libxcrypt.so.1 ${JAILPATH}/lib/
436 # needed for scp on RHEL
437 echo "export LD_LIBRARY_PATH=/usr/kerberos/lib" >> ${JAILPATH}/etc/profile
438 elif [ "$DISTRO" = DEBIAN ]; then
439 cp /lib/libnss_compat.so.2 /lib/libnsl.so.1 /lib/libnss_files.so.2 /lib/libcap.so.1 /lib/libnss_dns.so.2 ${JAILPATH}/lib/
441 cp /lib/libnss_compat.so.2 /lib/libnsl.so.1 /lib/libnss_files.so.2 /lib/libcap.so.1 /lib/libnss_dns.so.2 ${JAILPATH}/lib/
444 # if you are using a 64 bit system and have strange problems with login comment
445 # the following lines in, perhaps it works then (motto: if you can't find the
446 # needed library just copy all of them)
448 #cp /lib/*.* ${JAILPATH}/lib/
449 #cp /lib/lib64/*.* ${JAILPATH}/lib/lib64/
451 # if you are using PAM you need stuff from /etc/pam.d/ in the jail,
452 echo "Copying files from /etc/pam.d/ to jail"
453 cp /etc/pam.d/* ${JAILPATH}/etc/pam.d/
455 # ...and of course the PAM-modules...
456 echo "Copying PAM-Modules to jail"
457 cp -r /lib/security ${JAILPATH}/lib/
459 # ...and something else useful for PAM
460 cp -r /etc/security ${JAILPATH}/etc/
461 cp /etc/login.defs ${JAILPATH}/etc/
463 if [ -f /etc/DIR_COLORS ] ; then
464 cp /etc/DIR_COLORS ${JAILPATH}/etc/
467 # Don't give more permissions than necessary
468 chown root.root ${JAILPATH}/bin/su
469 chmod 700 ${JAILPATH}/bin/su