]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - etc/rc.d/jail
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / etc / rc.d / jail
1 #!/bin/sh
2 #
3 # $FreeBSD$
4 #
5
6 # PROVIDE: jail
7 # REQUIRE: LOGIN FILESYSTEMS
8 # BEFORE: securelevel
9 # KEYWORD: nojail shutdown
10
11 . /etc/rc.subr
12
13 name="jail"
14 rcvar="jail_enable"
15
16 start_cmd="jail_start"
17 start_postcmd="jail_warn"
18 stop_cmd="jail_stop"
19 config_cmd="jail_config"
20 console_cmd="jail_console"
21 status_cmd="jail_status"
22 extra_commands="config console status"
23 : ${jail_conf:=/etc/jail.conf}
24 : ${jail_program:=/usr/sbin/jail}
25 : ${jail_consolecmd:=/bin/sh}
26 : ${jail_jexec:=/usr/sbin/jexec}
27 : ${jail_jls:=/usr/sbin/jls}
28
29 need_dad_wait=
30
31 # extact_var jail name param num defval
32 #       Extract value from ${jail_$jail_$name} or ${jail_$name} and
33 #       set it to $param.  If not defined, $defval is used.
34 #       When $num is [0-9]*, ${jail_$jail_$name$num} are looked up and
35 #       $param is set by using +=.
36 #       When $num is YN or NY, the value is interpret as boolean.
37 extract_var()
38 {
39         local i _j _name _param _num _def _name1 _name2
40         _j=$1
41         _name=$2
42         _param=$3
43         _num=$4
44         _def=$5
45
46         case $_num in
47         YN)
48                 _name1=jail_${_j}_${_name}
49                 _name2=jail_${_name}
50                 eval $_name1=\"\${$_name1:-\${$_name2:-$_def}}\"
51                 if checkyesno $_name1; then
52                         echo "  $_param = 1;"
53                 else
54                         echo "  $_param = 0;"
55                 fi
56         ;;
57         NY)
58                 _name1=jail_${_j}_${_name}
59                 _name2=jail_${_name}
60                 eval $_name1=\"\${$_name1:-\${$_name2:-$_def}}\"
61                 if checkyesno $_name1; then
62                         echo "  $_param = 0;"
63                 else
64                         echo "  $_param = 1;"
65                 fi
66         ;;
67         [0-9]*)
68                 i=$_num
69                 while : ; do
70                         _name1=jail_${_j}_${_name}${i}
71                         _name2=jail_${_name}${i}
72                         eval _tmpargs=\"\${$_name1:-\${$_name2:-$_def}}\"
73                         if [ -n "$_tmpargs" ]; then 
74                                 echo "  $_param += \"$_tmpargs\";"
75                         else
76                                 break;
77                         fi
78                         i=$(($i + 1))
79                 done
80         ;;
81         *)
82                 _name1=jail_${_j}_${_name}
83                 _name2=jail_${_name}
84                 eval _tmpargs=\"\${$_name1:-\${$_name2:-$_def}}\"
85                 if [ -n "$_tmpargs" ]; then
86                         echo "  $_param = \"$_tmpargs\";"
87                 fi
88         ;;
89         esac
90 }
91
92 # parse_options _j
93 #       Parse options and create a temporary configuration file if necessary.
94 #
95 parse_options()
96 {
97         local _j
98         _j=$1
99
100         _confwarn=0
101         if [ -z "$_j" ]; then
102                 warn "parse_options: you must specify a jail"
103                 return
104         fi
105         eval _jconf=\"\${jail_${_j}_conf:-/etc/jail.${_j}.conf}\"
106         eval _rootdir=\"\$jail_${_j}_rootdir\"
107         eval _hostname=\"\$jail_${_j}_hostname\"
108         if [ -z "$_rootdir" -o \
109              -z "$_hostname" ]; then
110                 if [ -r "$_jconf" ]; then
111                         _conf="$_jconf"
112                         return 0
113                 elif [ -r "$jail_conf" ]; then
114                         _conf="$jail_conf"
115                         return 0
116                 else
117                         warn "Invalid configuration for $_j " \
118                             "(no jail.conf, no hostname, or no path).  " \
119                             "Jail $_j was ignored."
120                 fi
121                 return 1
122         fi
123         eval _ip=\"\$jail_${_j}_ip\"
124         if [ -z "$_ip" ] && ! check_kern_features vimage; then
125                 warn "no ipaddress specified and no vimage support.  " \
126                     "Jail $_j was ignored."
127                 return 1
128         fi
129         _conf=/var/run/jail.${_j}.conf
130         #
131         # To relieve confusion, show a warning message.
132         #
133         _confwarn=1
134         if [ -r "$jail_conf" -o -r "$_jconf" ]; then
135                 warn "$_conf is created and used for jail $_j."
136         fi
137         /usr/bin/install -m 0644 -o root -g wheel /dev/null $_conf || return 1
138
139         eval : \${jail_${_j}_flags:=${jail_flags}}
140         eval _exec=\"\$jail_${_j}_exec\"
141         eval _exec_start=\"\$jail_${_j}_exec_start\"
142         eval _exec_stop=\"\$jail_${_j}_exec_stop\"
143         if [ -n "${_exec}" ]; then
144                 #   simple/backward-compatible execution
145                 _exec_start="${_exec}"
146                 _exec_stop=""
147         else
148                 #   flexible execution
149                 if [ -z "${_exec_start}" ]; then
150                         _exec_start="/bin/sh /etc/rc"
151                         if [ -z "${_exec_stop}" ]; then
152                                 _exec_stop="/bin/sh /etc/rc.shutdown"
153                         fi
154                 fi
155         fi
156         eval _interface=\"\${jail_${_j}_interface:-${jail_interface}}\"
157         eval _parameters=\"\${jail_${_j}_parameters:-${jail_parameters}}\"
158         eval _fstab=\"\${jail_${_j}_fstab:-${jail_fstab:-/etc/fstab.$_j}}\"
159         (
160                 date +"# Generated by rc.d/jail at %Y-%m-%d %H:%M:%S"
161                 echo "$_j {"
162                 extract_var $_j hostname host.hostname - ""
163                 extract_var $_j rootdir path - ""
164                 if [ -n "$_ip" ]; then
165                         extract_var $_j interface interface - ""
166                         jail_handle_ips_option $_ip $_interface
167                         alias=0
168                         while : ; do
169                                 eval _x=\"\$jail_${_jail}_ip_multi${alias}\"
170                                 [ -z "$_x" ] && break
171
172                                 jail_handle_ips_option $_x $_interface
173                                 alias=$(($alias + 1))
174                         done
175                         case $need_dad_wait in
176                         1)
177                                 # Sleep to let DAD complete before
178                                 # starting services.
179                                 echo "  exec.start += \"sleep " \
180                                 $(($(${SYSCTL_N} net.inet6.ip6.dad_count) + 1)) \
181                                 "\";"
182                         ;;
183                         esac
184                         # These are applicable only to non-vimage jails. 
185                         extract_var $_j fib exec.fib - ""
186                         extract_var $_j socket_unixiproute_only \
187                             allow.raw_sockets NY YES
188                 else
189                         echo "  vnet;"
190                         extract_var $_j vnet_interface vnet.interface - ""
191                 fi
192
193                 echo "  exec.clean;"
194                 echo "  exec.system_user = \"root\";"
195                 echo "  exec.jail_user = \"root\";"
196                 extract_var $_j exec_prestart exec.prestart 0 ""
197                 extract_var $_j exec_poststart exec.poststart 0 ""
198                 extract_var $_j exec_prestop exec.prestop 0 ""
199                 extract_var $_j exec_poststop exec.poststop 0 ""
200
201                 echo "  exec.start += \"$_exec_start\";"
202                 extract_var $_j exec_afterstart exec.start 1 ""
203                 echo "  exec.stop = \"$_exec_stop\";"
204
205                 extract_var $_j consolelog exec.consolelog - \
206                     /var/log/jail_${_j}_console.log
207
208                 eval : \${jail_${_j}_devfs_enable:=${jail_devfs_enable:-NO}}
209                 if checkyesno jail_${_j}_devfs_enable; then
210                         echo "  mount.devfs;"
211                         case $_ruleset in
212                         "")     ;;
213                         [0-9]*) echo "  devfs_ruleset = \"$_ruleset\";" ;;
214                         devfsrules_jail)
215                                 # XXX: This is the default value,
216                                 # Let jail(8) to use the default because
217                                 # mount(8) only accepts an integer. 
218                                 # This should accept a ruleset name.
219                         ;;
220                         *)      warn "devfs_ruleset must be integer." ;;
221                         esac
222                         if [ -r $_fstab ]; then
223                                 echo "  mount.fstab = \"$_fstab\";"
224                         fi
225                 fi
226
227                 eval : \${jail_${_j}_fdescfs_enable:=${jail_fdescfs_enable:-NO}}
228                 if checkyesno jail_${_j}_fdescfs_enable; then
229                         echo "  mount += " \
230                             "\"fdescfs ${_rootdir%/}/dev/fd fdescfs rw 0 0\";"
231                 fi
232                 eval : \${jail_${_j}_procfs_enable:=${jail_procfs_enable:-NO}}
233                 if checkyesno jail_${_j}_procfs_enable; then
234                         echo "  mount += " \
235                             "\"procfs ${_rootdir%/}/proc procfs rw 0 0\";"
236                 fi
237
238                 echo "  ${_parameters};"
239
240                 eval : \${jail_${_j}_mount_enable:=${jail_mount_enable:-NO}}
241                 if checkyesno jail_${_j}_mount_enable; then
242                         echo "  allow.mount;" >> $_conf
243                 fi
244
245                 extract_var $_j set_hostname_allow allow.set_hostname YN NO
246                 extract_var $_j sysvipc_allow allow.sysvipc YN NO
247                 echo "}"
248         ) >> $_conf
249
250         return 0
251 }
252
253 # jail_extract_address argument iface
254 #       The second argument is the string from one of the _ip
255 #       or the _multi variables. In case of a comma separated list
256 #       only one argument must be passed in at a time.
257 #       The function alters the _type, _iface, _addr and _mask variables.
258 #
259 jail_extract_address()
260 {
261         local _i _interface
262         _i=$1
263         _interface=$2
264
265         if [ -z "${_i}" ]; then
266                 warn "jail_extract_address: called without input"
267                 return
268         fi
269
270         # Check if we have an interface prefix given and split into
271         # iFace and rest.
272         case "${_i}" in
273         *\|*)   # ifN|.. prefix there
274                 _iface=${_i%%|*}
275                 _r=${_i##*|}
276                 ;;
277         *)      _iface=""
278                 _r=${_i}
279                 ;;
280         esac
281
282         # In case the IP has no interface given, check if we have a global one.
283         _iface=${_iface:-${_interface}}
284
285         # Set address, cut off any prefix/netmask/prefixlen.
286         _addr=${_r}
287         _addr=${_addr%%[/ ]*}
288
289         # Theoretically we can return here if interface is not set,
290         # as we only care about the _mask if we call ifconfig.
291         # This is not done because we may want to santize IP addresses
292         # based on _type later, and optionally change the type as well.
293
294         # Extract the prefix/netmask/prefixlen part by cutting off the address.
295         _mask=${_r}
296         _mask=`expr "${_mask}" : "${_addr}\(.*\)"`
297
298         # Identify type {inet,inet6}.
299         case "${_addr}" in
300         *\.*\.*\.*)     _type="inet" ;;
301         *:*)            _type="inet6" ;;
302         *)              warn "jail_extract_address: type not identified"
303                         ;;
304         esac
305
306         # Handle the special /netmask instead of /prefix or
307         # "netmask xxx" case for legacy IP.
308         # We do NOT support shortend class-full netmasks.
309         if [ "${_type}" = "inet" ]; then
310                 case "${_mask}" in
311                 /*\.*\.*\.*)    _mask=" netmask ${_mask#/}" ;;
312                 *)              ;;
313                 esac
314
315                 # In case _mask is still not set use /32.
316                 _mask=${_mask:-/32}
317
318         elif [ "${_type}" = "inet6" ]; then
319                 # In case _maske is not set for IPv6, use /64.
320                 _mask=${_mask:-/64}
321         fi
322 }
323
324 # jail_handle_ips_option input iface
325 #       Handle a single argument imput which can be a comma separated
326 #       list of addresses (theoretically with an option interface and
327 #       prefix/netmask/prefixlen).
328 #
329 jail_handle_ips_option()
330 {
331         local _x _type _i _iface
332         _x=$1
333         _iface=$2
334
335         if [ -z "${_x}" ]; then
336                 # No IP given. This can happen for the primary address
337                 # of each address family.
338                 return
339         fi
340
341         # Loop, in case we find a comma separated list, we need to handle
342         # each argument on its own.
343         while [ ${#_x} -gt 0 ]; do
344                 case "${_x}" in
345                 *,*)    # Extract the first argument and strip it off the list.
346                         _i=`expr "${_x}" : '^\([^,]*\)'`
347                         _x=`expr "${_x}" : "^[^,]*,\(.*\)"`
348                 ;;
349                 *)      _i=${_x}
350                         _x=""
351                 ;;
352                 esac
353
354                 _type=""
355                 _addr=""
356                 _mask=""
357                 jail_extract_address $_i $_iface
358
359                 # make sure we got an address.
360                 case $_addr in
361                 "")     continue ;;
362                 *)      ;;
363                 esac
364
365                 # Append address to list of addresses for the jail command.
366                 case $_type in
367                 inet)
368                         echo "  ip4.addr += \"${_addr}${_mask}\";"
369                 ;;
370                 inet6)
371                         echo "  ip6.addr += \"${_addr}${_mask}\";"
372                         need_dad_wait=1
373                 ;;
374                 esac
375         done
376 }
377
378 jail_config()
379 {
380         case $1 in
381         _ALL)   return ;;
382         esac
383         for _jail in $@; do
384                 if parse_options $_jail; then 
385                         echo "$_jail: parameters are in $_conf."
386                 fi
387         done
388 }
389
390 jail_console()
391 {
392         # One argument that is not _ALL.
393         case $#:$1 in
394         1:_ALL) err 3 "Specify a jail name." ;;
395         1:*)    ;;
396         *)      err 3 "Specify a jail name." ;;
397         esac
398         eval _cmd=\${jail_$1_consolecmd:-$jail_consolecmd}
399         $jail_jexec $1 $_cmd
400 }
401
402 jail_status()
403 {
404
405         $jail_jls -N
406 }
407
408 jail_start()
409 {
410         if [ $# = 0 ]; then
411                 return
412         fi
413         echo -n 'Starting jails:'
414         case $1 in
415         _ALL)
416                 echo -n ' '
417                 command=$jail_program
418                 rc_flags=$jail_flags
419                 command_args="-f $jail_conf -c"
420                 $command $rc_flags $command_args "*"
421                 echo '.'
422                 return
423         ;;
424         esac
425         _tmp=`mktemp -t jail` || exit 3
426         for _jail in $@; do
427                 parse_options $_jail || continue
428
429                 eval rc_flags=\${jail_${_j}_flags:-$jail_flags}
430                 eval command=\${jail_${_j}_program:-$jail_program}
431                 if checkyesno jail_parallel_start; then
432                         command_args="-i -f $_conf -c $_jail &"
433                 else
434                         command_args="-i -f $_conf -c $_jail"
435                 fi
436                 if $command $rc_flags $command_args \
437                     >> $_tmp 2>&1 </dev/null; then
438                         echo -n " ${_hostname:-${_jail}}"
439                 else
440                         echo " cannot start jail \"${_hostname:-${jail}}\": "
441                         tail +2 $_tmp
442                 fi
443                 rm -f $_tmp
444         done
445         echo '.'
446 }
447
448 jail_stop()
449 {
450         if [ $# = 0 ]; then
451                 return
452         fi
453         echo -n 'Stopping jails:'
454         case $1 in
455         _ALL)
456                 echo -n ' '
457                 command=$jail_program
458                 rc_flags=$jail_flags
459                 command_args="-f $jail_conf -r"
460                 $command $rc_flags $command_args "*"
461                 echo '.'
462                 return
463         ;;
464         esac
465         for _jail in $@; do
466                 parse_options $_jail || continue
467                 eval command=\${jail_${_j}_program:-$jail_program}
468                 if $command -q -f $_conf -r $_jail; then
469                         echo -n " ${_hostname:-${_jail}}"
470                 fi
471         done
472         echo '.'
473 }
474
475 jail_warn()
476 {
477
478         # To relieve confusion, show a warning message.
479         case $_confwarn in
480         1)      warn "Per-jail configuration via jail_* variables " \
481                     "is obsolete.  Please consider to migrate to $jail_conf."
482         ;;
483         esac
484 }
485
486 load_rc_config $name
487 case $# in
488 1)      run_rc_command $@ ${jail_list:-_ALL} ;;
489 *)      run_rc_command $@ ;;
490 esac