# -*- mode: sh; -*- # vim: ft=sh # This file is intended to be a wrapper to /etc/rc.d/rc.subr # that makes it easy to run software inside of chroot jails. # It handles the copying of programs by automatically detecting # and installing required shared libraries. # # NOTE: This file sources /etc/rc.d/rc.subr! DO NOT source it yourself. # # To use this file, simply include it as # . /etc/rc.d/chroot_base # Then, use the provided functions in rc_pre and rc_post to # set up the chroot jail. # # The following variables MUST be defined BEFORE sourcing this file: # chroot_exec - program to run inside chroot jail # chroot_user - user to drop permissions to inside of chroot # chroot_group - group to drop permissions to inside of chroot # chroot_root - path of chroot jail. Should be owned by root:wheel # and writable only by root # # The following variables MAY be defined BEFORE sourcing this file: # chroot_home - if set, the value of $HOME is set to this before the program is started # chroot_bin - if set, programs will be coppied here instead of to /bin. See chroot_env_exec # for information about adding this to $PATH # chroot_env_exec - if set, will be used as the path to the 'env' program in the chroot. You # must install and remove this program yourself. If this is set and chroot_bin # set, chroot bin will be added to PATH # chroot_lib - if set, libraries will be coppied here instead of /usr/lib and it will be added # to $LD_LIBRARY_PATH # chroot_no_ldso - if set to YES, this script will not touch ld.so in the jail # chroot_no_vars - if set to YES, this script will not set any of the daemon* variables or pexp. # In addition, you may ignore all the variables except chroot_root # # The following function are defined by this script: # chroot_install - copy files to the chroot # chroot_install_program - copy a program and all of its libraries into the chroot # chroot_rm - delete files from the chroot # chroot_rm_program - delete a program from the chroot along with all of its libraries # chroot_mkdev - create device files in the chroot's /dev # chroot_mknull - create /dev/null in the chroot # Internal variables used by functions _chroot_root_dir="${chroot_root%/}/" if [ -z "${chroot_home}" ]; then _chroot_user_home="$(grep "${chroot_user}" /etc/passwd | cut -d ":" -f6)" else _chroot_user_home="${chroot_home}" fi if [ -z "${chroot_bin}" ]; then _chroot_bin_dir="${_chroot_root_dir}bin/" _chroot_env_path="PATH='$(getconf PATH)'" else chroot_bin="${chroot_bin%/}" _chroot_bin_dir="${_chroot_root_dir}${chroot_bin#/}/" _chroot_env_path="PATH='${chroot_bin}:$(getconf PATH)'" fi if [ -z "${chroot_lib}" ]; then _chroot_lib_dir="${_chroot_root_dir}usr/lib/" else chroot_lib="${chroot_lib%/}" _chroot_lib_dir="${_chroot_root_dir}${chroot_lib#/}/" _chroot_env_ld="LD_LIBRARY_PATH='${chroot_lib}'" fi _chroot_chroot_cmd="/usr/sbin/chroot -u '${chroot_user}' -g '${chroot_user}' '${chroot_root}'" # find our env command if [ -z "${chroot_env_exec}" ]; then # There is no env inside the chroot, therefore we run it before chroot # However, this means we cannon env PATH because the chroot resets it _chroot_env_cmd="/usr/bin/env HOME='${_chroot_user_home}' ${_chroot_env_ld}" else # The user has put env inside the chroot # Run it inside, allowing us to set path _chroot_inside_env_cmd="${chroot_env_exec} HOME='${_chroot_user_home}' ${_chroot_env_ld} ${_chroot_env_path}" fi # Set normal rc.subr variables from chroot_* variables if [ "${chroot_no_vars}" != "YES" ]; then daemon_user="root" daemon="${_chroot_env_cmd} ${_chroot_chroot_cmd} ${_chroot_inside_env_cmd} ${chroot_exec}" fi # Source rc.subr . /etc/rc.d/rc.subr # Fix the pexp for the chroot if [ "${chroot_no_vars}" != "YES" ]; then pexp="$(eval echo ${chroot_exec}${daemon_flags:+ ${daemon_flags}})" fi # usage: chroot_install [files ...] # Copy files into the chroot. Permissions, owner, group, and flags are preserved. function chroot_install { for file in ${@}; do local rel_file if echo "${file}" | grep -E '^/' >/dev/null; then rel_file="$(echo "${file}" | cut -c '2-')" # remove leading / else rel_file="${file}" fi local dir="$(dirname "${rel_file}")" if ! [ -d "${_chroot_root_dir}${dir}" ]; then mkdir -p "${_chroot_root_dir}${dir}" echo "Created '${_chroot_root_dir}${dir}'" fi cp -Rp "${file}" "${_chroot_root_dir}${rel_file}" echo "Installed '${file}' to '${_chroot_root_dir}${rel_file}'" done } # usage: chroot_install_program [name] # Install the program FILE and all of its shared library dependencies # to the chroot. Dependencies are found with ldd. If NAME is provided, # the program will be coppied as NAME. # # NOTE: By default, the program is installed to /bin in the chroot function chroot_install_program { echo "Installing dependencies for '${1}':" for dep in $(ldd "${1}" | tail -n '+4' | grep -Eo '/.+$'); do if [ "${dep}" == "/usr/libexec/ld.so" ]; then if [ "${chroot_no_ldso}" != "YES" ]; then if ! [ -d "${_chroot_root_dir}usr/libexec" ]; then mkdir -p "${_chroot_root_dir}usr/libexec" echo " - Created '${_chroot_root_dir}usr/libexec'" fi install -o root -g bin -m 0444 "${dep}" "${_chroot_root_dir}usr/libexec/ld.so" echo " - Installed '${dep}' to '${_chroot_root_dir}usr/libexec/ld.so'" fi else if ! [ -d "${_chroot_lib_dir}" ]; then mkdir -p "${_chroot_lib_dir}" echo " - Created '${_chroot_lib_dir}'" fi local name="$(basename "${dep}")" install -o root -g bin -m 0444 "${dep}" "${_chroot_lib_dir}${name}" echo " - Installed '${dep}' to '${_chroot_lib_dir}${name}'" fi done if ! [ -d "${_chroot_bin_dir}" ]; then mkdir -p "${_chroot_bin_dir}" echo "Created '${_chroot_bin_dir}'" fi local name if [ -z "${2}" ]; then name="$(basename "${1}")" else name="${2}" fi install -o root -g bin -m 0755 "${1}" "${_chroot_bin_dir}${name}" echo "Installed '${1}' to '${_chroot_bin_dir}${name}'" } # usage: chroot_rm_program # Find all libraries of program with ldd and delete them. # Then, delete the program FILE from /bin of the chroot. # # EXAMPLE: # The usage # chroot_rm_program "/usr/local/bin/git" # would run ldd on /bin/git in the chroot and delete all the # resulting libraries. It would then remove /bin/git from the # chroot. function chroot_rm_program { local name="$(basename "${1}")" local path="${_chroot_bin_dir}${name}" echo "Deleting dependencies for '${1}'" for dep in $(ldd "${path}" | tail -n '+4' | grep -Eo '/.+$'); do if [ "${dep}" == "/usr/libexec/ld.so" ]; then if [ "${chroot_no_ldso}" != "YES" ]; then rm -f "${_chroot_root_dir}usr/libexec/ld.so" echo " - Deleted '${_chroot_root_dir}usr/libexec/ld.so'" fi else local name="$(basename "${dep}")" rm -f "${_chroot_lib_dir}${name}" echo " - Deleted '${_chroot_lib_dir}${name}'" fi done rm -f "${path}" echo "Deleted '${path}'" } # usage: chroot_rm [files ...] # Remove files from the chroot function chroot_rm { for file in ${@}; do if echo "${file}" | grep -E '^/' >/dev/null; then file="$(echo "${file}" | cut -c '2-')" # remove leading / fi rm -rf "${_chroot_root_dir}${file}" echo "Deleted '${_chroot_root_dir}${file}'" done } # usage: chroot_mkdev [names ...] # Runs /dev/MAKEDEV with NAMES as the argument in the chroot's # /dev directory function chroot_mkdev { if ! [ -d "${_chroot_root_dir}dev" ]; then mkdir "${_chroot_root_dir}dev" echo "Created '${_chroot_root_dir}dev'" fi (cd "${_chroot_root_dir}dev" && /dev/MAKEDEV "$@") echo "Created device files for '$@' in '${_chroot_root_dir}dev'" } # usage: chroot_mknull # This is a convinience function that creates /dev/null in the # chroot. function chroot_mknull { if ! [ -d "${_chroot_root_dir}dev" ]; then mkdir "${_chroot_root_dir}dev" echo "Created '${_chroot_root_dir}dev'" fi mknod -m 0666 "${_chroot_root_dir}dev/null" c 2 2 echo "Created /dev/null as '${_chroot_root_dir}dev/null'" }