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-01-07
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 /usr/lib/ssh/sftp-server"
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 /usr/libexec/openssh/sftp-server"
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 /usr/libexec/openssh/sftp-server"
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 /usr/lib/sftp-server"
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 /usr/lib/misc/sftp-server"
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
145 Please install dirname-binary (to be found eg in the package coreutils)!
150 # Get accountname to create
153 if ! [ -z "$2" ] ; then
156 SHELL=/bin/chroot-shell
159 if ! [ -z "$3" ] ; then
165 # Exit if user already exists
166 #id $CHROOT_USERNAME > /dev/null 2>&1 && { echo "User exists."; echo "Exiting."; exit 1; }
167 if ( id $CHROOT_USERNAME > /dev/null 2>&1 ) ; then {
169 -----------------------------
170 User $CHROOT_USERNAME exists.
172 Are you sure you want to modify the users home directory and lock him into the
175 Say only yes if you absolutely know what you are doing!"
176 read -p "(yes/no) -> " MODIFYUSER
177 if [ "$MODIFYUSER" != "yes" ]; then
179 Not entered yes. Exiting...."
187 # Create $SHELL (shell for jailed accounts)
188 if [ -f ${SHELL} ] ; then
190 -----------------------------
191 The file $SHELL exists.
192 Probably it was created by this script.
194 Are you sure you want to overwrite it?
195 (you want to say yes for example if you are running the script for the second
196 time when adding more than one account to the jail)"
197 read -p "(yes/no) -> " OVERWRITE
198 if [ "$OVERWRITE" != "yes" ]; then
200 Not entered yes. Exiting...."
204 echo "Creating $SHELL"
205 echo '#!/bin/sh' > $SHELL
206 echo "`which sudo` `which chroot` $JAILPATH /bin/su - \$USER" \"\$@\" >> $SHELL
210 # make common jail for everybody if inexistent
211 if [ ! -d ${JAILPATH} ] ; then
213 echo "Creating ${JAILPATH}"
217 # Create directories in jail that do not exist yet
218 JAILDIRS="dev etc etc/pam.d bin home sbin usr usr/bin usr/lib"
219 for directory in $JAILDIRS ; do
220 if [ ! -d "$JAILPATH/$directory" ] ; then
221 mkdir $JAILPATH/"$directory"
222 echo "Creating $JAILPATH/$directory"
227 # Comment in the following lines if your apache can't read the directories and
228 # uses the security contexts
229 # Fix security contexts so Apache can read files
230 #CHCON=$(`which chcon`)
231 #if [ -n "$CHCON" ] && [ -x $CHCON ]; then
232 # $CHCON -t home_root_t $JAILPATH/home
233 # $CHCON -t user_home_dir_t $JAILPATH/home/$CHROOT_USERNAME
236 # Creating necessary devices
237 [ -r $JAILPATH/dev/urandom ] || mknod $JAILPATH/dev/urandom c 1 9
238 [ -r $JAILPATH/dev/null ] || mknod -m 666 $JAILPATH/dev/null c 1 3
239 [ -r $JAILPATH/dev/zero ] || mknod -m 666 $JAILPATH/dev/zero c 1 5
240 [ -r $JAILPATH/dev/tty ] || mknod -m 666 $JAILPATH/dev/tty c 5 0
242 # if we only want to update the files in the jail
243 # skip the creation of the new account
244 if [ "$1" != "update" ]; then
246 # Modifiy /etc/sudoers to enable chroot-ing for users
247 # must be removed by hand if account is deleted
248 echo "Modifying /etc/sudoers"
249 echo "$CHROOT_USERNAME ALL=NOPASSWD: `which chroot`, /bin/su - $CHROOT_USERNAME" >> /etc/sudoers
251 # Define HomeDir for simple referencing
252 HOMEDIR="$JAILPATH/home/$CHROOT_USERNAME"
254 # Create new account, setting $SHELL to the above created script and
255 # $HOME to $JAILPATH/home/*
256 if [ "$CREATEUSER" != "yes" ] ; then echo "
257 Not creating new User account
258 Modifying User \"$CHROOT_USERNAME\"
259 Copying files in $CHROOT_USERNAME's \$HOME to \"$HOMEDIR\"
261 usermod -d "$HOMEDIR" -m -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
264 if [ "$CREATEUSER" = "yes" ] ; then {
265 echo "Adding User \"$CHROOT_USERNAME\" to system"
266 useradd -m -d "$HOMEDIR" -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
268 # Enter password for new account
269 if !(passwd $CHROOT_USERNAME);
270 then echo "Passwords are probably not the same, try again."
277 # Create /usr/bin/groups in the jail
278 echo "#!/bin/bash" > usr/bin/groups
279 echo "id -Gn" >> usr/bin/groups
280 chmod 755 usr/bin/groups
282 # Add users to etc/passwd
284 # check if file exists (ie we are not called for the first time)
285 # if yes skip root's entry and do not overwrite the file
286 if [ ! -f etc/passwd ] ; then
287 grep /etc/passwd -e "^root" > ${JAILPATH}/etc/passwd
289 if [ ! -f etc/group ] ; then
290 grep /etc/group -e "^root" > ${JAILPATH}/etc/group
291 # add the group for all users to etc/group (otherwise there is a nasty error
292 # message and probably because of that changing directories doesn't work with
294 grep /etc/group -e "^users" >> ${JAILPATH}/etc/group
297 # grep the username which was given to us from /etc/passwd and add it
298 # to ./etc/passwd replacing the $HOME with the directory as it will then
300 echo "Adding User $CHROOT_USERNAME to jail"
301 grep -e "^$CHROOT_USERNAME:" /etc/passwd | \
302 sed -e "s#$JAILPATH##" \
303 -e "s#$SHELL#/bin/bash#" >> ${JAILPATH}/etc/passwd
305 # if the system uses one account/one group we write the
306 # account's group to etc/group
307 grep -e "^$CHROOT_USERNAME:" /etc/group >> ${JAILPATH}/etc/group
309 # write the user's line from /etc/shadow to /home/jail/etc/shadow
310 grep -e "^$CHROOT_USERNAME:" /etc/shadow >> ${JAILPATH}/etc/shadow
311 chmod 600 ${JAILPATH}/etc/shadow
313 # endif for =! update
316 # Copy the apps and the related libs
317 echo "Copying necessary library-files to jail (may take some time)"
319 # The original code worked fine on RedHat 7.3, but did not on FC3.
320 # On FC3, when the 'ldd' is done, there is a 'linux-gate.so.1' that
321 # points to nothing (or a 90xb.....), and it also does not pick up
322 # some files that start with a '/'. To fix this, I am doing the ldd
323 # to a file called ldlist, then going back into the file and pulling
324 # out the libs that start with '/'
328 # The original code worked fine on 2.4 kernel systems. Kernel 2.6
329 # introduced an internal library called 'linux-gate.so.1'. This
330 # 'phantom' library caused non-critical errors to display during the
331 # copy since the file does not actually exist on the file system.
332 # To fix re-direct output of ldd to a file, parse the file and get
333 # library files that start with /
335 if [ -x ${HOME}/ldlist ]; then
336 mv ${HOME}/ldlist ${HOME}/ldlist.bak
338 if [ -x ${HOME}/lddlist2 ]; then
339 mv ${HOME}/lddlist2 ${HOME}/lddlist2.bak
344 # First of all, check that this application exists
346 # Check that the directory exists; create it if not.
347 app_path=`echo $app | sed -e 's#\(.\+\)/[^/]\+#\1#'`
348 if ! [ -d .$app_path ]; then
352 # If the files in the chroot are on the same file system as the
353 # original files you should be able to use hard links instead of
354 # copying the files, too. Symbolic links cannot be used, because the
355 # original files are outside the chroot.
358 # get list of necessary libraries
359 ldd $app >> ${HOME}/ldlist
363 # Clear out any old temporary file before we start
364 if [ -e ${HOME}/ldlist2 ]; then
367 for libs in `cat /root/ldlist`; do
368 frst_char="`echo $libs | cut -c1`"
369 if [ "$frst_char" = "/" ]; then
370 echo "$libs" >> /root/ldlist2
373 for lib in `cat /root/ldlist2`; do
374 mkdir -p .`dirname $lib` > /dev/null 2>&1
376 # If the files in the chroot are on the same file system as the original
377 # files you should be able to use hard links instead of copying the files,
378 # too. Symbolic links cannot be used, because the original files are
379 # outside the chroot.
384 # Now, cleanup the 2 files we created for the library list
386 /bin/rm -f ${HOME}/ldlist
387 /bin/rm -f ${HOME}/ldlist2
389 # Necessary files that are not listed by ldd.
391 # There might be errors because of files that do not exist but in the end it
392 # may work nevertheless (I added new file names at the end without deleting old
393 # ones for reasons of backward compatibility).
394 # So please test ssh/scp before reporting a bug.
395 if [ "$DISTRO" = SUSE ]; then
396 cp /lib/libnss_compat.so.2 /lib/libnss_files.so.2 /lib/libnss_dns.so.2 /lib/libxcrypt.so.1 ${JAILPATH}/lib/
397 elif [ "$DISTRO" = FEDORA ]; then
398 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/
399 cp /lib/*.* ${JAILPATH}/lib/
400 cp /usr/lib/libcrack.so.2 ${JAILPATH}/usr/lib/
401 elif [ "$DISTRO" = REDHAT ]; then
402 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/
403 # needed for scp on RHEL
404 echo "export LD_LIBRARY_PATH=/usr/kerberos/lib" >> ${JAILPATH}/etc/profile
405 elif [ "$DISTRO" = DEBIAN ]; then
406 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/
408 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/
411 # if you are using a 64 bit system and have strange problems with login comment
412 # the following lines in, perhaps it works then (motto: if you can't find the
413 # needed library just copy all of them)
415 #cp /lib/*.* ${JAILPATH}/lib/
416 #cp /lib/lib64/*.* ${JAILPATH}/lib/lib64/
418 # if you are using PAM you need stuff from /etc/pam.d/ in the jail,
419 echo "Copying files from /etc/pam.d/ to jail"
420 cp /etc/pam.d/* ${JAILPATH}/etc/pam.d/
422 # ...and of course the PAM-modules...
423 echo "Copying PAM-Modules to jail"
424 cp -r /lib/security ${JAILPATH}/lib/
426 # ...and something else useful for PAM
427 cp -r /etc/security ${JAILPATH}/etc/
428 cp /etc/login.defs ${JAILPATH}/etc/
430 if [ -f /etc/DIR_COLORS ] ; then
431 cp /etc/DIR_COLORS ${JAILPATH}/etc/
434 # Don't give more permissions than necessary
435 chown root.root ${JAILPATH}/bin/su
436 chmod 700 ${JAILPATH}/bin/su