initial checkin
[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: 2006-07-17
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 ################################################################################
33
34 # Check if we are called with username or update
35 if [ -z "$1" ] ; then
36   echo
37   echo "Error: Parameter missing. Did you forget the username?"
38   echo "-------------------------------------------------------------"
39   echo "Creating new chrooted account:"
40   echo "Usage: $0 username"
41   echo
42   echo "or specify \$SHELL and path where the jail should be located:"
43   echo "Usage: $0 username [/path/to/chroot-shell [/path/to/jail]]"
44   echo "Default shell       = /bin/chroot-shell"
45   echo "Default chroot-path = /home/jail"
46   echo "-------------------------------------------------------------"
47   echo "Updating files in the chroot-jail:"
48   echo "Usage: $0 update [/path/to/chroot-shell [/path/to/jail]]"
49   echo "-------------------------------------------------------------"
50   echo "To uninstall: # userdel \$USER"
51   echo "              # rm -rf /home/jail"
52   echo "              # rm -f /bin/chroot-shell"
53   echo "              delete the User's line from /etc/sudoers"
54   exit
55 fi
56
57 echo "Am I root?  "
58 if [ "$(whoami &2>/dev/null)" != "root" ] && [ "$(id -un &2>/dev/null)" != "root" ] ; then
59   echo "  NO!
60
61 Error: You must be root to run this script."
62   exit 1
63 fi
64 echo "  OK";
65
66 # Check existence of necessary files
67 echo "Checking distribution... "
68 if [ -f /etc/debian_version ];
69   then echo "  Supported Distribution found"
70        echo -e "  System is running Debian Linux\n"
71        DISTRO=DEBIAN;
72 elif [ -f /etc/SuSE-release ];
73   then echo "  Supported Distribution found"
74        echo -e "  System is running SuSE Linux\n"
75        DISTRO=SUSE;
76 elif [ -f /etc/fedora-release ];
77   then echo "  Supported Distribution found"
78        echo -e "  System is running Fedora Linux\n"
79        DISTRO=FEDORA;
80 elif [ -f /etc/redhat-release ];
81   then echo "  Supported Distribution found"
82        echo -e "  System is running Red Hat Linux\n"
83        DISTRO=REDHAT;
84 else echo -e "  failed...........\nThis script works best on Debian, Red Hat and SuSE Linux!\nLet's try it nevertheless....\n"
85 #exit 1
86 fi
87
88 # Specify the apps you want to copy to the jail
89 if [ "$DISTRO" = SUSE ]; then
90   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"
91 elif [ "$DISTRO" = FEDORA ]; 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/nc /usr/bin/rsync /usr/bin/ssh /usr/bin/scp /sbin/unix_chkpwd /usr/libexec/openssh/sftp-server"
93 elif [ "$DISTRO" = REDHAT ]; 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" = DEBIAN ]; 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/rsync /usr/bin/ssh /usr/bin/scp /sbin/unix_chkpwd /usr/lib/sftp-server"
97 else
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 /usr/sbin/unix_chkpwd /usr/lib/misc/sftp-server"
99 fi
100
101 # Check existence of necessary files
102 echo "Checking for chroot..." 
103 if [ `which chroot` ];
104   then echo "  OK";
105   else echo "  failed
106
107 Please install chroot-package/binary!
108 "
109 exit 1
110 fi
111
112 echo "Checking for sudo..." 
113 if [ `which sudo` ]; then
114   echo "  OK
115 ";
116 else 
117   echo "  failed
118
119 Please install sudo-package/binary!
120 "
121 exit 1
122 fi
123
124 # Get accountname to create
125 CHROOT_USERNAME=$1
126
127 if ! [ -z "$2" ] ; then
128   SHELL=$2
129 else
130   SHELL=/bin/chroot-shell
131 fi
132
133 if ! [ -z "$3" ] ; then
134   JAILPATH=$3
135 else
136   JAILPATH=/home/jail
137 fi
138
139 # Exit if user already exists
140 id $CHROOT_USERNAME > /dev/null 2>&1 && { echo "User exists."; echo "Exiting."; exit 1; }
141
142 # Create $SHELL (shell for jailed accounts)
143 if [ -f ${SHELL} ] ; then
144   echo "$SHELL exists. Don't want to overwrite it.
145 Please delete it before running the script."
146   exit 1
147 else
148   echo "Creating $SHELL"
149   echo '#!/bin/sh' > $SHELL
150   echo "`which sudo` `which chroot` $JAILPATH /bin/su - \$USER" \"\$@\" >> $SHELL
151   chmod 755 $SHELL
152 fi
153
154 # make common jail for everybody if inexistent
155 if [ ! -d $JAILPATH ] ; then
156   mkdir -p $JAILPATH
157   echo "Creating $JAILPATH"
158 fi
159 cd $JAILPATH
160
161 # Create directories in jail that do not exist yet
162 JAILDIRS="dev etc etc/pam.d bin home sbin usr usr/bin"
163 for directory in $JAILDIRS ; do
164   if [ ! -d "$JAILPATH/$directory" ] ; then
165     mkdir $JAILPATH/"$directory"
166     echo "Creating $JAILPATH/$directory"
167   fi
168 done
169 echo
170
171 # Comment in the following lines if your apache can't read the directories and
172 # uses the security contexts
173 # Fix security contexts so Apache can read files
174 #CHCON=$(`which chcon`)
175 #if [ -n "$CHCON" ] && [ -x $CHCON ]; then
176 #    $CHCON -t home_root_t $JAILPATH/home
177 #    $CHCON -t user_home_dir_t $JAILPATH/home/$CHROOT_USERNAME
178 #fi
179
180 # Creating necessary devices
181 [ -r $JAILPATH/dev/urandom ] || mknod $JAILPATH/dev/urandom c 1 9
182 [ -r $JAILPATH/dev/null ]    || mknod -m 666 $JAILPATH/dev/null    c 1 3
183 [ -r $JAILPATH/dev/zero ]    || mknod -m 666 $JAILPATH/dev/zero    c 1 5
184 [ -r $JAILPATH/dev/tty ]     || mknod -m 666 $JAILPATH/dev/tty     c 5 0 
185
186 # if we only want to update the files in the jail
187 # skip the creation of the new account
188 if [ "$1" != "update" ]; then
189
190 # Modifiy /etc/sudoers to enable chroot-ing for users
191 # must be removed by hand if account is deleted
192 echo "Modifying /etc/sudoers"
193 echo "$CHROOT_USERNAME       ALL=NOPASSWD: `which chroot`, /bin/su - $CHROOT_USERNAME" >> /etc/sudoers
194
195 # Define HomeDir for simple referencing
196 HOMEDIR="$JAILPATH/home/$CHROOT_USERNAME"
197
198 # Create new account, setting $SHELL to the above created script and
199 # $HOME to $JAILPATH/home/*
200 echo "Adding User \"$CHROOT_USERNAME\" to system"
201 useradd -m -d "$HOMEDIR" -s "$SHELL" $CHROOT_USERNAME && chmod 700 "$HOMEDIR"
202 # Enter password for new account
203 passwd $CHROOT_USERNAME
204 echo
205
206 # Create /usr/bin/groups in the jail
207 echo "#!/bin/bash" > usr/bin/groups
208 echo "id -Gn" >> usr/bin/groups
209 chmod 755 usr/bin/groups
210
211 # Add users to etc/passwd
212 #
213 # check if file exists (ie we are not called for the first time)
214 # if yes skip root's entry and do not overwrite the file
215 if [ ! -f etc/passwd ] ; then
216  grep /etc/passwd -e "^root" > etc/passwd
217 fi
218 if [ ! -f etc/group ] ; then
219  grep /etc/group -e "^root" > etc/group
220 # add the group for all users to etc/group (otherwise there is a nasty error
221 # message and probably because of that changing directories doesn't work with
222 # winSCP)
223  grep /etc/group -e "^users" >> etc/group
224 fi
225
226 # grep the username which was given to us from /etc/passwd and add it
227 # to ./etc/passwd replacing the $HOME with the directory as it will then 
228 # appear in the jail
229 echo "Adding User $CHROOT_USERNAME to jail"
230 grep -e "^$CHROOT_USERNAME:" /etc/passwd | \
231  sed -e "s#$JAILPATH##"      \
232      -e "s#$SHELL#/bin/bash#"  >> etc/passwd
233
234 # if the system uses one account/one group we write the
235 # account's group to etc/group
236 grep -e "^$CHROOT_USERNAME:" /etc/group >> etc/group
237
238 # write the user's line from /etc/shadow to /home/jail/etc/shadow
239 grep -e "^$CHROOT_USERNAME:" /etc/shadow >> etc/shadow
240
241 # endif for =! update
242 fi
243
244 # Copy the apps and the related libs
245 echo "Copying necessary library-files to jail (may take some time)"
246
247 # The original code worked fine on RedHat 7.3, but did not on FC3.
248 # On FC3, when the 'ldd' is done, there is a 'linux-gate.so.1' that 
249 # points to nothing (or a 90xb.....), and it also does not pick up
250 # some files that start with a '/'. To fix this, I am doing the ldd
251 # to a file called ldlist, then going back into the file and pulling
252 # out the libs that start with '/'
253
254 # Randy K.
255 #
256 # The original code worked fine on 2.4 kernel systems. Kernel 2.6
257 # introduced an internal library called 'linux-gate.so.1'. This 
258 # 'phantom' library caused non-critical errors to display during the 
259 # copy since the file does not actually exist on the file system. 
260 # To fix re-direct output of ldd to a file, parse the file and get 
261 # library files that start with /
262 #
263 if [ -x ${HOME}/ldlist ]; then 
264    mv ${HOME}/ldlist ${HOME}/ldlist.bak
265 fi
266 if [ -x ${HOME}/lddlist2 ]; then 
267    mv ${HOME}/lddlist2 ${HOME}/lddlist2.bak
268 fi
269
270 for app in $APPS;  do
271
272     # First of all, check that this application exists
273     if [ -x $app ]; then
274         # Check that the directory exists; create it if not.
275         app_path=`echo $app | sed -e 's#\(.\+\)/[^/]\+#\1#'`
276         if ! [ -d .$app_path ]; then
277             mkdir -p .$app_path
278         fi
279
280                 # If the files in the chroot are on the same file system as the
281                 # original files you should be able to use hard links instead of
282                 # copying the files, too. Symbolic links cannot be used, because the
283                 # original files are outside the chroot.
284                 cp -p $app .$app
285
286         # get list of necessary libraries
287         ldd $app >> ${HOME}/ldlist
288     fi
289 done
290
291 # Clear out any old temporary file before we start
292 if [ -e ${HOME}/ldlist2 ]; then
293     rm ${HOME}/ldlist2
294 fi
295 for libs in `cat /root/ldlist`; do
296    frst_char="`echo $libs | cut -c1`"
297    if [ "$frst_char" = "/" ]; then
298      echo "$libs" >> /root/ldlist2
299    fi
300 done
301 for lib in `cat /root/ldlist2`; do
302     mkdir -p .`dirname $lib` > /dev/null 2>&1
303
304         # If the files in the chroot are on the same file system as the original
305         # files you should be able to use hard links instead of copying the files,
306         # too. Symbolic links cannot be used, because the original files are
307         # outside the chroot.
308     cp $lib .$lib
309 done
310
311 #
312 # Now, cleanup the 2 files we created for the library list
313 #
314 /bin/rm -f ${HOME}/ldlist
315 /bin/rm -f ${HOME}/ldlist2
316
317 # Necessary files that are not listed by ldd
318 if [ "$DISTRO" = SUSE ]; then
319   cp /lib/libnss_compat.so.2 /lib/libnss_files.so.2 /lib/libnss_dns.so.2 /lib/libxcrypt.so.1 ${JAILPATH}/lib/
320 elif [ "$DISTRO" = FEDORA ]; then
321   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/libnss_dns.so.2 /lib/libxcrypt.so.1 ${JAILPATH}/lib/
322   cp /lib/*.* ${JAILPATH}/lib/
323 elif [ "$DISTRO" = REDHAT ]; then
324   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/
325   # needed for scp on RHEL
326   echo "export LD_LIBRARY_PATH=/usr/kerberos/lib" >> ${JAILPATH}/etc/profile
327 elif [ "$DISTRO" = DEBIAN ]; then
328   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/
329 else
330   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/
331 fi
332
333 # if you are using a 64 bit system and have strange problems with login comment
334 # the following lines in, perhaps it works then (motto: if you can't find the
335 # needed library just copy all of them)
336 #
337 #cp /lib/*.* ${JAILPATH}/lib/
338 #cp /lib/lib64/*.* ${JAILPATH}/lib/lib64/ 
339
340 # if you are using PAM you need stuff from /etc/pam.d/ in the jail,
341 echo "Copying files from /etc/pam.d/ to jail"
342 cp /etc/pam.d/* ${JAILPATH}/etc/pam.d/
343
344 # ...and of course the PAM-modules...
345 echo "Copying PAM-Modules to jail"
346 cp -r /lib/security ${JAILPATH}/lib/
347
348 # ...and something else useful for PAM
349 cp -r /etc/security ${JAILPATH}/etc/
350 cp /etc/login.defs ${JAILPATH}/etc/
351
352 if [ -f /etc/DIR_COLORS ] ; then
353   cp /etc/DIR_COLORS ${JAILPATH}/etc/
354 fi 
355
356 exit
357