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