Release new version 2.13.0
[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-02-24
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." >&2
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"
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"
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"
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 " >&2
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 " >&2
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 " >&2
134 exit 1
135 fi
136
137 echo "Checking for dirname..."
138 if [ `which dirname` ]; then
139   echo "  OK";
140 else
141   echo "  failed
142
143 dirname not found!
144 Please install dirname-binary (to be found eg in the package coreutils)!
145 " >&2
146 exit 1
147 fi
148
149 echo "Checking for awk..."
150 if [ `which awk` ]; then
151   echo "  OK
152 ";
153 else
154   echo "  failed
155
156 awk not found!
157 Please install (g)awk-package/binary!
158 " >&2
159 exit 1
160 fi
161
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
166 #
167 if  (test ! -f /etc/ssh/sshd_config >/dev/null 2>&1); then
168   echo "
169 File /etc/ssh/sshd_config not found.
170 Not checking for path to sftp-server.
171   ";
172 else
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.
175 ";
176   else SFTP_SERVER=$(grep -v "^#" /etc/ssh/sshd_config | grep -i sftp-server | awk  '{ print $3}')
177   fi
178 fi
179
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"
182
183 # Get accountname to create
184 CHROOT_USERNAME=$1
185
186 if ! [ -z "$2" ] ; then
187   SHELL=$2
188 else
189   SHELL=/bin/chroot-shell
190 fi
191
192 if ! [ -z "$3" ] ; then
193   JAILPATH=$3
194 else
195   JAILPATH=/home/jail
196 fi
197
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 {
201 echo "
202 -----------------------------
203 User $CHROOT_USERNAME exists.
204
205 Are you sure you want to modify the users home directory and lock him into the
206 chroot directory?
207 Are you REALLY sure?
208 Say only yes if you absolutely know what you are doing!
209 (yes/no) -> "
210   read MODIFYUSER
211   if [ "$MODIFYUSER" != "yes" ]; then
212     echo "
213 Not entered yes. Exiting...." >&2
214     exit 1
215   fi
216 }
217 else
218   CREATEUSER="yes"
219 fi
220
221 # Create $SHELL (shell for jailed accounts)
222 if [ -f ${SHELL} ] ; then
223   echo "
224 -----------------------------
225 The file $SHELL exists.
226 Probably it was created by this script.
227
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)
231 (yes/no) -> "
232 read OVERWRITE
233 if [ "$OVERWRITE" != "yes" ]; then
234   echo "
235 Not entered yes. Exiting...." >&2
236   exit 1
237 fi
238 else
239   echo "Creating $SHELL"
240   echo '#!/bin/sh' > $SHELL
241   echo "`which sudo` `which chroot` $JAILPATH /bin/su - \$USER" \"\$@\" >> $SHELL
242   chmod 755 $SHELL
243 fi
244
245 # make common jail for everybody if inexistent
246 if [ ! -d ${JAILPATH} ] ; then
247   mkdir -p ${JAILPATH}
248   echo "Creating ${JAILPATH}"
249 fi
250 cd ${JAILPATH}
251
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"
258   fi
259 done
260 echo
261
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
269 #fi
270
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
276
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
280
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"
288 else
289   echo "Modifying /etc/sudoers"
290   echo "$SUDOERS" >> /etc/sudoers
291 fi
292
293 # Define HomeDir for simple referencing
294 HOMEDIR="$JAILPATH/home/$CHROOT_USERNAME"
295
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\"
302 "
303 usermod -d "$HOMEDIR" -m -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
304 fi
305
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"
309
310 # Enter password for new account
311 if !(passwd $CHROOT_USERNAME);
312   then echo "Passwords are probably not the same, try again." >&2
313   exit 1;
314 fi
315 echo
316 }
317 fi
318
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
323
324 # Add users to etc/passwd
325 #
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
330 fi
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
335 # winSCP)
336  grep /etc/group -e "^users" >> ${JAILPATH}/etc/group
337 fi
338
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
341 # appear in the jail
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
346
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
350
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
354
355 # endif for =! update
356 fi
357
358 # Copy the apps and the related libs
359 echo "Copying necessary library-files to jail (may take some time)"
360
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 '/'
367 #
368 # Randy K.
369 #
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 /
376 #
377 if [ -x ${HOME}/ldlist ]; then
378    mv ${HOME}/ldlist ${HOME}/ldlist.bak
379 fi
380 if [ -x ${HOME}/lddlist2 ]; then
381    mv ${HOME}/lddlist2 ${HOME}/lddlist2.bak
382 fi
383
384 for app in $APPS;  do
385
386     # First of all, check that this application exists
387     if [ -x $app ]; then
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
391             mkdir -p .$app_path
392         fi
393
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.
398                 cp -p $app .$app
399
400         # get list of necessary libraries
401         ldd $app >> ${HOME}/ldlist
402     fi
403 done
404
405 # Clear out any old temporary file before we start
406 if [ -e ${HOME}/ldlist2 ]; then
407     rm ${HOME}/ldlist2
408 fi
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
413    fi
414 done
415 for lib in `cat ${HOME}/ldlist2`; do
416     mkdir -p .`dirname $lib` > /dev/null 2>&1
417
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.
422     cp $lib .$lib
423 done
424
425 #
426 # Now, cleanup the 2 files we created for the library list
427 #
428 /bin/rm -f ${HOME}/ldlist
429 /bin/rm -f ${HOME}/ldlist2
430
431 # Necessary files that are not listed by ldd.
432 #
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/
449 else
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/
451 fi
452
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)
456 #
457 #cp /lib/*.* ${JAILPATH}/lib/
458 #cp /lib/lib64/*.* ${JAILPATH}/lib/lib64/
459
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/
463
464 # ...and of course the PAM-modules...
465 echo "Copying PAM-Modules to jail"
466 cp -r /lib/security ${JAILPATH}/lib/
467
468 # ...and something else useful for PAM
469 cp -r /etc/security ${JAILPATH}/etc/
470 cp /etc/login.defs ${JAILPATH}/etc/
471
472 if [ -f /etc/DIR_COLORS ] ; then
473   cp /etc/DIR_COLORS ${JAILPATH}/etc/
474 fi
475
476 # Don't give more permissions than necessary
477 chown root.root ${JAILPATH}/bin/su
478 chmod 700 ${JAILPATH}/bin/su
479
480 exit
481