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