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