]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - etc/rc.d/jail
This commit was generated by cvs2svn to compensate for changes in r173619,
[FreeBSD/FreeBSD.git] / etc / rc.d / jail
1 #!/bin/sh
2 #
3 # $FreeBSD$
4 #
5
6 # PROVIDE: jail
7 # REQUIRE: LOGIN cleanvar
8 # BEFORE: securelevel
9 # KEYWORD: nojail shutdown
10
11 . /etc/rc.subr
12
13 name="jail"
14 rcvar=`set_rcvar`
15 start_cmd="jail_start"
16 stop_cmd="jail_stop"
17
18 # init_variables _j
19 #       Initialize the various jail variables for jail _j.
20 #
21 init_variables()
22 {
23         _j="$1"
24
25         if [ -z "$_j" ]; then
26                 warn "init_variables: you must specify a jail"
27                 return
28         fi
29
30         eval _rootdir=\"\$jail_${_j}_rootdir\"
31         _devdir="${_rootdir}/dev"
32         _fdescdir="${_devdir}/fd"
33         _procdir="${_rootdir}/proc"
34         eval _hostname=\"\$jail_${_j}_hostname\"
35         eval _ip=\"\$jail_${_j}_ip\"
36         eval _interface=\"\${jail_${_j}_interface:-${jail_interface}}\"
37         eval _exec=\"\$jail_${_j}_exec\"
38         eval _exec_start=\"\${jail_${_j}_exec_start:-${jail_exec_start}}\"
39
40         i=1
41         while [ true ]; do
42                 eval _exec_afterstart${i}=\"\${jail_${_j}_exec_afterstart${i}:-\${jail_exec_afterstart${i}}}\"
43                 [ -z "$(eval echo \"\$_exec_afterstart${i}\")" ] &&  break
44                 i=$((i + 1))
45         done
46         
47         eval _exec_stop=\"\${jail_${_j}_exec_stop:-${jail_exec_stop}}\"
48         if [ -n "${_exec}" ]; then
49                 #   simple/backward-compatible execution
50                 _exec_start="${_exec}"
51                 _exec_stop=""
52         else
53                 #   flexible execution
54                 if [ -z "${_exec_start}" ]; then
55                         _exec_start="/bin/sh /etc/rc"
56                         if [ -z "${_exec_stop}" ]; then
57                                 _exec_stop="/bin/sh /etc/rc.shutdown"
58                         fi
59                 fi
60         fi
61
62         # The default jail ruleset will be used by rc.subr if none is specified.
63         eval _ruleset=\"\${jail_${_j}_devfs_ruleset:-${jail_devfs_ruleset}}\"
64         eval _devfs=\"\${jail_${_j}_devfs_enable:-${jail_devfs_enable}}\"
65         [ -z "${_devfs}" ] && _devfs="NO"
66         eval _fdescfs=\"\${jail_${_j}_fdescfs_enable:-${jail_fdescfs_enable}}\"
67         [ -z "${_fdescfs}" ] && _fdescfs="NO"
68         eval _procfs=\"\${jail_${_j}_procfs_enable:-${jail_procfs_enable}}\"
69         [ -z "${_procfs}" ] && _procfs="NO"
70
71         eval _mount=\"\${jail_${_j}_mount_enable:-${jail_mount_enable}}\"
72         [ -z "${_mount}" ] && _mount="NO"
73         # "/etc/fstab.${_j}" will be used for {,u}mount(8) if none is specified.
74         eval _fstab=\"\${jail_${_j}_fstab:-${jail_fstab}}\"
75         [ -z "${_fstab}" ] && _fstab="/etc/fstab.${_j}"
76         eval _flags=\"\${jail_${_j}_flags:-${jail_flags}}\"
77         [ -z "${_flags}" ] && _flags="-l -U root"
78         eval _consolelog=\"\${jail_${_j}_consolelog:-${jail_consolelog}}\"
79         [ -z "${_consolelog}" ] && _consolelog="/var/log/jail_${_j}_console.log"
80
81         # Debugging aid
82         #
83         debug "$_j devfs enable: $_devfs"
84         debug "$_j fdescfs enable: $_fdescfs"
85         debug "$_j procfs enable: $_procfs"
86         debug "$_j mount enable: $_mount"
87         debug "$_j hostname: $_hostname"
88         debug "$_j ip: $_ip"
89         debug "$_j interface: $_interface"
90         debug "$_j root: $_rootdir"
91         debug "$_j devdir: $_devdir"
92         debug "$_j fdescdir: $_fdescdir"
93         debug "$_j procdir: $_procdir"
94         debug "$_j ruleset: $_ruleset"
95         debug "$_j fstab: $_fstab"
96         debug "$_j exec start: $_exec_start"
97         debug "$_j consolelog: $_consolelog"
98
99         i=1
100         while [ true ]; do
101                 eval out=\"\${_exec_afterstart${i}:-''}\"
102
103                 if [ -z "$out" ]; then
104                         break;
105                 fi
106
107                 debug "$_j exec after start #${i}: ${out}"
108                 i=$((i + 1))
109         done
110
111         debug "$_j exec stop: $_exec_stop"
112         debug "$_j flags: $_flags"
113         debug "$_j consolelog: $_consolelog"
114
115         if [ -z "${_hostname}" ]; then
116                 err 3 "$name: No hostname has been defined for ${_j}"
117         fi
118         if [ -z "${_rootdir}" ]; then
119                 err 3 "$name: No root directory has been defined for ${_j}"
120         fi
121         if [ -z "${_ip}" ]; then
122                 err 3 "$name: No IP address has been defined for ${_j}"
123         fi
124
125 }
126
127 # set_sysctl rc_knob mib msg
128 #       If the mib sysctl is set according to what rc_knob
129 #       specifies, this function does nothing. However if
130 #       rc_knob is set differently than mib, then the mib
131 #       is set accordingly and msg is displayed followed by
132 #       an '=" sign and the word 'YES' or 'NO'.
133 #
134 set_sysctl()
135 {
136         _knob="$1"
137         _mib="$2"
138         _msg="$3"
139
140         _current=`${SYSCTL} -n $_mib 2>/dev/null`
141         if checkyesno $_knob ; then
142                 if [ "$_current" -ne 1 ]; then
143                         echo -n " ${_msg}=YES"
144                         ${SYSCTL_W} 1>/dev/null ${_mib}=1
145                 fi
146         else
147                 if [ "$_current" -ne 0 ]; then
148                         echo -n " ${_msg}=NO"
149                         ${SYSCTL_W} 1>/dev/null ${_mib}=0
150                 fi
151         fi
152 }
153
154 # is_current_mountpoint()
155 #       Is the directory mount point for a currently mounted file
156 #       system?
157 #
158 is_current_mountpoint()
159 {
160         local _dir _dir2
161
162         _dir=$1
163
164         _dir=`echo $_dir | sed -Ee 's#//+#/#g' -e 's#/$##'`
165         [ ! -d "${_dir}" ] && return 1
166         _dir2=`df ${_dir} | tail +2 | awk '{ print $6 }'`
167         [ "${_dir}" = "${_dir2}" ]
168         return $?
169 }
170
171 # is_symlinked_mountpoint()
172 #       Is a mount point, or any of its parent directories, a symlink?
173 #
174 is_symlinked_mountpoint()
175 {
176         local _dir
177
178         _dir=$1
179
180         [ -L "$_dir" ] && return 0
181         [ "$_dir" = "/" ] && return 1
182         is_symlinked_mountpoint `dirname $_dir`
183         return $?
184 }
185
186 # secure_umount
187 #       Try to unmount a mount point without being vulnerable to
188 #       symlink attacks.
189 #
190 secure_umount()
191 {
192         local _dir
193
194         _dir=$1
195
196         if is_current_mountpoint ${_dir}; then
197                 umount -f ${_dir} >/dev/null 2>&1
198         else
199                 debug "Nothing mounted on ${_dir} - not unmounting"
200         fi
201 }
202
203
204 # jail_umount_fs
205 #       This function unmounts certain special filesystems in the
206 #       currently selected jail. The caller must call the init_variables()
207 #       routine before calling this one.
208 #
209 jail_umount_fs()
210 {
211         local _device _mountpt _rest
212
213         if checkyesno _fdescfs; then
214                 if [ -d "${_fdescdir}" ] ; then
215                         secure_umount ${_fdescdir}
216                 fi
217         fi
218         if checkyesno _devfs; then
219                 if [ -d "${_devdir}" ] ; then
220                         secure_umount ${_devdir}
221                 fi
222         fi
223         if checkyesno _procfs; then
224                 if [ -d "${_procdir}" ] ; then
225                         secure_umount ${_procdir}
226                 fi
227         fi
228         if checkyesno _mount; then
229                 [ -f "${_fstab}" ] || warn "${_fstab} does not exist"
230                 tail -r ${_fstab} | while read _device _mountpt _rest; do
231                         case ":${_device}" in
232                         :#* | :)
233                                 continue
234                                 ;;
235                         esac
236                         secure_umount ${_mountpt}
237                 done
238         fi
239 }
240
241 # jail_mount_fstab()
242 #       Mount file systems from a per jail fstab while trying to
243 #       secure against symlink attacks at the mount points.
244 #
245 #       If we are certain we cannot secure against symlink attacks we
246 #       do not mount all of the file systems (since we cannot just not
247 #       mount the file system with the problematic mount point).
248 #
249 #       The caller must call the init_variables() routine before
250 #       calling this one.
251 #
252 jail_mount_fstab()
253 {
254         local _device _mountpt _rest
255
256         while read _device _mountpt _rest; do
257                 case ":${_device}" in
258                 :#* | :)
259                         continue
260                         ;;
261                 esac
262                 if is_symlinked_mountpoint ${_mountpt}; then
263                         warn "${_mountpt} has symlink as parent - not mounting from ${_fstab}"
264                         return
265                 fi
266         done <${_fstab}
267         mount -a -F "${_fstab}"
268 }
269
270 jail_start()
271 {
272         echo -n 'Configuring jails:'
273         set_sysctl jail_set_hostname_allow security.jail.set_hostname_allowed \
274             set_hostname_allow
275         set_sysctl jail_socket_unixiproute_only \
276             security.jail.socket_unixiproute_only unixiproute_only
277         set_sysctl jail_sysvipc_allow security.jail.sysvipc_allowed \
278             sysvipc_allow
279         echo '.'
280
281         echo -n 'Starting jails:'
282         _tmp_dir=`mktemp -d /tmp/jail.XXXXXXXX` || \
283             err 3 "$name: Can't create temp dir, exiting..."
284         for _jail in ${jail_list}
285         do
286                 init_variables $_jail
287                 if [ -f /var/run/jail_${_jail}.id ]; then
288                         echo -n " [${_hostname} already running (/var/run/jail_${_jail}.id exists)]"
289                         continue;
290                 fi
291                 if [ -n "${_interface}" ]; then
292                         ifconfig ${_interface} alias ${_ip} netmask 255.255.255.255
293                 fi
294                 if checkyesno _mount; then
295                         info "Mounting fstab for jail ${_jail} (${_fstab})"
296                         if [ ! -f "${_fstab}" ]; then
297                                 err 3 "$name: ${_fstab} does not exist"
298                         fi
299                         jail_mount_fstab
300                 fi
301                 if checkyesno _devfs; then
302                         # If devfs is already mounted here, skip it.
303                         df -t devfs "${_devdir}" >/dev/null
304                         if [ $? -ne 0 ]; then
305                                 if is_symlinked_mountpoint ${_devdir}; then
306                                         warn "${_devdir} has symlink as parent - not starting jail ${_jail}"
307                                         continue
308                                 fi
309                                 info "Mounting devfs on ${_devdir}"
310                                 devfs_mount_jail "${_devdir}" ${_ruleset}
311                                 # Transitional symlink for old binaries
312                                 if [ ! -L "${_devdir}/log" ]; then
313                                         __pwd="`pwd`"
314                                         cd "${_devdir}"
315                                         ln -sf ../var/run/log log
316                                         cd "$__pwd"
317                                 fi
318                         fi
319
320                         # XXX - It seems symlinks don't work when there
321                         #       is a devfs(5) device of the same name.
322                         # Jail console output
323                         #       __pwd="`pwd`"
324                         #       cd "${_devdir}"
325                         #       ln -sf ../var/log/console console
326                         #       cd "$__pwd"
327                 fi
328                 if checkyesno _fdescfs; then
329                         if is_symlinked_mountpoint ${_fdescdir}; then
330                                 warn "${_fdescdir} has symlink as parent, not mounting"
331                         else
332                                 info "Mounting fdescfs on ${_fdescdir}"
333                                 mount -t fdescfs fdesc "${_fdescdir}"
334                         fi
335                 fi
336                 if checkyesno _procfs; then
337                         if is_symlinked_mountpoint ${_procdir}; then
338                                 warn "${_procdir} has symlink as parent, not mounting"
339                         else
340                                 info "Mounting procfs onto ${_procdir}"
341                                 if [ -d "${_procdir}" ] ; then
342                                         mount -t procfs proc "${_procdir}"
343                                 fi
344                         fi
345                 fi
346                 _tmp_jail=${_tmp_dir}/jail.$$
347                 eval jail ${_flags} -i ${_rootdir} ${_hostname} \
348                         ${_ip} ${_exec_start} > ${_tmp_jail} 2>&1
349
350                 if [ "$?" -eq 0 ] ; then
351                         _jail_id=$(head -1 ${_tmp_jail})
352                         i=1
353                         while [ true ]; do
354                                 eval out=\"\${_exec_afterstart${i}:-''}\"
355
356                                 if [ -z "$out" ]; then
357                                         break;
358                                 fi
359
360                                 jexec "${_jail_id}" ${out}
361                                 i=$((i + 1))
362                         done
363
364                         echo -n " $_hostname"
365                         tail +2 ${_tmp_jail} >${_consolelog}
366                         echo ${_jail_id} > /var/run/jail_${_jail}.id
367                 else
368                         jail_umount_fs
369                         if [ -n "${_interface}" ]; then
370                                 ifconfig ${_interface} -alias ${_ip}
371                         fi
372                         echo " cannot start jail \"${_jail}\": "
373                         tail +2 ${_tmp_jail}
374                 fi
375                 rm -f ${_tmp_jail}
376         done
377         rmdir ${_tmp_dir}
378         echo '.'
379 }
380
381 jail_stop()
382 {
383         echo -n 'Stopping jails:'
384         for _jail in ${jail_list}
385         do
386                 if [ -f "/var/run/jail_${_jail}.id" ]; then
387                         _jail_id=$(cat /var/run/jail_${_jail}.id)
388                         if [ ! -z "${_jail_id}" ]; then
389                                 init_variables $_jail
390                                 if [ -n "${_exec_stop}" ]; then
391                                         eval env -i /usr/sbin/jexec ${_jail_id} ${_exec_stop} \
392                                                 >> ${_consolelog} 2>&1
393                                 fi
394                                 killall -j ${_jail_id} -TERM > /dev/null 2>&1
395                                 sleep 1
396                                 killall -j ${_jail_id} -KILL > /dev/null 2>&1
397                                 jail_umount_fs
398                                 echo -n " $_hostname"
399                         fi
400                         if [ -n "${_interface}" ]; then
401                                 ifconfig ${_interface} -alias ${_ip}
402                         fi
403                         rm /var/run/jail_${_jail}.id
404                 else
405                         echo " cannot stop jail ${_jail}. No jail id in /var/run"
406                 fi
407         done
408         echo '.'
409 }
410
411 load_rc_config $name
412 cmd="$1"
413 if [ $# -gt 0 ]; then
414         shift
415 fi
416 if [ -n "$*" ]; then
417         jail_list="$*"
418 fi
419 run_rc_command "${cmd}"