Drop grml-postfix
[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."
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 "
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 else
141   echo "  failed
142
143 dirname not found!
144 Please install dirname-binary (to be found eg in the package coreutils)!
145 "
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 "
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...."
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...."
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 # 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
285
286 # Define HomeDir for simple referencing
287 HOMEDIR="$JAILPATH/home/$CHROOT_USERNAME"
288
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\"
295 "
296 usermod -d "$HOMEDIR" -m -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
297 fi
298
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"
302
303 # Enter password for new account
304 if !(passwd $CHROOT_USERNAME);
305   then echo "Passwords are probably not the same, try again."
306   exit 1;
307 fi
308 echo
309 }
310 fi
311
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
316
317 # Add users to etc/passwd
318 #
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
323 fi
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
328 # winSCP)
329  grep /etc/group -e "^users" >> ${JAILPATH}/etc/group
330 fi
331
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
334 # appear in the jail
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
339
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
343
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
347
348 # endif for =! update
349 fi
350
351 # Copy the apps and the related libs
352 echo "Copying necessary library-files to jail (may take some time)"
353
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 '/'
360 #
361 # Randy K.
362 #
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 /
369 #
370 if [ -x ${HOME}/ldlist ]; then
371    mv ${HOME}/ldlist ${HOME}/ldlist.bak
372 fi
373 if [ -x ${HOME}/lddlist2 ]; then
374    mv ${HOME}/lddlist2 ${HOME}/lddlist2.bak
375 fi
376
377 for app in $APPS;  do
378
379     # First of all, check that this application exists
380     if [ -x $app ]; then
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
384             mkdir -p .$app_path
385         fi
386
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.
391                 cp -p $app .$app
392
393         # get list of necessary libraries
394         ldd $app >> ${HOME}/ldlist
395     fi
396 done
397
398 # Clear out any old temporary file before we start
399 if [ -e ${HOME}/ldlist2 ]; then
400     rm ${HOME}/ldlist2
401 fi
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
406    fi
407 done
408 for lib in `cat ${HOME}/ldlist2`; do
409     mkdir -p .`dirname $lib` > /dev/null 2>&1
410
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.
415     cp $lib .$lib
416 done
417
418 #
419 # Now, cleanup the 2 files we created for the library list
420 #
421 /bin/rm -f ${HOME}/ldlist
422 /bin/rm -f ${HOME}/ldlist2
423
424 # Necessary files that are not listed by ldd.
425 #
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/
442 else
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/
444 fi
445
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)
449 #
450 #cp /lib/*.* ${JAILPATH}/lib/
451 #cp /lib/lib64/*.* ${JAILPATH}/lib/lib64/
452
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/
456
457 # ...and of course the PAM-modules...
458 echo "Copying PAM-Modules to jail"
459 cp -r /lib/security ${JAILPATH}/lib/
460
461 # ...and something else useful for PAM
462 cp -r /etc/security ${JAILPATH}/etc/
463 cp /etc/login.defs ${JAILPATH}/etc/
464
465 if [ -f /etc/DIR_COLORS ] ; then
466   cp /etc/DIR_COLORS ${JAILPATH}/etc/
467 fi
468
469 # Don't give more permissions than necessary
470 chown root.root ${JAILPATH}/bin/su
471 chmod 700 ${JAILPATH}/bin/su
472
473 exit
474