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