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 $_mib 2>/dev/null` 110 if checkyesno $_knob ; then 111 if [ "$_current" -ne 1 ]; then 112 echo -n " ${_msg}=YES" 113 ${SYSCTL_W} 1>/dev/null ${_mib}=1 114 fi 115 else 116 if [ "$_current" -ne 0 ]; then 117 echo -n " ${_msg}=NO" 118 ${SYSCTL_W} 1>/dev/null ${_mib}=0 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 'Configuring jails:' 237 set_sysctl jail_set_hostname_allow jail.set_hostname_allowed \ 238 set_hostname_allow 239 set_sysctl jail_socket_unixiproute_only \ 240 jail.socket_unixiproute_only unixiproute_only 241 set_sysctl jail_sysvipc_allow jail.sysvipc_allowed \ 242 sysvipc_allow 243 echo '.' 244 245 echo -n 'Starting jails:' 246 _tmp_dir=`mktemp -d /tmp/jail.XXXXXXXX` || \ 247 err 3 "$name: Can't create temp dir, exiting..." 248 for _jail in ${jail_list} 249 do 250 init_variables $_jail 251 if [ -f /var/run/jail_${_jail}.id ]; then 252 echo -n " [${_hostname} already running (/var/run/jail_${_jail}.id exists)]" 253 continue; 254 fi 255 if [ -n "${_interface}" ]; then 256 ifconfig ${_interface} alias ${_ip} netmask 255.255.255.255 257 fi 258 if checkyesno _mount; then 259 info "Mounting fstab for jail ${_jail} (${_fstab})" 260 if [ ! -f "${_fstab}" ]; then 261 err 3 "$name: ${_fstab} does not exist" 262 fi 263 jail_mount_fstab 264 fi 265 if checkyesno _devfs; then 266 # If devfs is already mounted here, skip it. 267 df -t devfs "${_devdir}" >/dev/null 268 if [ $? -ne 0 ]; then 269 if is_symlinked_mountpoint ${_devdir}; then 270 warn "${_devdir} has symlink as parent" \ 271 "- not starting jail ${_jail}" 272 continue 273 fi 274 info "Mounting devfs on ${_devdir}" 275 devfs_mount_jail "${_devdir}" 276 fi 277 fi 278 if checkyesno _procfs; then 279 if is_symlinked_mountpoint ${_procdir}; then 280 warn "${_procdir} has symlink as parent, not mounting" 281 else 282 info "Mounting procfs onto ${_procdir}" 283 if [ -d "${_procdir}" ] ; then 284 mount -t procfs proc "${_procdir}" 285 fi 286 fi 287 fi 288 _tmp_jail=${_tmp_dir}/jail.$$ 289 eval jail ${_flags} -i ${_rootdir} ${_hostname} \ 290 ${_ip} ${_exec_start} > ${_tmp_jail} 2>&1 291 if [ "$?" -eq 0 ] ; then 292 echo -n " $_hostname" 293 _jail_id=$(head -1 ${_tmp_jail}) 294 tail +2 ${_tmp_jail} >${_consolelog} 295 echo ${_jail_id} > /var/run/jail_${_jail}.id 296 else 297 jail_umount_fs 298 if [ -n "${_interface}" ]; then 299 ifconfig ${_interface} -alias ${_ip} 300 fi 301 echo " cannot start jail \"${_jail}\": " 302 tail +2 ${_tmp_jail} 303 fi 304 rm -f ${_tmp_jail} 305 done 306 rmdir ${_tmp_dir} 307 echo '.' 308} 309 310jail_stop() 311{ 312 echo -n 'Stopping jails:' 313 for _jail in ${jail_list} 314 do 315 if [ -f "/var/run/jail_${_jail}.id" ]; then 316 _jail_id=$(cat /var/run/jail_${_jail}.id) 317 if [ ! -z "${_jail_id}" ]; then 318 init_variables $_jail 319 if [ -n "${_exec_stop}" ]; then 320 eval env -i /usr/sbin/jexec ${_jail_id} ${_exec_stop} \ 321 >> ${_consolelog} 2>&1 322 fi 323 killall -j ${_jail_id} -TERM > /dev/null 2>&1 324 sleep 1 325 killall -j ${_jail_id} -KILL > /dev/null 2>&1 326 jail_umount_fs 327 echo -n " $_hostname" 328 fi 329 if [ -n "${_interface}" ]; then 330 ifconfig ${_interface} -alias ${_ip} 331 fi 332 rm /var/run/jail_${_jail}.id 333 else 334 echo " cannot stop jail ${_jail}. No jail id in /var/run" 335 fi 336 done 337 echo '.' 338} 339 340load_rc_config $name 341cmd="$1" 342if [ $# -gt 0 ]; then 343 shift 344fi 345if [ -n "$*" ]; then 346 jail_list="$*" 347fi 348run_rc_command "${cmd}" 349