Deleted Added
full compact
jail (187708) jail (191620)
1#!/bin/sh
2#
1#!/bin/sh
2#
3# $FreeBSD: head/etc/rc.d/jail 187708 2009-01-26 12:59:11Z bz $
3# $FreeBSD: head/etc/rc.d/jail 191620 2009-04-28 09:45:32Z ru $
4#
5
6# PROVIDE: jail
7# REQUIRE: LOGIN cleanvar
8# BEFORE: securelevel
9# KEYWORD: nojail shutdown
10
11# WARNING: This script deals with untrusted data (the data and
12# processes inside the jails) and care must be taken when changing the
13# code related to this! If you have any doubt whether a change is
14# correct and have security impact, please get the patch reviewed by
15# the FreeBSD Security Team prior to commit.
16
17. /etc/rc.subr
18
19name="jail"
20rcvar=`set_rcvar`
21start_cmd="jail_start"
22stop_cmd="jail_stop"
23
24# init_variables _j
25# Initialize the various jail variables for jail _j.
26#
27init_variables()
28{
29 _j="$1"
30
31 if [ -z "$_j" ]; then
32 warn "init_variables: you must specify a jail"
33 return
34 fi
35
36 eval _rootdir=\"\$jail_${_j}_rootdir\"
37 _devdir="${_rootdir}/dev"
38 _fdescdir="${_devdir}/fd"
39 _procdir="${_rootdir}/proc"
40 eval _hostname=\"\$jail_${_j}_hostname\"
41 eval _ip=\"\$jail_${_j}_ip\"
42 eval _interface=\"\${jail_${_j}_interface:-${jail_interface}}\"
43 eval _exec=\"\$jail_${_j}_exec\"
4#
5
6# PROVIDE: jail
7# REQUIRE: LOGIN cleanvar
8# BEFORE: securelevel
9# KEYWORD: nojail shutdown
10
11# WARNING: This script deals with untrusted data (the data and
12# processes inside the jails) and care must be taken when changing the
13# code related to this! If you have any doubt whether a change is
14# correct and have security impact, please get the patch reviewed by
15# the FreeBSD Security Team prior to commit.
16
17. /etc/rc.subr
18
19name="jail"
20rcvar=`set_rcvar`
21start_cmd="jail_start"
22stop_cmd="jail_stop"
23
24# init_variables _j
25# Initialize the various jail variables for jail _j.
26#
27init_variables()
28{
29 _j="$1"
30
31 if [ -z "$_j" ]; then
32 warn "init_variables: you must specify a jail"
33 return
34 fi
35
36 eval _rootdir=\"\$jail_${_j}_rootdir\"
37 _devdir="${_rootdir}/dev"
38 _fdescdir="${_devdir}/fd"
39 _procdir="${_rootdir}/proc"
40 eval _hostname=\"\$jail_${_j}_hostname\"
41 eval _ip=\"\$jail_${_j}_ip\"
42 eval _interface=\"\${jail_${_j}_interface:-${jail_interface}}\"
43 eval _exec=\"\$jail_${_j}_exec\"
44
45 i=0
46 while : ; do
47 eval _exec_prestart${i}=\"\${jail_${_j}_exec_prestart${i}:-\${jail_exec_prestart${i}}}\"
48 [ -z "$(eval echo \"\$_exec_prestart${i}\")" ] && break
49 i=$((i + 1))
50 done
51
44 eval _exec_start=\"\${jail_${_j}_exec_start:-${jail_exec_start}}\"
45
46 i=1
47 while [ true ]; do
48 eval _exec_afterstart${i}=\"\${jail_${_j}_exec_afterstart${i}:-\${jail_exec_afterstart${i}}}\"
49 [ -z "$(eval echo \"\$_exec_afterstart${i}\")" ] && break
50 i=$((i + 1))
51 done
52 eval _exec_start=\"\${jail_${_j}_exec_start:-${jail_exec_start}}\"
53
54 i=1
55 while [ true ]; do
56 eval _exec_afterstart${i}=\"\${jail_${_j}_exec_afterstart${i}:-\${jail_exec_afterstart${i}}}\"
57 [ -z "$(eval echo \"\$_exec_afterstart${i}\")" ] && break
58 i=$((i + 1))
59 done
52
60
61 i=0
62 while : ; do
63 eval _exec_poststart${i}=\"\${jail_${_j}_exec_poststart${i}:-\${jail_exec_poststart${i}}}\"
64 [ -z "$(eval echo \"\$_exec_poststart${i}\")" ] && break
65 i=$((i + 1))
66 done
67
68 i=0
69 while : ; do
70 eval _exec_prestop${i}=\"\${jail_${_j}_exec_prestop${i}:-\${jail_exec_prestop${i}}}\"
71 [ -z "$(eval echo \"\$_exec_prestop${i}\")" ] && break
72 i=$((i + 1))
73 done
74
53 eval _exec_stop=\"\${jail_${_j}_exec_stop:-${jail_exec_stop}}\"
75 eval _exec_stop=\"\${jail_${_j}_exec_stop:-${jail_exec_stop}}\"
76
77 i=0
78 while : ; do
79 eval _exec_poststop${i}=\"\${jail_${_j}_exec_poststop${i}:-\${jail_exec_poststop${i}}}\"
80 [ -z "$(eval echo \"\$_exec_poststop${i}\")" ] && break
81 i=$((i + 1))
82 done
83
54 if [ -n "${_exec}" ]; then
55 # simple/backward-compatible execution
56 _exec_start="${_exec}"
57 _exec_stop=""
58 else
59 # flexible execution
60 if [ -z "${_exec_start}" ]; then
61 _exec_start="/bin/sh /etc/rc"
62 if [ -z "${_exec_stop}" ]; then
63 _exec_stop="/bin/sh /etc/rc.shutdown"
64 fi
65 fi
66 fi
67
68 # The default jail ruleset will be used by rc.subr if none is specified.
69 eval _ruleset=\"\${jail_${_j}_devfs_ruleset:-${jail_devfs_ruleset}}\"
70 eval _devfs=\"\${jail_${_j}_devfs_enable:-${jail_devfs_enable}}\"
71 [ -z "${_devfs}" ] && _devfs="NO"
72 eval _fdescfs=\"\${jail_${_j}_fdescfs_enable:-${jail_fdescfs_enable}}\"
73 [ -z "${_fdescfs}" ] && _fdescfs="NO"
74 eval _procfs=\"\${jail_${_j}_procfs_enable:-${jail_procfs_enable}}\"
75 [ -z "${_procfs}" ] && _procfs="NO"
76
77 eval _mount=\"\${jail_${_j}_mount_enable:-${jail_mount_enable}}\"
78 [ -z "${_mount}" ] && _mount="NO"
79 # "/etc/fstab.${_j}" will be used for {,u}mount(8) if none is specified.
80 eval _fstab=\"\${jail_${_j}_fstab:-${jail_fstab}}\"
81 [ -z "${_fstab}" ] && _fstab="/etc/fstab.${_j}"
82 eval _flags=\"\${jail_${_j}_flags:-${jail_flags}}\"
83 [ -z "${_flags}" ] && _flags="-l -U root"
84 eval _consolelog=\"\${jail_${_j}_consolelog:-${jail_consolelog}}\"
85 [ -z "${_consolelog}" ] && _consolelog="/var/log/jail_${_j}_console.log"
86 eval _fib=\"\${jail_${_j}_fib:-${jail_fib}}\"
87
88 # Debugging aid
89 #
90 debug "$_j devfs enable: $_devfs"
91 debug "$_j fdescfs enable: $_fdescfs"
92 debug "$_j procfs enable: $_procfs"
93 debug "$_j mount enable: $_mount"
94 debug "$_j hostname: $_hostname"
95 debug "$_j ip: $_ip"
96 jail_show_addresses ${_j}
97 debug "$_j interface: $_interface"
98 debug "$_j fib: $_fib"
99 debug "$_j root: $_rootdir"
100 debug "$_j devdir: $_devdir"
101 debug "$_j fdescdir: $_fdescdir"
102 debug "$_j procdir: $_procdir"
103 debug "$_j ruleset: $_ruleset"
104 debug "$_j fstab: $_fstab"
84 if [ -n "${_exec}" ]; then
85 # simple/backward-compatible execution
86 _exec_start="${_exec}"
87 _exec_stop=""
88 else
89 # flexible execution
90 if [ -z "${_exec_start}" ]; then
91 _exec_start="/bin/sh /etc/rc"
92 if [ -z "${_exec_stop}" ]; then
93 _exec_stop="/bin/sh /etc/rc.shutdown"
94 fi
95 fi
96 fi
97
98 # The default jail ruleset will be used by rc.subr if none is specified.
99 eval _ruleset=\"\${jail_${_j}_devfs_ruleset:-${jail_devfs_ruleset}}\"
100 eval _devfs=\"\${jail_${_j}_devfs_enable:-${jail_devfs_enable}}\"
101 [ -z "${_devfs}" ] && _devfs="NO"
102 eval _fdescfs=\"\${jail_${_j}_fdescfs_enable:-${jail_fdescfs_enable}}\"
103 [ -z "${_fdescfs}" ] && _fdescfs="NO"
104 eval _procfs=\"\${jail_${_j}_procfs_enable:-${jail_procfs_enable}}\"
105 [ -z "${_procfs}" ] && _procfs="NO"
106
107 eval _mount=\"\${jail_${_j}_mount_enable:-${jail_mount_enable}}\"
108 [ -z "${_mount}" ] && _mount="NO"
109 # "/etc/fstab.${_j}" will be used for {,u}mount(8) if none is specified.
110 eval _fstab=\"\${jail_${_j}_fstab:-${jail_fstab}}\"
111 [ -z "${_fstab}" ] && _fstab="/etc/fstab.${_j}"
112 eval _flags=\"\${jail_${_j}_flags:-${jail_flags}}\"
113 [ -z "${_flags}" ] && _flags="-l -U root"
114 eval _consolelog=\"\${jail_${_j}_consolelog:-${jail_consolelog}}\"
115 [ -z "${_consolelog}" ] && _consolelog="/var/log/jail_${_j}_console.log"
116 eval _fib=\"\${jail_${_j}_fib:-${jail_fib}}\"
117
118 # Debugging aid
119 #
120 debug "$_j devfs enable: $_devfs"
121 debug "$_j fdescfs enable: $_fdescfs"
122 debug "$_j procfs enable: $_procfs"
123 debug "$_j mount enable: $_mount"
124 debug "$_j hostname: $_hostname"
125 debug "$_j ip: $_ip"
126 jail_show_addresses ${_j}
127 debug "$_j interface: $_interface"
128 debug "$_j fib: $_fib"
129 debug "$_j root: $_rootdir"
130 debug "$_j devdir: $_devdir"
131 debug "$_j fdescdir: $_fdescdir"
132 debug "$_j procdir: $_procdir"
133 debug "$_j ruleset: $_ruleset"
134 debug "$_j fstab: $_fstab"
105 debug "$_j exec start: $_exec_start"
106 debug "$_j consolelog: $_consolelog"
107
135 debug "$_j consolelog: $_consolelog"
136
137 i=0
138 while : ; do
139 eval out=\"\${_exec_prestart${i}:-''}\"
140 if [ -z "$out" ]; then
141 break
142 fi
143 debug "$_j exec pre-start #${i}: ${out}"
144 i=$((i + 1))
145 done
146
147 debug "$_j exec start: $_exec_start"
148
108 i=1
109 while [ true ]; do
110 eval out=\"\${_exec_afterstart${i}:-''}\"
111
112 if [ -z "$out" ]; then
113 break;
114 fi
115
116 debug "$_j exec after start #${i}: ${out}"
117 i=$((i + 1))
118 done
119
149 i=1
150 while [ true ]; do
151 eval out=\"\${_exec_afterstart${i}:-''}\"
152
153 if [ -z "$out" ]; then
154 break;
155 fi
156
157 debug "$_j exec after start #${i}: ${out}"
158 i=$((i + 1))
159 done
160
161 i=0
162 while : ; do
163 eval out=\"\${_exec_poststart${i}:-''}\"
164 if [ -z "$out" ]; then
165 break
166 fi
167 debug "$_j exec post-start #${i}: ${out}"
168 i=$((i + 1))
169 done
170
171 i=0
172 while : ; do
173 eval out=\"\${_exec_prestop${i}:-''}\"
174 if [ -z "$out" ]; then
175 break
176 fi
177 debug "$_j exec pre-stop #${i}: ${out}"
178 i=$((i + 1))
179 done
180
120 debug "$_j exec stop: $_exec_stop"
181 debug "$_j exec stop: $_exec_stop"
182
183 i=0
184 while : ; do
185 eval out=\"\${_exec_poststop${i}:-''}\"
186 if [ -z "$out" ]; then
187 break
188 fi
189 debug "$_j exec post-stop #${i}: ${out}"
190 i=$((i + 1))
191 done
192
121 debug "$_j flags: $_flags"
122 debug "$_j consolelog: $_consolelog"
123
124 if [ -z "${_hostname}" ]; then
125 err 3 "$name: No hostname has been defined for ${_j}"
126 fi
127 if [ -z "${_rootdir}" ]; then
128 err 3 "$name: No root directory has been defined for ${_j}"
129 fi
130}
131
132# set_sysctl rc_knob mib msg
133# If the mib sysctl is set according to what rc_knob
134# specifies, this function does nothing. However if
135# rc_knob is set differently than mib, then the mib
136# is set accordingly and msg is displayed followed by
137# an '=" sign and the word 'YES' or 'NO'.
138#
139set_sysctl()
140{
141 _knob="$1"
142 _mib="$2"
143 _msg="$3"
144
145 _current=`${SYSCTL} -n $_mib 2>/dev/null`
146 if checkyesno $_knob ; then
147 if [ "$_current" -ne 1 ]; then
148 echo -n " ${_msg}=YES"
149 ${SYSCTL_W} 1>/dev/null ${_mib}=1
150 fi
151 else
152 if [ "$_current" -ne 0 ]; then
153 echo -n " ${_msg}=NO"
154 ${SYSCTL_W} 1>/dev/null ${_mib}=0
155 fi
156 fi
157}
158
159# is_current_mountpoint()
160# Is the directory mount point for a currently mounted file
161# system?
162#
163is_current_mountpoint()
164{
165 local _dir _dir2
166
167 _dir=$1
168
169 _dir=`echo $_dir | sed -Ee 's#//+#/#g' -e 's#/$##'`
170 [ ! -d "${_dir}" ] && return 1
171 _dir2=`df ${_dir} | tail +2 | awk '{ print $6 }'`
172 [ "${_dir}" = "${_dir2}" ]
173 return $?
174}
175
176# is_symlinked_mountpoint()
177# Is a mount point, or any of its parent directories, a symlink?
178#
179is_symlinked_mountpoint()
180{
181 local _dir
182
183 _dir=$1
184
185 [ -L "$_dir" ] && return 0
186 [ "$_dir" = "/" ] && return 1
187 is_symlinked_mountpoint `dirname $_dir`
188 return $?
189}
190
191# secure_umount
192# Try to unmount a mount point without being vulnerable to
193# symlink attacks.
194#
195secure_umount()
196{
197 local _dir
198
199 _dir=$1
200
201 if is_current_mountpoint ${_dir}; then
202 umount -f ${_dir} >/dev/null 2>&1
203 else
204 debug "Nothing mounted on ${_dir} - not unmounting"
205 fi
206}
207
208
209# jail_umount_fs
210# This function unmounts certain special filesystems in the
211# currently selected jail. The caller must call the init_variables()
212# routine before calling this one.
213#
214jail_umount_fs()
215{
216 local _device _mountpt _rest
217
218 if checkyesno _fdescfs; then
219 if [ -d "${_fdescdir}" ] ; then
220 secure_umount ${_fdescdir}
221 fi
222 fi
223 if checkyesno _devfs; then
224 if [ -d "${_devdir}" ] ; then
225 secure_umount ${_devdir}
226 fi
227 fi
228 if checkyesno _procfs; then
229 if [ -d "${_procdir}" ] ; then
230 secure_umount ${_procdir}
231 fi
232 fi
233 if checkyesno _mount; then
234 [ -f "${_fstab}" ] || warn "${_fstab} does not exist"
235 tail -r ${_fstab} | while read _device _mountpt _rest; do
236 case ":${_device}" in
237 :#* | :)
238 continue
239 ;;
240 esac
241 secure_umount ${_mountpt}
242 done
243 fi
244}
245
246# jail_mount_fstab()
247# Mount file systems from a per jail fstab while trying to
248# secure against symlink attacks at the mount points.
249#
250# If we are certain we cannot secure against symlink attacks we
251# do not mount all of the file systems (since we cannot just not
252# mount the file system with the problematic mount point).
253#
254# The caller must call the init_variables() routine before
255# calling this one.
256#
257jail_mount_fstab()
258{
259 local _device _mountpt _rest
260
261 while read _device _mountpt _rest; do
262 case ":${_device}" in
263 :#* | :)
264 continue
265 ;;
266 esac
267 if is_symlinked_mountpoint ${_mountpt}; then
268 warn "${_mountpt} has symlink as parent - not mounting from ${_fstab}"
269 return
270 fi
271 done <${_fstab}
272 mount -a -F "${_fstab}"
273}
274
275# jail_show_addresses jail
276# Debug print the input for the given _multi aliases
277# for a jail for init_variables().
278#
279jail_show_addresses()
280{
281 local _j _type alias
282 _j="$1"
283 alias=0
284
285 if [ -z "${_j}" ]; then
286 warn "jail_show_addresses: you must specify a jail"
287 return
288 fi
289
290 while : ; do
291 eval _addr=\"\$jail_${_j}_ip_multi${alias}\"
292 if [ -n "${_addr}" ]; then
293 debug "${_j} ip_multi${alias}: $_addr"
294 alias=$((${alias} + 1))
295 else
296 break
297 fi
298 done
299}
300
301# jail_extract_address argument
302# The second argument is the string from one of the _ip
303# or the _multi variables. In case of a comma separated list
304# only one argument must be passed in at a time.
305# The function alters the _type, _iface, _addr and _mask variables.
306#
307jail_extract_address()
308{
309 local _i
310 _i=$1
311
312 if [ -z "${_i}" ]; then
313 warn "jail_extract_address: called without input"
314 return
315 fi
316
317 # Check if we have an interface prefix given and split into
318 # iFace and rest.
319 case "${_i}" in
320 *\|*) # ifN|.. prefix there
321 _iface=${_i%%|*}
322 _r=${_i##*|}
323 ;;
324 *) _iface=""
325 _r=${_i}
326 ;;
327 esac
328
329 # In case the IP has no interface given, check if we have a global one.
330 _iface=${_iface:-${_interface}}
331
332 # Set address, cut off any prefix/netmask/prefixlen.
333 _addr=${_r}
334 _addr=${_addr%%[/ ]*}
335
336 # Theoretically we can return here if interface is not set,
337 # as we only care about the _mask if we call ifconfig.
338 # This is not done because we may want to santize IP addresses
339 # based on _type later, and optionally change the type as well.
340
341 # Extract the prefix/netmask/prefixlen part by cutting off the address.
342 _mask=${_r}
343 _mask=`expr "${_mask}" : "${_addr}\(.*\)"`
344
345 # Identify type {inet,inet6}.
346 case "${_addr}" in
347 *\.*\.*\.*) _type="inet" ;;
348 *:*) _type="inet6" ;;
349 *) warn "jail_extract_address: type not identified"
350 ;;
351 esac
352
353 # Handle the special /netmask instead of /prefix or
354 # "netmask xxx" case for legacy IP.
355 # We do NOT support shortend class-full netmasks.
356 if [ "${_type}" = "inet" ]; then
357 case "${_mask}" in
358 /*\.*\.*\.*) _mask=" netmask ${_mask#/}" ;;
359 *) ;;
360 esac
361
362 # In case _mask is still not set use /32.
363 _mask=${_mask:-/32}
364
365 elif [ "${_type}" = "inet6" ]; then
366 # In case _maske is not set for IPv6, use /128.
367 _mask=${_mask:-/128}
368 fi
369}
370
371# jail_handle_ips_option {add,del} input
372# Handle a single argument imput which can be a comma separated
373# list of addresses (theoretically with an option interface and
374# prefix/netmask/prefixlen).
375#
376jail_handle_ips_option()
377{
378 local _x _action _type _i
379 _action=$1
380 _x=$2
381
382 if [ -z "${_x}" ]; then
383 # No IP given. This can happen for the primary address
384 # of each address family.
385 return
386 fi
387
388 # Loop, in case we find a comma separated list, we need to handle
389 # each argument on its own.
390 while [ ${#_x} -gt 0 ]; do
391 case "${_x}" in
392 *,*) # Extract the first argument and strip it off the list.
393 _i=`expr "${_x}" : '^\([^,]*\)'`
394 _x=`expr "${_x}" : "^[^,]*,\(.*\)"`
395 ;;
396 *) _i=${_x}
397 _x=""
398 ;;
399 esac
400
401 _type=""
402 _iface=""
403 _addr=""
404 _mask=""
405 jail_extract_address "${_i}"
406
407 # make sure we got an address.
408 case "${_addr}" in
409 "") continue ;;
410 *) ;;
411 esac
412
413 # Append address to list of addresses for the jail command.
414 case "${_addrl}" in
415 "") _addrl="${_addr}" ;;
416 *) _addrl="${_addrl},${_addr}" ;;
417 esac
418
419 # Configure interface alias if requested by a given interface
420 # and if we could correctly parse everything.
421 case "${_iface}" in
422 "") continue ;;
423 esac
424 case "${_type}" in
425 inet) ;;
426 inet6) ;;
427 *) warn "Could not determine address family. Not going" \
428 "to ${_action} address '${_addr}' for ${_jail}."
429 continue
430 ;;
431 esac
432 case "${_action}" in
433 add) ifconfig ${_iface} ${_type} ${_addr}${_mask} alias
434 ;;
435 del) # When removing the IP, ignore the _mask.
436 ifconfig ${_iface} ${_type} ${_addr} -alias
437 ;;
438 esac
439 done
440}
441
442# jail_ips {add,del}
443# Extract the comma separated list of addresses and return them
444# for the jail command.
445# Handle more than one address via the _multi option as well.
446# If an interface is given also add/remove an alias for the
447# address with an optional netmask.
448#
449jail_ips()
450{
451 local _action
452 _action=$1
453
454 case "${_action}" in
455 add) ;;
456 del) ;;
457 *) warn "jail_ips: invalid action '${_action}'"
458 return
459 ;;
460 esac
461
462 # Handle addresses.
463 jail_handle_ips_option ${_action} "${_ip}"
464 # Handle jail_xxx_ip_multi<N>
465 alias=0
466 while : ; do
467 eval _x=\"\$jail_${_jail}_ip_multi${alias}\"
468 case "${_x}" in
469 "") break ;;
470 *) jail_handle_ips_option ${_action} "${_x}"
471 alias=$((${alias} + 1))
472 ;;
473 esac
474 done
475}
476
477jail_start()
478{
479 echo -n 'Configuring jails:'
480 set_sysctl jail_set_hostname_allow security.jail.set_hostname_allowed \
481 set_hostname_allow
482 set_sysctl jail_socket_unixiproute_only \
483 security.jail.socket_unixiproute_only unixiproute_only
484 set_sysctl jail_sysvipc_allow security.jail.sysvipc_allowed \
485 sysvipc_allow
486 echo '.'
487
488 echo -n 'Starting jails:'
489 _tmp_dir=`mktemp -d /tmp/jail.XXXXXXXX` || \
490 err 3 "$name: Can't create temp dir, exiting..."
491 for _jail in ${jail_list}
492 do
493 init_variables $_jail
494 if [ -f /var/run/jail_${_jail}.id ]; then
495 echo -n " [${_hostname} already running (/var/run/jail_${_jail}.id exists)]"
496 continue;
497 fi
498 _addrl=""
499 jail_ips "add"
500 if [ -n "${_fib}" ]; then
501 _setfib="setfib -F '${_fib}'"
502 else
503 _setfib=""
504 fi
505 if checkyesno _mount; then
506 info "Mounting fstab for jail ${_jail} (${_fstab})"
507 if [ ! -f "${_fstab}" ]; then
508 err 3 "$name: ${_fstab} does not exist"
509 fi
510 jail_mount_fstab
511 fi
512 if checkyesno _devfs; then
513 # If devfs is already mounted here, skip it.
514 df -t devfs "${_devdir}" >/dev/null
515 if [ $? -ne 0 ]; then
516 if is_symlinked_mountpoint ${_devdir}; then
517 warn "${_devdir} has symlink as parent - not starting jail ${_jail}"
518 continue
519 fi
520 info "Mounting devfs on ${_devdir}"
521 devfs_mount_jail "${_devdir}" ${_ruleset}
522 # Transitional symlink for old binaries
523 if [ ! -L "${_devdir}/log" ]; then
524 __pwd="`pwd`"
525 cd "${_devdir}"
526 ln -sf ../var/run/log log
527 cd "$__pwd"
528 fi
529 fi
530
531 # XXX - It seems symlinks don't work when there
532 # is a devfs(5) device of the same name.
533 # Jail console output
534 # __pwd="`pwd`"
535 # cd "${_devdir}"
536 # ln -sf ../var/log/console console
537 # cd "$__pwd"
538 fi
539 if checkyesno _fdescfs; then
540 if is_symlinked_mountpoint ${_fdescdir}; then
541 warn "${_fdescdir} has symlink as parent, not mounting"
542 else
543 info "Mounting fdescfs on ${_fdescdir}"
544 mount -t fdescfs fdesc "${_fdescdir}"
545 fi
546 fi
547 if checkyesno _procfs; then
548 if is_symlinked_mountpoint ${_procdir}; then
549 warn "${_procdir} has symlink as parent, not mounting"
550 else
551 info "Mounting procfs onto ${_procdir}"
552 if [ -d "${_procdir}" ] ; then
553 mount -t procfs proc "${_procdir}"
554 fi
555 fi
556 fi
557 _tmp_jail=${_tmp_dir}/jail.$$
193 debug "$_j flags: $_flags"
194 debug "$_j consolelog: $_consolelog"
195
196 if [ -z "${_hostname}" ]; then
197 err 3 "$name: No hostname has been defined for ${_j}"
198 fi
199 if [ -z "${_rootdir}" ]; then
200 err 3 "$name: No root directory has been defined for ${_j}"
201 fi
202}
203
204# set_sysctl rc_knob mib msg
205# If the mib sysctl is set according to what rc_knob
206# specifies, this function does nothing. However if
207# rc_knob is set differently than mib, then the mib
208# is set accordingly and msg is displayed followed by
209# an '=" sign and the word 'YES' or 'NO'.
210#
211set_sysctl()
212{
213 _knob="$1"
214 _mib="$2"
215 _msg="$3"
216
217 _current=`${SYSCTL} -n $_mib 2>/dev/null`
218 if checkyesno $_knob ; then
219 if [ "$_current" -ne 1 ]; then
220 echo -n " ${_msg}=YES"
221 ${SYSCTL_W} 1>/dev/null ${_mib}=1
222 fi
223 else
224 if [ "$_current" -ne 0 ]; then
225 echo -n " ${_msg}=NO"
226 ${SYSCTL_W} 1>/dev/null ${_mib}=0
227 fi
228 fi
229}
230
231# is_current_mountpoint()
232# Is the directory mount point for a currently mounted file
233# system?
234#
235is_current_mountpoint()
236{
237 local _dir _dir2
238
239 _dir=$1
240
241 _dir=`echo $_dir | sed -Ee 's#//+#/#g' -e 's#/$##'`
242 [ ! -d "${_dir}" ] && return 1
243 _dir2=`df ${_dir} | tail +2 | awk '{ print $6 }'`
244 [ "${_dir}" = "${_dir2}" ]
245 return $?
246}
247
248# is_symlinked_mountpoint()
249# Is a mount point, or any of its parent directories, a symlink?
250#
251is_symlinked_mountpoint()
252{
253 local _dir
254
255 _dir=$1
256
257 [ -L "$_dir" ] && return 0
258 [ "$_dir" = "/" ] && return 1
259 is_symlinked_mountpoint `dirname $_dir`
260 return $?
261}
262
263# secure_umount
264# Try to unmount a mount point without being vulnerable to
265# symlink attacks.
266#
267secure_umount()
268{
269 local _dir
270
271 _dir=$1
272
273 if is_current_mountpoint ${_dir}; then
274 umount -f ${_dir} >/dev/null 2>&1
275 else
276 debug "Nothing mounted on ${_dir} - not unmounting"
277 fi
278}
279
280
281# jail_umount_fs
282# This function unmounts certain special filesystems in the
283# currently selected jail. The caller must call the init_variables()
284# routine before calling this one.
285#
286jail_umount_fs()
287{
288 local _device _mountpt _rest
289
290 if checkyesno _fdescfs; then
291 if [ -d "${_fdescdir}" ] ; then
292 secure_umount ${_fdescdir}
293 fi
294 fi
295 if checkyesno _devfs; then
296 if [ -d "${_devdir}" ] ; then
297 secure_umount ${_devdir}
298 fi
299 fi
300 if checkyesno _procfs; then
301 if [ -d "${_procdir}" ] ; then
302 secure_umount ${_procdir}
303 fi
304 fi
305 if checkyesno _mount; then
306 [ -f "${_fstab}" ] || warn "${_fstab} does not exist"
307 tail -r ${_fstab} | while read _device _mountpt _rest; do
308 case ":${_device}" in
309 :#* | :)
310 continue
311 ;;
312 esac
313 secure_umount ${_mountpt}
314 done
315 fi
316}
317
318# jail_mount_fstab()
319# Mount file systems from a per jail fstab while trying to
320# secure against symlink attacks at the mount points.
321#
322# If we are certain we cannot secure against symlink attacks we
323# do not mount all of the file systems (since we cannot just not
324# mount the file system with the problematic mount point).
325#
326# The caller must call the init_variables() routine before
327# calling this one.
328#
329jail_mount_fstab()
330{
331 local _device _mountpt _rest
332
333 while read _device _mountpt _rest; do
334 case ":${_device}" in
335 :#* | :)
336 continue
337 ;;
338 esac
339 if is_symlinked_mountpoint ${_mountpt}; then
340 warn "${_mountpt} has symlink as parent - not mounting from ${_fstab}"
341 return
342 fi
343 done <${_fstab}
344 mount -a -F "${_fstab}"
345}
346
347# jail_show_addresses jail
348# Debug print the input for the given _multi aliases
349# for a jail for init_variables().
350#
351jail_show_addresses()
352{
353 local _j _type alias
354 _j="$1"
355 alias=0
356
357 if [ -z "${_j}" ]; then
358 warn "jail_show_addresses: you must specify a jail"
359 return
360 fi
361
362 while : ; do
363 eval _addr=\"\$jail_${_j}_ip_multi${alias}\"
364 if [ -n "${_addr}" ]; then
365 debug "${_j} ip_multi${alias}: $_addr"
366 alias=$((${alias} + 1))
367 else
368 break
369 fi
370 done
371}
372
373# jail_extract_address argument
374# The second argument is the string from one of the _ip
375# or the _multi variables. In case of a comma separated list
376# only one argument must be passed in at a time.
377# The function alters the _type, _iface, _addr and _mask variables.
378#
379jail_extract_address()
380{
381 local _i
382 _i=$1
383
384 if [ -z "${_i}" ]; then
385 warn "jail_extract_address: called without input"
386 return
387 fi
388
389 # Check if we have an interface prefix given and split into
390 # iFace and rest.
391 case "${_i}" in
392 *\|*) # ifN|.. prefix there
393 _iface=${_i%%|*}
394 _r=${_i##*|}
395 ;;
396 *) _iface=""
397 _r=${_i}
398 ;;
399 esac
400
401 # In case the IP has no interface given, check if we have a global one.
402 _iface=${_iface:-${_interface}}
403
404 # Set address, cut off any prefix/netmask/prefixlen.
405 _addr=${_r}
406 _addr=${_addr%%[/ ]*}
407
408 # Theoretically we can return here if interface is not set,
409 # as we only care about the _mask if we call ifconfig.
410 # This is not done because we may want to santize IP addresses
411 # based on _type later, and optionally change the type as well.
412
413 # Extract the prefix/netmask/prefixlen part by cutting off the address.
414 _mask=${_r}
415 _mask=`expr "${_mask}" : "${_addr}\(.*\)"`
416
417 # Identify type {inet,inet6}.
418 case "${_addr}" in
419 *\.*\.*\.*) _type="inet" ;;
420 *:*) _type="inet6" ;;
421 *) warn "jail_extract_address: type not identified"
422 ;;
423 esac
424
425 # Handle the special /netmask instead of /prefix or
426 # "netmask xxx" case for legacy IP.
427 # We do NOT support shortend class-full netmasks.
428 if [ "${_type}" = "inet" ]; then
429 case "${_mask}" in
430 /*\.*\.*\.*) _mask=" netmask ${_mask#/}" ;;
431 *) ;;
432 esac
433
434 # In case _mask is still not set use /32.
435 _mask=${_mask:-/32}
436
437 elif [ "${_type}" = "inet6" ]; then
438 # In case _maske is not set for IPv6, use /128.
439 _mask=${_mask:-/128}
440 fi
441}
442
443# jail_handle_ips_option {add,del} input
444# Handle a single argument imput which can be a comma separated
445# list of addresses (theoretically with an option interface and
446# prefix/netmask/prefixlen).
447#
448jail_handle_ips_option()
449{
450 local _x _action _type _i
451 _action=$1
452 _x=$2
453
454 if [ -z "${_x}" ]; then
455 # No IP given. This can happen for the primary address
456 # of each address family.
457 return
458 fi
459
460 # Loop, in case we find a comma separated list, we need to handle
461 # each argument on its own.
462 while [ ${#_x} -gt 0 ]; do
463 case "${_x}" in
464 *,*) # Extract the first argument and strip it off the list.
465 _i=`expr "${_x}" : '^\([^,]*\)'`
466 _x=`expr "${_x}" : "^[^,]*,\(.*\)"`
467 ;;
468 *) _i=${_x}
469 _x=""
470 ;;
471 esac
472
473 _type=""
474 _iface=""
475 _addr=""
476 _mask=""
477 jail_extract_address "${_i}"
478
479 # make sure we got an address.
480 case "${_addr}" in
481 "") continue ;;
482 *) ;;
483 esac
484
485 # Append address to list of addresses for the jail command.
486 case "${_addrl}" in
487 "") _addrl="${_addr}" ;;
488 *) _addrl="${_addrl},${_addr}" ;;
489 esac
490
491 # Configure interface alias if requested by a given interface
492 # and if we could correctly parse everything.
493 case "${_iface}" in
494 "") continue ;;
495 esac
496 case "${_type}" in
497 inet) ;;
498 inet6) ;;
499 *) warn "Could not determine address family. Not going" \
500 "to ${_action} address '${_addr}' for ${_jail}."
501 continue
502 ;;
503 esac
504 case "${_action}" in
505 add) ifconfig ${_iface} ${_type} ${_addr}${_mask} alias
506 ;;
507 del) # When removing the IP, ignore the _mask.
508 ifconfig ${_iface} ${_type} ${_addr} -alias
509 ;;
510 esac
511 done
512}
513
514# jail_ips {add,del}
515# Extract the comma separated list of addresses and return them
516# for the jail command.
517# Handle more than one address via the _multi option as well.
518# If an interface is given also add/remove an alias for the
519# address with an optional netmask.
520#
521jail_ips()
522{
523 local _action
524 _action=$1
525
526 case "${_action}" in
527 add) ;;
528 del) ;;
529 *) warn "jail_ips: invalid action '${_action}'"
530 return
531 ;;
532 esac
533
534 # Handle addresses.
535 jail_handle_ips_option ${_action} "${_ip}"
536 # Handle jail_xxx_ip_multi<N>
537 alias=0
538 while : ; do
539 eval _x=\"\$jail_${_jail}_ip_multi${alias}\"
540 case "${_x}" in
541 "") break ;;
542 *) jail_handle_ips_option ${_action} "${_x}"
543 alias=$((${alias} + 1))
544 ;;
545 esac
546 done
547}
548
549jail_start()
550{
551 echo -n 'Configuring jails:'
552 set_sysctl jail_set_hostname_allow security.jail.set_hostname_allowed \
553 set_hostname_allow
554 set_sysctl jail_socket_unixiproute_only \
555 security.jail.socket_unixiproute_only unixiproute_only
556 set_sysctl jail_sysvipc_allow security.jail.sysvipc_allowed \
557 sysvipc_allow
558 echo '.'
559
560 echo -n 'Starting jails:'
561 _tmp_dir=`mktemp -d /tmp/jail.XXXXXXXX` || \
562 err 3 "$name: Can't create temp dir, exiting..."
563 for _jail in ${jail_list}
564 do
565 init_variables $_jail
566 if [ -f /var/run/jail_${_jail}.id ]; then
567 echo -n " [${_hostname} already running (/var/run/jail_${_jail}.id exists)]"
568 continue;
569 fi
570 _addrl=""
571 jail_ips "add"
572 if [ -n "${_fib}" ]; then
573 _setfib="setfib -F '${_fib}'"
574 else
575 _setfib=""
576 fi
577 if checkyesno _mount; then
578 info "Mounting fstab for jail ${_jail} (${_fstab})"
579 if [ ! -f "${_fstab}" ]; then
580 err 3 "$name: ${_fstab} does not exist"
581 fi
582 jail_mount_fstab
583 fi
584 if checkyesno _devfs; then
585 # If devfs is already mounted here, skip it.
586 df -t devfs "${_devdir}" >/dev/null
587 if [ $? -ne 0 ]; then
588 if is_symlinked_mountpoint ${_devdir}; then
589 warn "${_devdir} has symlink as parent - not starting jail ${_jail}"
590 continue
591 fi
592 info "Mounting devfs on ${_devdir}"
593 devfs_mount_jail "${_devdir}" ${_ruleset}
594 # Transitional symlink for old binaries
595 if [ ! -L "${_devdir}/log" ]; then
596 __pwd="`pwd`"
597 cd "${_devdir}"
598 ln -sf ../var/run/log log
599 cd "$__pwd"
600 fi
601 fi
602
603 # XXX - It seems symlinks don't work when there
604 # is a devfs(5) device of the same name.
605 # Jail console output
606 # __pwd="`pwd`"
607 # cd "${_devdir}"
608 # ln -sf ../var/log/console console
609 # cd "$__pwd"
610 fi
611 if checkyesno _fdescfs; then
612 if is_symlinked_mountpoint ${_fdescdir}; then
613 warn "${_fdescdir} has symlink as parent, not mounting"
614 else
615 info "Mounting fdescfs on ${_fdescdir}"
616 mount -t fdescfs fdesc "${_fdescdir}"
617 fi
618 fi
619 if checkyesno _procfs; then
620 if is_symlinked_mountpoint ${_procdir}; then
621 warn "${_procdir} has symlink as parent, not mounting"
622 else
623 info "Mounting procfs onto ${_procdir}"
624 if [ -d "${_procdir}" ] ; then
625 mount -t procfs proc "${_procdir}"
626 fi
627 fi
628 fi
629 _tmp_jail=${_tmp_dir}/jail.$$
630
631 i=0
632 while : ; do
633 eval out=\"\${_exec_prestart${i}:-''}\"
634 [ -z "$out" ] && break
635 ${out}
636 i=$((i + 1))
637 done
638
558 eval ${_setfib} jail ${_flags} -i ${_rootdir} ${_hostname} \
559 \"${_addrl}\" ${_exec_start} > ${_tmp_jail} 2>&1
560
561 if [ "$?" -eq 0 ] ; then
562 _jail_id=$(head -1 ${_tmp_jail})
563 i=1
564 while [ true ]; do
565 eval out=\"\${_exec_afterstart${i}:-''}\"
566
567 if [ -z "$out" ]; then
568 break;
569 fi
570
571 jexec "${_jail_id}" ${out}
572 i=$((i + 1))
573 done
574
575 echo -n " $_hostname"
576 tail +2 ${_tmp_jail} >${_consolelog}
577 echo ${_jail_id} > /var/run/jail_${_jail}.id
639 eval ${_setfib} jail ${_flags} -i ${_rootdir} ${_hostname} \
640 \"${_addrl}\" ${_exec_start} > ${_tmp_jail} 2>&1
641
642 if [ "$?" -eq 0 ] ; then
643 _jail_id=$(head -1 ${_tmp_jail})
644 i=1
645 while [ true ]; do
646 eval out=\"\${_exec_afterstart${i}:-''}\"
647
648 if [ -z "$out" ]; then
649 break;
650 fi
651
652 jexec "${_jail_id}" ${out}
653 i=$((i + 1))
654 done
655
656 echo -n " $_hostname"
657 tail +2 ${_tmp_jail} >${_consolelog}
658 echo ${_jail_id} > /var/run/jail_${_jail}.id
659
660 i=0
661 while : ; do
662 eval out=\"\${_exec_poststart${i}:-''}\"
663 [ -z "$out" ] && break
664 ${out}
665 i=$((i + 1))
666 done
578 else
579 jail_umount_fs
580 jail_ips "del"
581 echo " cannot start jail \"${_jail}\": "
582 tail +2 ${_tmp_jail}
583 fi
584 rm -f ${_tmp_jail}
585 done
586 rmdir ${_tmp_dir}
587 echo '.'
588}
589
590jail_stop()
591{
592 echo -n 'Stopping jails:'
593 for _jail in ${jail_list}
594 do
595 if [ -f "/var/run/jail_${_jail}.id" ]; then
596 _jail_id=$(cat /var/run/jail_${_jail}.id)
597 if [ ! -z "${_jail_id}" ]; then
598 init_variables $_jail
667 else
668 jail_umount_fs
669 jail_ips "del"
670 echo " cannot start jail \"${_jail}\": "
671 tail +2 ${_tmp_jail}
672 fi
673 rm -f ${_tmp_jail}
674 done
675 rmdir ${_tmp_dir}
676 echo '.'
677}
678
679jail_stop()
680{
681 echo -n 'Stopping jails:'
682 for _jail in ${jail_list}
683 do
684 if [ -f "/var/run/jail_${_jail}.id" ]; then
685 _jail_id=$(cat /var/run/jail_${_jail}.id)
686 if [ ! -z "${_jail_id}" ]; then
687 init_variables $_jail
688
689 i=0
690 while : ; do
691 eval out=\"\${_exec_prestop${i}:-''}\"
692 [ -z "$out" ] && break
693 ${out}
694 i=$((i + 1))
695 done
696
599 if [ -n "${_exec_stop}" ]; then
600 eval env -i /usr/sbin/jexec ${_jail_id} ${_exec_stop} \
601 >> ${_consolelog} 2>&1
602 fi
603 killall -j ${_jail_id} -TERM > /dev/null 2>&1
604 sleep 1
605 killall -j ${_jail_id} -KILL > /dev/null 2>&1
606 jail_umount_fs
607 echo -n " $_hostname"
697 if [ -n "${_exec_stop}" ]; then
698 eval env -i /usr/sbin/jexec ${_jail_id} ${_exec_stop} \
699 >> ${_consolelog} 2>&1
700 fi
701 killall -j ${_jail_id} -TERM > /dev/null 2>&1
702 sleep 1
703 killall -j ${_jail_id} -KILL > /dev/null 2>&1
704 jail_umount_fs
705 echo -n " $_hostname"
706
707 i=0
708 while : ; do
709 eval out=\"\${_exec_poststop${i}:-''}\"
710 [ -z "$out" ] && break
711 ${out}
712 i=$((i + 1))
713 done
608 fi
609 jail_ips "del"
610 rm /var/run/jail_${_jail}.id
611 else
612 echo " cannot stop jail ${_jail}. No jail id in /var/run"
613 fi
614 done
615 echo '.'
616}
617
618load_rc_config $name
619cmd="$1"
620if [ $# -gt 0 ]; then
621 shift
622fi
623if [ -n "$*" ]; then
624 jail_list="$*"
625fi
626run_rc_command "${cmd}"
714 fi
715 jail_ips "del"
716 rm /var/run/jail_${_jail}.id
717 else
718 echo " cannot stop jail ${_jail}. No jail id in /var/run"
719 fi
720 done
721 echo '.'
722}
723
724load_rc_config $name
725cmd="$1"
726if [ $# -gt 0 ]; then
727 shift
728fi
729if [ -n "$*" ]; then
730 jail_list="$*"
731fi
732run_rc_command "${cmd}"