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." >&2
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...." >&2
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...." >&2
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 # Modify sudo config to enable chroot-ing for users,
282 # must be removed by hand if account is deleted
283 SUDOERS="$CHROOT_USERNAME ALL=NOPASSWD: $(which chroot), /bin/su - $CHROOT_USERNAME"
284 if [ -d /etc/sudoers.d ]; then
285 echo "Installing sudoers configuration file /etc/sudoers.d/jail-$CHROOT_USERNAME"
286 echo "$SUDOERS" > "/etc/sudoers.d/jail-$CHROOT_USERNAME"
287 chmod 0440 "/etc/sudoers.d/jail-$CHROOT_USERNAME"
289 echo "Modifying /etc/sudoers"
290 echo "$SUDOERS" >> /etc/sudoers
293 # Define HomeDir for simple referencing
294 HOMEDIR="$JAILPATH/home/$CHROOT_USERNAME"
296 # Create new account, setting $SHELL to the above created script and
297 # $HOME to $JAILPATH/home/*
298 if [ "$CREATEUSER" != "yes" ] ; then echo "
299 Not creating new User account
300 Modifying User \"$CHROOT_USERNAME\"
301 Copying files in $CHROOT_USERNAME's \$HOME to \"$HOMEDIR\"
303 usermod -d "$HOMEDIR" -m -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
306 if [ "$CREATEUSER" = "yes" ] ; then {
307 echo "Adding User \"$CHROOT_USERNAME\" to system"
308 useradd -m -d "$HOMEDIR" -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
310 # Enter password for new account
311 if !(passwd $CHROOT_USERNAME);
312 then echo "Passwords are probably not the same, try again." >&2
319 # Create /usr/bin/groups in the jail
320 echo "#!/bin/bash" > usr/bin/groups
321 echo "id -Gn" >> usr/bin/groups
322 chmod 755 usr/bin/groups
324 # Add users to etc/passwd
326 # check if file exists (ie we are not called for the first time)
327 # if yes skip root's entry and do not overwrite the file
328 if [ ! -f etc/passwd ] ; then
329 grep /etc/passwd -e "^root" > ${JAILPATH}/etc/passwd
331 if [ ! -f etc/group ] ; then
332 grep /etc/group -e "^root" > ${JAILPATH}/etc/group
333 # add the group for all users to etc/group (otherwise there is a nasty error
334 # message and probably because of that changing directories doesn't work with
336 grep /etc/group -e "^users" >> ${JAILPATH}/etc/group
339 # grep the username which was given to us from /etc/passwd and add it
340 # to ./etc/passwd replacing the $HOME with the directory as it will then
342 echo "Adding User $CHROOT_USERNAME to jail"
343 grep -e "^$CHROOT_USERNAME:" /etc/passwd | \
344 sed -e "s#$JAILPATH##" \
345 -e "s#$SHELL#/bin/bash#" >> ${JAILPATH}/etc/passwd
347 # if the system uses one account/one group we write the
348 # account's group to etc/group
349 grep -e "^$CHROOT_USERNAME:" /etc/group >> ${JAILPATH}/etc/group
351 # write the user's line from /etc/shadow to /home/jail/etc/shadow
352 grep -e "^$CHROOT_USERNAME:" /etc/shadow >> ${JAILPATH}/etc/shadow
353 chmod 600 ${JAILPATH}/etc/shadow
355 # endif for =! update
358 # Copy the apps and the related libs
359 echo "Copying necessary library-files to jail (may take some time)"
361 # The original code worked fine on RedHat 7.3, but did not on FC3.
362 # On FC3, when the 'ldd' is done, there is a 'linux-gate.so.1' that
363 # points to nothing (or a 90xb.....), and it also does not pick up
364 # some files that start with a '/'. To fix this, I am doing the ldd
365 # to a file called ldlist, then going back into the file and pulling
366 # out the libs that start with '/'
370 # The original code worked fine on 2.4 kernel systems. Kernel 2.6
371 # introduced an internal library called 'linux-gate.so.1'. This
372 # 'phantom' library caused non-critical errors to display during the
373 # copy since the file does not actually exist on the file system.
374 # To fix re-direct output of ldd to a file, parse the file and get
375 # library files that start with /
377 if [ -x ${HOME}/ldlist ]; then
378 mv ${HOME}/ldlist ${HOME}/ldlist.bak
380 if [ -x ${HOME}/lddlist2 ]; then
381 mv ${HOME}/lddlist2 ${HOME}/lddlist2.bak
386 # First of all, check that this application exists
388 # Check that the directory exists; create it if not.
389 app_path=`echo $app | sed -e 's#\(.\+\)/[^/]\+#\1#'`
390 if ! [ -d .$app_path ]; then
394 # If the files in the chroot are on the same file system as the
395 # original files you should be able to use hard links instead of
396 # copying the files, too. Symbolic links cannot be used, because the
397 # original files are outside the chroot.
400 # get list of necessary libraries
401 ldd $app >> ${HOME}/ldlist
405 # Clear out any old temporary file before we start
406 if [ -e ${HOME}/ldlist2 ]; then
409 for libs in `cat ${HOME}/ldlist`; do
410 frst_char="`echo $libs | cut -c1`"
411 if [ "$frst_char" = "/" ]; then
412 echo "$libs" >> ${HOME}/ldlist2
415 for lib in `cat ${HOME}/ldlist2`; do
416 mkdir -p .`dirname $lib` > /dev/null 2>&1
418 # If the files in the chroot are on the same file system as the original
419 # files you should be able to use hard links instead of copying the files,
420 # too. Symbolic links cannot be used, because the original files are
421 # outside the chroot.
426 # Now, cleanup the 2 files we created for the library list
428 /bin/rm -f ${HOME}/ldlist
429 /bin/rm -f ${HOME}/ldlist2
431 # Necessary files that are not listed by ldd.
433 # There might be errors because of files that do not exist but in the end it
434 # may work nevertheless (I added new file names at the end without deleting old
435 # ones for reasons of backward compatibility).
436 # So please test ssh/scp before reporting a bug.
437 if [ "$DISTRO" = SUSE ]; then
438 cp /lib/libnss_compat.so.2 /lib/libnss_files.so.2 /lib/libnss_dns.so.2 /lib/libxcrypt.so.1 ${JAILPATH}/lib/
439 elif [ "$DISTRO" = FEDORA ]; then
440 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/
441 cp /lib/*.* ${JAILPATH}/lib/
442 cp /usr/lib/libcrack.so.2 ${JAILPATH}/usr/lib/
443 elif [ "$DISTRO" = REDHAT ]; then
444 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/
445 # needed for scp on RHEL
446 echo "export LD_LIBRARY_PATH=/usr/kerberos/lib" >> ${JAILPATH}/etc/profile
447 elif [ "$DISTRO" = DEBIAN ]; then
448 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/
450 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/
453 # if you are using a 64 bit system and have strange problems with login comment
454 # the following lines in, perhaps it works then (motto: if you can't find the
455 # needed library just copy all of them)
457 #cp /lib/*.* ${JAILPATH}/lib/
458 #cp /lib/lib64/*.* ${JAILPATH}/lib/lib64/
460 # if you are using PAM you need stuff from /etc/pam.d/ in the jail,
461 echo "Copying files from /etc/pam.d/ to jail"
462 cp /etc/pam.d/* ${JAILPATH}/etc/pam.d/
464 # ...and of course the PAM-modules...
465 echo "Copying PAM-Modules to jail"
466 cp -r /lib/security ${JAILPATH}/lib/
468 # ...and something else useful for PAM
469 cp -r /etc/security ${JAILPATH}/etc/
470 cp /etc/login.defs ${JAILPATH}/etc/
472 if [ -f /etc/DIR_COLORS ] ; then
473 cp /etc/DIR_COLORS ${JAILPATH}/etc/
476 # Don't give more permissions than necessary
477 chown root.root ${JAILPATH}/bin/su
478 chmod 700 ${JAILPATH}/bin/su