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 2>&1); 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 2&1); 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 2&1); 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!
211 if [ "$MODIFYUSER" != "yes" ]; then
213 Not entered yes. Exiting...."
221 # Create $SHELL (shell for jailed accounts)
222 if [ -f ${SHELL} ] ; then
224 -----------------------------
225 The file $SHELL exists.
226 Probably it was created by this script.
228 Are you sure you want to overwrite it?
229 (you want to say yes for example if you are running the script for the second
230 time when adding more than one account to the jail)
233 if [ "$OVERWRITE" != "yes" ]; then
235 Not entered yes. Exiting...."
239 echo "Creating $SHELL"
240 echo '#!/bin/sh' > $SHELL
241 echo "`which sudo` `which chroot` $JAILPATH /bin/su - \$USER" \"\$@\" >> $SHELL
245 # make common jail for everybody if inexistent
246 if [ ! -d ${JAILPATH} ] ; then
248 echo "Creating ${JAILPATH}"
252 # Create directories in jail that do not exist yet
253 JAILDIRS="dev etc etc/pam.d bin home sbin usr usr/bin usr/lib"
254 for directory in $JAILDIRS ; do
255 if [ ! -d "$JAILPATH/$directory" ] ; then
256 mkdir $JAILPATH/"$directory"
257 echo "Creating $JAILPATH/$directory"
262 # Comment in the following lines if your apache can't read the directories and
263 # uses the security contexts
264 # Fix security contexts so Apache can read files
265 #CHCON=$(`which chcon`)
266 #if [ -n "$CHCON" ] && [ -x $CHCON ]; then
267 # $CHCON -t home_root_t $JAILPATH/home
268 # $CHCON -t user_home_dir_t $JAILPATH/home/$CHROOT_USERNAME
271 # Creating necessary devices
272 [ -r $JAILPATH/dev/urandom ] || mknod $JAILPATH/dev/urandom c 1 9
273 [ -r $JAILPATH/dev/null ] || mknod -m 666 $JAILPATH/dev/null c 1 3
274 [ -r $JAILPATH/dev/zero ] || mknod -m 666 $JAILPATH/dev/zero c 1 5
275 [ -r $JAILPATH/dev/tty ] || mknod -m 666 $JAILPATH/dev/tty c 5 0
277 # if we only want to update the files in the jail
278 # skip the creation of the new account
279 if [ "$1" != "update" ]; then
281 # Modifiy /etc/sudoers to enable chroot-ing for users
282 # must be removed by hand if account is deleted
283 echo "Modifying /etc/sudoers"
284 echo "$CHROOT_USERNAME ALL=NOPASSWD: `which chroot`, /bin/su - $CHROOT_USERNAME" >> /etc/sudoers
286 # Define HomeDir for simple referencing
287 HOMEDIR="$JAILPATH/home/$CHROOT_USERNAME"
289 # Create new account, setting $SHELL to the above created script and
290 # $HOME to $JAILPATH/home/*
291 if [ "$CREATEUSER" != "yes" ] ; then echo "
292 Not creating new User account
293 Modifying User \"$CHROOT_USERNAME\"
294 Copying files in $CHROOT_USERNAME's \$HOME to \"$HOMEDIR\"
296 usermod -d "$HOMEDIR" -m -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
299 if [ "$CREATEUSER" = "yes" ] ; then {
300 echo "Adding User \"$CHROOT_USERNAME\" to system"
301 useradd -m -d "$HOMEDIR" -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
303 # Enter password for new account
304 if !(passwd $CHROOT_USERNAME);
305 then echo "Passwords are probably not the same, try again."
312 # Create /usr/bin/groups in the jail
313 echo "#!/bin/bash" > usr/bin/groups
314 echo "id -Gn" >> usr/bin/groups
315 chmod 755 usr/bin/groups
317 # Add users to etc/passwd
319 # check if file exists (ie we are not called for the first time)
320 # if yes skip root's entry and do not overwrite the file
321 if [ ! -f etc/passwd ] ; then
322 grep /etc/passwd -e "^root" > ${JAILPATH}/etc/passwd
324 if [ ! -f etc/group ] ; then
325 grep /etc/group -e "^root" > ${JAILPATH}/etc/group
326 # add the group for all users to etc/group (otherwise there is a nasty error
327 # message and probably because of that changing directories doesn't work with
329 grep /etc/group -e "^users" >> ${JAILPATH}/etc/group
332 # grep the username which was given to us from /etc/passwd and add it
333 # to ./etc/passwd replacing the $HOME with the directory as it will then
335 echo "Adding User $CHROOT_USERNAME to jail"
336 grep -e "^$CHROOT_USERNAME:" /etc/passwd | \
337 sed -e "s#$JAILPATH##" \
338 -e "s#$SHELL#/bin/bash#" >> ${JAILPATH}/etc/passwd
340 # if the system uses one account/one group we write the
341 # account's group to etc/group
342 grep -e "^$CHROOT_USERNAME:" /etc/group >> ${JAILPATH}/etc/group
344 # write the user's line from /etc/shadow to /home/jail/etc/shadow
345 grep -e "^$CHROOT_USERNAME:" /etc/shadow >> ${JAILPATH}/etc/shadow
346 chmod 600 ${JAILPATH}/etc/shadow
348 # endif for =! update
351 # Copy the apps and the related libs
352 echo "Copying necessary library-files to jail (may take some time)"
354 # The original code worked fine on RedHat 7.3, but did not on FC3.
355 # On FC3, when the 'ldd' is done, there is a 'linux-gate.so.1' that
356 # points to nothing (or a 90xb.....), and it also does not pick up
357 # some files that start with a '/'. To fix this, I am doing the ldd
358 # to a file called ldlist, then going back into the file and pulling
359 # out the libs that start with '/'
363 # The original code worked fine on 2.4 kernel systems. Kernel 2.6
364 # introduced an internal library called 'linux-gate.so.1'. This
365 # 'phantom' library caused non-critical errors to display during the
366 # copy since the file does not actually exist on the file system.
367 # To fix re-direct output of ldd to a file, parse the file and get
368 # library files that start with /
370 if [ -x ${HOME}/ldlist ]; then
371 mv ${HOME}/ldlist ${HOME}/ldlist.bak
373 if [ -x ${HOME}/lddlist2 ]; then
374 mv ${HOME}/lddlist2 ${HOME}/lddlist2.bak
379 # First of all, check that this application exists
381 # Check that the directory exists; create it if not.
382 app_path=`echo $app | sed -e 's#\(.\+\)/[^/]\+#\1#'`
383 if ! [ -d .$app_path ]; then
387 # If the files in the chroot are on the same file system as the
388 # original files you should be able to use hard links instead of
389 # copying the files, too. Symbolic links cannot be used, because the
390 # original files are outside the chroot.
393 # get list of necessary libraries
394 ldd $app >> ${HOME}/ldlist
398 # Clear out any old temporary file before we start
399 if [ -e ${HOME}/ldlist2 ]; then
402 for libs in `cat ${HOME}/ldlist`; do
403 frst_char="`echo $libs | cut -c1`"
404 if [ "$frst_char" = "/" ]; then
405 echo "$libs" >> ${HOME}/ldlist2
408 for lib in `cat ${HOME}/ldlist2`; do
409 mkdir -p .`dirname $lib` > /dev/null 2>&1
411 # If the files in the chroot are on the same file system as the original
412 # files you should be able to use hard links instead of copying the files,
413 # too. Symbolic links cannot be used, because the original files are
414 # outside the chroot.
419 # Now, cleanup the 2 files we created for the library list
421 /bin/rm -f ${HOME}/ldlist
422 /bin/rm -f ${HOME}/ldlist2
424 # Necessary files that are not listed by ldd.
426 # There might be errors because of files that do not exist but in the end it
427 # may work nevertheless (I added new file names at the end without deleting old
428 # ones for reasons of backward compatibility).
429 # So please test ssh/scp before reporting a bug.
430 if [ "$DISTRO" = SUSE ]; then
431 cp /lib/libnss_compat.so.2 /lib/libnss_files.so.2 /lib/libnss_dns.so.2 /lib/libxcrypt.so.1 ${JAILPATH}/lib/
432 elif [ "$DISTRO" = FEDORA ]; then
433 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/
434 cp /lib/*.* ${JAILPATH}/lib/
435 cp /usr/lib/libcrack.so.2 ${JAILPATH}/usr/lib/
436 elif [ "$DISTRO" = REDHAT ]; then
437 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/
438 # needed for scp on RHEL
439 echo "export LD_LIBRARY_PATH=/usr/kerberos/lib" >> ${JAILPATH}/etc/profile
440 elif [ "$DISTRO" = DEBIAN ]; then
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/
443 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/
446 # if you are using a 64 bit system and have strange problems with login comment
447 # the following lines in, perhaps it works then (motto: if you can't find the
448 # needed library just copy all of them)
450 #cp /lib/*.* ${JAILPATH}/lib/
451 #cp /lib/lib64/*.* ${JAILPATH}/lib/lib64/
453 # if you are using PAM you need stuff from /etc/pam.d/ in the jail,
454 echo "Copying files from /etc/pam.d/ to jail"
455 cp /etc/pam.d/* ${JAILPATH}/etc/pam.d/
457 # ...and of course the PAM-modules...
458 echo "Copying PAM-Modules to jail"
459 cp -r /lib/security ${JAILPATH}/lib/
461 # ...and something else useful for PAM
462 cp -r /etc/security ${JAILPATH}/etc/
463 cp /etc/login.defs ${JAILPATH}/etc/
465 if [ -f /etc/DIR_COLORS ] ; then
466 cp /etc/DIR_COLORS ${JAILPATH}/etc/
469 # Don't give more permissions than necessary
470 chown root.root ${JAILPATH}/bin/su
471 chmod 700 ${JAILPATH}/bin/su