#!/bin/sh # bastille-init # Bastille Extension for XigmaNAS x64 12.x and later. # Bastille Extension Forum: https://www.xigmanas.com/forums/viewtopic.php?f=71&t=14848 # Bastille Extension GitHub: https://github.com/JRGTH/xigmanas-bastille-extension # Bastille Homepage: http://bastillebsd.org/ # Bastille GitHub: https://github.com/BastilleBSD/bastille # # Debug script #set -x # Copyright (c) 2019-2025, Jose Rivera (joserprg@gmail.com). # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of the developer nor the names of contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # Set environment. PATH=${PATH}:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin # Determine full working directory. CWDIR=$(dirname $(realpath $0)) # Global variables. PLATFORM=$(uname -m) PRODUCT=$(uname -i) PRDVERSION=$(uname -r | cut -d '-' -f1 | tr -d '.') HOSTVERSION=$(freebsd-version | cut -d '-' -f1) BASTILLE_DIR=$(echo "${CWDIR}" | grep -o '[^/]*$') PRDPLATFORM=$(cat /etc/platform) PRDPRODUCT=$(cat /etc/prd.name) SCRIPTNAME=$(basename $0) CONFIG="/cf/conf/config.xml" PRDNAME="Bastille" APPNAME="bastille" EXTLOGFILE="${CWDIR}/log/bastille_ext.log" EXTLOCKFILE="/tmp/bastille_ext.lock" FULLAPPNAME="${APPNAME}-dist" WWWPATH="/usr/local/www" PKGCACHE="/var/cache/pkg" USRLOCAL="/usr/local" VARLOG="/var/log" EXTCONF="/conf/${APPNAME}_config" EXTCONFLINK="/var/etc/${APPNAME}_conf" BASTILLERCD="/usr/local/etc/rc.d/${APPNAME}" BASTILLEPATH="${USRLOCAL}/bin" BASTILLECONF="${USRLOCAL}/etc/${APPNAME}/${APPNAME}.conf" BASTILLECONFFILE="/conf/bastille_config" BASTILLECONFLINK="/var/etc/bastille_conf" BASTILLECONF_EXT="${CWDIR}/conf/bastille.conf.ext" INCLUDE_PATH="${CWDIR}/conf/system" FREEBSD_UPDATE="${INCLUDE_PATH}/freebsd-update/${HOSTVERSION}" SYSTEM_INCLUDE="${INCLUDE_PATH}/include/${HOSTVERSION}" INSTALLPATH="${CWDIR}/${FULLAPPNAME}" BRANCH="master" BASTILLE_URL="https://github.com/BastilleBSD/${APPNAME}/archive/${BRANCH}.zip" # Official Bastille Repository) BASTILLE_ALT="https://github.com/JRGTH/${APPNAME}/archive/${BRANCH}.zip" # Alternate Bastille Repository, early updates) BASTILLE_VERSION="https://raw.githubusercontent.com/BastilleBSD/${APPNAME}/${BRANCH}/usr/local/bin/${APPNAME}" GITURL="https://github.com/JRGTH/xigmanas-${APPNAME}-extension/archive/${BRANCH}.zip" VERFILE="https://raw.githubusercontent.com/JRGTH/xigmanas-${APPNAME}-extension/${BRANCH}/version" URL_FREEBSD="http://ftp.freebsd.org/pub/FreeBSD/releases/" URL_FREEBSD_OLD="https://ftp-archive.freebsd.org/pub/FreeBSD-Archive/old-releases/" URL_HARDENEDBSD="https://installers.hardenedbsd.org/pub/" URL_MIDNIGHTBSD="https://www.midnightbsd.org/ftp/MidnightBSD/releases/" OPT="${1}" ARG="${2}" # Load bastille configuration file. if [ -f "${BASTILLECONF}" ]; then . /${BASTILLECONF} elif [ -f "${INSTALLPATH}/${BASTILLECONF}" ]; then . /${INSTALLPATH}/${BASTILLECONF} fi # Unset variables. REQUIRED_UPDATE= CWDIR_TRIM= BASTILLE_ZFS_PREFIX_TRIM= BASTILLE_ZFS_ZPOOL_MOUNTPOINT= BASTILLE_ZFS_ZPOOL_MOUNTPOINT_TRIM= # Get extension ZFS config info. if [ "${bastille_zfs_enable}" = "YES" ] || [ "${bastille_zfs_enable}" = "yes" ]; then if [ -n "${bastille_zfs_prefix}" ] && [ -n "${bastille_zfs_zpool}" ]; then # Always enforce ZFS activation below "/mnt/" from the extension. if echo "${CWDIR}" | grep -q '/mnt/'; then CWDIR_TRIM=$(echo "${CWDIR}" | sed "s|/mnt/||;s|/${bastille_zfs_prefix}||") fi BASTILLE_ZFS_ZPOOL_MOUNTPOINT=$(zfs get -H -o value mountpoint "${bastille_zfs_zpool}" 2>/dev/null) if echo "${BASTILLE_ZFS_ZPOOL_MOUNTPOINT}" | grep -q '/mnt/'; then BASTILLE_ZFS_ZPOOL_MOUNTPOINT_TRIM=$(echo "${BASTILLE_ZFS_ZPOOL_MOUNTPOINT}" | sed "s|/mnt/||;s|/${bastille_zfs_prefix}||") fi BASTILLE_ZFS_PREFIX_TRIM=$(echo "${bastille_zfs_prefix}" | sed "s|/${APPNAME}||") fi # Check bastille ZFS config match on disk ZFS config. BASTILLE_CONFIG_DISK=$(zfs list -H "${bastille_prefix}" 2>/dev/null | awk '{print $1}') BASTILLE_CONFIG_FILE=$(echo "${bastille_zfs_zpool}/${bastille_zfs_prefix}") fi error_notify() { # Log/notify message on error and exit. MSG="$*" logger -t "${SCRIPTNAME}" "${MSG}" echo -e "$*" >&2; exit 1 } runtime_config() { # Run-time configuration and checks. if [ -f "${INSTALLPATH}/${BASTILLECONF}" ]; then if ! sysrc -f ${BASTILLECONF} -qc bastille_prefix="${CWDIR}"; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_prefix="${CWDIR}" >/dev/null 2>&1 fi fi # Check for required directories and files. if [ ! -d "${CWDIR}/backups" ]; then mkdir -p ${CWDIR}/backups fi if [ ! -d "${CWDIR}/conf" ]; then mkdir -p ${CWDIR}/conf fi if [ ! -d "${CWDIR}/log" ]; then mkdir -p ${CWDIR}/log fi if [ ! -d "${CWDIR}/locale-bastille" ]; then mkdir -p ${CWDIR}/locale-bastille fi if [ ! -d "${CWDIR}/freebsd-update" ]; then mkdir ${CWDIR}/freebsd-update fi if [ ! -f "${CWDIR}${BASTILLECONFFILE}" ]; then touch ${CWDIR}${BASTILLECONFFILE} fi if [ ! -d "${CWDIR}/system" ]; then mkdir -p ${CWDIR}/system fi # Check for permissions. if [ -f "${FREEBSD_UPDATE}/freebsd-update" ]; then FREEBSD_UPDATE_PERMS=$(stat -f "%Op" ${FREEBSD_UPDATE}/freebsd-update) if [ "${FREEBSD_UPDATE_PERMS}" != 100555 ]; then chmod 0555 ${FREEBSD_UPDATE}/freebsd-update fi fi # Workaround to check for host /tmp sane permissions. # This is because after working with Linux jails, this may be changed to 0777 but XigmaNAS wants 1777. if grep -qw '\"chmod\ 777\ /tmp\"' ${INSTALLPATH}/usr/local/share/bastille/create.sh; then sed -i '' 's|\"chmod\ 777\ /tmp\"|\"chmod\ 1777\ /tmp\"|g' ${INSTALLPATH}/usr/local/share/bastille/create.sh else if [ -d "/tmp" ]; then TMP_PERMS=$(stat -f "%Op" "/tmp") if [ "${TMP_PERMS}" != "41777" ]; then chmod 1777 /tmp fi fi fi # Check and append new config parameters. update_config } bastille_initial_download() { # Check if bastille already exist. if [ -n "${REQUIRED_UPDATE}" ] || [ ! -f "${CWDIR}/${FULLAPPNAME}${BASTILLEPATH}/${APPNAME}" ]; then # Fetch latest bastille package. echo "Fetching ${APPNAME} files..." fetch -ao ${CWDIR}/${BRANCH}.zip --no-verify-peer --timeout=30 ${BASTILLE_URL} || \ error_notify "Error: A problem has occurred while fetching ${APPNAME}." bastille_pkg_extract fi } bastille_pkg_extract() { # Extract bastille files from package. if [ -n "${REQUIRED_UPDATE}" ] || [ -f "${CWDIR}/${BRANCH}.zip" ]; then if [ -n "${REQUIRED_UPDATE}" ] || [ ! -f "${CWDIR}/${FULLAPPNAME}${BASTILLEPATH}/${APPNAME}" ]; then echo "Extracting ${APPNAME}..." tar -xf ${CWDIR}/${BRANCH}.zip --exclude='.git*' --exclude='docs' --exclude='bastille.conf' --strip-components 1 -C ${CWDIR}/${FULLAPPNAME} || \ error_notify "Error: A problem has occurred while extractig ${APPNAME} files." chmod 555 ${CWDIR}/${FULLAPPNAME}${BASTILLEPATH}/${APPNAME} chmod 555 ${CWDIR}/${FULLAPPNAME}${BASTILLERCD} rm -f ${CWDIR}/${BRANCH}.zip echo "Done!" fi fi } bastille_upgrade() { # Perform an online bastille upgrade. DATE=$(date +"%a %b %d %T %Y") echo "Looking for new ${APPNAME} package!" mkdir -p ${CWDIR}/update fetch -ao ${CWDIR}/update --no-verify-peer --timeout=30 ${BASTILLE_VERSION} || \ error_notify "Error: A problem has occurred while fetching version file." # Compare version files and fetch latest package if available. if [ -f "${CWDIR}/update/${APPNAME}" ]; then UPDATEVER=$(cat ${CWDIR}/update/${APPNAME} | grep BASTILLE_VERSION= | egrep -o "([0-9]{1,}\.)+[0-9]{1,}" | tr -d '.') CURRENTVER=$(cat ${BASTILLEPATH}/${APPNAME} | grep BASTILLE_VERSION= | egrep -o "([0-9]{1,}\.)+[0-9]{1,}" | tr -d '.') if [ "${UPDATEVER}" -gt "${CURRENTVER}" ]; then echo "New ${APPNAME} package found, performing upgrade..." fetch -ao ${CWDIR}/update --no-verify-peer --timeout=30 ${BASTILLE_URL} || \ error_notify "Error: A problem has occurred while fetching ${APPNAME} package." tar -xf ${CWDIR}/update/${BRANCH}.zip --exclude='.git*' --exclude='docs' --exclude='bastille.conf' --strip-components 1 -C ${CWDIR}/update rm -f ${CWDIR}/update/${BRANCH}.zip rm -f ${CWDIR}/update/${APPNAME} chmod 555 ${CWDIR}/update/${BASTILLEPATH}/${APPNAME} chmod 555 ${CWDIR}/${FULLAPPNAME}${BASTILLERCD} cp -Rf ${CWDIR}/update/* ${CWDIR}/${FULLAPPNAME}/ rm -R ${CWDIR}/update # Logging the update event. UPDATEVERSION=$(cat ${BASTILLEPATH}/${APPNAME} | grep BASTILLE_VERSION= | cut -d"=" -f2 | tr -d '."') echo "${DATE}: ${APPNAME} upgraded to ${UPDATEVERSION}" >> ${EXTLOGFILE} echo "${APPNAME} upgraded to version ${UPDATEVERSION}" echo "${APPNAME} package upgrade completed!" else echo "${APPNAME} is on the latest version!" rm -R ${CWDIR}/update fi # Workaround to update legacy config. if [ "${UPDATEVER}" -gt "0620200202" ]; then update_config fi fi } bastille_core_update() { # Check if bastille already exist. if [ -f "${CWDIR}/${FULLAPPNAME}${BASTILLEPATH}/${APPNAME}" ]; then # Fetch latest bastille package. echo "Fetching ${APPNAME} files..." fetch -ao ${CWDIR}/${BRANCH}.zip --no-verify-peer --timeout=30 ${BASTILLE_URL} || \ error_notify "Error: A problem has occurred while fetching ${APPNAME}." bastille_pkg_extract fi if [ -f "${CWDIR}/${BRANCH}.zip" ] && [ -f "${CWDIR}/${FULLAPPNAME}${BASTILLEPATH}/${APPNAME}" ]; then echo "Extracting ${APPNAME}..." tar -xf ${CWDIR}/${BRANCH}.zip --exclude='.git*' --exclude='docs' --exclude='bastille.conf' --strip-components 1 -C ${CWDIR}/${FULLAPPNAME} || \ error_notify "Error: A problem has occurred while extractig ${APPNAME} files." chmod 555 ${CWDIR}/${FULLAPPNAME}${BASTILLEPATH}/${APPNAME} chmod 555 ${CWDIR}/${FULLAPPNAME}${BASTILLERCD} rm -f ${CWDIR}/${BRANCH}.zip echo "Done!" fi echo "${PRDNAME} core package update completed!" exit 0 } ext_initial_download() { # Always ensure the version file is present, otherwise update the extension files on startup. if [ ! -f "${CWDIR}/version" ]; then echo "Fetching and extracting extension files..." mkdir -p ${CWDIR}/update fetch -ao ${CWDIR}/update --no-verify-peer --timeout=30 ${GITURL} || \ error_notify "Error: A problem has occurred while fetching extension package." tar -xf ${CWDIR}/update/${BRANCH}.zip --exclude='.git*' --strip-components 1 -C ${CWDIR}/update chmod +x ${CWDIR}/update/${SCRIPTNAME} rm -f ${CWDIR}/update/${BRANCH}.zip cp -Rf ${CWDIR}/update/* ${CWDIR}/ rm -R ${CWDIR}/update echo "Done!" fi } extension_upgrade() { # Perform an online extension upgrade. DATE=$(date +"%a %b %d %T %Y") echo "Looking for new Extension package!" mkdir -p ${CWDIR}/update fetch -ao ${CWDIR}/update --no-verify-peer --timeout=30 ${VERFILE} || \ error_notify "Error: A problem has occurred while fetching version file." # Compare version files and fetch latest package if available. if [ -f "${CWDIR}/update/version" ]; then UPDATEVER_FULL=$(cat ${CWDIR}/update/version) CURRENTVER_FULL=$(cat ${CWDIR}/version) UPDATEVER=$(cat ${CWDIR}/update/version | tr -d .) CURRENTVER=$(cat ${CWDIR}/version | tr -d .) if [ "${UPDATEVER}" -gt "${CURRENTVER}" ]; then echo "New Extension package found, performing upgrade..." fetch -ao ${CWDIR}/update --no-verify-peer --timeout=30 ${GITURL} || \ error_notify "Error: A problem has occurred while fetching extension package." tar -xf ${CWDIR}/update/${BRANCH}.zip --exclude='.git*' --strip-components 1 -C ${CWDIR}/update chmod +x ${CWDIR}/update/${SCRIPTNAME} rm -f ${CWDIR}/update/${BRANCH}.zip cp -Rf ${CWDIR}/update/* ${CWDIR}/ rm -R ${CWDIR}/update # Logging the update event. UPDATEVERSION=$(cat ${CWDIR}/version) echo "${DATE}: Extension upgraded to ${UPDATEVERSION}" >> ${EXTLOGFILE} echo "Extension upgraded to version ${UPDATEVERSION}" echo "Extension package upgrade completed!" if [ "${CURRENTVER}" -le "1153" ]; then echo "***********************************************************************************" echo "* WARNING: System reboot is required when upgrading from v${CURRENTVER_FULL} to v${UPDATEVER_FULL} *" echo "***********************************************************************************" fi # Tell the extension was upgraded. sysrc -f ${CWDIR}${EXTCONF} EXTENSION_UPGRADED="1" >/dev/null 2>&1 else echo "Extension is on the latest version!" rm -R ${CWDIR}/update fi fi } create_addon_env() { # Set bastille dir/files required permissions. chmod 0750 ${CWDIR} if [ -f "${CWDIR}/unionfs.sh" ]; then chmod 0755 ${CWDIR}/unionfs.sh fi # Create required directories. if [ ! -d "${CWDIR}/backups" ]; then mkdir -p ${CWDIR}/backups fi if [ ! -d "${CWDIR}/log" ]; then mkdir -p ${CWDIR}/log fi if [ ! -d "${CWDIR}/${FULLAPPNAME}" ]; then mkdir -p ${CWDIR}/${FULLAPPNAME} fi if [ ! -d "${CWDIR}/${FULLAPPNAME}${BASTILLEPATH}" ]; then mkdir -p ${CWDIR}/${FULLAPPNAME}${BASTILLEPATH} fi if [ ! -d "${CWDIR}/freebsd-update" ]; then mkdir ${CWDIR}/freebsd-update fi # Link bastille-init to /usr/local/sbin. if [ ! -f "${USRLOCAL}/sbin/${SCRIPTNAME}" ]; then ln -fs ${CWDIR}/${SCRIPTNAME} ${USRLOCAL}/sbin/${SCRIPTNAME} fi } platform_check() { # Check for working platform. if [ "${PRDPLATFORM}" = "x64-embedded" ]; then create_addon_env ext_initial_download bastille_initial_download sys_symlinkdir include_files elif [ "${PRDPLATFORM}" = "x64-full" ]; then create_addon_env ext_initial_download bastille_initial_download sys_symlinkdir include_files fi } bin_symlinks() { # Main bastille symlinks. if [ -d "${INSTALLPATH}/${BASTILLEPATH}" ]; then cd ${INSTALLPATH}/${BASTILLEPATH} for file in * do ln -fhs ${INSTALLPATH}/${BASTILLEPATH}/${file} ${USRLOCAL}/bin/${file} done fi } sys_symlinkdir() { # Check and create/relink required symlinks/dirs for bastille. # This environment will be checked each time the script is started for consistency. # Link required binaries. bin_symlinks # Required directories for bastille. if [ ! -d "${USRLOCAL}/share/licenses" ]; then mkdir -p ${USRLOCAL}/share/licenses fi # Required symlinks for bastille. if [ -d "${INSTALLPATH}${USRLOCAL}/share/licenses" ]; then cd ${INSTALLPATH}${USRLOCAL}/share/licenses for file in * do ln -fhs ${INSTALLPATH}${USRLOCAL}/share/licenses/${file} ${USRLOCAL}/share/licenses/${file} done fi # Link bastille config file directory. if [ -d "${INSTALLPATH}${USRLOCAL}/etc/${APPNAME}" ]; then ln -fhs ${INSTALLPATH}${USRLOCAL}/etc/${APPNAME} ${USRLOCAL}/etc/${APPNAME} fi if [ -f "${BASTILLECONF_EXT}" ]; then if [ ! -f "${INSTALLPATH}${USRLOCAL}/etc/${APPNAME}/${APPNAME}.conf" ]; then cp ${BASTILLECONF_EXT} ${INSTALLPATH}${USRLOCAL}/etc/${APPNAME}/${APPNAME}.conf fi fi # Copy bastille shared. if [ -d "${INSTALLPATH}${USRLOCAL}/share/${APPNAME}" ]; then ln -fhs ${INSTALLPATH}${USRLOCAL}/share/${APPNAME} ${USRLOCAL}/share/${APPNAME} fi # Copy bastille rc. if [ -f "${INSTALLPATH}${USRLOCAL}/etc/rc.d/${APPNAME}" ]; then cp ${INSTALLPATH}${USRLOCAL}/etc/rc.d/${APPNAME} ${USRLOCAL}/etc/rc.d/${APPNAME} fi } include_files() { if [ "$(freebsd-version | cut -d '.' -f1)" -ge 12 ]; then sysrc -f ${CWDIR}${EXTCONF} VNET_ENABLE="YES" >/dev/null 2>&1 # Include missing system files. # Symlink the files in embedded platforms. USRBIN_FILES="ar diff3 makewhatis setfib sum" LOCALBIN_FILES="jib" if [ "${PRDPLATFORM}" = "x64-embedded" ]; then for _usrbin_file in ${USRBIN_FILES}; do if [ -f "/usr/bin/${_usrbin_file}" ] && [ ! -L "/usr/bin/${_usrbin_file}" ]; then rm -r /usr/bin/${_usrbin_file} fi if [ ! -f "/usr/bin/${_usrbin_file}" ]; then chmod 0555 "${SYSTEM_INCLUDE}/${_usrbin_file}" ln -fhs ${SYSTEM_INCLUDE}/${_usrbin_file} /usr/bin/${_usrbin_file} fi done for _localbin_file in ${LOCALBIN_FILES}; do if [ -f "/usr/local/bin/${_localbin_file}" ] && [ ! -L "/usr/local/bin/${_localbin_file}" ]; then rm -r /usr/local/bin/${_localbin_file} fi if [ ! -f "/usr/bin/${_localbin_file}" ]; then chmod 0555 "${SYSTEM_INCLUDE}/${_localbin_file}" ln -fhs ${SYSTEM_INCLUDE}/${_localbin_file} /usr/local/bin/${_localbin_file} fi done else # Install the files in full platforms natively. for _usrbin_file in ${USRBIN_FILES}; do if [ ! -f "/usr/bin/${_usrbin_file}" ]; then install -m 0555 "${SYSTEM_INCLUDE}/${_usrbin_file}" /usr/bin/${_usrbin_file} fi done for _localbin_file in ${LOCALBIN_FILES}; do if [ ! -f "/usr/local/bin/${_localbin_file}" ]; then install -m 0544 ${SYSTEM_INCLUDE}/${_localbin_file} /usr/local/bin/${_localbin_file} fi done fi else sysrc -f ${CWDIR}${EXTCONF} VNET_ENABLE="NO" >/dev/null 2>&1 fi if [ "$(freebsd-version | cut -d '.' -f1)" -ge 12 ]; then # Include missing pf(packet filter) files. PF_FILES="/pfctl /pfilctl /pflogd /pf.os" for _file in ${PF_FILES}; do if [ ! -f "/sbin/${_file}" ]; then if [ "${_file}" = "/pf.os" ]; then if [ ! -f "/etc/${_file}" ]; then if [ -f "${SYSTEM_INCLUDE}/${_file}" ]; then install -m 0644 ${SYSTEM_INCLUDE}/${_file} /etc/${_file} fi fi else if [ -f "${SYSTEM_INCLUDE}/${_file}" ]; then install -m 0555 ${SYSTEM_INCLUDE}/${_file} /sbin/${_file} fi fi fi done fi } required_updates() { # Check for critical and/or required updates and bug fixes and apply them. # This is because not always the bastille version is increased on updates and/or bug fixes. if [ -f "${INSTALLPATH}${USRLOCAL}/share/${APPNAME}/rename.sh" ]; then if ! grep -qw '{ZFS_DATASET_ORIGIN}.*{ZFS_DATASET_TARGET}' ${INSTALLPATH}${USRLOCAL}/share/${APPNAME}/rename.sh; then echo "Required update found, performing update..." echo "${DATE}: ${APPNAME} required update has been applied" >> ${EXTLOGFILE} REQUIRED_UPDATE="1" bastille_initial_download fi fi # Check for a critical bug that prevents VNET jail creation. if grep -q '\\"vnet host interface for Bastille jail ${NAME}"' ${INSTALLPATH}${USRLOCAL}/share/${APPNAME}/create.sh; then sed -i '' 's|\\"vnet host interface for Bastille jail ${NAME}"|\\"vnet host interface for Bastille jail ${NAME}\\"|g' ${INSTALLPATH}${USRLOCAL}/share/${APPNAME}/create.sh fi } postinit_cmd() { # Check and generate temporary php script for postinit command. if ! grep -qw ${CWDIR}/${SCRIPTNAME} ${CONFIG}; then touch ${CWDIR}/postinit || error_notify "Error: A problem has occurred while creating the postinit file." chmod +x ${CWDIR}/postinit if [ "${PRDVERSION}" -ge "110" ]; then # Generate php script only for start command for extension version 1.2 and later. cat << EOF > ${CWDIR}/postinit EOF fi # Execute temporary php script. if [ "${OBI_INSTALL}" != "ON" ]; then echo "Creating postinit command..." php-cgi -f ${CWDIR}/postinit && rm ${CWDIR}/postinit || \ error_notify "Error: A problem has occurred while executing postinit file." echo "Done!" fi # Set extension to enable by default. sysrc -f ${CWDIR}${EXTCONF} GUI_ENABLE=YES INSTALL_DIR=${CWDIR} >/dev/null 2>&1 fi } gui_start() { # Initialize the extension gui. if [ -d "${CWDIR}/gui" ]; then # Always ensure the config directory/file exist. if [ ! -f "${CWDIR}${EXTCONF}" ]; then # Try to restore default configuration. runtime_config # Set default config. sysrc -f ${CWDIR}${EXTCONF} GUI_ENABLE=YES INSTALL_DIR=${CWDIR} >/dev/null 2>&1 fi GUI_STATUS=$(sysrc -f ${CWDIR}${EXTCONF} -qn GUI_ENABLE) if [ "${GUI_STATUS}" = "YES" ]; then # Store the installation path and link conf. if ! sysrc -f ${CWDIR}${EXTCONF} -n INSTALL_DIR | grep -q "${CWDIR}"; then sysrc -f ${CWDIR}${EXTCONF} INSTALL_DIR=${CWDIR} >/dev/null 2>&1 fi mkdir -p ${BASTILLECONFLINK} ln -fhs ${CWDIR}/conf ${BASTILLECONFLINK}/conf # Link the gui files. if [ ! -d "${WWWPATH}/ext" ]; then mkdir -p ${WWWPATH}/ext fi ln -fhs ${CWDIR}/gui/ext/bastille ${WWWPATH}/ext/ || error_notify "Error: A problem has occurred while copying extension gui files." ln -fhs ${CWDIR}/gui/images ${WWWPATH}/ext/bastille/ || error_notify "Error: A problem has occurred while copying extension gui files." ln -fhs ${CWDIR}/gui/bastille_manager_*.php ${WWWPATH}/ || error_notify "Error: A problem has occurred while linking extension gui files." fi fi } gui_enable() { # Relink conf and gui files. if [ -d "${CWDIR}/gui" ]; then mkdir -p ${BASTILLECONFLINK} ln -fhs ${CWDIR}/conf ${BASTILLECONFLINK}/conf sysrc -f ${CWDIR}${EXTCONF} GUI_ENABLE=YES >/dev/null 2>&1 if [ ! -d "${WWWPATH}/ext" ]; then mkdir -p ${WWWPATH}/ext fi ln -fhs ${CWDIR}/gui/ext/bastille ${WWWPATH}/ext/ || error_notify "Error: A problem has occurred while copying extension gui files." ln -fhs ${CWDIR}/gui/images ${WWWPATH}/ext/bastille/ || error_notify "Error: A problem has occurred while copying extension gui files." ln -fhs ${CWDIR}/gui/bastille_manager_*.php ${WWWPATH}/ || error_notify "Error: A problem has occurred while copying extension gui files." exit 0 else error_notify "Error: Extension gui files not found." fi exit 0 } gui_disable() { # Disable gui if -t option specified. if [ -d "${CWDIR}/gui" ]; then rm -f ${WWWPATH}bastille_manager_*.php rm -rf ${WWWPATH}/ext/bastille rm -rf ${WWWPATH}/ext/bastille/images rm -rf ${LOCALSHAREPATH}/locale-bastille rm -rf ${BASTILLECONFLINK} sysrc -f ${CWDIR}${EXTCONF} GUI_ENABLE=NO >/dev/null 2>&1 || error_notify "Error: A problem while removing extension gui files." exit 0 else error_notify "Error: Extension gui files not found." fi # Remove empty ext folder to prevent empty "Extensions" tab. if [ -d "${WWWPATH}/ext" ]; then if [ ! "$(ls -A ${WWWPATH}/ext)" ]; then rm -r ${WWWPATH}/ext fi fi exit 0 } jail_update() { # Workaround since XigmaNAS does not ship with freebsd-update command. if [ "${PRDPRODUCT}" = "XigmaNAS" ] || [ "${PRDPRODUCT}" = "NAS4Free" ]; then if [ ! -d "${FREEBSD_UPDATE}" ]; then echo "Not supported on ${PRDPRODUCT} platform." exit 1 fi else echo "Unsupported platform!"; exit 1 fi if [ ! -z "$(freebsd-version | grep -i HBSD)" ]; then echo "Not supported on HardenedBSD." exit 1 fi if [ -d "${bastille_jailsdir}/${TARGET}" ]; then if ! cat "${bastille_jailsdir}/${TARGET}/fstab" 2>/dev/null | grep -w "${TARGET}" | grep -qw "/.*/.bastille"; then if [ -f "${bastille_jailsdir}/${TARGET}/root/COPYRIGHT" ]; then if [ "$(jls name | grep -w "${TARGET}")" ]; then # Update a thick container. CURRENT_VERSION=$(jexec -l ${TARGET} freebsd-version) if [ -z "${CURRENT_VERSION}" ]; then echo "Can't determine '${TARGET}' version." exit 1 else if [ -n "${_forceopt}" ]; then echo "Performing a forced jail update..." else echo "Performing a jail update..." fi env PAGER="/bin/cat" ${FREEBSD_UPDATE}/freebsd-update ${_forceopt} --not-running-from-cron -f ${FREEBSD_UPDATE}/freebsd-update.conf \ -d ${CWDIR}/freebsd-update -b "${bastille_jailsdir}/${TARGET}/root" fetch --currently-running "${CURRENT_VERSION}" ${FREEBSD_UPDATE}/freebsd-update --not-running-from-cron -f ${FREEBSD_UPDATE}/freebsd-update.conf \ -d ${CWDIR}/freebsd-update -b "${bastille_jailsdir}/${TARGET}/root" install --currently-running "${CURRENT_VERSION}" echo "Setting OS release for ${TARGET}." CURRENT_VERSION=$(jexec -l ${TARGET} freebsd-version) bastille config ${TARGET} set osrelease ${CURRENT_VERSION} fi else echo "Container not running." echo "See 'bastille start ${TARGET}'." exit 1 fi else echo "${TARGET} state is unknown." exit 1 fi else echo "${TARGET} is not a thick container." exit 1 fi else if [ -d "${bastille_releasesdir}/${TARGET}" ]; then if [ -n "${_forceopt}" ]; then echo "Performing a forced base update..." else echo "Performing a base update..." fi # Update container base(affects base child containers). env PAGER="/bin/cat" ${FREEBSD_UPDATE}/freebsd-update ${_forceopt} --not-running-from-cron -f ${FREEBSD_UPDATE}/freebsd-update.conf \ -d ${CWDIR}/freebsd-update -b "${bastille_releasesdir}/${TARGET}" fetch --currently-running "${TARGET}" ${FREEBSD_UPDATE}/freebsd-update --not-running-from-cron -f ${FREEBSD_UPDATE}/freebsd-update.conf \ -d ${CWDIR}/freebsd-update -b "${bastille_releasesdir}/${TARGET}" install --currently-running "${TARGET}" echo "Please manually set OS release on jail.conf for the required jails." else echo "${TARGET} not found. See bootstrap." exit 1 fi fi exit 0 } release_upgrade() { if [ -d "${bastille_releasesdir}/${TARGET}" ]; then if [ -f "${bastille_releasesdir}/${TARGET}/COPYRIGHT" ]; then if [ "${TARGET}" = "${RELEASE}" ]; then echo "Specified releases name match." exit 0 fi # Upgrade a release base. if [ -n "${_forceopt}" ]; then echo "Performing a forced release upgrade..." else echo "Performing a release upgrade..." fi echo "=> Run the command below several times when asked to finish installing updates." echo "bastille-init install ${TARGET}" echo env PAGER="/bin/cat" ${FREEBSD_UPDATE}/freebsd-update ${_forceopt} --not-running-from-cron -f ${FREEBSD_UPDATE}/freebsd-update.conf \ -d ${CWDIR}/freebsd-update -b "${bastille_releasesdir}/${TARGET}" --currently-running "${TARGET}" -r ${RELEASE} upgrade echo echo "=> Please run: 'bastille-init install ${TARGET}' to finish installing updates." else echo "Unknown ${RELEASE}. See bootstrap."; exit 1 fi else echo "${TARGET} not found. See bootstrap."; exit 1 fi exit 0 } release_install() { if [ -d "${bastille_releasesdir}/${TARGET}" ]; then if [ -f "${bastille_releasesdir}/${TARGET}/COPYRIGHT" ]; then # Finish installing upgrade on a thick container. env PAGER="/bin/cat" ${FREEBSD_UPDATE}/freebsd-update --not-running-from-cron -f ${FREEBSD_UPDATE}/freebsd-update.conf \ -d ${CWDIR}/freebsd-update -b "${bastille_releasesdir}/${TARGET}" install else echo "${TARGET} state is unknown." exit 1 fi else echo "${TARGET} not found. See bootstrap."; exit 1 fi exit 0 } release_change() { if [ ! -z "$(freebsd-version | grep -i HBSD)" ]; then echo "Not supported on HardenedBSD." exit 1 fi # Verify for user input and handle some errors. if [ -d "${bastille_jailsdir}/${TARGET}" ]; then if [ -d "${bastille_releasesdir}/${RELEASE}" ]; then if [ -f "${bastille_releasesdir}/${RELEASE}/COPYRIGHT" ]; then # Check if the container is running. if [ "$(jls name | grep -w "${TARGET}")" ]; then echo "${TARGET} running." echo "See 'bastille stop ${TARGET}'." exit 1 elif [ "${RELEASE}" = "${NEWRELEASE}" ]; then echo "Specified releases name match." exit 0 fi if [ -d "${bastille_releasesdir}/${NEWRELEASE}" ]; then if [ -f "${bastille_releasesdir}/${NEWRELEASE}/COPYRIGHT" ]; then if [ -f "${bastille_jailsdir}/${TARGET}/fstab" ]; then # Check if is a thin container. if cat "${bastille_jailsdir}/${TARGET}/fstab" | grep "${RELEASE}" | grep -qw "/.*/.bastille"; then # If the previous conditions meets, proceed with the container base upgrade. sed -i '' "s/${RELEASE}/${NEWRELEASE}/g" ${bastille_jailsdir}/${TARGET}/fstab echo "${TARGET} release changed to ${NEWRELEASE}." echo "Setting OS release for ${TARGET}." bastille config ${TARGET} set osrelease ${NEWRELEASE} elif cat "${bastille_jailsdir}/${TARGET}/fstab" | grep "${NEWRELEASE}" | grep -qw "/.*/.bastille"; then echo "${TARGET} already using ${NEWRELEASE}." exit 0 else if cat "${bastille_jailsdir}/${TARGET}/fstab" | grep -qw "/.*/.bastille"; then echo "${TARGET} container does not use ${RELEASE}."; exit 1 else echo "${TARGET} is not a thin container."; exit 1 fi fi else echo "${TARGET} fstab not found."; exit 1 fi else echo "Unknown ${NEWRELEASE}. See bootstrap."; exit 1 fi else echo "${NEWRELEASE} not found, bootstrap starting...." bastille bootstrap ${NEWRELEASE} if [ ! $? -ne 0 ]; then release_change fi fi else echo "Unknown ${RELEASE}. See bootstrap."; exit 1 fi else echo "${RELEASE} not found. See bootstrap."; exit 1 fi else echo "${TARGET} not found. See create."; exit 1 fi exit 0 } thickjail_upgrade() { # Workaround since XigmaNAS does not ship with freebsd-update command. if [ "${PRDPRODUCT}" = "XigmaNAS" ] || [ "${PRDPRODUCT}" = "NAS4Free" ]; then if [ ! -d "${FREEBSD_UPDATE}" ]; then echo "Not supported on ${PRDPRODUCT} platform." exit 1 fi else echo "Unsupported platform!"; exit 1 fi if [ ! -z "$(freebsd-version | grep -i HBSD)" ]; then echo "Not supported on HardenedBSD." exit 1 fi # Verify for user input and handle some errors. if [ -d "${bastille_jailsdir}/${TARGET}" ]; then if ! cat "${bastille_jailsdir}/${TARGET}/fstab" 2>/dev/null | grep -w "${TARGET}" | grep -qw "/.*/.bastille"; then if [ -f "${bastille_jailsdir}/${TARGET}/root/COPYRIGHT" ]; then if [ "$(jls name | grep -w "${TARGET}")" ]; then # Upgrade a thick container. if [ -n "${_forceopt}" ]; then echo "Performing a forced jail upgrade..." else echo "Performing a jail upgrade..." fi echo "=> Run the command below several times when asked to finish installing updates." echo "bastille-init install ${TARGET}" echo CURRENT_VERSION=$(jexec -l ${TARGET} freebsd-version) env PAGER="/bin/cat" ${FREEBSD_UPDATE}/freebsd-update ${_forceopt} --not-running-from-cron -f ${FREEBSD_UPDATE}/freebsd-update.conf \ -d ${CWDIR}/freebsd-update -b "${bastille_jailsdir}/${TARGET}/root" --currently-running "${CURRENT_VERSION}" -r ${RELEASE} upgrade echo echo "=> Please run: 'bastille-init install ${TARGET}' to finish installing updates." else echo "Container not running." echo "See 'bastille start ${TARGET}'." exit 1 fi else echo "${TARGET} state is unknown." exit 1 fi else echo "${TARGET} is not a thick container." exit 1 fi elif [ -d "${bastille_releasesdir}/${RELEASE}" ]; then # Try to upgrade a release instead. release_upgrade fi exit 0 } thickjail_install() { # Workaround since XigmaNAS does not ship with freebsd-update command. if [ "${PRDPRODUCT}" = "XigmaNAS" ] || [ "${PRDPRODUCT}" = "NAS4Free" ]; then if [ ! -d "${FREEBSD_UPDATE}" ]; then echo "Not supported on ${PRDPRODUCT} platform." exit 1 fi else echo "Unsupported platform!"; exit 1 fi if [ ! -z "$(freebsd-version | grep -i HBSD)" ]; then echo "Not supported on HardenedBSD." exit 1 fi if [ -d "${bastille_jailsdir}/${TARGET}" ]; then if ! cat "${bastille_jailsdir}/${TARGET}/fstab" 2>/dev/null | grep -w "${TARGET}" | grep -qw "/.*/.bastille"; then if [ -f "${bastille_jailsdir}/${TARGET}/root/COPYRIGHT" ]; then if [ "$(jls name | grep -w "${TARGET}")" ]; then # Finish installing upgrade on a thick container. env PAGER="/bin/cat" ${FREEBSD_UPDATE}/freebsd-update --not-running-from-cron -f ${FREEBSD_UPDATE}/freebsd-update.conf \ -d ${CWDIR}/freebsd-update -b "${bastille_jailsdir}/${TARGET}/root" install else echo "Container not running." echo "See 'bastille start ${TARGET}'." exit 1 fi else echo "${TARGET} state is unknown." exit 1 fi else echo "${TARGET} is not a thick container." exit 1 fi elif [ -d "${bastille_releasesdir}/${RELEASE}" ]; then # Try to upgrade a release instead. release_install fi exit 0 } zfs_activate() { # Check if ZFS is already configured. # Always enforce ZFS activation below "/mnt/" from the extension. if echo "${BASTILLE_ZFS_ZPOOL_MOUNTPOINT_TRIM}" | grep -qw "${CWDIR_TRIM}$"; then if zfs list "${bastille_zfs_zpool}/${bastille_zfs_prefix}" > /dev/null 2>&1; then echo "Bastille ZFS is already configured." sysrc -f ${CWDIR}${EXTCONF} ZFS_ACTIVATED="YES" >/dev/null 2>&1 exit 0 else BASTILLE_DIRS="cache jails logs releases templates" for dir in ${BASTILLE_DIRS}; do if [ -d "${CWDIR}/${dir}" ]; then # Stop if any of the listed dirs already exist. error_notify "Bastille has been bootstrapped already, aborting." fi done fi echo "Enabling ZFS on ${PRDNAME} Extension..." # Confirm before conversion. while :; do read -p "Do you really want to enable ZFS for ${PRDNAME} Extension? [y/N]:" _yn case ${_yn} in [Yy]) break ;; [Nn]) exit 0 ;; esac done echo "Proceeding..." if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then if zfs list "${bastille_zfs_zpool}" > /dev/null 2>&1; then if ! zfs list "${bastille_zfs_zpool}/${bastille_zfs_prefix}" > /dev/null 2>&1; then echo "Renaming existing '${BASTILLE_DIR}' directory..." mv ${CWDIR} ${CWDIR}.old echo "Creating a new ZFS dataset for '${BASTILLE_DIR}'..." zfs create ${bastille_zfs_options} ${bastille_zfs_zpool}/${bastille_zfs_prefix} if [ $? -ne 0 ]; then MSG="Failed to enable ZFS, reverting changes." echo "${MSG}" mv ${CWDIR}.old ${CWDIR} logger -t "${SCRIPTNAME}" "${MSG}" error_notify "${MSG}" else echo "Synchronizing '${BASTILLE_DIR}' data on new dataset" rsync -a ${CWDIR}.old/ ${CWDIR}/ fi else echo "Bastille ZFS is already configured." fi else error_notify "ERROR: ${bastille_zfs_zpool} is not a ZFS pool." fi else error_notify "Bastille ZPOOL is not set." fi echo "ZFS Enabled for ${PRDNAME} Extension successfully." else error_notify "Bastille ZFS option is not set." fi else error_notify "Invalid ZFS configuration." fi sysrc -f ${CWDIR}${EXTCONF} ZFS_ACTIVATED="YES" >/dev/null 2>&1 exit 0 } pkg_upgrade() { # Re-fetch bastille package and extract. if [ -f "${CWDIR}/${FULLAPPNAME}${BASTILLEPATH}/${APPNAME}" ]; then bastille_upgrade else bastille_initial_download fi # Check for extension updates. extension_upgrade } reset_install() { # Confirm for addon config reset. while :; do read -p "Do you really want to proceed with the ${PRDNAME} Extension config reset? [y/N]:" _yn case ${_yn} in [Yy]) break ;; [Nn]) exit 0 ;; esac done echo "Proceeding..." # Check for running jails before config reset. for _jail in $(bastille list jail); do if jls -j ${_jail} >/dev/null 2>&1; then echo "Looks like there are running bastille jails, aborting." exit 1 fi done # Reset the extension environment. echo "Removing extension files..." if [ -f "${CWDIR}/conf/bastille_config" ]; then echo "Backup current extension config file." if [ -f "${CWDIR}/conf/bastille_config.old" ]; then # Remove previous backup file. rm -f ${CWDIR}/conf/bastille_config.old fi mv -vf ${CWDIR}/conf/bastille_config ${CWDIR}/conf/bastille_config.old fi if [ -d "${CWDIR}/${FULLAPPNAME}" ]; then rm -rf ${CWDIR}/${FULLAPPNAME} fi if [ -d "${CWDIR}/download" ]; then rm -rf ${CWDIR}/download fi if [ -f "${CWDIR}/version" ]; then rm -f ${CWDIR}/version fi sleep 3 # Set default config. touch ${CWDIR}/conf/bastille_config sysrc -f ${CWDIR}${EXTCONF} GUI_ENABLE="YES" >/dev/null 2>&1 sysrc -f ${CWDIR}${EXTCONF} INSTALL_DIR="${CWDIR}" >/dev/null 2>&1 sysrc -f ${CWDIR}${EXTCONF} BASTILLE_CONFIG="${CWDIR}/${FULLAPPNAME}${BASTILLECONF}" >/dev/null 2>&1 sysrc -f ${CWDIR}${EXTCONF} BACKUP_DIR="${CWDIR}/backups" >/dev/null 2>&1 sysrc -f ${CWDIR}${EXTCONF} ZFS_SUPPORT="NO" >/dev/null 2>&1 echo "" echo "*************************************************************************************************************" echo "* The configuration was reset, please go to [Extensions > Bastille > Configuration] to configure bastille. *" echo "* Alternatively you can edit the 'addon/bastille-dist/usr/local/etc/bastille/bastille.conf' file manually. *" echo "*************************************************************************************************************" echo "" echo "Notice: If Linux Jail support was enabled, please execute the below command to manually re-enable it:" echo "==> sysrc -f ${CWDIR}${EXTCONF} LINUX_COMPAT_SUPPORT=\"YES\"" echo "" # Tell Bastille Extension that config was reset. touch ${CWDIR}/conf/config_reset.lock } remove_addon() { # Confirm for addon removal. while :; do read -p "Do you want to proceed with the ${FULLAPPNAME} removal? [y/N]:" _yn case ${_yn} in [Yy]) break ;; [Nn]) exit 0 ;; esac done echo "Proceeding..." # Check and disable extension unionfs in case it is enabled. ${CWDIR}/unionfs.sh unionfs_off # Check and remove extension files/symlinks. if [ -d "${USRLOCAL}/share/licenses/${APPNAME}-*" ]; then rm -rf ${USRLOCAL}/share/licenses/${APPNAME}-* fi if [ -d "${USRLOCAL}/share/locale-bastille" ]; then rm -rf ${USRLOCAL}/share/locale-bastille fi if [ -f "${USRLOCAL}/etc/rc.d/${APPNAME}" ]; then rm -f ${USRLOCAL}/etc/rc.d/${APPNAME} fi if [ -f "${USRLOCAL}/etc/${APPNAME}" ]; then rm -f ${USRLOCAL}/etc/${APPNAME} fi if [ -f "${BASTILLEPATH}/${APPNAME}" ]; then rm -f ${BASTILLEPATH}/${APPNAME} fi if [ -f "${BASTILLEPATH}/${APPNAME}-init" ]; then rm -rf ${BASTILLEPATH}/${APPNAME}-init fi if [ -d "${VARLOG}/${APPNAME}" ]; then rm -rf ${VARLOG}/${APPNAME} fi # Remove extension and GUI components. if [ -f "${WWWPATH}/bastille_manager_gui.php" ]; then rm -f ${WWWPATH}/bastille_manager_*.php fi if [ -d "${WWWPATH}/ext/bastille" ]; then rm -rf ${WWWPATH}/ext/bastille fi if [ -f "${USRLOCAL}/bin/${APPNAME}" ]; then rm -rf ${USRLOCAL}/bin/${APPNAME} fi if [ -d "${VARLOG}/${APPNAME}" ]; then rm -rf ${VARLOG}/${APPNAME} fi # Remove empty ext folder to prevent empty "Extensions" tab. if [ -d "${WWWPATH}/ext" ]; then if [ ! "$(ls -A ${WWWPATH}/ext)" ]; then rm -R ${WWWPATH}/ext fi fi # Remove addon related files and folders only- # to protect any user-created custom files- # as well as for the containers dirs/files. FILES="bastille-dist conf download freebsd-update gui locale-bastille log system CHANGELOG LICENSE README.md bastille-init postinit unionfs.sh version" for FILE in ${FILES}; do if [ -f "${CWDIR}/${FILE}" ] || [ -d "${CWDIR}/${FILE}" ]; then rm -rf ${CWDIR}/${FILE} fi done # Remove this files since they are not part of the base. BIN_FILES="/usr/bin/ar /usr/local/bin/jib /usr/sbin/setfib /usr/bin/sum /usr/bin/diff3 /usr/bin/makewhatis" for FILE in ${BIN_FILES}; do if [ -f "${FILE}" ]; then rm -rf ${FILE} fi done # Don't remove this files on 13.x and later versions since they are part of the base. if [ "$(freebsd-version | cut -d '.' -f1)" -le 12 ]; then PF_FILES="/sbin/pfctl /sbin/pfilctl /sbin/pflogd /etc/pf.os" for FILE in ${PF_FILES}; do if [ -f "${FILE}" ]; then rm -rf ${FILE} fi done fi echo "Done!" echo "Please manually remove the Bastille Extension Command Script from the WebGUI." exit 0 } get_versions() { # Get product versions. if [ -f "${CWDIR}/version" ]; then APPVERSION=$(cat ${CWDIR}/version) else APPVERSION="version file not found!" fi # Display product versions. BASTILLEVER=$(${USRLOCAL}/bin/bastille --version) echo "Bastille version: ${BASTILLEVER}" echo "Extension version: ${APPVERSION}" exit 0 } post_upgrade() { # Check/apply for required/pending updates/fixes if any. # This file will be removed after success execution. if sysrc -f ${CWDIR}${EXTCONF} -qc EXTENSION_UPGRADED=1; then if [ -f "${CWDIR}/post_upgrade.sh" ]; then echo "Executing post_upgrade.sh file..." ${CWDIR}/post_upgrade.sh sleep 5 else echo "No post upgrade changes pending." fi sysrc -f ${CWDIR}${EXTCONF} EXTENSION_UPGRADED="0" >/dev/null 2>&1 fi } ext_start() { if sysrc -f ${CWDIR}${EXTCONF} -qc LINUX_COMPAT_SUPPORT=YES; then ${CWDIR}/unionfs.sh load_kmods fi # Start bastille jails. if [ -d "${CWDIR}/jails" ]; then # Required for embedded platforms due late startup. if [ "${PRDPLATFORM}" = "x64-embedded" ]; then if sysrc -qc bastille_enable=YES; then if [ ! -f "${EXTLOCKFILE}" ]; then service bastille start fi fi fi fi # Create extension lock file after boot. if [ ! -f "${EXTLOCKFILE}" ]; then touch ${EXTLOCKFILE} fi if [ $? -eq 0 ]; then post_upgrade MSG="script has been started successfully!" logger -t ${SCRIPTNAME} ${MSG} exit 0 else MSG="script started with faults!" logger -t ${SCRIPTNAME} ${MSG} exit 1 fi } zfs_support_enabled() { sysrc -f ${CWDIR}${EXTCONF} ZFS_SUPPORT="YES" >/dev/null 2>&1 sysrc -f ${CWDIR}${EXTCONF} ZFS_ACTIVATED="YES" >/dev/null 2>&1 } zfs_support_error() { echo "WARNING: Invalid ZFS configuration." sysrc -f ${CWDIR}${EXTCONF} ZFS_SUPPORT="ERR" >/dev/null 2>&1 sysrc -f ${CWDIR}${EXTCONF} -x ZFS_ACTIVATED >/dev/null 2>&1 } zfs_support_avail() { echo "WARNING: ZFS support available but not enabled." sysrc -f ${CWDIR}${EXTCONF} ZFS_SUPPORT="AVA" >/dev/null 2>&1 } zfs_support_disabled() { sysrc -f ${CWDIR}${EXTCONF} ZFS_SUPPORT="NO" >/dev/null 2>&1 sysrc -f ${CWDIR}${EXTCONF} -x ZFS_ACTIVATED >/dev/null 2>&1 } rc_params() { # Bastille required parameters. # Set bastille prefix. if ! sysrc -f ${BASTILLECONF} -qc bastille_prefix="${CWDIR}"; then sysrc -f ${BASTILLECONF} bastille_prefix="${CWDIR}" >/dev/null 2>&1 fi # Set required variables. if ! sysrc -f ${BASTILLECONF} -qc bastille_compress_gz_options; then sysrc -f ${BASTILLECONF} bastille_compress_gz_options="-1 -v" >/dev/null 2>&1 fi if ! sysrc -f ${BASTILLECONF} -qc bastille_decompress_gz_options; then sysrc -f ${BASTILLECONF} bastille_decompress_gz_options="-k -d -c -v" >/dev/null 2>&1 fi if ! sysrc -f ${BASTILLECONF} -qc bastille_pf_conf; then sysrc -f ${BASTILLECONF} bastille_pf_conf="${CWDIR}/pf.conf" >/dev/null 2>&1 fi # Set bastille.conf location. if ! sysrc -f ${CWDIR}${EXTCONF} -qc BASTILLE_CONFIG="${CWDIR}/${FULLAPPNAME}${BASTILLECONF}"; then sysrc -f ${CWDIR}${EXTCONF} BASTILLE_CONFIG="${CWDIR}/${FULLAPPNAME}${BASTILLECONF}" >/dev/null 2>&1 fi # Default first network interface. ACTIVE_NETIF=$(ifconfig | grep "UP,BROADCAST" | awk -F":" '{print $1}' | sed 1q) if ! sysrc -f ${BASTILLECONF} -qc bastille_network_shared="${ACTIVE_NETIF}" >/dev/null 2>&1; then #echo "" >> ${BASTILLECONF} && echo "## default network interface" >> ${BASTILLECONF} sysrc -f ${BASTILLECONF} bastille_network_shared="${ACTIVE_NETIF}" >/dev/null 2>&1 else EXT_NETIF=$(sysrc -f ${BASTILLECONF} -qn bastille_network_shared) if [ -z "${EXT_NETIF}" ]; then #echo "" >> ${BASTILLECONF} && echo "## default network interface" >> ${BASTILLECONF} sysrc -f ${BASTILLECONF} bastille_network_shared="${ACTIVE_NETIF}" >/dev/null 2>&1 fi fi # Check if extension config was reset. if [ -f "${CWDIR}/conf/config_reset.lock" ]; then zfs_support_error echo "WARNING: ${PRDNAME} Extension config was reset." rm ${CWDIR}/conf/config_reset.lock fi # Check for sane ZFS parameters in this setup. if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then if zfs list "${bastille_zfs_zpool}" >/dev/null 2>&1; then # Check and don't allow child datasets in bastille_zfs_zpool. if echo "${bastille_zfs_zpool}" | grep -q '\/'; then zfs_support_error exit 1 fi # Check and make sure bastille_zfs_prefix end with "bastille". if ! echo "${bastille_zfs_prefix}" | grep -qw "${APPNAME}"; then zfs_support_error exit 1 fi # Check bastille ZFS config match on disk ZFS config if activation is already enabled in the config file. if sysrc -f ${CWDIR}${EXTCONF} -qc ZFS_SUPPORT=YES && sysrc -f ${CWDIR}${EXTCONF} -qc ZFS_ACTIVATED=YES; then if [ "${BASTILLE_CONFIG_DISK}" != "${BASTILLE_CONFIG_FILE}" ]; then zfs_support_error exit 1 fi fi # Perform some checks against on-disk and file configurations. if zfs list "${bastille_zfs_zpool}/${BASTILLE_ZFS_PREFIX_TRIM}/${APPNAME}" >/dev/null 2>&1; then # Looks like ZFS support is already configured, then set parameters. zfs_support_enabled elif zfs list "${bastille_zfs_zpool}" >/dev/null 2>&1 && \ [ "${bastille_zfs_prefix}" = "${BASTILLE_ZFS_PREFIX_TRIM}/${APPNAME}" ]; then # Looks like ZFS support is available for activation. zfs_support_avail elif zfs list "${bastille_zfs_zpool}/${APPNAME}" >/dev/null 2>&1; then zfs_support_enabled elif zfs list "${bastille_zfs_zpool}" >/dev/null 2>&1 && \ [ "${BASTILLE_ZFS_PREFIX_TRIM}" = "${APPNAME}" ]; then # Looks like ZFS support is available for activation. zfs_support_avail elif zfs list "${bastille_zfs_zpool}/${APPNAME}" >/dev/null 2>&1; then zfs_support_enabled else zfs_support_error fi else zfs_support_error fi else zfs_support_error fi else # Check for orphaned configuration and/or config reset. if zfs list -H "${CWDIR}" >/dev/null 2>&1; then zfs_support_error else zfs_support_disabled fi fi # Enable bastille in /etc/rc.conf sysrc bastille_enable="YES" >/dev/null 2>&1 } update_config() { # Update config based on minimum version. # Network parameters. if grep -qw 'bastille_jail_loopback=' ${INSTALLPATH}/${BASTILLECONF}; then sed -i '' 's/bastille_jail_loopback=/bastille_network_loopback=/' ${INSTALLPATH}/${BASTILLECONF} fi if grep -qw 'bastille_jail_external=' ${INSTALLPATH}/${BASTILLECONF}; then sed -i '' 's/bastille_jail_external=/bastille_network_shared=/' ${INSTALLPATH}/${BASTILLECONF} fi if grep -qw 'bastille_jail_gateway=' ${INSTALLPATH}/${BASTILLECONF}; then sed -i '' 's/bastille_jail_gateway=/bastille_network_gateway=/' ${INSTALLPATH}/${BASTILLECONF} fi if ! grep -qw 'bastille_url_freebsd=' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_url_freebsd="${URL_FREEBSD}" fi if ! grep -qw 'bastille_url_hardenedbsd=' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_url_hardenedbsd="${URL_HARDENEDBSD}" fi if ! grep -qw 'bastille_url_midnightbsd=' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_url_midnightbsd="${URL_MIDNIGHTBSD}" fi if ! grep -qw 'bastille_network_pf_ext_if=' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_network_pf_ext_if="ext_if" fi if ! grep -qw 'bastille_network_pf_table=' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_network_pf_table="jails" fi if ! grep -qw 'bastille_network_gateway6=' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_network_gateway6="" fi # Template parameters. if ! grep -qw 'bastille_template_base=' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_template_base="default/base" fi if ! grep -qw 'bastille_template_empty=' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_template_empty="" fi if ! grep -qw 'bastille_template_thick=' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_template_thick="default/thick" fi if ! grep -qw 'bastille_template_thin=' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_template_thin="default/thin" fi if ! grep -qw 'bastille_template_vnet=' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_template_vnet="default/vnet" fi # Remove deprecated parameters based on minimum version. if grep -qw 'bastille_jail_interface' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} -x bastille_jail_interface fi if grep -qw 'bastille_jail_addr' ${INSTALLPATH}/${BASTILLECONF}; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} -x bastille_jail_addr fi # Update the bootstrap urls accordingly. if ! sysrc -f ${INSTALLPATH}/${BASTILLECONF} -n bastille_url_hardenedbsd | grep -qw "${URL_HARDENEDBSD}"; then sysrc -f ${INSTALLPATH}/${BASTILLECONF} bastille_url_hardenedbsd="${URL_HARDENEDBSD}" fi } bastille_start() { # Start all bastille containers. echo "${PRDNAME} Extension: Starting all containers..." bastille start ALL if [ $? -eq 0 ]; then exit 0 else exit 1 fi } bastille_stop() { # Stop all bastille containers. echo "${PRDNAME} Extension: Stopping all containers..." bastille stop ALL if [ $? -eq 0 ]; then exit 0 else exit 1 fi } bastille_restart() { # Restart all bastille containers. echo "${PRDNAME} Extension: Restarting all containers..." bastille restart ALL if [ $? -eq 0 ]; then exit 0 else exit 1 fi } bastille_init() { # Check for system compatibility. if [ ! "${PLATFORM}" = "amd64" ]; then echo "Unsupported platform!"; exit 1 fi # Check for product compatibility. if [ ! "${PRDVERSION}" -ge "112" ]; then echo "Unsupported version!"; exit 1 fi echo "Initializing ${APPNAME}..." # Function calls. platform_check required_updates postinit_cmd gui_start rc_params ext_start } linux_compat_enable() { # Experimental feature. if ping -c1 -t5 freebsd.org > /dev/null; then # Manually enable Linux compatibility(Experimental). if ! sysrc -f ${CWDIR}${EXTCONF} -qc LINUX_COMPAT_SUPPORT=YES; then echo "Enabling Linux compatibility support..." #${CWDIR}/unionfs.sh fetch_pkg && ${CWDIR}/unionfs.sh load_kmods && ${CWDIR}/unionfs.sh unionfs_on && sysrc -f ${CWDIR}${EXTCONF} LINUX_COMPAT_SUPPORT="YES" >/dev/null 2>&1 ${CWDIR}/unionfs.sh fetch_debootstrap && ${CWDIR}/unionfs.sh load_kmods && sysrc -f ${CWDIR}${EXTCONF} LINUX_COMPAT_SUPPORT="YES" >/dev/null 2>&1 else echo "Linux compatibility already enabled." fi exit 0 else echo "Internet connection required to enable this feature." exit 1 fi } bootstrap_dist() { # Workaround since XigmaNAS does not ship with debootstrap command. if sysrc -f ${CWDIR}${EXTCONF} -qc LINUX_COMPAT_SUPPORT=YES; then # List of tested/working Linux distributions on FreeBSD 14.x. LINUX_FLAVORS="ubuntu-bionic ubuntu-focal ubuntu-jammy ubuntu-noble debian-buster debian-bullseye debian-bookworm" if [ -n "${LINUX_DIST}" ]; then for _linux_flavor in ${LINUX_FLAVORS}; do if [ "${LINUX_DIST}" = "${_linux_flavor}" ]; then LINUX_FLAVOR="${_linux_flavor}" break fi done fi if [ -z "${LINUX_FLAVOR}" ]; then echo "Available Linux flavors:" echo "${LINUX_FLAVORS}" echo -e "\nTo fetch latest debootstrap/keyring packages run 'bastille-init update_debootstrap'" exit 1 fi # Enable debootstrap environment. ${CWDIR}/unionfs.sh unionfs_on # Bootstrap Linux flavor using bastille. bastille bootstrap ${_linux_flavor} # Disable debootstrap environment. ${CWDIR}/unionfs.sh unionfs_off else echo "Linux compatibility disabled." exit 1 fi exit 0 } update_debootstrap() { # Update debootstrap and dependencies. if sysrc -f ${CWDIR}${EXTCONF} -qc LINUX_COMPAT_SUPPORT=YES; then ${CWDIR}/unionfs.sh update_debootstrap else echo "Linux compatibility disabled." exit 1 fi exit 0 } linux_compat_disable() { if sysrc -f ${CWDIR}${EXTCONF} -qc LINUX_COMPAT_SUPPORT=YES; then echo "Disabling Linux compatibility support..." sysrc -f ${CWDIR}${EXTCONF} -x LINUX_COMPAT_SUPPORT ${CWDIR}/unionfs.sh unionfs_off ${CWDIR}/unionfs.sh unload_kmods if [ -d "${CWDIR}/system/usr" ]; then echo "Removing debootstrap environment..." rm -rf ${CWDIR}/system/usr if [ -d "${CWDIR}/system/var" ]; then rm -rf ${CWDIR}/system/var fi fi echo "Done!, please reboot server now." else echo "Linux compatibility disabled." exit 1 fi exit 0 } # Run-time configuration. runtime_config TARGET="${2}" RELEASE="${3}" NEWRELEASE="${4}" # Handle additional commands. case "${OPT}" in install|--install) if [ $# -gt 2 ] || [ $# -lt 2 ]; then echo "Usage: ${SCRIPTNAME} [install|--install] [container]" exit 1 fi thickjail_install ;; upgrade|--upgrade) # Check container type to upgrade if [ -z "${NEWRELEASE}" ]; then if [ $# -gt 3 ] || [ $# -lt 3 ]; then echo "Usage: ${SCRIPTNAME} [upgrade|--upgrade] [container|release] [release]" exit 1 fi thickjail_upgrade else if [ $# -gt 4 ] || [ $# -lt 4 ]; then echo "Usage: ${SCRIPTNAME} [upgrade|--upgrade] [container] [release] [newrelease]" exit 1 fi release_change fi _forceopt= ;; upgrade_force|--upgrade-force) # Check container type to upgrade if [ -z "${NEWRELEASE}" ]; then if [ $# -gt 3 ] || [ $# -lt 3 ]; then echo "Usage: ${SCRIPTNAME} [upgrade_force|--upgrade-force] [container|release] [release]" exit 1 fi thickjail_upgrade else if [ $# -gt 4 ] || [ $# -lt 4 ]; then echo "Usage: ${SCRIPTNAME} [upgrade_force|--upgrade-force] [container] [release] [newrelease]" exit 1 fi release_change fi _forceopt="-F" ;; update|--update) if [ $# -gt 2 ] || [ $# -lt 2 ]; then echo "Usage: ${SCRIPTNAME} [update|--update] [container] | [release]" exit 1 fi _forceopt= jail_update ;; update_force|--update-force) if [ $# -gt 2 ] || [ $# -lt 2 ]; then echo "Usage: ${SCRIPTNAME} [update_force|--update-force] [container] | [release]" exit 1 fi _forceopt="-F" jail_update ;; clean|--clean) for file in ${CWDIR}/freebsd-update/*; do rm -rf ${file} done exit 0 ;; linux_compat) linux_compat_enable ;; bootstrap) LINUX_DIST="${ARG}" bootstrap_dist ;; update_debootstrap) update_debootstrap ;; linux_compat_disable) linux_compat_disable ;; bastillebsd_update) bastille_core_update ;; esac while getopts "ospruxUvgtZh" option; do case ${option} in [h]) echo "Usage: ${SCRIPTNAME} -[option] | [container] | [path]"; echo "Options:" echo " -s Start All ${PRDNAME} Containers." echo " -p Stop All ${PRDNAME} Containers." echo " -r Restart All ${PRDNAME} Containers." echo " -u Upgrade ${PRDNAME}/Extension packages." echo " -v Display product versions." echo " -g Enables the addon GUI." echo " -t Disable the addon GUI." echo " -Z Activate ZFS for ${PRDNAME} Extension." echo " -x Reset ${PRDNAME}/Extension config." echo " -U Uninstall ${PRDNAME} (Extension files only)." #echo " -L Enable Linux compatibility(Experimental)." echo " -h Display this help message." echo echo "Advanced Usage: ${SCRIPTNAME} [option] [container] [release] | [newrelease]" echo "Options:" echo " update|--update Update a container/release to base -pX release." echo " update_force|--update-force Update a container/release to base -pX release forcefully." echo " upgrade|--upgrade Upgrade a container/release to X.Y-RELEASE." echo " upgrade_force|--upgrade-force Upgrade a container/release to X.Y-RELEASE. forcefully" echo " install|--install Finish installing pending updates on container/release." echo " clean|--clean Cleanup the FreeBSD update/upgrade cached files/folders." echo "" echo "" echo "Experimental:" echo "To enable experimental Linux jail support please execute: \"${SCRIPTNAME} linux_compat\"" echo "To disable experimental Linux jail support please execute: \"${SCRIPTNAME} linux_compat_disable\"" echo "" echo "" echo "Support:" echo "To update BastilleBSD core files only to the latest patches and fixes, please execute: \"${SCRIPTNAME} bastillebsd_update\"" echo "To bootstrap a Linux distribution please execute: \"${SCRIPTNAME} bootstrap linux_flavor\"" echo "To update debootstrap package and dependencies please execute: \"${SCRIPTNAME} update_debootstrap\"" echo ""; exit 0;; [o]) OBI_INSTALL="ON";; # To prevent nested PHP-CGI call for installation with OBI. [s]) bastille_start;; [p]) bastille_stop;; [r]) bastille_restart;; [u]) pkg_upgrade;; [x]) reset_install;; [U]) remove_addon;; [v]) get_versions;; [g]) gui_enable;; # Enable the addon gui. [t]) gui_disable;; # Disable the addon gui. [Z]) zfs_activate;; #[L]) linux_compat;; [?]) echo "Invalid option, -h for usage."; exit 1;; esac done bastille_init