From 3c2c7f64d3758be4c2d6a39426cf0fbe413d9cf3 Mon Sep 17 00:00:00 2001 From: Alexander Rosenberg Date: Fri, 23 Sep 2022 03:33:01 -0700 Subject: [PATCH] Initial commit --- README.md | 6 ++ chroot_base | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 README.md create mode 100644 chroot_base diff --git a/README.md b/README.md new file mode 100644 index 0000000..719df50 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# chroot_base + +This is a simple script that makes it easier to run rc.d scripts +in a chroot on OpenBSD. To start, put the script into your /etc/rc.d/ +directory. Then, take a look at the documentation in the script to +learn how to use it. diff --git a/chroot_base b/chroot_base new file mode 100644 index 0000000..8c0d3db --- /dev/null +++ b/chroot_base @@ -0,0 +1,218 @@ +# -*- 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'" +}