diff --git a/AUTHORS.md b/AUTHORS.md index decabda..1c28321 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -7,13 +7,21 @@ Christer Edwards [christer.edwards@gmail.com] ## Contributors (code) - Barry McCormick - Brian Downs +- Carsten Bäcker +- Chris Wells - Dave Cottlehuber - Giacomo Olgeni +- Gleb Popov - JP Mens - Jose Rivera +- Juan David Hurtado G. - Lars E. +- Marius van Witzenburg +- Matt Audesse - Paul C. +- Petru T. Garstea - Sven R. +- Tobias Tom ### Special thanks Software doesn't happen in a vacuum. Thank you to the following people who may diff --git a/LICENSE b/LICENSE index 994cf0b..f0848e3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2018-2020, Christer Edwards +Copyright (c) 2018-2021, Christer Edwards All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index 629c769..dfaa8c7 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ Use "bastille command -h|--help" for more information about a command. ``` -## 0.8-beta +## 0.9-beta This document outlines the basic usage of the Bastille container management framework. This release is still considered beta. @@ -131,13 +131,15 @@ nat on $ext_if from to any -> ($ext_if:0) rdr-anchor "rdr/*" block in all -pass out quick modulate state +pass out quick keep state antispoof for $ext_if inet pass in inet proto tcp from any to any port ssh flags S/SA keep state ## make sure you also open up ports that you are going to use for dynamic rdr # pass in inet proto tcp from any to any port : flags S/SA keep state # pass in inet proto udp from any to any port : flags S/SA keep state +## for IPv6 networks please uncomment the following rule +# pass inet6 proto icmp6 icmp6-type { echoreq, routersol, routeradv, neighbradv, neighbrsol } ``` @@ -215,7 +217,7 @@ Two values are required for Bastille to use ZFS. The default values in the bastille_zfs_enable="" ## default: "" bastille_zfs_zpool="" ## default: "" bastille_zfs_prefix="bastille" ## default: "${bastille_zfs_zpool}/bastille" -bastille_zfs_mountpoint=${bastille_prefix} ## default: "${bastille_prefix}" +bastille_prefix="/bastille" ## default: "/usr/local/bastille". ${bastille_zfs_prefix} gets mounted here bastille_zfs_options="-o compress=lz4 -o atime=off" ## default: "-o compress=lz4 -o atime=off" ``` @@ -234,8 +236,8 @@ not using ZFS and can safely ignore these settings. bastille bootstrap ------------------ Before you can begin creating containers, Bastille needs to "bootstrap" a -release. Current supported releases are 11.3-RELEASE, 12.0-RELEASE and -12.1-RELEASE. +release. Current supported releases are 11.4-RELEASE, 12.2-RELEASE and +13.0-RELEASE. **Important: If you need ZFS support see the above section BEFORE bootstrapping.** @@ -243,14 +245,14 @@ bootstrapping.** To `bootstrap` a release, run the bootstrap sub-command with the release version as the argument. -**FreeBSD 11.3-RELEASE** +**FreeBSD 11.4-RELEASE** ```shell -ishmael ~ # bastille bootstrap 11.3-RELEASE +ishmael ~ # bastille bootstrap 11.4-RELEASE ``` -**FreeBSD 12.1-RELEASE** +**FreeBSD 12.2-RELEASE** ```shell -ishmael ~ # bastille bootstrap 12.1-RELEASE +ishmael ~ # bastille bootstrap 12.2-RELEASE ``` **HardenedBSD 11-STABLE-BUILD-XX** @@ -290,6 +292,37 @@ bootstrapping templates from GitHub or GitLab. See `bastille update` to ensure your bootstrapped releases include the latest patches. +** Ubuntu Linux [new since 0.9] ** + +The bootstrap process for Linux containers is very different from the BSD process. +You will need the package debootstrap and some kernel modules for that. +But don't worry, Bastille will do that for you. + +```shell +ishmael ~ # bastille bootstrap focal +sysrc: unknown variable 'linprocfs_load' +sysrc: unknown variable 'linsysfs_load' +sysrc: unknown variable 'tmpfs_load' +linprocfs_load, linsysfs_load, tmpfs_load not enabled in /boot/loader.conf or linux_enable not active. Should I do that for you? (N|y) +#y +Loading modules +Persisting modules +linux_enable: -> YES +linprocfs_load: -> YES +linsysfs_load: -> YES +tmpfs_load: -> YES +Debootstrap not found. Should it be installed? (N|y) +#y +FreeBSD repository is up to date. +All repositories are up to date. +Checking integrity... done (0 conflicting) +The following 1 package(s) will be affected (of 0 checked): + +New packages to be INSTALLED: + debootstrap: 1.0.123_4 +[...] +``` +As of 0.9.20210714 Bastille supports Ubuntu 18.04 (bionic) and Ubuntu 20.04 (focal). bastille create --------------- @@ -306,24 +339,24 @@ IP at container creation. **ip4** ```shell -ishmael ~ # bastille create folsom 12.1-RELEASE 10.17.89.10 +ishmael ~ # bastille create folsom 12.2-RELEASE 10.17.89.10 Valid: (10.17.89.10). NAME: folsom. IP: 10.17.89.10. -RELEASE: 12.1-RELEASE. +RELEASE: 12.2-RELEASE. syslogd_flags: -s -> -ss sendmail_enable: NO -> NONE cron_flags: -> -J 60 ``` -This command will create a 12.1-RELEASE container assigning the 10.17.89.10 ip +This command will create a 12.2-RELEASE container assigning the 10.17.89.10 ip address to the new system. **ip6** ```shell -ishmael ~ # bastille create folsom 12.1-RELEASE fd35:f1fd:2cb6:6c5c::13 +ishmael ~ # bastille create folsom 12.2-RELEASE fd35:f1fd:2cb6:6c5c::13 Valid: (fd35:f1fd:2cb6:6c5c::13). NAME: folsom. @@ -335,12 +368,12 @@ sendmail_enable: NO -> NONE cron_flags: -> -J 60 ``` -This command will create a 12.1-RELEASE container assigning the +This command will create a 12.2-RELEASE container assigning the fd35:f1fd:2cb6:6c5c::13 ip address to the new system. **VNET** ```shell -ishmael ~ # bastille create -V vnetjail 12.1-RELEASE 192.168.87.55/24 em0 +ishmael ~ # bastille create -V vnetjail 12.2-RELEASE 192.168.87.55/24 em0 Valid: (192.168.87.55/24). Valid: (em0). @@ -356,7 +389,7 @@ ifconfig_e0b_bastille0_name: -> vnet0 ifconfig_vnet0: -> inet 192.168.87.55/24 ``` -This command will create a 12.1-RELEASE container assigning the +This command will create a 12.2-RELEASE container assigning the 192.168.87.55/24 ip address to the new system. VNET-enabled containers are attached to a virtual bridge interface for @@ -376,9 +409,18 @@ private base. This is sometimes referred to as a "thick" container (whereas the shared base container is a "thin"). ```shell -ishmael ~ # bastille create -T folsom 12.0-RELEASE 10.17.89.10 +ishmael ~ # bastille create -T folsom 12.2-RELEASE 10.17.89.10 ``` +**Linux** +```shell +ishmael ~ # bastille create folsom focal 10.17.89.10 +``` + +Systemd is not supported due to the missing boot process. + + + I recommend using private (rfc1918) ip address ranges for your containers. These ranges include: @@ -628,9 +670,8 @@ Templates](https://gitlab.com/BastilleBSD-Templates)? Bastille supports a templating system allowing you to apply files, pkgs and execute commands inside the container automatically. -Currently supported template hooks are: `ARG`, `LIMITS`, `INCLUDE`, `PRE`, - `FSTAB`, `PKG`, `OVERLAY`, `SYSRC`, `SERVICE`, `CMD`, `RENDER`. -Planned template hooks include: `PF`, `LOG` +Currently supported template hooks are: `ARG`, `LIMITS`, `INCLUDE`, + `MOUNT`, `PKG`, `CP`, `SYSRC`, `SERVICE`, `RDR`, `CMD`, `RENDER`. Templates are created in `${bastille_prefix}/templates` and can leverage any of the template hooks. Simply create a new directory in the format project/repo, @@ -644,9 +685,9 @@ To leverage a template hook, create an UPPERCASE file in the root of the template directory named after the hook you want to execute. eg; ```shell -echo "zsh vim-console git-lite htop" > /usr/local/bastille/templates/username/base-template/PKG -echo "/usr/bin/chsh -s /usr/local/bin/zsh" > /usr/local/bastille/templates/username/base-template/CMD -echo "usr" > /usr/local/bastille/templates/username/base-template/OVERLAY +echo "PKG zsh vim-console git-lite htop" >> /usr/local/bastille/templates/username/base-template/Bastillefile +echo "CMD /usr/bin/chsh -s /usr/local/bin/zsh" >> /usr/local/bastille/templates/username/base-template/Bastillefile +echo "CP usr" > /usr/local/bastille/templates/username/base-template/Bastillefile ``` Template hooks are executed in specific order and require specific syntax to @@ -665,11 +706,7 @@ work as expected. This table outlines that order and those requirements: | SERVICE | service command(s) | nginx restart | | CMD | /bin/sh command | /usr/bin/chsh -s /usr/local/bin/zsh | | RENDER | paths (one/line) | /usr/local/etc/nginx | - -| PLANNED | format | example | -|---------|------------------|----------------------------------------------------------------| -| RDR | pf rdr entry | rdr pass inet proto tcp from any to any port 80 -> 10.17.89.80 | -| LOG | path | /var/log/nginx/access.log | +| RDR | protocol port port | tcp 2200 22 | Note: SYSRC requires NO quotes or that quotes (`"`) be escaped. ie; `\"`) @@ -698,8 +735,8 @@ After populating `usr/local/` with custom config files that your container will use, be sure to include `usr` in the template OVERLAY definition. eg; ```shell -echo "etc" > /usr/local/bastille/templates/username/base/OVERLAY -echo "usr" >> /usr/local/bastille/templates/username/base/OVERLAY +echo "CP etc" >> /usr/local/bastille/templates/username/base/Bastillefile +echo "CP usr" >> /usr/local/bastille/templates/username/base/Bastillefile ``` The above example will include anything under "etc" and "usr" inside @@ -890,21 +927,21 @@ The `update` command targets a release instead of a container. Because every container is based on a release, when the release is updated all the containers are automatically updated as well. -To update all containers based on the 11.2-RELEASE `release`: +To update all containers based on the 11.4-RELEASE `release`: -Up to date 11.2-RELEASE: +Up to date 11.4-RELEASE: ```shell -ishmael ~ # bastille update 11.2-RELEASE +ishmael ~ # bastille update 11.4-RELEASE Targeting specified release. -11.2-RELEASE +11.4-RELEASE Looking up update.FreeBSD.org mirrors... 2 mirrors found. -Fetching metadata signature for 11.2-RELEASE from update4.freebsd.org... done. +Fetching metadata signature for 11.4-RELEASE from update4.freebsd.org... done. Fetching metadata index... done. Inspecting system... done. Preparing to download files... done. -No updates needed to update system to 11.2-RELEASE-p4. +No updates needed to update system to 11.4-RELEASE-p4. No updates are available to install. ``` @@ -916,11 +953,21 @@ bastille upgrade This sub-command lets you upgrade a release to a new release. Depending on the workflow this can be similar to a `bootstrap`. +For standard containers you need to upgrade the shared base jail: ```shell -ishmael ~ # bastille upgrade 11.3-RELEASE 12.0-RELEASE +ishmael ~ # bastille upgrade 12.1-RELEASE 12.2-RELEASE ... ``` +For thick jails you need to upgrade every single container (according the freebsd-update procedure): +```shell +ishmael ~ # bastille upgrade folsom 12.2-RELEASE +ishmael ~ # bastille upgrade folsom install +... +ishmael ~ # bastille restart folsom +ishmael ~ # bastille upgrade folsom install +``` + bastille verify --------------- @@ -1028,11 +1075,7 @@ Example (create, start, console) This example creates, starts and consoles into the container. ```shell -ishmael ~ # bastille create alcatraz 11.2-RELEASE 10.17.89.7 - -RELEASE: 11.2-RELEASE. -NAME: alcatraz. -IP: 10.17.89.7. +ishmael ~ # bastille create alcatraz 11.4-RELEASE 10.17.89.7 ``` ```shell @@ -1044,7 +1087,7 @@ alcatraz: created ```shell ishmael ~ # bastille console alcatraz [alcatraz]: -FreeBSD 11.2-RELEASE-p4 (GENERIC) #0: Thu Sep 27 08:16:24 UTC 2018 +FreeBSD 11.4-RELEASE-p4 (GENERIC) #0: Thu Sep 27 08:16:24 UTC 2018 Welcome to FreeBSD! diff --git a/docs/chapters/installation.rst b/docs/chapters/installation.rst index 25c1c85..d62553f 100644 --- a/docs/chapters/installation.rst +++ b/docs/chapters/installation.rst @@ -4,7 +4,7 @@ Bastille is available in the official FreeBSD ports tree at `sysutils/bastille`. Binary packages available in `quarterly` and `latest` repositories. -Current version is `0.8.20210101`. +Current version is `0.9.20210714`. To install from the FreeBSD package repository: diff --git a/docs/chapters/networking.rst b/docs/chapters/networking.rst index fb52e8a..397a6d4 100644 --- a/docs/chapters/networking.rst +++ b/docs/chapters/networking.rst @@ -165,23 +165,14 @@ Create the firewall rules: set skip on lo table persist - nat on $ext_if from to any -> ($ext_if) - - ## static rdr example - ## rdr pass inet proto tcp from any to any port {80, 443} -> 10.17.89.45 - - ## dynamic rdr anchor (see below) + nat on $ext_if from to any -> ($ext_if:0) rdr-anchor "rdr/*" block in all - pass out quick modulate state + pass out quick keep state antispoof for $ext_if inet pass in inet proto tcp from any to any port ssh flags S/SA modulate state - # If you are using dynamic rdr also need to ensure that the external port - # range you are using is open - # pass in inet proto tcp from any to any port : - - Make sure to change the `ext_if` variable to match your host system interface. - Make sure to include the last line (`port ssh`) or you'll end up locked out. @@ -192,30 +183,26 @@ to containers are: nat on $ext_if from to any -> ($ext_if) - ## static rdr example - ## rdr pass inet proto tcp from any to any port {80, 443} -> 10.17.89.45 - The `nat` routes traffic from the loopback interface to the external interface for outbound access. -The `rdr pass ...` will redirect traffic from the host firewall on port X to -the ip of Container Y. The example shown redirects web traffic (80 & 443) to the -containers at `10.17.89.45`. +.. code-block:: shell - ## dynamic rdr anchor (see below) rdr-anchor "rdr/*" The `rdr-anchor "rdr/*"` enables dynamic rdr rules to be setup using the `bastille rdr` command at runtime - eg. +.. code-block:: shell + bastille rdr tcp 2001 22 # Redirects tcp port 2001 on host to 22 on jail bastille rdr udp 2053 53 # Same for udp bastille rdr list # List dynamic rdr rules bastille rdr clear # Clear dynamic rdr rules - Note that if you are redirecting ports where the host is also listening - (eg. ssh) you should make sure that the host service is not listening on - the cloned interface - eg. for ssh set sshd_flags in rc.conf +Note that if you are redirecting ports where the host is also listening (eg. +ssh) you should make sure that the host service is not listening on the cloned +interface - eg. for ssh set sshd_flags in rc.conf sshd_flags="-o ListenAddress=" diff --git a/docs/chapters/subcommands/export.rst b/docs/chapters/subcommands/export.rst index 23e95dd..db10920 100644 --- a/docs/chapters/subcommands/export.rst +++ b/docs/chapters/subcommands/export.rst @@ -11,7 +11,8 @@ container backups. ishmael ~ # bastille export azkaban The export sub-command supports both UFS and ZFS storage. ZFS based containers -will use ZFS snapshots. UFS based containers will use `txz` archives. +will use ZFS snapshots. UFS based containers will use `txz` archives and they +can be exported only when the jail is not running. .. code-block:: shell diff --git a/docs/chapters/subcommands/pkg.rst b/docs/chapters/subcommands/pkg.rst index 5571c5b..3ab1e32 100644 --- a/docs/chapters/subcommands/pkg.rst +++ b/docs/chapters/subcommands/pkg.rst @@ -6,7 +6,7 @@ To manage binary packages within the container use `bastille pkg`. .. code-block:: shell - ishmael ~ # bastille pkg folsom 'install vim-console git-lite zsh' + ishmael ~ # bastille pkg folsom install vim-console git-lite zsh [folsom]: The package management tool is not yet installed on your system. Do you want to fetch and install it now? [y/N]: y diff --git a/docs/chapters/template.rst b/docs/chapters/template.rst index c92e3c7..346920f 100644 --- a/docs/chapters/template.rst +++ b/docs/chapters/template.rst @@ -7,14 +7,14 @@ Templates](https://gitlab.com/BastilleBSD-Templates)? Bastille supports a templating system allowing you to apply files, pkgs and execute commands inside the containers automatically. -Currently supported template hooks are: `LIMITS`, `INCLUDE`, `PRE`, `FSTAB`, -`PKG`, `OVERLAY`, `SYSRC`, `SERVICE`, `CMD`. +Currently supported template hooks are: `CMD`, `CP`, `INCLUDE`, `LIMITS`, `MOUNT`, +`PKG`, `RDR`, `SERVICE`, `SYSRC`. Templates are created in `${bastille_prefix}/templates` and can leverage any of the template hooks. -Bastille 0.7.x --------------- +Bastille 0.7.x+ +--------------- Bastille 0.7.x introduces a template syntax that is more flexible and allows any-order scripting. Previous versions had a hard template execution order and instructions were spread across multiple files. The new syntax is done in a @@ -27,23 +27,23 @@ Template Automation Hooks +---------+-------------------+-----------------------------------------+ | HOOK | format | example | +=========+===================+=========================================+ -| LIMITS | resource value | memoryuse 1G | +| CMD | /bin/sh command | /usr/bin/chsh -s /usr/local/bin/zsh | ++---------+-------------------+-----------------------------------------+ +| CP | path(s) | etc root usr (one per line) | +---------+-------------------+-----------------------------------------+ | INCLUDE | template path/URL | http?://TEMPLATE_URL or project/path | +---------+-------------------+-----------------------------------------+ -| PRE | /bin/sh command | mkdir -p /usr/local/my_app/html | +| LIMITS | resource value | memoryuse 1G | +---------+-------------------+-----------------------------------------+ -| FSTAB | fstab syntax | /host/path container/path nullfs ro 0 0 | +| MOUNT | fstab syntax | /host/path container/path nullfs ro 0 0 | +---------+-------------------+-----------------------------------------+ | PKG | port/pkg name(s) | vim-console zsh git-lite tree htop | +---------+-------------------+-----------------------------------------+ -| OVERLAY | path(s) | etc root usr (one per line) | -+---------+-------------------+-----------------------------------------+ -| SYSRC | sysrc command(s) | nginx_enable=YES | +| RDR | tcp port port | tcp 2200 22 (hostport jailport) | +---------+-------------------+-----------------------------------------+ | SERVICE | service command | 'nginx start' OR 'postfix reload' | +---------+-------------------+-----------------------------------------+ -| CMD | /bin/sh command | /usr/bin/chsh -s /usr/local/bin/zsh | +| SYSRC | sysrc command(s) | nginx_enable=YES | +---------+-------------------+-----------------------------------------+ Note: SYSRC requires that NO quotes be used or that quotes (`"`) be escaped @@ -71,7 +71,7 @@ use, be sure to include `usr` in the template OVERLAY definition. eg; .. code-block:: shell - echo "usr" > /usr/local/bastille/templates/username/template/OVERLAY + echo "CP usr" >> /usr/local/bastille/templates/username/template/Bastillefile The above example "usr" will include anything under "usr" inside the template. You do not need to list individual files. Just include the top-level directory diff --git a/docs/conf.py b/docs/conf.py index ca3c958..9960669 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -8,13 +8,13 @@ else: # -- Project information ----------------------------------------------------- project = 'Bastille' -copyright = '2018-2020, Christer Edwards' +copyright = '2018-2021, Christer Edwards' author = 'Christer Edwards' # The short X.Y version -version = '0.8.20210101' +version = '0.9.20210714' # The full version, including alpha/beta/rc tags -release = '0.8.20210101-beta' +release = '0.8.20210714-beta' # -- General configuration --------------------------------------------------- diff --git a/usr/local/bin/bastille b/usr/local/bin/bastille index 46ec8f2..ac9a55c 100755 --- a/usr/local/bin/bastille +++ b/usr/local/bin/bastille @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -70,7 +70,7 @@ bastille_perms_check() { bastille_perms_check ## version -BASTILLE_VERSION="0.8.20210101" +BASTILLE_VERSION="0.9.20210714" usage() { cat << EOF @@ -135,10 +135,10 @@ version|-v|--version) help|-h|--help) usage ;; -bootstrap|create|destroy|import|list|rdr|restart|start|update|upgrade|verify) +bootstrap|create|destroy|export|import|list|rdr|restart|start|update|upgrade|verify) # Nothing "extra" to do for these commands. -- cwells ;; -clone|config|cmd|console|convert|cp|edit|export|htop|limits|mount|pkg|rename|service|stop|sysrc|template|top|umount|zfs) +clone|config|cmd|console|convert|cp|edit|htop|limits|mount|pkg|rename|service|stop|sysrc|template|top|umount|zfs) # Parse the target and ensure it exists. -- cwells if [ $# -eq 0 ]; then # No target was given, so show the command's help. -- cwells PARAMS='help' diff --git a/usr/local/etc/bastille/bastille.conf.sample b/usr/local/etc/bastille/bastille.conf.sample index a47da94..22653b3 100644 --- a/usr/local/etc/bastille/bastille.conf.sample +++ b/usr/local/etc/bastille/bastille.conf.sample @@ -33,6 +33,7 @@ bastille_resolv_conf="/etc/resolv.conf" ## default ## bootstrap urls bastille_url_freebsd="http://ftp.freebsd.org/pub/FreeBSD/releases/" ## default: "http://ftp.freebsd.org/pub/FreeBSD/releases/" bastille_url_hardenedbsd="http://installer.hardenedbsd.org/pub/hardenedbsd/" ## default: "https://installer.hardenedbsd.org/pub/HardenedBSD/releases/" +bastille_url_midnightbsd="https://www.midnightbsd.org/ftp/MidnightBSD/releases/" ## default: "https://www.midnightbsd.org/pub/MidnightBSD/releases/" ## ZFS options bastille_zfs_enable="" ## default: "" @@ -43,15 +44,18 @@ bastille_zfs_options="-o compress=lz4 -o atime=off" ## default ## Export/Import options bastille_compress_xz_options="-0 -v" ## default "-0 -v" bastille_decompress_xz_options="-c -d -v" ## default "-c -d -v" +bastille_compress_gz_options="-1 -v" ## default "-1 -v" +bastille_decompress_gz_options="-k -d -c -v" ## default "-k -d -c -v" ## Networking bastille_network_loopback="bastille0" ## default: "bastille0" bastille_network_shared="" ## default: "" bastille_network_gateway="" ## default: "" +bastille_network_gateway6="" ## default: "" ## Default Templates bastille_template_base="default/base" ## default: "default/base" -bastille_template_empty="default/empty" ## default: "default/empty" +bastille_template_empty="" ## default: "default/empty" bastille_template_thick="default/thick" ## default: "default/thick" bastille_template_thin="default/thin" ## default: "default/thin" bastille_template_vnet="default/vnet" ## default: "default/vnet" diff --git a/usr/local/share/bastille/bootstrap.sh b/usr/local/share/bastille/bootstrap.sh index 504ddae..269e1b3 100644 --- a/usr/local/share/bastille/bootstrap.sh +++ b/usr/local/share/bastille/bootstrap.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -45,14 +45,12 @@ esac #Validate if ZFS is enabled in rc.conf and bastille.conf. if [ "$(sysrc -n zfs_enable)" = "YES" ] && [ ! "${bastille_zfs_enable}" = "YES" ]; then warn "ZFS is enabled in rc.conf but not bastille.conf. Do you want to continue? (N|y)" - read answer + read answer case $answer in no|No|n|N|"") error_exit "ERROR: Missing ZFS parameters. See bastille_zfs_enable." ;; - yes|Yes|y|Y) - continue - ;; + yes|Yes|y|Y) ;; esac fi @@ -85,7 +83,7 @@ validate_release_url() { info "Bootstrapping ${PLATFORM_OS} distfiles..." # Alternate RELEASE/ARCH fetch support - if [ "${OPTION}" = "--i386" -o "${OPTION}" = "--32bit" ]; then + if [ "${OPTION}" = "--i386" ] || [ "${OPTION}" = "--32bit" ]; then ARCH="i386" RELEASE="${RELEASE}-${ARCH}" fi @@ -178,7 +176,6 @@ bootstrap_directories() { else mkdir -p "${bastille_templatesdir}" fi - ln -s "${bastille_sharedir}/templates/default" "${bastille_templatesdir}/default" fi ## ${bastille_releasesdir} @@ -216,7 +213,7 @@ bootstrap_release() { ## check if release already bootstrapped, else continue bootstrapping if [ -z "${bastille_bootstrap_archives}" ]; then - error_exit "Bootstrap appears complete." + error_notify "Bootstrap appears complete." else info "Bootstrapping additional distfiles..." fi @@ -254,12 +251,12 @@ bootstrap_release() { fi if [ -d "${bastille_cachedir}/${RELEASE}" ]; then if [ ! "$(ls -A "${bastille_cachedir}/${RELEASE}")" ]; then - rm -rf "${bastille_cachedir}/${RELEASE}" + rm -rf "${bastille_cachedir:?}/${RELEASE}" fi fi if [ -d "${bastille_releasesdir}/${RELEASE}" ]; then if [ ! "$(ls -A "${bastille_releasesdir}/${RELEASE}")" ]; then - rm -rf "${bastille_releasesdir}/${RELEASE}" + rm -rf "${bastille_releasesdir:?}/${RELEASE}" fi fi error_exit "Bootstrap failed." @@ -267,8 +264,7 @@ bootstrap_release() { ## fetch for missing dist files if [ ! -f "${bastille_cachedir}/${RELEASE}/${_archive}.txz" ]; then - fetch "${UPSTREAM_URL}/${_archive}.txz" -o "${bastille_cachedir}/${RELEASE}/${_archive}.txz" - if [ "$?" -ne 0 ]; then + if ! fetch "${UPSTREAM_URL}/${_archive}.txz" -o "${bastille_cachedir}/${RELEASE}/${_archive}.txz"; then ## alert only if unable to fetch additional dist files error_notify "Failed to fetch ${_archive}.txz." fi @@ -329,15 +325,15 @@ bootstrap_template() { _template=${bastille_templatesdir}/${_user}/${_repo} ## support for non-git - if [ ! -x "$(which git)" ]; then + if ! which -s git; then error_notify "Git not found." error_exit "Not yet implemented." - elif [ -x "$(which git)" ]; then + else if [ ! -d "${_template}/.git" ]; then - $(which git) clone "${_url}" "${_template}" ||\ + git clone "${_url}" "${_template}" ||\ error_notify "Clone unsuccessful." elif [ -d "${_template}/.git" ]; then - cd "${_template}" && $(which git) pull ||\ + git -C "${_template}" pull ||\ error_notify "Template update unsuccessful." fi fi @@ -345,6 +341,43 @@ bootstrap_template() { bastille verify "${_user}/${_repo}" } +check_linux_prerequisites() { + #check and install OS dependencies @hackacad + if [ ! "$(sysrc -f /boot/loader.conf -n linprocfs_load)" = "YES" ] && [ ! "$(sysrc -f /boot/loader.conf -n linsysfs_load)" = "YES" ] && [ ! "$(sysrc -f /boot/loader.conf -n tmpfs_load)" = "YES" ]; then + warn "linprocfs_load, linsysfs_load, tmpfs_load not enabled in /boot/loader.conf or linux_enable not active. Should I do that for you? (N|y)" + read answer + case $answer in + [Nn][Oo]|[Nn]|"") + error_exit "Exiting." + ;; + [Yy][Ee][Ss]|[Yy]) + info "Loading modules" + kldload linux linux64 linprocfs linsysfs tmpfs + info "Persisting modules" + sysrc linux_enable=YES + sysrc -f /boot/loader.conf linprocfs_load=YES + sysrc -f /boot/loader.conf linsysfs_load=YES + sysrc -f /boot/loader.conf tmpfs_load=YES + ;; + esac + fi +} + +ensure_debootstrap() { + if ! which -s debootstrap; then + warn "Debootstrap not found. Should it be installed? (N|y)" + read answer + case $answer in + [Nn][Oo]|[Nn]|"") + error_exit "Exiting. You need to install debootstap before boostrapping a Linux jail." + ;; + [Yy][Ee][Ss]|[Yy]) + pkg install -y debootstrap + ;; + esac + fi +} + HW_MACHINE=$(sysctl hw.machine | awk '{ print $2 }') HW_MACHINE_ARCH=$(sysctl hw.machine_arch | awk '{ print $2 }') RELEASE="${1}" @@ -353,7 +386,7 @@ OPTION="${2}" # Alternate RELEASE/ARCH fetch support(experimental) if [ -n "${OPTION}" ] && [ "${OPTION}" != "${HW_MACHINE}" ] && [ "${OPTION}" != "update" ]; then # Supported architectures - if [ "${OPTION}" = "--i386" -o "${OPTION}" = "--32bit" ]; then + if [ "${OPTION}" = "--i386" ] || [ "${OPTION}" = "--32bit" ]; then HW_MACHINE="i386" HW_MACHINE_ARCH="i386" else @@ -363,6 +396,13 @@ fi ## Filter sane release names case "${1}" in +2.[0-9]*) + ## check for MidnightBSD releases name + NAME_VERIFY=$(echo "${RELEASE}") + UPSTREAM_URL="${bastille_url_midnightbsd}${HW_MACHINE_ARCH}/${NAME_VERIFY}" + PLATFORM_OS="MidnightBSD" + validate_release_url + ;; *-CURRENT|*-current) ## check for FreeBSD releases name NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]{2,2})\.[0-9](-CURRENT)$' | tr '[:lower:]' '[:upper:]') @@ -370,9 +410,9 @@ case "${1}" in PLATFORM_OS="FreeBSD" validate_release_url ;; -*-RELEASE|*-release|*-RC1|*-rc1|*-RC2|*-rc2) +*-RELEASE|*-release|*-RC1|*-rc1|*-RC2|*-rc2|*-RC3|*-rc3|*-RC4|*-rc4|*-RC5|*-rc5|*-BETA1|*-BETA2|*-BETA3|*-BETA4|*-BETA5) ## check for FreeBSD releases name - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]{2,2})\.[0-9](-RELEASE|-RC[1-2])$' | tr '[:lower:]' '[:upper:]') + NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]{2,2})\.[0-9](-RELEASE|-RC[1-5]|-BETA[1-5])$' | tr '[:lower:]' '[:upper:]') UPSTREAM_URL="${bastille_url_freebsd}${HW_MACHINE}/${HW_MACHINE_ARCH}/${NAME_VERIFY}" PLATFORM_OS="FreeBSD" validate_release_url @@ -420,17 +460,45 @@ current-build-latest|current-BUILD-LATEST|CURRENT-BUILD-LATEST) PLATFORM_OS="HardenedBSD" validate_release_url ;; -http?://github.com/*/*|http?://gitlab.com/*/*) +http?://*/*/*) BASTILLE_TEMPLATE_URL=${1} BASTILLE_TEMPLATE_USER=$(echo "${1}" | awk -F / '{ print $4 }') BASTILLE_TEMPLATE_REPO=$(echo "${1}" | awk -F / '{ print $5 }') bootstrap_template ;; +#adding Ubuntu Bionic as valid "RELEASE" for POC @hackacad +ubuntu_bionic|bionic|ubuntu-bionic) + check_linux_prerequisites + ensure_debootstrap + debootstrap --foreign --arch=amd64 --no-check-gpg bionic "${bastille_releasesdir}"/Ubuntu_1804 + echo "APT::Cache-Start 251658240;" > "${bastille_releasesdir}"/Ubuntu_1804/etc/apt/apt.conf.d/00aptitude + ;; +ubuntu_focal|focal|ubuntu-focal) + check_linux_prerequisites + ensure_debootstrap + debootstrap --foreign --arch=amd64 --no-check-gpg focal "${bastille_releasesdir}"/Ubuntu_2004 + ;; +debian_stretch|stretch|debian-stretch) + check_linux_prerequisites + ensure_debootstrap + debootstrap --foreign --arch=amd64 --no-check-gpg stretch "${bastille_releasesdir}"/Debian9 + echo "Increasing APT::Cache-Start" + echo "APT::Cache-Start 251658240;" > "${bastille_releasesdir}"/Debian9/etc/apt/apt.conf.d/00aptitude + ;; +debian_buster|buster|debian-buster) + check_linux_prerequisites + ensure_debootstrap + debootstrap --foreign --arch=amd64 --no-check-gpg buster "${bastille_releasesdir}"/Debian10 + echo "Increasing APT::Cache-Start" + echo "APT::Cache-Start 251658240;" > "${bastille_releasesdir}"/Debian10/etc/apt/apt.conf.d/00aptitude + ;; *) usage ;; esac + + case "${OPTION}" in update) bastille update "${RELEASE}" diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index bc9c34e..069bf6a 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr/local/share/bastille/cmd.sh b/usr/local/share/bastille/cmd.sh index 28ce03b..5f56e9d 100644 --- a/usr/local/share/bastille/cmd.sh +++ b/usr/local/share/bastille/cmd.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -51,23 +51,22 @@ RETURN=0 for _jail in ${JAILS}; do COUNT=$(($COUNT+1)) info "[${_jail}]:" - jexec -l "${_jail}" "$@" + jexec -l -U root "${_jail}" "$@" ERROR_CODE=$? - info "[${_jail} - Return code]: ${ERROR_CODE}" - + info "[${_jail}]: ${ERROR_CODE}" + if [ "$COUNT" -eq 1 ]; then RETURN=$ERROR_CODE else RETURN=$(($RETURN+$ERROR_CODE)) fi - + echo done # Check when a command is executed in all running jails. (bastille cmd ALL ...) - if [ "$COUNT" -gt 1 ] && [ "$RETURN" -gt 0 ]; then RETURN=1 -fi +fi -return "$RETURN" +return "$RETURN" \ No newline at end of file diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index 4dd30c1..1220fb2 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -28,7 +28,19 @@ # 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. -. /usr/local/share/bastille/colors.pre.sh +COLOR_RED= +COLOR_GREEN= +COLOR_YELLOW= +COLOR_RESET= + +enable_color() { + . /usr/local/share/bastille/colors.pre.sh +} + +# If "NO_COLOR" environment variable is present, disable output colors. +if ! export | grep -q "NO_COLOR"; then + enable_color +fi # Notify message on error, but do not exit error_notify() { diff --git a/usr/local/share/bastille/config.sh b/usr/local/share/bastille/config.sh index 42f0160..592ff57 100644 --- a/usr/local/share/bastille/config.sh +++ b/usr/local/share/bastille/config.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -76,7 +76,7 @@ for _jail in ${JAILS}; do MATCH_FOUND=$? if [ "${ACTION}" = 'get' ]; then - if [ $MATCH_FOUND -ne 0 ]; then + if [ "${MATCH_FOUND}" -ne 0 ]; then warn "not set" elif ! echo "${MATCH_LINE}" | grep '=' > /dev/null 2>&1; then echo "enabled" @@ -99,7 +99,7 @@ for _jail in ${JAILS}; do LINE=" ${PROPERTY};" fi - if [ $MATCH_FOUND -ne 0 ]; then # No match, so insert the property at the end. -- cwells + if [ "${MATCH_FOUND}" -ne 0 ]; then # No match, so insert the property at the end. -- cwells echo "$(awk -v line="${LINE}" '$0 == "}" { print line; } 1 { print $0; }' "${FILE}")" > "${FILE}" else # Replace the existing value. -- cwells sed -i '' -E "s/ *${ESCAPED_PROPERTY}[ =;].*/${LINE}/" "${FILE}" diff --git a/usr/local/share/bastille/console.sh b/usr/local/share/bastille/console.sh index baec8da..3363c9a 100644 --- a/usr/local/share/bastille/console.sh +++ b/usr/local/share/bastille/console.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille console TARGET [user]'" + error_exit "Usage: bastille console TARGET [user]" } # Handle special-case commands first. @@ -53,7 +53,7 @@ validate_user() { USER_SHELL="$(jexec -l "${_jail}" getent passwd "${USER}" | cut -d: -f7)" if [ -n "${USER_SHELL}" ]; then if jexec -l "${_jail}" grep -qwF "${USER_SHELL}" /etc/shells; then - jexec -l "${_jail}" /usr/bin/login -f "${USER}" + jexec -l "${_jail}" $LOGIN -f "${USER}" else echo "Invalid shell for user ${USER}" fi @@ -76,11 +76,12 @@ check_fib() { for _jail in ${JAILS}; do info "[${_jail}]:" + LOGIN="$(jexec -l "${_jail}" which login)" if [ -n "${USER}" ]; then validate_user else - check_fib - ${_setfib} jexec -l "${_jail}" /usr/bin/login -f root + LOGIN="$(jexec -l "${_jail}" which login)" + ${_setfib} jexec -l "${_jail}" $LOGIN -f root fi echo done diff --git a/usr/local/share/bastille/convert.sh b/usr/local/share/bastille/convert.sh index 29aa7af..30d3469 100644 --- a/usr/local/share/bastille/convert.sh +++ b/usr/local/share/bastille/convert.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -57,6 +57,7 @@ convert_symlinks() { done # Copy new files to destination jail + info "Copying required base files to container..." for _link in ${SYMLINKS}; do if [ ! -d "${_link}" ]; then if [ -d "${bastille_releasesdir}/${RELEASE}/${_link}" ]; then @@ -100,13 +101,15 @@ revert_convert() { start_convert() { # Attempt container conversion and handle some errors + DATE=$(date) if [ -d "${bastille_jailsdir}/${TARGET}" ]; then info "Converting '${TARGET}' into a thickjail. This may take a while..." # Set some variables - RELEASE=$(grep -owE '([1-9]{2,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-2])|([0-9]{1,2}-stable-build-[0-9]{1,3})|(current-build)-([0-9]{1,3})|(current-BUILD-LATEST)|([0-9]{1,2}-stable-BUILD-LATEST)|(current-BUILD-LATEST)' "${bastille_jailsdir}/${TARGET}/fstab") + RELEASE=$(grep -w "${bastille_releasesdir}/.* ${bastille_jailsdir}/${TARGET}/root/.bastille" ${bastille_jailsdir}/${TARGET}/fstab | sed "s|${bastille_releasesdir}/||;s| .*||") FSTABMOD=$(grep -w "${bastille_releasesdir}/${RELEASE} ${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab") SYMLINKS="bin boot lib libexec rescue sbin usr/bin usr/include usr/lib usr/lib32 usr/libdata usr/libexec usr/ports usr/sbin usr/share usr/src" + HASPORTS=$(grep -w ${bastille_releasesdir}/${RELEASE}/usr/ports ${bastille_jailsdir}/${TARGET}/fstab) if [ -n "${RELEASE}" ]; then cd "${bastille_jailsdir}/${TARGET}/root" @@ -115,7 +118,12 @@ start_convert() { convert_symlinks # Comment the line containing .bastille and rename mountpoint - sed -i '' -E "s|${FSTABMOD}|# Converted from thin to thick container on $(date)|g" "${bastille_jailsdir}/${TARGET}/fstab" + sed -i '' -E "s|${FSTABMOD}|# Converted from thin to thick container on ${DATE}|g" "${bastille_jailsdir}/${TARGET}/fstab" + if [ -n "${HASPORTS}" ]; then + sed -i '' -E "s|${HASPORTS}|# Ports copied from base to container on ${DATE}|g" "${bastille_jailsdir}/${TARGET}/fstab" + info "Copying ports to container..." + cp -a "${bastille_releasesdir}/${RELEASE}/usr/ports" "${bastille_jailsdir}/${TARGET}/root/usr" + fi mv "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/root/.bastille.old" info "Conversion of '${TARGET}' completed successfully!" diff --git a/usr/local/share/bastille/cp.sh b/usr/local/share/bastille/cp.sh index 0ed4473..2d486ec 100644 --- a/usr/local/share/bastille/cp.sh +++ b/usr/local/share/bastille/cp.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,27 +32,41 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille cp TARGET HOST_PATH CONTAINER_PATH" + error_exit "Usage: bastille cp [OPTION] TARGET HOST_PATH CONTAINER_PATH" } +CPSOURCE="${1}" +CPDEST="${2}" + # Handle special-case commands first. case "$1" in help|-h|--help) usage ;; +-q|--quiet) + OPTION="${1}" + CPSOURCE="${2}" + CPDEST="${3}" + ;; esac if [ $# -ne 2 ]; then usage fi -CPSOURCE="${1}" -CPDEST="${2}" +case "${OPTION}" in + -q|--quiet) + OPTION="-a" + ;; + *) + OPTION="-av" + ;; +esac for _jail in ${JAILS}; do info "[${_jail}]:" bastille_jail_path="${bastille_jailsdir}/${_jail}/root" - cp -av "${CPSOURCE}" "${bastille_jail_path}/${CPDEST}" + cp "${OPTION}" "${CPSOURCE}" "${bastille_jail_path}/${CPDEST}" RETURN="$?" if [ "${TARGET}" = "ALL" ]; then # Display the return status for reference diff --git a/usr/local/share/bastille/create.sh b/usr/local/share/bastille/create.sh index 1be8126..c9d9cd5 100644 --- a/usr/local/share/bastille/create.sh +++ b/usr/local/share/bastille/create.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,20 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille create [option] name release ip [interface]" + # Build an independent usage for the create command + # If no option specified, will create a thin container by default + error_notify "Usage: bastille create [option(s)] name release ip [interface]" + + cat << EOF + Options: + + -E | --empty -- Creates an empty container, intended for custom jail builds (thin/thick/linux or unsupported). + -L | --linux -- This option is intended for testing with Linux jails, this is considered experimental. + -T | --thick -- Creates a thick container, they consume more space as they are self contained and independent. + -V | --vnet -- Enables VNET, VNET containers are attached to a virtual bridge interface for connectivity. + +EOF + exit 1 } running_jail() { @@ -46,7 +59,9 @@ running_jail() { validate_name() { local NAME_VERIFY=${NAME} local NAME_SANITY=$(echo "${NAME_VERIFY}" | tr -c -d 'a-zA-Z0-9-_') - if [ "${NAME_VERIFY}" != "${NAME_SANITY}" ]; then + if [ -n "$(echo "${NAME_SANITY}" | awk "/^[-_].*$/" )" ]; then + error_exit "Container names may not begin with (-|_) characters!" + elif [ "${NAME_VERIFY}" != "${NAME_SANITY}" ]; then error_exit "Container names may not contain special characters!" fi } @@ -139,6 +154,28 @@ ${NAME} { EOF } +generate_linux_jail_conf() { + cat << EOF > "${bastille_jail_conf}" +${NAME} { + host.hostname = ${NAME}; + mount.fstab = ${bastille_jail_fstab}; + path = ${bastille_jail_path}; + devfs_ruleset = 4; + + exec.start = '/bin/true'; + exec.stop = '/bin/true'; + persist; + + allow.mount; + allow.mount.devfs; + + interface = ${bastille_jail_conf_interface}; + ${IPX_ADDR} = ${IP}; + ip6 = ${IP6_MODE}; +} +EOF +} + generate_vnet_jail_conf() { ## determine number of containers + 1 ## iterate num and grep all jail configs @@ -174,7 +211,7 @@ ${NAME} { vnet; vnet.interface = e0b_${uniq_epair}; - exec.prestart += "jib addm ${uniq_epair} ${INTERFACE}"; + exec.prestart += "jib addm ${uniq_epair} ${bastille_jail_conf_interface}"; exec.poststop += "jib destroy ${uniq_epair}"; } EOF @@ -203,8 +240,51 @@ create_jail() { mkdir -p "${bastille_jailsdir}/${NAME}/root" fi fi + ## PoC for Linux jails @hackacad + if [ -n "${LINUX_JAIL}" ]; then + if [ ! -d "${bastille_jail_base}" ]; then + mkdir -p "${bastille_jail_base}" + fi + mkdir -p "${bastille_jail_path}/dev" + mkdir -p "${bastille_jail_path}/proc" + mkdir -p "${bastille_jail_path}/sys" + mkdir -p "${bastille_jail_path}/home" + mkdir -p "${bastille_jail_path}/tmp" + touch "${bastille_jail_path}/dev/shm" + touch "${bastille_jail_path}/dev/fd" + cp -RPf ${bastille_releasesdir}/${RELEASE}/* ${bastille_jail_path}/ + echo "${NAME}" > ${bastille_jail_path}/etc/hostname - if [ -z "${EMPTY_JAIL}" ]; then + if [ ! -d "${bastille_jail_template}" ]; then + mkdir -p "${bastille_jail_template}" + fi + + if [ ! -f "${bastille_jail_fstab}" ]; then + touch "${bastille_jail_fstab}" + fi + echo -e "devfs ${bastille_jail_path}/dev devfs rw 0 0" >> "${bastille_jail_fstab}" + echo -e "tmpfs ${bastille_jail_path}/dev/shm tmpfs rw,size=1g,mode=1777 0 0" >> "${bastille_jail_fstab}" + echo -e "fdescfs ${bastille_jail_path}/dev/fd fdescfs rw,linrdlnk 0 0" >> "${bastille_jail_fstab}" + echo -e "linprocfs ${bastille_jail_path}/proc linprocfs rw 0 0" >> "${bastille_jail_fstab}" + echo -e "linsysfs ${bastille_jail_path}/sys linsysfs rw 0 0" >> "${bastille_jail_fstab}" + echo -e "/tmp ${bastille_jail_path}/tmp nullfs rw 0 0" >> "${bastille_jail_fstab}" + ## removed temporarely / only for X11 jails? @hackacad + #echo -e "/home ${bastille_jail_path}/home nullfs rw 0 0" >> "${bastille_jail_fstab}" + + if [ ! -f "${bastille_jail_conf}" ]; then + if [ -z "${bastille_network_loopback}" ] && [ -n "${bastille_network_shared}" ]; then + local bastille_jail_conf_interface=${bastille_network_shared} + fi + if [ -n "${bastille_network_loopback}" ] && [ -z "${bastille_network_shared}" ]; then + local bastille_jail_conf_interface=${bastille_network_loopback} + fi + if [ -n "${INTERFACE}" ]; then + local bastille_jail_conf_interface=${INTERFACE} + fi + fi + fi + + if [ -z "${EMPTY_JAIL}" ] && [ -z "${LINUX_JAIL}" ]; then if [ ! -d "${bastille_jail_base}" ]; then mkdir -p "${bastille_jail_base}" fi @@ -235,7 +315,7 @@ create_jail() { if [ -n "${INTERFACE}" ]; then local bastille_jail_conf_interface=${INTERFACE} fi - + ## generate the jail configuration file if [ -n "${VNET_JAIL}" ]; then generate_vnet_jail_conf @@ -248,19 +328,19 @@ create_jail() { ## MAKE SURE WE'RE IN THE RIGHT PLACE cd "${bastille_jail_path}" echo - info "NAME: ${NAME}." - info "IP: ${IP}." - if [ -n "${INTERFACE}" ]; then - info "INTERFACE: ${INTERFACE}." - fi - info "RELEASE: ${RELEASE}." - echo if [ -z "${THICK_JAIL}" ]; then LINK_LIST="bin boot lib libexec rescue sbin usr/bin usr/include usr/lib usr/lib32 usr/libdata usr/libexec usr/sbin usr/share usr/src" for _link in ${LINK_LIST}; do ln -sf /.bastille/${_link} ${_link} done + # Properly link shared ports on thin jails in read-write. + if [ -d "${bastille_releasesdir}/${RELEASE}/usr/ports" ]; then + if [ ! -d "${bastille_jail_path}/usr/ports" ]; then + mkdir ${bastille_jail_path}/usr/ports + fi + echo -e "${bastille_releasesdir}/${RELEASE}/usr/ports ${bastille_jail_path}/usr/ports nullfs rw 0 0" >> "${bastille_jail_fstab}" + fi fi if [ -z "${THICK_JAIL}" ]; then @@ -269,8 +349,7 @@ create_jail() { FILE_LIST=".cshrc .profile COPYRIGHT dev etc media mnt net proc root tmp var usr/obj usr/tests" for files in ${FILE_LIST}; do if [ -f "${bastille_releasesdir}/${RELEASE}/${files}" ] || [ -d "${bastille_releasesdir}/${RELEASE}/${files}" ]; then - cp -a "${bastille_releasesdir}/${RELEASE}/${files}" "${bastille_jail_path}/${files}" - if [ "$?" -ne 0 ]; then + if ! cp -a "${bastille_releasesdir}/${RELEASE}/${files}" "${bastille_jail_path}/${files}"; then ## notify and clean stale files/directories bastille destroy "${NAME}" error_exit "Failed to copy release files. Please retry create!" @@ -317,23 +396,25 @@ create_jail() { fi fi - ## create home directory if missing - if [ ! -d "${bastille_jail_path}/usr/home" ]; then - mkdir -p "${bastille_jail_path}/usr/home" - fi - ## link home properly - if [ ! -L "home" ]; then - ln -s usr/home home - fi + if [ -z "${LINUX_JAIL}" ]; then + ## create home directory if missing + if [ ! -d "${bastille_jail_path}/usr/home" ]; then + mkdir -p "${bastille_jail_path}/usr/home" + fi + ## link home properly + if [ ! -L "home" ]; then + ln -s usr/home home + fi - ## TZ: configurable (default: Etc/UTC) - ln -s "/usr/share/zoneinfo/${bastille_tzdata}" etc/localtime + ## TZ: configurable (default: Etc/UTC) + ln -s "/usr/share/zoneinfo/${bastille_tzdata}" etc/localtime - # Post-creation jail misc configuration - # Create a dummy fstab file - touch "etc/fstab" - # Disables adjkerntz, avoids spurious error messages - sed -i '' 's|[0-9],[0-9]\{2\}.*[0-9]-[0-9].*root.*kerntz -a|#& # Disabled by bastille|' "etc/crontab" + # Post-creation jail misc configuration + # Create a dummy fstab file + touch "etc/fstab" + # Disables adjkerntz, avoids spurious error messages + sed -i '' 's|[0-9],[0-9]\{2\}.*[0-9]-[0-9].*root.*kerntz -a|#& # Disabled by bastille|' "etc/crontab" + fi ## VNET specific if [ -n "${VNET_JAIL}" ]; then @@ -344,7 +425,10 @@ create_jail() { fi fi fi - else + elif [ -n "${LINUX_JAIL}" ]; then + ## Generate configuration for Linux jail + generate_linux_jail_conf + elif [ -n "${EMPTY_JAIL}" ]; then ## Generate minimal configuration for empty jail generate_minimal_conf fi @@ -353,41 +437,75 @@ create_jail() { chmod 0700 "${bastille_jailsdir}/${NAME}" # Jail must be started before applying the default template. -- cwells - bastille start "${NAME}" + if [ -z "${EMPTY_JAIL}" ]; then + bastille start "${NAME}" + elif [ -n "${EMPTY_JAIL}" ]; then + # Don't start empty jails unless a template defined. + if [ -n "${bastille_template_empty}" ]; then + bastille start "${NAME}" + fi + fi if [ -n "${VNET_JAIL}" ]; then - if [ -n ${bastille_template_vnet} ]; then + if [ -n "${bastille_template_vnet}" ]; then ## rename interface to generic vnet0 uniq_epair=$(grep vnet.interface "${bastille_jailsdir}/${NAME}/jail.conf" | awk '{print $3}' | sed 's/;//') _gateway='' + _gateway6='' _ifconfig=SYNCDHCP if [ "${IP}" != "0.0.0.0" ]; then # not using DHCP, so set static address. - _ifconfig="inet ${IP}" + if [ -n "${ip6}" ]; then + _ifconfig="inet6 ${IP}" + else + _ifconfig="inet ${IP}" + fi if [ -n "${bastille_network_gateway}" ]; then _gateway="${bastille_network_gateway}" + elif [ -n "${bastille_network_gateway6}" ]; then + _gateway6="${bastille_network_gateway6}" else - _gateway="$(netstat -rn | awk '/default/ {print $2}')" + if [ -z ${ip6} ]; then + _gateway="$(netstat -4rn | awk '/default/ {print $2}')" + else + _gateway="$(netstat -6rn | awk '/default/ {print $2}')" + fi fi fi - bastille template "${NAME}" ${bastille_template_vnet} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" --arg EPAIR="${uniq_epair}" --arg GATEWAY="${_gateway}" --arg IFCONFIG="${_ifconfig}" + bastille template "${NAME}" ${bastille_template_vnet} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" --arg EPAIR="${uniq_epair}" --arg GATEWAY="${_gateway}" --arg GATEWAY6="${_gateway6}" --arg IFCONFIG="${_ifconfig}" fi elif [ -n "${THICK_JAIL}" ]; then - if [ -n ${bastille_template_thick} ]; then + if [ -n "${bastille_template_thick}" ]; then bastille template "${NAME}" ${bastille_template_thick} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" fi elif [ -n "${EMPTY_JAIL}" ]; then - if [ -n ${bastille_template_empty} ]; then + if [ -n "${bastille_template_empty}" ]; then bastille template "${NAME}" ${bastille_template_empty} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" fi - else # Thin jail. - if [ -n ${bastille_template_thin} ]; then + ## Using templating function to fetch necessary packges @hackacad + elif [ -n "${LINUX_JAIL}" ]; then + info "Fetching packages..." + jexec -l "${NAME}" /bin/bash -c "DEBIAN_FRONTEND=noninteractive rm /var/cache/apt/archives/rsyslog*.deb" + jexec -l "${NAME}" /bin/bash -c "DEBIAN_FRONTEND=noninteractive dpkg --force-depends --force-confdef --force-confold -i /var/cache/apt/archives/*.deb" + jexec -l "${NAME}" /bin/bash -c "DEBIAN_FRONTEND=noninteractive dpkg --force-depends --force-confdef --force-confold -i /var/cache/apt/archives/*.deb" + jexec -l "${NAME}" /bin/bash -c "chmod 777 /tmp" + jexec -l "${NAME}" /bin/bash -c "apt update" + else + # Thin jail. + if [ -n "${bastille_template_thin}" ]; then bastille template "${NAME}" ${bastille_template_thin} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" fi fi # Apply values changed by the template. -- cwells - bastille restart "${NAME}" + if [ -z "${EMPTY_JAIL}" ] && [ -z "${LINUX_JAIL}" ]; then + bastille restart "${NAME}" + elif [ -n "${EMPTY_JAIL}" ]; then + # Don't restart empty jails unless a template defined. + if [ -n "${bastille_template_empty}" ]; then + bastille restart "${NAME}" + fi + fi } # Handle special-case commands first. @@ -406,33 +524,46 @@ fi EMPTY_JAIL="" THICK_JAIL="" VNET_JAIL="" +LINUX_JAIL="" -## handle combined options then shift -if [ "${1}" = "-T" -o "${1}" = "--thick" -o "${1}" = "thick" ] && \ - [ "${2}" = "-V" -o "${2}" = "--vnet" -o "${2}" = "vnet" ]; then - THICK_JAIL="1" - VNET_JAIL="1" - shift 2 -else - ## handle single options +# Handle and parse options +while [ $# -gt 0 ]; do case "${1}" in -E|--empty|empty) - shift EMPTY_JAIL="1" + shift + ;; + -L|--linux|linux) + LINUX_JAIL="1" + shift ;; -T|--thick|thick) - shift THICK_JAIL="1" + shift ;; -V|--vnet|vnet) - shift VNET_JAIL="1" + shift ;; - -*) + -*|--*) error_notify "Unknown Option." usage ;; + *) + break + ;; esac +done + +## validate for combined options +if [ -n "${EMPTY_JAIL}" ]; then + if [ -n "${THICK_JAIL}" ] || [ -n "${VNET_JAIL}" ] || [ -n "${LINUX_JAIL}" ]; then + error_exit "Error: Empty jail option can't be used with other options." + fi +elif [ -n "${LINUX_JAIL}" ]; then + if [ -n "${EMPTY_JAIL}" ] || [ -n "${VNET_JAIL}" ] || [ -n "${THICK_JAIL}" ]; then + error_exit "Error: Linux jail option can't be used with other options." + fi fi NAME="$1" @@ -455,17 +586,47 @@ if [ -n "${NAME}" ]; then validate_name fi +if [ -n "${LINUX_JAIL}" ]; then + case "${RELEASE}" in + bionic|ubuntu_bionic|ubuntu|ubuntu-bionic) + ## check for FreeBSD releases name + NAME_VERIFY=ubuntu_bionic + ;; + focal|ubuntu_focal|ubuntu-focal) + ## check for FreeBSD releases name + NAME_VERIFY=ubuntu_focal + ;; + debian_stretch|stretch|debian-stretch) + ## check for FreeBSD releases name + NAME_VERIFY=stretch + ;; + debian_buster|buster|debian-buster) + ## check for FreeBSD releases name + NAME_VERIFY=buster + ;; + *) + error_notify "Unknown Linux." + usage + ;; + esac +fi + if [ -z "${EMPTY_JAIL}" ]; then ## verify release case "${RELEASE}" in + 2.[0-9]*) + ## check for MidnightBSD releases name + NAME_VERIFY=$(echo "${RELEASE}") + validate_release + ;; *-CURRENT|*-CURRENT-I386|*-CURRENT-i386|*-current) ## check for FreeBSD releases name NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]{2,2})\.[0-9](-CURRENT|-CURRENT-i386)$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') validate_release ;; - *-RELEASE|*-RELEASE-I386|*-RELEASE-i386|*-release|*-RC1|*-rc1|*-RC2|*-rc2) + *-RELEASE|*-RELEASE-I386|*-RELEASE-i386|*-release|*-RC1|*-rc1|*-RC2|*-rc2|*-BETA1|*-BETA2|*-BETA3|*-BETA4|*-BETA5) ## check for FreeBSD releases name - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]{2,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-2])$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') + NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]{2,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-2]|-BETA[1-5])$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') validate_release ;; *-stable-LAST|*-STABLE-last|*-stable-last|*-STABLE-LAST) @@ -493,6 +654,22 @@ if [ -z "${EMPTY_JAIL}" ]; then NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '(current-build-latest)' | sed 's/CURRENT/current/g' | sed 's/build/BUILD/g' | sed 's/latest/LATEST/g') validate_release ;; + ubuntu_bionic|bionic|ubuntu-bionic) + NAME_VERIFY=Ubuntu_1804 + validate_release + ;; + ubuntu_focal|focal|ubuntu-focal) + NAME_VERIFY=Ubuntu_2004 + validate_release + ;; + debian_stretch|stretch|debian-stretch) + NAME_VERIFY=Debian9 + validate_release + ;; + debian_buster|buster|debian-buster) + NAME_VERIFY=Debian10 + validate_release + ;; *) error_notify "Unknown Release." usage @@ -520,6 +697,15 @@ if [ -z "${EMPTY_JAIL}" ]; then if [ -n "${INTERFACE}" ]; then validate_netif validate_netconf + elif [ -n "${VNET_JAIL}" ]; then + if [ -z "${INTERFACE}" ]; then + if [ -z "${bastille_network_shared}" ]; then + # User must specify interface on vnet jails. + error_exit "Error: Network interface not defined." + else + validate_netconf + fi + fi else validate_netconf fi @@ -545,6 +731,9 @@ fi if [ -z ${bastille_template_empty+x} ]; then bastille_template_empty='default/empty' fi +if [ -z ${bastille_template_linux+x} ]; then + bastille_template_linux='default/linux' +fi if [ -z ${bastille_template_thick+x} ]; then bastille_template_thick='default/thick' fi diff --git a/usr/local/share/bastille/destroy.sh b/usr/local/share/bastille/destroy.sh index a4bb3c5..8d068e6 100644 --- a/usr/local/share/bastille/destroy.sh +++ b/usr/local/share/bastille/destroy.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille destroy [option] | [container|release]" + error_exit "Usage: bastille destroy [force] | [container|release]" } destroy_jail() { @@ -76,6 +76,12 @@ destroy_jail() { rm -rf "${bastille_jail_base}" fi + # Remove target from bastille_list if exist + # Mute sysrc output here as it may be undesirable on large startup list + if [ -n "$(sysrc -qn bastille_list | tr -s " " "\n" | awk "/^${TARGET}$/")" ]; then + sysrc bastille_list-="${TARGET}" > /dev/null + fi + ## archive jail log if [ -f "${bastille_jail_log}" ]; then mv "${bastille_jail_log}" "${bastille_jail_log}"-"$(date +%F)" @@ -194,9 +200,9 @@ case "${TARGET}" in NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})\.[0-9](-CURRENT|-CURRENT-i386)$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') destroy_rel ;; -*-RELEASE|*-RELEASE-I386|*-RELEASE-i386|*-release|*-RC1|*-rc1|*-RC2|*-rc2) +*-RELEASE|*-RELEASE-I386|*-RELEASE-i386|*-release|*-RC1|*-rc1|*-RC2|*-rc2|*-RC3|*-rc3|*-RC4|*-rc4|*-RC5|*-rc5|*-BETA1|*-BETA2|*-BETA3|*-BETA4|*-BETA5) ## check for FreeBSD releases name - NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-2])$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-5]|-BETA[1-5])$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') destroy_rel ;; *-stable-LAST|*-STABLE-last|*-stable-last|*-STABLE-LAST) diff --git a/usr/local/share/bastille/edit.sh b/usr/local/share/bastille/edit.sh index c7f2517..7283025 100644 --- a/usr/local/share/bastille/edit.sh +++ b/usr/local/share/bastille/edit.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index 398c163..f9d6672 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,27 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille export TARGET [option] | PATH" + # Build an independent usage for the export command + # Valid compress/options for ZFS systems are raw, .gz, .tgz, .txz and .xz + # Valid compress/options for non ZFS configured systems are .tgz and .txz + # If no compression option specified, user must redirect standard output + error_notify "Usage: bastille export | option(s) | TARGET | PATH" + + cat << EOF + Options: + + --gz -- Export a ZFS jail using GZIP(.gz) compressed image. + -r | --raw -- Export a ZFS jail to an uncompressed RAW image. + -s | --safe -- Safely stop and start a ZFS jail before the exporting process. + --tgz -- Export a jail using simple .tgz compressed archive instead. + --txz -- Export a jail using simple .txz compressed archive instead. + -v | --verbose -- Be more verbose during the ZFS send operation. + --xz -- Export a ZFS jail using XZ(.xz) compressed image. + +Tip: If no option specified, container should be exported to standard output. + +EOF + exit 1 } # Handle special-case commands first @@ -47,74 +67,258 @@ if [ "${TARGET}" = "ALL" ]; then error_exit "Batch export is unsupported." fi -if [ $# -gt 2 ] || [ $# -lt 0 ]; then +if [ $# -gt 5 ] || [ $# -lt 1 ]; then usage fi -OPTION="${1}" -EXPATH="${2}" +zfs_enable_check() { + # Temporarily disable ZFS so we can create a standard backup archive + if [ "${bastille_zfs_enable}" = "YES" ]; then + bastille_zfs_enable="NO" + fi +} -# Handle some options -if [ -n "${OPTION}" ]; then - if [ "${OPTION}" = "-t" -o "${OPTION}" = "--txz" ]; then - if [ "${bastille_zfs_enable}" = "YES" ]; then - # Temporarily disable ZFS so we can create a standard backup archive - bastille_zfs_enable="NO" - fi - elif echo "${OPTION}" | grep -q "\/"; then - if [ -d "${OPTION}" ]; then - EXPATH="${OPTION}" - else - error_exit "Error: Path not found." - fi - else - error_notify "Invalid option!" - usage +TARGET="${1}" +GZIP_EXPORT= +SAFE_EXPORT= +USER_EXPORT= +RAW_EXPORT= +DIR_EXPORT= +TXZ_EXPORT= +TGZ_EXPORT= +OPT_ZSEND="-R" +COMP_OPTION="0" + +opt_count() { + COMP_OPTION=$(expr ${COMP_OPTION} + 1) +} + +# Handle and parse option args +while [ $# -gt 0 ]; do + case "${1}" in + --gz) + GZIP_EXPORT="1" + TARGET="${2}" + opt_count + shift + ;; + --xz) + XZ_EXPORT="1" + TARGET="${2}" + opt_count + shift + ;; + --tgz) + TGZ_EXPORT="1" + TARGET="${2}" + opt_count + zfs_enable_check + shift + ;; + --txz) + TXZ_EXPORT="1" + TARGET="${2}" + opt_count + zfs_enable_check + shift + ;; + -s|--safe) + SAFE_EXPORT="1" + TARGET="${2}" + shift + ;; + -r|--raw) + RAW_EXPORT="1" + TARGET="${2}" + opt_count + shift + ;; + -v|--verbose) + OPT_ZSEND="-Rv" + TARGET="${2}" + shift + ;; + -*|--*) + error_notify "Unknown Option." + usage + ;; + *) + if echo "${1}" | grep -q "\/"; then + DIR_EXPORT="${1}" + else + if [ $# -gt 2 ] || [ $# -lt 1 ]; then + usage + fi + fi + shift + ;; + esac +done + +# Validate for combined options +if [ "${COMP_OPTION}" -gt "1" ]; then + error_exit "Error: Only one compression format can be used during export." +fi + +if [ -n "${TXZ_EXPORT}" -o -n "${TGZ_EXPORT}" ] && [ -n "${SAFE_EXPORT}" ]; then + error_exit "Error: Simple archive modes with safe ZFS export can't be used together." +fi + +if [ -z "${bastille_zfs_enable}" ]; then + if [ -n "${GZIP_EXPORT}" -o -n "${RAW_EXPORT}" -o -n "${SAFE_EXPORT}" -o "${OPT_ZSEND}" = "-Rv" ]; then + error_exit "Options --gz, --raw, --safe, --verbose are valid for ZFS configured systems only." + fi +fi + +if [ -n "${SAFE_EXPORT}" ]; then + # Check if container is running, otherwise just ignore + if [ -z "$(jls name | awk "/^${TARGET}$/")" ]; then + SAFE_EXPORT= fi fi # Export directory check -if [ -n "${EXPATH}" ]; then - if [ -d "${EXPATH}" ]; then +if [ -n "${DIR_EXPORT}" ]; then + if [ -d "${DIR_EXPORT}" ]; then # Set the user defined export directory - bastille_backupsdir="${EXPATH}" + bastille_backupsdir="${DIR_EXPORT}" else error_exit "Error: Path not found." fi fi -jail_export() -{ +# Fallback to default if missing config parameters +if [ -z "${bastille_compress_xz_options}" ]; then + bastille_compress_xz_options="-0 -v" +fi +if [ -z "${bastille_compress_gz_options}" ]; then + bastille_compress_gz_options="-1 -v" +fi + +create_zfs_snap() { + # Take a recursive temporary snapshot + if [ -z "${USER_EXPORT}" ]; then + info "Creating temporary ZFS snapshot for export..." + fi + zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" +} + +clean_zfs_snap() { + # Cleanup the recursive temporary snapshot + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" + zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" +} + +export_check() { + # Inform the user about the exporting method + if [ -z "${USER_EXPORT}" ]; then + if [ -n "$(jls name | awk "/^${TARGET}$/")" ]; then + if [ -n "${SAFE_EXPORT}" ]; then + EXPORT_AS="Safely exporting" + else + EXPORT_AS="Hot exporting" + fi + else + EXPORT_AS="Exporting" + fi + + if [ "${FILE_EXT}" = ".xz" -o "${FILE_EXT}" = ".gz" -o "${FILE_EXT}" = "" ]; then + EXPORT_TYPE="image" + else + EXPORT_TYPE="archive" + fi + + if [ -n "${RAW_EXPORT}" ]; then + EXPORT_INFO="to a raw ${EXPORT_TYPE}" + else + EXPORT_INFO="to a compressed ${FILE_EXT} ${EXPORT_TYPE}" + fi + + info "${EXPORT_AS} '${TARGET}' ${EXPORT_INFO}..." + fi + + # Safely stop and snapshot the jail + if [ -n "${SAFE_EXPORT}" ]; then + bastille stop ${TARGET} + create_zfs_snap + bastille start ${TARGET} + else + create_zfs_snap + fi + + if [ "${bastille_zfs_enable}" = "YES" ]; then + if [ -z "${USER_EXPORT}" ]; then + info "Sending ZFS data stream..." + fi + fi +} + +jail_export() { # Attempt to export the container DATE=$(date +%F-%H%M%S) if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then - FILE_EXT="xz" - info "Exporting '${TARGET}' to a compressed .${FILE_EXT} archive." - info "Sending ZFS data stream..." - # Take a recursive temporary snapshot - zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + if [ -n "${RAW_EXPORT}" ]; then + FILE_EXT="" + export_check - # Export the container recursively and cleanup temporary snapshots - zfs send -R "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ - xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}/root@bastille_export_${DATE}" - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + # Export the raw container recursively and cleanup temporary snapshots + zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" \ + > "${bastille_backupsdir}/${TARGET}_${DATE}" + clean_zfs_snap + elif [ -n "${GZIP_EXPORT}" ]; then + FILE_EXT=".gz" + export_check + + # Export the raw container recursively and cleanup temporary snapshots + zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ + gzip ${bastille_compress_gz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" + clean_zfs_snap + elif [ -n "${XZ_EXPORT}" ]; then + FILE_EXT=".xz" + export_check + + # Export the container recursively and cleanup temporary snapshots + zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" | \ + xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" + clean_zfs_snap + else + FILE_EXT="" + USER_EXPORT="1" + export_check + + # Quietly export the container recursively, user must redirect standard output + zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" + clean_zfs_snap + fi fi else - # Create standard backup archive - FILE_EXT="txz" - info "Exporting '${TARGET}' to a compressed .${FILE_EXT} archive..." - cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}" + if [ -n "${TGZ_EXPORT}" ]; then + FILE_EXT=".tgz" + + # Create standard tgz backup archive + info "Exporting '${TARGET}' to a compressed ${FILE_EXT} archive..." + cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | gzip ${bastille_compress_gz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" + elif [ -n "${TXZ_EXPORT}" ]; then + FILE_EXT=".txz" + + # Create standard txz backup archive + info "Exporting '${TARGET}' to a compressed ${FILE_EXT} archive..." + cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}" + else + error_exit "Error: export option required" + fi fi if [ "$?" -ne 0 ]; then error_exit "Failed to export '${TARGET}' container." else - # Generate container checksum file - cd "${bastille_backupsdir}" - sha256 -q "${TARGET}_${DATE}.${FILE_EXT}" > "${TARGET}_${DATE}.sha256" - info "Exported '${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}' successfully." + if [ -z "${USER_EXPORT}" ]; then + # Generate container checksum file + cd "${bastille_backupsdir}" + sha256 -q "${TARGET}_${DATE}${FILE_EXT}" > "${TARGET}_${DATE}.sha256" + info "Exported '${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}' successfully." + fi exit 0 fi } @@ -124,12 +328,17 @@ if [ ! -d "${bastille_backupsdir}" ]; then error_exit "Backups directory/dataset does not exist. See 'bastille bootstrap'." fi -# Check if is a ZFS system -if [ "${bastille_zfs_enable}" != "YES" ]; then - # Check if container is running and ask for stop in UFS systems - if [ -n "$(jls name | awk "/^${TARGET}$/")" ]; then - error_exit "${TARGET} is running. See 'bastille stop'." +if [ -n "${TARGET}" ]; then + if [ ! -d "${bastille_jailsdir}/${TARGET}" ]; then + error_exit "[${TARGET}]: Not found." fi -fi -jail_export + # Check if is a ZFS system + if [ "${bastille_zfs_enable}" != "YES" ]; then + # Check if container is running and ask for stop in non ZFS systems + if [ -n "$(jls name | awk "/^${TARGET}$/")" ]; then + error_exit "${TARGET} is running. See 'bastille stop'." + fi + fi + jail_export +fi diff --git a/usr/local/share/bastille/htop.sh b/usr/local/share/bastille/htop.sh index df792ee..8104521 100644 --- a/usr/local/share/bastille/htop.sh +++ b/usr/local/share/bastille/htop.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index 75d5026..22eddc4 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,20 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille import file [option]" + # Build an independent usage for the import command + # If no file/extension specified, will import from standard input + error_notify "Usage: bastille import [option(s)] FILE" + + cat << EOF + Options: + + -f | --force -- Force an archive import regardless if the checksum file does not match or missing. + -v | --verbose -- Be more verbose during the ZFS receive operation. + +Tip: If no option specified, container should be imported from standard input. + +EOF + exit 1 } # Handle special-case commands first @@ -42,39 +55,70 @@ help|-h|--help) ;; esac -if [ $# -gt 2 ] || [ $# -lt 1 ]; then +if [ $# -gt 3 ] || [ $# -lt 1 ]; then usage fi TARGET="${1}" -OPTION="${2}" -shift +OPT_FORCE= +USER_IMPORT= +OPT_ZRECV="-u" + +# Handle and parse option args +while [ $# -gt 0 ]; do + case "${1}" in + -f|--force) + OPT_FORCE="1" + TARGET="${2}" + shift + ;; + -v|--verbose) + OPT_ZRECV="-u -v" + TARGET="${2}" + shift + ;; + -*|--*) + error_notify "Unknown Option." + usage + ;; + *) + if [ $# -gt 1 ] || [ $# -lt 1 ]; then + usage + fi + shift + ;; + esac +done + +# Fallback to default if missing config parameters +if [ -z "${bastille_decompress_xz_options}" ]; then + bastille_decompress_xz_options="-c -d -v" +fi +if [ -z "${bastille_decompress_gz_options}" ]; then + bastille_decompress_gz_options="-k -d -c -v" +fi validate_archive() { # Compare checksums on the target archive - # Skip validation for unsupported archives - if [ "${FILE_EXT}" != ".tar.gz" ] && [ "${FILE_EXT}" != ".tar" ]; then - if [ -f "${bastille_backupsdir}/${TARGET}" ]; then - if [ -f "${bastille_backupsdir}/${FILE_TRIM}.sha256" ]; then - info "Validating file: ${TARGET}..." - SHA256_DIST=$(cat "${bastille_backupsdir}/${FILE_TRIM}.sha256") - SHA256_FILE=$(sha256 -q "${bastille_backupsdir}/${TARGET}") - if [ "${SHA256_FILE}" != "${SHA256_DIST}" ]; then - error_exit "Failed validation for ${TARGET}." - else - info "File validation successful!" - fi + # Skip validation for unsupported archive + if [ -f "${bastille_backupsdir}/${TARGET}" ]; then + if [ -f "${bastille_backupsdir}/${FILE_TRIM}.sha256" ]; then + info "Validating file: ${TARGET}..." + SHA256_DIST=$(cat "${bastille_backupsdir}/${FILE_TRIM}.sha256") + SHA256_FILE=$(sha256 -q "${bastille_backupsdir}/${TARGET}") + if [ "${SHA256_FILE}" != "${SHA256_DIST}" ]; then + error_exit "Failed validation for ${TARGET}." else - # Check if user opt to force import - if [ "${OPTION}" = "-f" -o "${OPTION}" = "force" ]; then - warn "Warning: Skipping archive validation!" - else - error_exit "Checksum file not found. See 'bastille import TARGET -f'." - fi + info "File validation successful!" + fi + else + # Check if user opt to force import + if [ -n "${OPT_FORCE}" ]; then + warn "Warning: Skipping archive validation!" + else + error_exit "Checksum file not found. See 'bastille import [option(s)] FILE'." fi fi - else - warn "Warning: Skipping archive validation!" fi } @@ -313,23 +357,34 @@ remove_zfs_datasets() { jail_import() { # Attempt to import container from file - FILE_TRIM=$(echo "${TARGET}" | sed 's/\.xz//g;s/\.txz//g;s/\.zip//g;s/\.tar\.gz//g;s/\.tar//g') + FILE_TRIM=$(echo "${TARGET}" | sed 's/\.xz//g;s/\.gz//g;s/\.tgz//g;s/\.txz//g;s/\.zip//g;s/\.tar\.gz//g;s/\.tar//g') FILE_EXT=$(echo "${TARGET}" | sed "s/${FILE_TRIM}//g") - validate_archive if [ -d "${bastille_jailsdir}" ]; then if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then if [ "${FILE_EXT}" = ".xz" ]; then + validate_archive # Import from compressed xz on ZFS systems - info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} archive." + info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} image." info "Receiving ZFS data stream..." xz ${bastille_decompress_xz_options} "${bastille_backupsdir}/${TARGET}" | \ - zfs receive -u "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" + + # Update ZFS mountpoint property if required + update_zfsmount + elif [ "${FILE_EXT}" = ".gz" ]; then + validate_archive + # Import from compressed xz on ZFS systems + info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} image." + info "Receiving ZFS data stream..." + gzip ${bastille_decompress_gz_options} "${bastille_backupsdir}/${TARGET}" | \ + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" # Update ZFS mountpoint property if required update_zfsmount elif [ "${FILE_EXT}" = ".txz" ]; then + validate_archive # Prepare the ZFS environment and restore from existing .txz file create_zfs_datasets @@ -340,7 +395,20 @@ jail_import() { if [ "$?" -ne 0 ]; then remove_zfs_datasets fi + elif [ "${FILE_EXT}" = ".tgz" ]; then + validate_archive + # Prepare the ZFS environment and restore from existing .tgz file + create_zfs_datasets + + # Extract required files to the new datasets + info "Extracting files from '${TARGET}' archive..." + tar --exclude='root' -xf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}" + tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components 2 -C "${bastille_jailsdir}/${TARGET_TRIM}/root" "${TARGET_TRIM}/root" + if [ "$?" -ne 0 ]; then + remove_zfs_datasets + fi elif [ "${FILE_EXT}" = ".zip" ]; then + validate_archive # Attempt to import a foreign/iocage container info "Importing '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive." # Sane bastille ZFS options @@ -353,9 +421,9 @@ jail_import() { rm -f "${FILE_TRIM}" "${FILE_TRIM}_root" fi info "Receiving ZFS data stream..." - zfs receive -u "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${FILE_TRIM}" + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${FILE_TRIM}" zfs set ${ZFS_OPTIONS} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" - zfs receive -u "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" < "${FILE_TRIM}_root" + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" < "${FILE_TRIM}_root" # Update ZFS mountpoint property if required update_zfsmount @@ -403,6 +471,27 @@ jail_import() { else update_config fi + elif [ -z "${FILE_EXT}" ]; then + if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$'; then + validate_archive + # Based on the file name, looks like we are importing a raw bastille image + # Import from uncompressed image file + info "Importing '${TARGET_TRIM}' from uncompressed image archive." + info "Receiving ZFS data stream..." + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${bastille_backupsdir}/${TARGET}" + + # Update ZFS mountpoint property if required + update_zfsmount + else + # Based on the file name, looks like we are importing from previous redirected bastille image + # Quietly import from previous redirected bastille image + if ! zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}"; then + exit 1 + else + # Update ZFS mountpoint property if required + update_zfsmount + fi + fi else error_exit "Unknown archive format." fi @@ -412,6 +501,9 @@ jail_import() { if [ "${FILE_EXT}" = ".txz" ]; then info "Extracting files from '${TARGET}' archive..." tar -Jxf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" + elif [ "${FILE_EXT}" = ".tgz" ]; then + info "Extracting files from '${TARGET}' archive..." + tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" elif [ "${FILE_EXT}" = ".tar.gz" ]; then # Attempt to import/configure foreign/ezjail container info "Extracting files from '${TARGET}' archive..." @@ -442,7 +534,9 @@ jail_import() { # This is required on foreign imports only update_jailconf update_fstab - info "Container '${TARGET_TRIM}' imported successfully." + if [ -z "${USER_IMPORT}" ]; then + info "Container '${TARGET_TRIM}' imported successfully." + fi exit 0 fi else @@ -465,22 +559,32 @@ fi # Check if archive exist then trim archive name if [ -f "${bastille_backupsdir}/${TARGET}" ]; then # Filter unsupported/unknown archives - if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.xz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.txz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}.zip$\|-[0-9]\{12\}.[0-9]\{2\}.tar.gz$\|@[0-9]\{12\}.[0-9]\{2\}.tar$'; then + if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.xz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.gz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.tgz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.txz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}.zip$\|-[0-9]\{12\}.[0-9]\{2\}.tar.gz$\|@[0-9]\{12\}.[0-9]\{2\}.tar$'; then if ls "${bastille_backupsdir}" | awk "/^${TARGET}$/" >/dev/null; then - TARGET_TRIM=$(echo "${TARGET}" | sed "s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.xz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.txz//;s/_[0-9]*-[0-9]*-[0-9]*.zip//;s/-[0-9]\{12\}.[0-9]\{2\}.tar.gz//;s/@[0-9]\{12\}.[0-9]\{2\}.tar//") + TARGET_TRIM=$(echo "${TARGET}" | sed "s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.xz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.gz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.tgz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.txz//;s/_[0-9]*-[0-9]*-[0-9]*.zip//;s/-[0-9]\{12\}.[0-9]\{2\}.tar.gz//;s/@[0-9]\{12\}.[0-9]\{2\}.tar//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*//") fi else error_exit "Unrecognized archive name." fi else - error_exit "Archive '${TARGET}' not found." + if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.*$'; then + error_exit "Archive '${TARGET}' not found." + else + # Assume user will import from standard input + TARGET_TRIM=${TARGET} + USER_IMPORT="1" + fi fi # Check if a running jail matches name or already exist if [ -n "$(jls name | awk "/^${TARGET_TRIM}$/")" ]; then error_exit "A running jail matches name." -elif [ -d "${bastille_jailsdir}/${TARGET_TRIM}" ]; then - error_exit "Container: ${TARGET_TRIM} already exists." +elif [ -n "${TARGET_TRIM}" ]; then + if [ -d "${bastille_jailsdir}/${TARGET_TRIM}" ]; then + error_exit "Container: ${TARGET_TRIM} already exists." + fi fi -jail_import +if [ -n "${TARGET}" ]; then + jail_import +fi diff --git a/usr/local/share/bastille/limits.sh b/usr/local/share/bastille/limits.sh index 56a659b..455b3fa 100644 --- a/usr/local/share/bastille/limits.sh +++ b/usr/local/share/bastille/limits.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # Ressource limits added by Sven R github.com/hackacad # diff --git a/usr/local/share/bastille/list.sh b/usr/local/share/bastille/list.sh index 5301f34..611fdf3 100644 --- a/usr/local/share/bastille/list.sh +++ b/usr/local/share/bastille/list.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille list [-j] [release|template|(jail|container)|log|limit|(import|export|backup)]" + error_exit "Usage: bastille list [-j|-a] [release|template|(jail|container)|log|limit|(import|export|backup)]" } if [ $# -eq 0 ]; then @@ -50,6 +50,84 @@ if [ $# -gt 0 ]; then help|-h|--help) usage ;; + all|-a|--all) + if [ -d "${bastille_jailsdir}" ]; then + DEFAULT_VALUE="-" + SPACER=2 + MAX_LENGTH_JAIL_NAME=$(find "${bastille_jailsdir}" -maxdepth 2 -type f -name jail.conf | sed "s/^.*\/\(.*\)\/jail.conf$/\1/" | awk '{ print length($0) }' | sort -nr | head -n 1) + MAX_LENGTH_JAIL_NAME=${MAX_LENGTH_JAIL_NAME:-3} + if [ ${MAX_LENGTH_JAIL_NAME} -lt 3 ]; then MAX_LENGTH_JAIL_NAME=3; fi + MAX_LENGTH_JAIL_IP=$(find "${bastille_jailsdir}" -maxdepth 2 -type f -name jail.conf -exec sed -n "s/^[ ]*ip[4,6].addr[ ]*=[ ]*\(.*\);$/\1/p" {} \; | sed 's/\// /g' | awk '{ print length($1) }' | sort -nr | head -n 1) + MAX_LENGTH_JAIL_IP=${MAX_LENGTH_JAIL_IP:-10} + MAX_LENGTH_JAIL_VNET_IP=$(find "${bastille_jailsdir}" -maxdepth 2 -type f -name jail.conf -exec grep -l "vnet;" {} + | sed 's/\(.*\)jail.conf$/grep "ifconfig_vnet0=" \1root\/etc\/rc.conf/' | sh | sed -n 's/^ifconfig_vnet0="\(.*\)"$/\1/p' | sed 's/\// /g' | awk '{ if ($1 ~ /^[inet|inet6]/) print length($2); else print 15 }' | sort -nr | head -n 1) + MAX_LENGTH_JAIL_VNET_IP=${MAX_LENGTH_JAIL_VNET_IP:-10} + if [ ${MAX_LENGTH_JAIL_VNET_IP} -gt ${MAX_LENGTH_JAIL_IP} ]; then MAX_LENGTH_JAIL_IP=${MAX_LENGTH_JAIL_VNET_IP}; fi + if [ ${MAX_LENGTH_JAIL_IP} -lt 10 ]; then MAX_LENGTH_JAIL_IP=10; fi + MAX_LENGTH_JAIL_HOSTNAME=$(find "${bastille_jailsdir}" -maxdepth 2 -type f -name jail.conf -exec sed -n "s/^[ ]*host.hostname[ ]*=[ ]*\(.*\);$/\1/p" {} \; | awk '{ print length($0) }' | sort -nr | head -n 1) + MAX_LENGTH_JAIL_HOSTNAME=${MAX_LENGTH_JAIL_HOSTNAME:-8} + if [ ${MAX_LENGTH_JAIL_HOSTNAME} -lt 8 ]; then MAX_LENGTH_JAIL_HOSTNAME=8; fi + MAX_LENGTH_JAIL_PORTS=$(find "${bastille_jailsdir}" -maxdepth 2 -type f -name rdr.conf -exec awk '{ lines++; chars += length($0)} END { chars += lines - 1; print chars }' {} \; | sort -nr | head -n 1) + MAX_LENGTH_JAIL_PORTS=${MAX_LENGTH_JAIL_PORTS:-15} + if [ ${MAX_LENGTH_JAIL_PORTS} -lt 15 ]; then MAX_LENGTH_JAIL_PORTS=15; fi + if [ ${MAX_LENGTH_JAIL_PORTS} -gt 30 ]; then MAX_LENGTH_JAIL_PORTS=30; fi + MAX_LENGTH_JAIL_RELEASE=$(find "${bastille_jailsdir}" -maxdepth 2 -type f -name fstab 2> /dev/null -exec grep "/releases/.*/root/.bastille nullfs" {} \; | sed -n "s/^\(.*\) \/.*$/grep \"\^USERLAND_VERSION=\" \1\/bin\/freebsd-version 2\> \/dev\/null/p" | awk '!_[$0]++' | sh | sed -n "s/^USERLAND_VERSION=\"\(.*\)\"$/\1/p" | awk '{ print length($0) }' | sort -nr | head -n 1) + MAX_LENGTH_JAIL_RELEASE=${MAX_LENGTH_JAIL_RELEASE:-7} + MAX_LENGTH_THICK_JAIL_RELEASE=$(find ""${bastille_jailsdir}/*/root/bin"" -maxdepth 1 -type f -name freebsd-version 2> /dev/null -exec grep "^USERLAND_VERSION=" {} \; | sed -n "s/^USERLAND_VERSION=\"\(.*\)\"$/\1/p" | awk '{ print length($0) }' | sort -nr | head -n 1) + MAX_LENGTH_THICK_JAIL_RELEASE=${MAX_LENGTH_THICK_JAIL_RELEASE:-7} + if [ ${MAX_LENGTH_THICK_JAIL_RELEASE} -gt ${MAX_LENGTH_JAIL_RELEASE} ]; then MAX_LENGTH_JAIL_RELEASE=${MAX_LENGTH_THICK_JAIL_RELEASE}; fi + if [ ${MAX_LENGTH_JAIL_RELEASE} -lt 7 ]; then MAX_LENGTH_JAIL_RELEASE=7; fi + printf " JID%*sState%*sIP Address%*sPublished Ports%*sHostname%*sRelease%*sPath\n" "$((${MAX_LENGTH_JAIL_NAME} + ${SPACER} - 3))" "" "$((${SPACER}))" "" "$((${MAX_LENGTH_JAIL_IP} + ${SPACER} - 10))" "" "$((${MAX_LENGTH_JAIL_PORTS} + ${SPACER} - 15))" "" "$((${MAX_LENGTH_JAIL_HOSTNAME} + ${SPACER} - 8))" "" "$((${MAX_LENGTH_JAIL_RELEASE} + ${SPACER} - 7))" "" + JAIL_LIST=$(ls "${bastille_jailsdir}" | sed "s/\n//g") + for _JAIL in ${JAIL_LIST}; do + if [ -f "${bastille_jailsdir}/${_JAIL}/jail.conf" ]; then + if [ "$(jls name | awk "/^${_JAIL}$/")" ]; then + JAIL_STATE="Up" + if [ "$(awk '$1 == "vnet;" { print $1 }' "${bastille_jailsdir}/${_JAIL}/jail.conf")" ]; then + JAIL_IP=$(jexec -l ${_JAIL} ifconfig -n vnet0 inet 2> /dev/null | sed -n "/.inet /{s///;s/ .*//;p;}") + if [ ! ${JAIL_IP} ]; then JAIL_IP=$(jexec -l ${_JAIL} ifconfig -n vnet0 inet6 2> /dev/null | awk '/inet6 / && (!/fe80::/ || !/%vnet0/)' | sed -n "/.inet6 /{s///;s/ .*//;p;}"); fi + else + JAIL_IP=$(jls -j ${_JAIL} ip4.addr 2> /dev/null) + if [ ${JAIL_IP} = "-" ]; then JAIL_IP=$(jls -j ${_JAIL} ip6.addr 2> /dev/null); fi + fi + JAIL_HOSTNAME=$(jls -j ${_JAIL} host.hostname 2> /dev/null) + JAIL_PORTS=$(pfctl -a "rdr/${_JAIL}" -Psn 2> /dev/null | awk '{ printf "%s/%s:%s"",",$7,$14,$18 }' | sed "s/,$//") + JAIL_PATH=$(jls -j ${_JAIL} path 2> /dev/null) + JAIL_RELEASE=$(jexec -l ${_JAIL} freebsd-version -u 2> /dev/null) + else + JAIL_STATE=$(if [ "$(sed -n "/^${_JAIL} {$/,/^}$/p" "${bastille_jailsdir}/${_JAIL}/jail.conf" | awk '$0 ~ /^'${_JAIL}' \{|\}/ { printf "%s",$0 }')" == "${_JAIL} {}" ]; then echo "Down"; else echo "n/a"; fi) + if [ "$(awk '$1 == "vnet;" { print $1 }' "${bastille_jailsdir}/${_JAIL}/jail.conf")" ]; then + JAIL_IP=$(sed -n 's/^ifconfig_vnet0="\(.*\)"$/\1/p' "${bastille_jailsdir}/${_JAIL}/root/etc/rc.conf" | sed "s/\// /g" | awk '{ if ($1 ~ /^[inet|inet6]/) print $2; else print $1 }') + else + JAIL_IP=$(sed -n "s/^[ ]*ip[4,6].addr[ ]*=[ ]*\(.*\);$/\1/p" "${bastille_jailsdir}/${_JAIL}/jail.conf" | sed "s/\// /g" | awk '{ print $1 }') + fi + JAIL_HOSTNAME=$(sed -n "s/^[ ]*host.hostname[ ]*=[ ]*\(.*\);$/\1/p" "${bastille_jailsdir}/${_JAIL}/jail.conf") + if [ -f "${bastille_jailsdir}/${_JAIL}/rdr.conf" ]; then JAIL_PORTS=$(awk '$1 ~ /^[tcp|udp]/ { printf "%s/%s:%s,",$1,$2,$3 }' "${bastille_jailsdir}/${_JAIL}/rdr.conf" | sed "s/,$//"); else JAIL_PORTS=""; fi + JAIL_PATH=$(sed -n "s/^[ ]*path[ ]*=[ ]*\(.*\);$/\1/p" "${bastille_jailsdir}/${_JAIL}/jail.conf") + if [ ${JAIL_PATH} ]; then + if [ -f "${JAIL_PATH}/bin/freebsd-version" ]; then + JAIL_RELEASE=$(sed -n "s/^USERLAND_VERSION=\"\(.*\)\"$/\1/p" "${JAIL_PATH}/bin/freebsd-version") + else + JAIL_RELEASE=$(grep "/releases/.*/root/.bastille nullfs" "${bastille_jailsdir}/${_JAIL}/fstab" 2> /dev/null | sed -n "s/^\(.*\) \/.*$/grep \"\^USERLAND_VERSION=\" \1\/bin\/freebsd-version 2\> \/dev\/null/p" | awk '!_[$0]++' | sh | sed -n "s/^USERLAND_VERSION=\"\(.*\)\"$/\1/p") + fi + else + JAIL_RELEASE="" + fi + fi + if [ ${#JAIL_PORTS} -gt ${MAX_LENGTH_JAIL_PORTS} ]; then JAIL_PORTS="$(echo ${JAIL_PORTS} | cut -c-$((${MAX_LENGTH_JAIL_PORTS} - 3)))..."; fi + JAIL_NAME=${JAIL_NAME:-${DEFAULT_VALUE}} + JAIL_STATE=${JAIL_STATE:-${DEFAULT_VALUE}} + JAIL_IP=${JAIL_IP:-${DEFAULT_VALUE}} + JAIL_PORTS=${JAIL_PORTS:-${DEFAULT_VALUE}} + JAIL_HOSTNAME=${JAIL_HOSTNAME:-${DEFAULT_VALUE}} + JAIL_RELEASE=${JAIL_RELEASE:-${DEFAULT_VALUE}} + JAIL_PATH=${JAIL_PATH:-${DEFAULT_VALUE}} + printf " ${_JAIL}%*s${JAIL_STATE}%*s${JAIL_IP}%*s${JAIL_PORTS}%*s${JAIL_HOSTNAME}%*s${JAIL_RELEASE}%*s${JAIL_PATH}\n" "$((${MAX_LENGTH_JAIL_NAME} - ${#_JAIL} + ${SPACER}))" "" "$((5 - ${#JAIL_STATE} + ${SPACER}))" "" "$((${MAX_LENGTH_JAIL_IP} - ${#JAIL_IP} + ${SPACER}))" "" "$((${MAX_LENGTH_JAIL_PORTS} - ${#JAIL_PORTS} + ${SPACER}))" "" "$((${MAX_LENGTH_JAIL_HOSTNAME} - ${#JAIL_HOSTNAME} + ${SPACER}))" "" "$((${MAX_LENGTH_JAIL_RELEASE} - ${#JAIL_RELEASE} + ${SPACER}))" "" + fi + done + else + error_exit "unfortunately there are no jails here (${bastille_jailsdir})" + fi + ;; release|releases) if [ -d "${bastille_releasesdir}" ]; then REL_LIST=$(ls "${bastille_releasesdir}" | sed "s/\n//g") @@ -80,7 +158,7 @@ if [ $# -gt 0 ]; then rctl -h jail: ;; import|imports|export|exports|backup|backups) - ls "${bastille_backupsdir}" | grep -Ev "*.sha256" + ls "${bastille_backupsdir}" | grep -v ".sha256$" exit 0 ;; *) diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index fc37b1e..298d42a 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -97,8 +97,8 @@ for _jail in ${JAILS}; do _fstab_entry="${_hostpath} ${_jailpath} ${_type} ${_perms} ${_checks}" ## Create mount point if it does not exist. -- cwells - if [ ! -d "${bastille_jailsdir}/${_jail}/root/${_jailpath}" ]; then - if ! mkdir -p "${bastille_jailsdir}/${_jail}/root/${_jailpath}"; then + if [ ! -d "${_jailpath}" ]; then + if ! mkdir -p "${_jailpath}"; then error_exit "Failed to create mount point inside jail." fi fi @@ -110,6 +110,7 @@ for _jail in ${JAILS}; do fi echo "Added: ${_fstab_entry}" else + warn "Mountpoint already present in ${bastille_jailsdir}/${_jail}/fstab" egrep "[[:blank:]]${_jailpath}[[:blank:]]" "${bastille_jailsdir}/${_jail}/fstab" fi mount -F "${bastille_jailsdir}/${_jail}/fstab" -a diff --git a/usr/local/share/bastille/pkg.sh b/usr/local/share/bastille/pkg.sh index 715b643..4df3efc 100644 --- a/usr/local/share/bastille/pkg.sh +++ b/usr/local/share/bastille/pkg.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -47,6 +47,10 @@ fi for _jail in ${JAILS}; do info "[${_jail}]:" - jexec -l "${_jail}" /usr/sbin/pkg "$@" + if [ -f "/usr/sbin/pkg" ]; then + jexec -l "${_jail}" /usr/sbin/pkg "$@" + else + jexec -l "${_jail}" /usr/sbin/mport "$@" + fi echo done diff --git a/usr/local/share/bastille/rdr.sh b/usr/local/share/bastille/rdr.sh index 2490eb2..a133d4a 100644 --- a/usr/local/share/bastille/rdr.sh +++ b/usr/local/share/bastille/rdr.sh @@ -1,5 +1,8 @@ #!/bin/sh # +# Copyright (c) 2018-2021, Christer Edwards +# All rights reserved. +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # @@ -29,7 +32,7 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille rdr TARGET [clear] | [list] | [tcp ] | [udp ]" + error_exit "Usage: bastille rdr TARGET [clear|list|(tcp|udp host_port jail_port)]" } # Handle special-case commands first. @@ -51,13 +54,13 @@ if [ "${TARGET}" = 'ALL' ]; then error_exit "Can only redirect to a single jail." fi -# Check jail name valid +# Check if jail name is valid JAIL_NAME=$(jls -j "${TARGET}" name 2>/dev/null) if [ -z "${JAIL_NAME}" ]; then error_exit "Jail not found: ${TARGET}" fi -# Check jail ip4 address valid +# Check if jail ip4 address (ip4.addr) is valid (non-VNET only) if [ "$(bastille config $TARGET get vnet)" != 'enabled' ]; then JAIL_IP=$(jls -j "${TARGET}" ip4.addr 2>/dev/null) if [ -z "${JAIL_IP}" -o "${JAIL_IP}" = "-" ]; then @@ -65,17 +68,31 @@ if [ "$(bastille config $TARGET get vnet)" != 'enabled' ]; then fi fi -# Check rdr-anchor is setup in pf.conf +# Check if rdr-anchor is defined in pf.conf if ! (pfctl -sn | grep rdr-anchor | grep 'rdr/\*' >/dev/null); then error_exit "rdr-anchor not found in pf.conf" fi -# Check ext_if is setup in pf.conf +# Check if ext_if is defined in pf.conf EXT_IF=$(grep '^[[:space:]]*ext_if[[:space:]]*=' /etc/pf.conf) -if [ -z "${JAIL_NAME}" ]; then +if [ -z "${EXT_IF}" ]; then error_exit "ext_if not defined in pf.conf" fi +# function: write rule to rdr.conf +persist_rdr_rule() { +if ! grep -qs "$1 $2 $3" "${bastille_jailsdir}/${JAIL_NAME}/rdr.conf"; then + echo "$1 $2 $3" >> "${bastille_jailsdir}/${JAIL_NAME}/rdr.conf" +fi +} + +# function: load rdr rule via pfctl +load_rdr_rule() { +( pfctl -a "rdr/${JAIL_NAME}" -Psn; + printf '%s\nrdr pass on $ext_if inet proto %s to port %s -> %s port %s\n' "$EXT_IF" "$1" "$2" "$JAIL_IP" "$3" ) \ + | pfctl -a "rdr/${JAIL_NAME}" -f- +} + while [ $# -gt 0 ]; do case "$1" in list) @@ -86,22 +103,12 @@ while [ $# -gt 0 ]; do pfctl -a "rdr/${JAIL_NAME}" -Fn shift ;; - tcp) + tcp|udp) if [ $# -lt 3 ]; then usage fi - ( pfctl -a "rdr/${JAIL_NAME}" -Psn; - printf '%s\nrdr pass on $ext_if inet proto tcp to port %s -> %s port %s\n' "$EXT_IF" "$2" "$JAIL_IP" "$3" ) \ - | pfctl -a "rdr/${JAIL_NAME}" -f- - shift 3 - ;; - udp) - if [ $# -lt 3 ]; then - usage - fi - ( pfctl -a "rdr/${JAIL_NAME}" -Psn; - printf '%s\nrdr pass on $ext_if inet proto udp to port %s -> %s port %s\n' "$EXT_IF" "$2" "$JAIL_IP" "$3" ) \ - | pfctl -a "rdr/${JAIL_NAME}" -f- + persist_rdr_rule $1 $2 $3 + load_rdr_rule $1 $2 $3 shift 3 ;; *) diff --git a/usr/local/share/bastille/rename.sh b/usr/local/share/bastille/rename.sh index 1fb73d2..498c487 100644 --- a/usr/local/share/bastille/rename.sh +++ b/usr/local/share/bastille/rename.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -38,7 +38,9 @@ usage() { validate_name() { local NAME_VERIFY=${NEWNAME} local NAME_SANITY=$(echo "${NAME_VERIFY}" | tr -c -d 'a-zA-Z0-9-_') - if [ "${NAME_VERIFY}" != "${NAME_SANITY}" ]; then + if [ -n "$(echo "${NAME_SANITY}" | awk "/^[-_].*$/" )" ]; then + error_exit "Container names may not begin with (-|_) characters!" + elif [ "${NAME_VERIFY}" != "${NAME_SANITY}" ]; then error_exit "Container names may not contain special characters!" fi } diff --git a/usr/local/share/bastille/restart.sh b/usr/local/share/bastille/restart.sh index 5e42df3..b2afefd 100644 --- a/usr/local/share/bastille/restart.sh +++ b/usr/local/share/bastille/restart.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr/local/share/bastille/service.sh b/usr/local/share/bastille/service.sh index 9ef37a7..b12b1b2 100644 --- a/usr/local/share/bastille/service.sh +++ b/usr/local/share/bastille/service.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -41,7 +41,7 @@ help|-h|--help) ;; esac -if [ $# -ne 2 ]; then +if [ $# -lt 1 -o $# -gt 2 ]; then usage fi diff --git a/usr/local/share/bastille/start.sh b/usr/local/share/bastille/start.sh index 66c1fe8..9f2b095 100644 --- a/usr/local/share/bastille/start.sh +++ b/usr/local/share/bastille/start.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -83,6 +83,8 @@ for _jail in ${JAILS}; do error_notify "Error: IP address (${ip}) already in use." continue fi + ## add ip4.addr to firewall table:jails + pfctl -q -t jails -T add "${ip}" fi ## start the container @@ -102,13 +104,6 @@ for _jail in ${JAILS}; do bastille rdr "${_jail}" ${_rules} done < "${bastille_jailsdir}/${_jail}/rdr.conf" fi - - ## add ip4.addr to firewall table:jails - if [ -n "${bastille_network_loopback}" ]; then - if grep -qw "interface.*=.*${bastille_network_loopback}" "${bastille_jailsdir}/${_jail}/jail.conf"; then - pfctl -q -t jails -T add "$(jls -j ${_jail} ip4.addr)" - fi - fi fi echo done diff --git a/usr/local/share/bastille/stop.sh b/usr/local/share/bastille/stop.sh index bfe6793..60a33e0 100644 --- a/usr/local/share/bastille/stop.sh +++ b/usr/local/share/bastille/stop.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -55,9 +55,12 @@ for _jail in ${JAILS}; do pfctl -q -t jails -T delete "$(jls -j ${_jail} ip4.addr)" fi fi - - if [ "$(bastille rdr ${_jail} list)" ]; then - bastille rdr ${_jail} clear + + # Check if pfctl is present + if which -s pfctl; then + if [ "$(bastille rdr ${_jail} list)" ]; then + bastille rdr ${_jail} clear + fi fi ## remove rctl limits diff --git a/usr/local/share/bastille/sysrc.sh b/usr/local/share/bastille/sysrc.sh index eb368ee..efd8376 100644 --- a/usr/local/share/bastille/sysrc.sh +++ b/usr/local/share/bastille/sysrc.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr/local/share/bastille/template.sh b/usr/local/share/bastille/template.sh index d43ba95..07cfae1 100644 --- a/usr/local/share/bastille/template.sh +++ b/usr/local/share/bastille/template.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -42,9 +42,6 @@ post_command_hook() { case $_cmd in rdr) - if ! grep -qs "${_args}" "${bastille_jailsdir}/${_jail}/rdr.conf"; then - echo "${_args}" >> "${bastille_jailsdir}/${_jail}/rdr.conf" - fi echo -e ${_args} esac } @@ -176,7 +173,7 @@ if [ "${TARGET}" = '--convert' ]; then fi case ${TEMPLATE} in - http?://github.com/*/*|http?://gitlab.com/*/*) + http?://*/*/*) TEMPLATE_DIR=$(echo "${TEMPLATE}" | awk -F / '{ print $4 "/" $5 }') if [ ! -d "${bastille_templatesdir}/${TEMPLATE_DIR}" ]; then info "Bootstrapping ${TEMPLATE}..." diff --git a/usr/local/share/bastille/templates/default/linux/Bastillefile b/usr/local/share/bastille/templates/default/linux/Bastillefile new file mode 100644 index 0000000..5fd4669 --- /dev/null +++ b/usr/local/share/bastille/templates/default/linux/Bastillefile @@ -0,0 +1,14 @@ +PRE mkdir -p home +PRE mkdir -p tmp + + +FSTAB devfs root/dev devfs rw 0 0 +FSTAB tmpfs dev/shm tmpfs rw,size=1g,mode=1777 0 0 +FSTAB fdescfs dev/fd fdescfs rw,linrdlnk 0 0 +FSTAB linprocfs proc linprocfs rw 0 0 +FSTAB linsysfs sys linsysfs rw 0 0 +FSTAB /tmp tmp nullfs rw 0 0 +FSTAB /home home nullfs rw 0 0 + +CMD mkdir etc/apt/apt.conf.d/00aptitude +CMD echo "APT::Cache-Start 251658240;" > etc/apt/apt.conf.d/00aptitude \ No newline at end of file diff --git a/usr/local/share/bastille/templates/default/vnet/Bastillefile b/usr/local/share/bastille/templates/default/vnet/Bastillefile index 92b76fc..902fe6d 100644 --- a/usr/local/share/bastille/templates/default/vnet/Bastillefile +++ b/usr/local/share/bastille/templates/default/vnet/Bastillefile @@ -5,9 +5,11 @@ INCLUDE ${BASE_TEMPLATE} --arg HOST_RESOLV_CONF="${HOST_RESOLV_CONF}" ARG EPAIR ARG GATEWAY +ARG GATEWAY6 ARG IFCONFIG="SYNCDHCP" SYSRC ifconfig_${EPAIR}_name=vnet0 SYSRC ifconfig_vnet0="${IFCONFIG}" # GATEWAY will be empty for a DHCP config. -- cwells CMD if [ -n "${GATEWAY}" ]; then /usr/sbin/sysrc defaultrouter="${GATEWAY}"; fi +CMD if [ -n "${GATEWAY6}" ]; then /usr/sbin/sysrc ipv6_defaultrouter="${GATEWAY6}"; fi diff --git a/usr/local/share/bastille/top.sh b/usr/local/share/bastille/top.sh index 05e2395..4d6e23c 100644 --- a/usr/local/share/bastille/top.sh +++ b/usr/local/share/bastille/top.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr/local/share/bastille/umount.sh b/usr/local/share/bastille/umount.sh index 518461b..91081b4 100644 --- a/usr/local/share/bastille/umount.sh +++ b/usr/local/share/bastille/umount.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/usr/local/share/bastille/update.sh b/usr/local/share/bastille/update.sh index acb958b..bd08630 100644 --- a/usr/local/share/bastille/update.sh +++ b/usr/local/share/bastille/update.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille update [release|container] | [option]" + error_exit "Usage: bastille update [release|container] | [force]" } # Handle special-case commands first. @@ -64,6 +64,11 @@ if [ "${TARGET}" = "ALL" ]; then error_exit "Batch upgrade is unsupported." fi +if [ -f "/bin/midnightbsd-version" ]; then + echo -e "${COLOR_RED}Not yet supported on MidnightBSD.${COLOR_RESET}" + exit 1 +fi + if freebsd-version | grep -qi HBSD; then error_exit "Not yet supported on HardenedBSD." fi diff --git a/usr/local/share/bastille/upgrade.sh b/usr/local/share/bastille/upgrade.sh index dbd0ee9..646266f 100644 --- a/usr/local/share/bastille/upgrade.sh +++ b/usr/local/share/bastille/upgrade.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille upgrade release newrelease | target newrelease | target install | [option]" + error_exit "Usage: bastille upgrade release newrelease | target newrelease | target install | [force]" } # Handle special-case commands first. @@ -55,6 +55,11 @@ if [ "${TARGET}" = "ALL" ]; then error_exit "Batch upgrade is unsupported." fi +if [ -f "/bin/midnightbsd-version" ]; then + echo -e "${COLOR_RED}Not yet supported on MidnightBSD.${COLOR_RESET}" + exit 1 +fi + if freebsd-version | grep -qi HBSD; then error_exit "Not yet supported on HardenedBSD." fi @@ -91,7 +96,9 @@ release_upgrade() { # Upgrade a release if [ -d "${bastille_releasesdir}/${TARGET}" ]; then release_check - freebsd-update ${OPTION} -b "${bastille_releasesdir}/${TARGET}" -r "${NEWRELEASE}" upgrade + env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" --currently-running "${TARGET}" -r "${NEWRELEASE}" upgrade + echo + echo -e "${COLOR_YELLOW}Please run 'bastille upgrade ${TARGET} install' to finish installing updates.${COLOR_RESET}" else error_exit "${TARGET} not found. See 'bastille bootstrap'." fi @@ -121,9 +128,22 @@ jail_updates_install() { fi } +release_updates_install() { + # Finish installing upgrade on a release + if [ -d "${bastille_releasesdir}/${TARGET}" ]; then + env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" install + else + error_exit "${TARGET} not found. See 'bastille bootstrap'." + fi +} + # Check what we should upgrade if echo "${TARGET}" | grep -q "[0-9]\{2\}.[0-9]-RELEASE"; then - release_upgrade + if [ "${NEWRELEASE}" = "install" ]; then + release_updates_install + else + release_upgrade + fi elif [ "${NEWRELEASE}" = "install" ]; then jail_updates_install else diff --git a/usr/local/share/bastille/verify.sh b/usr/local/share/bastille/verify.sh index 7239e25..5af8947 100644 --- a/usr/local/share/bastille/verify.sh +++ b/usr/local/share/bastille/verify.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -36,6 +36,10 @@ bastille_usage() { } verify_release() { + if [ -f "/bin/midnightbsd-version" ]; then + echo -e "${COLOR_RED}Not yet supported on MidnightBSD.${COLOR_RESET}" + exit 1 + fi if freebsd-version | grep -qi HBSD; then error_exit "Not yet supported on HardenedBSD." fi @@ -65,7 +69,7 @@ verify_template() { echo error_exit "Template validation failed." ## if INCLUDE; recursive verify - elif [ ${_hook} = 'INCLUDE' ]; then + elif [ "${_hook}" = 'INCLUDE' ]; then info "[${_hook}]:" cat "${_path}" echo @@ -73,7 +77,7 @@ verify_template() { info "[${_hook}]:[${_include}]:" case ${_include} in - http?://github.com/*/*|http?://gitlab.com/*/*) + http?://*/*/*) bastille bootstrap "${_include}" ;; */*) @@ -88,13 +92,13 @@ verify_template() { done < "${_path}" ## if tree; tree -a bastille_template/_dir - elif [ ${_hook} = 'OVERLAY' ]; then + elif [ "${_hook}" = 'OVERLAY' ]; then info "[${_hook}]:" cat "${_path}" echo while read _dir; do info "[${_hook}]:[${_dir}]:" - if [ -x /usr/local/bin/tree ]; then + if [ -x "/usr/local/bin/tree" ]; then /usr/local/bin/tree -a "${_template_path}/${_dir}" else find "${_template_path}/${_dir}" -print | sed -e 's;[^/]*/;|___;g;s;___|; |;g' @@ -110,7 +114,7 @@ verify_template() { done ## remove bad templates - if [ ${_hook_validate} -lt 1 ]; then + if [ "${_hook_validate}" -lt 1 ]; then error_notify "No valid template hooks found." error_notify "Template discarded." rm -rf "${bastille_template}" @@ -118,7 +122,7 @@ verify_template() { fi ## if validated; ready to use - if [ ${_hook_validate} -gt 0 ]; then + if [ "${_hook_validate}" -gt 0 ]; then info "Template ready to use." fi } diff --git a/usr/local/share/bastille/zfs.sh b/usr/local/share/bastille/zfs.sh index da4f065..82327a7 100644 --- a/usr/local/share/bastille/zfs.sh +++ b/usr/local/share/bastille/zfs.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2018-2020, Christer Edwards +# Copyright (c) 2018-2021, Christer Edwards # All rights reserved. # # Redistribution and use in source and binary forms, with or without