This repository has been archived on 2022-09-23. You can view files and clone it, but cannot push or open issues or pull requests.
chroot-base/chroot_base

219 lines
8.0 KiB
Bash

# -*- 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 <file> [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 <file>
# 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'"
}