update make_chroot_jail to latest upstream version
[grml-scripts.git] / usr_sbin / make_chroot_jail
1 #!/bin/sh
2 #
3 # (c) Copyright by Wolfgang Fuschlberger
4 #
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.
9 #
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 )
15
16 # first Release: 2004-07-30
17 # latest update: 2007-01-07
18 #
19 # The latest version of the script is available at
20 #   http://www.fuschlberger.net/programs/ssh-scp-chroot-jail/
21 #
22 # Feedback is welcome!
23 #
24 # Thanks for Bugfixes / Enhancements to 
25 # Michael Prokop <http://www.michael-prokop.at/chroot/>,
26 # Randy K., Randy D. and Jonathan Hunter.
27
28 #
29 # Features:
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 ################################################################################
35
36 # Check if we are called with username or update
37 if [ -z "$1" ] ; then
38   echo
39   echo "Error: Parameter missing. Did you forget the username?"
40   echo "-------------------------------------------------------------"
41   echo "Creating new chrooted account:"
42   echo "Usage: $0 username"
43   echo
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"
56   exit
57 fi
58
59 echo "Am I root?  "
60 if [ "$(whoami &2>/dev/null)" != "root" ] && [ "$(id -un &2>/dev/null)" != "root" ] ; then
61   echo "  NO!
62
63 Error: You must be root to run this script."
64   exit 1
65 fi
66 echo "  OK";
67
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"
73        DISTRO=DEBIAN;
74 elif [ -f /etc/SuSE-release ];
75   then echo "  Supported Distribution found"
76        echo "  System is running SuSE Linux"
77        DISTRO=SUSE;
78 elif [ -f /etc/fedora-release ];
79   then echo "  Supported Distribution found"
80        echo "  System is running Fedora Linux"
81        DISTRO=FEDORA;
82 elif [ -f /etc/redhat-release ];
83   then echo "  Supported Distribution found"
84        echo "  System is running Red Hat Linux"
85        DISTRO=REDHAT;
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"
87 #exit 1
88 fi
89
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"
99 else
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"
101 fi
102
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 );
106   then echo "  OK";
107   else echo "  failed
108
109 Please install which-binary!
110 "
111 exit 1
112 fi
113
114 echo "Checking for chroot..." 
115 if [ `which chroot` ];
116   then echo "  OK";
117   else echo "  failed
118
119 chroot not found!
120 Please install chroot-package/binary!
121 "
122 exit 1
123 fi
124
125 echo "Checking for sudo..." 
126 if [ `which sudo` ]; then
127   echo "  OK";
128 else 
129   echo "  failed
130
131 sudo not found!
132 Please install sudo-package/binary!
133 "
134 exit 1
135 fi
136
137 echo "Checking for dirname..." 
138 if [ `which dirname` ]; then
139   echo "  OK
140 ";
141 else 
142   echo "  failed
143
144 dirname not found!
145 Please install dirname-binary (to be found eg in the package coreutils)!
146 "
147 exit 1
148 fi
149
150 # Get accountname to create
151 CHROOT_USERNAME=$1
152
153 if ! [ -z "$2" ] ; then
154   SHELL=$2
155 else
156   SHELL=/bin/chroot-shell
157 fi
158
159 if ! [ -z "$3" ] ; then
160   JAILPATH=$3
161 else
162   JAILPATH=/home/jail
163 fi
164
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 {
168 echo "
169 -----------------------------
170 User $CHROOT_USERNAME exists. 
171
172 Are you sure you want to modify the users home directory and lock him into the
173 chroot directory?
174 Are you REALLY sure?
175 Say only yes if you absolutely know what you are doing!"
176   read -p "(yes/no) -> " MODIFYUSER
177   if [ "$MODIFYUSER" != "yes" ]; then
178     echo "
179 Not entered yes. Exiting...."
180     exit 1
181   fi
182 }
183 else
184   CREATEUSER="yes"
185 fi
186
187 # Create $SHELL (shell for jailed accounts)
188 if [ -f ${SHELL} ] ; then
189   echo "
190 -----------------------------
191 The file $SHELL exists. 
192 Probably it was created by this script.
193
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
199   echo "
200 Not entered yes. Exiting...."
201   exit 1
202 fi
203 else
204   echo "Creating $SHELL"
205   echo '#!/bin/sh' > $SHELL
206   echo "`which sudo` `which chroot` $JAILPATH /bin/su - \$USER" \"\$@\" >> $SHELL
207   chmod 755 $SHELL
208 fi
209
210 # make common jail for everybody if inexistent
211 if [ ! -d ${JAILPATH} ] ; then
212   mkdir -p ${JAILPATH}
213   echo "Creating ${JAILPATH}"
214 fi
215 cd ${JAILPATH}
216
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"
223   fi
224 done
225 echo
226
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
234 #fi
235
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 
241
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
245
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
250
251 # Define HomeDir for simple referencing
252 HOMEDIR="$JAILPATH/home/$CHROOT_USERNAME"
253
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\"
260 "
261 usermod -d "$HOMEDIR" -m -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
262 fi
263
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"
267
268 # Enter password for new account
269 if !(passwd $CHROOT_USERNAME);
270   then echo "Passwords are probably not the same, try again."
271   exit 1;
272 fi
273 echo
274 }
275 fi
276
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
281
282 # Add users to etc/passwd
283 #
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
288 fi
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
293 # winSCP)
294  grep /etc/group -e "^users" >> ${JAILPATH}/etc/group
295 fi
296
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 
299 # appear in the jail
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
304
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
308
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
312
313 # endif for =! update
314 fi
315
316 # Copy the apps and the related libs
317 echo "Copying necessary library-files to jail (may take some time)"
318
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 '/'
325
326 # Randy K.
327 #
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 /
334 #
335 if [ -x ${HOME}/ldlist ]; then 
336    mv ${HOME}/ldlist ${HOME}/ldlist.bak
337 fi
338 if [ -x ${HOME}/lddlist2 ]; then 
339    mv ${HOME}/lddlist2 ${HOME}/lddlist2.bak
340 fi
341
342 for app in $APPS;  do
343
344     # First of all, check that this application exists
345     if [ -x $app ]; then
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
349             mkdir -p .$app_path
350         fi
351
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.
356                 cp -p $app .$app
357
358         # get list of necessary libraries
359         ldd $app >> ${HOME}/ldlist
360     fi
361 done
362
363 # Clear out any old temporary file before we start
364 if [ -e ${HOME}/ldlist2 ]; then
365     rm ${HOME}/ldlist2
366 fi
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
371    fi
372 done
373 for lib in `cat /root/ldlist2`; do
374     mkdir -p .`dirname $lib` > /dev/null 2>&1
375
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.
380     cp $lib .$lib
381 done
382
383 #
384 # Now, cleanup the 2 files we created for the library list
385 #
386 /bin/rm -f ${HOME}/ldlist
387 /bin/rm -f ${HOME}/ldlist2
388
389 # Necessary files that are not listed by ldd.
390 #
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/
407 else
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/
409 fi
410
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)
414 #
415 #cp /lib/*.* ${JAILPATH}/lib/
416 #cp /lib/lib64/*.* ${JAILPATH}/lib/lib64/ 
417
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/
421
422 # ...and of course the PAM-modules...
423 echo "Copying PAM-Modules to jail"
424 cp -r /lib/security ${JAILPATH}/lib/
425
426 # ...and something else useful for PAM
427 cp -r /etc/security ${JAILPATH}/etc/
428 cp /etc/login.defs ${JAILPATH}/etc/
429
430 if [ -f /etc/DIR_COLORS ] ; then
431   cp /etc/DIR_COLORS ${JAILPATH}/etc/
432 fi 
433
434 # Don't give more permissions than necessary
435 chown root.root ${JAILPATH}/bin/su
436 chmod 700 ${JAILPATH}/bin/su
437
438 exit
439