mirror of
https://github.com/docker-mailserver/docker-mailserver.git
synced 2025-07-29 15:14:32 +02:00
Merge branch 'master' into add-send-only-aliases
This commit is contained in:
commit
bed51886f4
107 changed files with 2727 additions and 3301 deletions
|
@ -11,28 +11,39 @@ source /usr/local/bin/helpers/log.sh
|
|||
# shellcheck disable=SC2310
|
||||
_log_level_is 'trace' && QUIET='-y' || QUIET='-qq'
|
||||
|
||||
function _compile_dovecot_fts_xapian() {
|
||||
function _install_build_deps() {
|
||||
apt-get "${QUIET}" update
|
||||
apt-get "${QUIET}" --no-install-recommends install \
|
||||
apt-get "${QUIET}" install --no-install-recommends \
|
||||
automake libtool pkg-config libicu-dev libsqlite3-dev libxapian-dev make build-essential dh-make devscripts dovecot-dev
|
||||
|
||||
local XAPIAN_VERSION='1.7.12'
|
||||
curl -sSfL -o dovecot-fts-xapian.tar.gz \
|
||||
"https://github.com/grosjo/fts-xapian/releases/download/${XAPIAN_VERSION}/dovecot-fts-xapian-${XAPIAN_VERSION}.tar.gz"
|
||||
tar xf dovecot-fts-xapian.tar.gz
|
||||
|
||||
cd "fts-xapian-${XAPIAN_VERSION}"
|
||||
USER=root dh_make -p "dovecot-fts-xapian-${XAPIAN_VERSION}" --single --native --copyright gpl2 -y
|
||||
|
||||
rm debian/*.ex
|
||||
cp PACKAGES/DEB/control debian/
|
||||
cp PACKAGES/DEB/changelog debian/
|
||||
cp PACKAGES/DEB/compat debian/
|
||||
|
||||
sed -i -E "s|(dovecot-fts-xapian)-[1-9\.-]+|\1-${XAPIAN_VERSION}|g" debian/control
|
||||
sed -i -E "s|(dovecot-fts-xapian)-[1-9\.-]+ \(.*\)(.*)|\1-${XAPIAN_VERSION} (${XAPIAN_VERSION})\2|g" debian/changelog
|
||||
|
||||
debuild -us -uc -B | tee /tmp/debuild.log 2>&1
|
||||
}
|
||||
|
||||
_compile_dovecot_fts_xapian
|
||||
function _build_package() {
|
||||
local XAPIAN_VERSION='1.9'
|
||||
curl -fsSL "https://github.com/grosjo/fts-xapian/releases/download/${XAPIAN_VERSION}/dovecot-fts-xapian-${XAPIAN_VERSION}.tar.gz" \
|
||||
| tar -xz
|
||||
cd "fts-xapian-${XAPIAN_VERSION}"
|
||||
|
||||
# Prepare for building DEB source package:
|
||||
# https://manpages.debian.org/bookworm/dh-make/dh_make.1.en.html
|
||||
# License LGPL 2.1: https://github.com/grosjo/fts-xapian/issues/174#issuecomment-2422404568
|
||||
USER=root dh_make --packagename "dovecot-fts-xapian-${XAPIAN_VERSION}" --single --native --copyright lgpl2 -y
|
||||
# Remove generated example files:
|
||||
rm debian/*.ex
|
||||
# Add required package metadata:
|
||||
# https://www.debian.org/doc/manuals/maint-guide/dreq.en.html#control
|
||||
curl -fsSL https://raw.githubusercontent.com/grosjo/fts-xapian/refs/tags/1.7.16/PACKAGES/DEB/control > debian/control
|
||||
# Replace version number:
|
||||
sed -i -E "s|(dovecot-fts-xapian)-[1-9\.-]+|\1-${XAPIAN_VERSION}|g" debian/control
|
||||
# Required to proceed with debuild:
|
||||
# https://www.debian.org/doc/manuals/maint-guide/dother.en.html#compat
|
||||
# (13 is the default debhelper version from the original `dh_make` generated `debian/control`):
|
||||
echo '13' > debian/compat
|
||||
|
||||
# Build arch specific binary package via debuild:
|
||||
# https://manpages.debian.org/bookworm/devscripts/debuild.1.en.html
|
||||
# https://manpages.debian.org/bookworm/dpkg-dev/dpkg-buildpackage.1.en.html
|
||||
debuild --no-sign --build=any | tee /tmp/debuild.log 2>&1
|
||||
}
|
||||
|
||||
_install_build_deps
|
||||
_build_package
|
||||
|
|
|
@ -24,30 +24,58 @@ function _pre_installation_steps() {
|
|||
apt-get "${QUIET}" upgrade
|
||||
|
||||
_log 'trace' 'Installing packages that are needed early'
|
||||
# add packages usually required by apt to
|
||||
# - not log unnecessary warnings
|
||||
# - be able to add PPAs early (e.g., Rspamd)
|
||||
# Add packages usually required by apt to:
|
||||
local EARLY_PACKAGES=(
|
||||
apt-utils # avoid useless warnings
|
||||
apt-transport-https ca-certificates curl gnupg # required for adding PPAs
|
||||
systemd-standalone-sysusers # avoid problems with SA / Amavis (https://github.com/docker-mailserver/docker-mailserver/pull/3403#pullrequestreview-1596689953)
|
||||
# Avoid logging unnecessary warnings:
|
||||
apt-utils
|
||||
# Required for adding third-party repos (/etc/apt/sources.list.d) as alternative package sources (eg: Dovecot CE and Rspamd):
|
||||
apt-transport-https ca-certificates curl gnupg
|
||||
# Avoid problems with SA / Amavis (https://github.com/docker-mailserver/docker-mailserver/pull/3403#pullrequestreview-1596689953):
|
||||
systemd-standalone-sysusers
|
||||
)
|
||||
apt-get "${QUIET}" install --no-install-recommends "${EARLY_PACKAGES[@]}" 2>/dev/null
|
||||
}
|
||||
|
||||
# Install third-party commands to /usr/local/bin
|
||||
function _install_utils() {
|
||||
local ARCH_A
|
||||
ARCH_A=$(uname --machine)
|
||||
# Alternate naming convention support: x86_64 (amd64) / aarch64 (arm64)
|
||||
# https://en.wikipedia.org/wiki/X86-64#Industry_naming_conventions
|
||||
local ARCH_B
|
||||
case "${ARCH_A}" in
|
||||
( 'x86_64' ) ARCH_B='amd64' ;;
|
||||
( 'aarch64' ) ARCH_B='arm64' ;;
|
||||
( * )
|
||||
_log 'error' "Unsupported arch: '${ARCH_A}'"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# TIP: `*.tar.gz` releases tend to forget to reset UID/GID ownership when archiving.
|
||||
# When extracting with `tar` as `root` the archived UID/GID is kept, unless using `--no-same-owner`.
|
||||
# Likewise when the binary is in a nested location the full archived path
|
||||
# must be provided + `--strip-components` to extract the file to the target directory.
|
||||
# Doing this avoids the need for (`mv` + `rm`) or (`--to-stdout` + `chmod +x`)
|
||||
_log 'debug' 'Installing utils sourced from Github'
|
||||
|
||||
_log 'trace' 'Installing jaq'
|
||||
local JAQ_TAG='v1.3.0'
|
||||
curl -sSfL "https://github.com/01mf02/jaq/releases/download/${JAQ_TAG}/jaq-${JAQ_TAG}-$(uname -m)-unknown-linux-gnu" -o /usr/bin/jaq
|
||||
chmod +x /usr/bin/jaq
|
||||
local JAQ_TAG='v2.1.0'
|
||||
curl -sSfL "https://github.com/01mf02/jaq/releases/download/${JAQ_TAG}/jaq-$(uname -m)-unknown-linux-gnu" -o /usr/local/bin/jaq
|
||||
chmod +x /usr/local/bin/jaq
|
||||
|
||||
_log 'trace' 'Installing step'
|
||||
local STEP_RELEASE='0.28.2'
|
||||
curl -sSfL "https://github.com/smallstep/cli/releases/download/v${STEP_RELEASE}/step_linux_${STEP_RELEASE}_${ARCH_B}.tar.gz" \
|
||||
| tar -xz --directory /usr/local/bin --no-same-owner --strip-components=2 "step_${STEP_RELEASE}/bin/step"
|
||||
|
||||
_log 'trace' 'Installing swaks'
|
||||
# `perl-doc` is required for `swaks --help` to work:
|
||||
apt-get "${QUIET}" install --no-install-recommends perl-doc
|
||||
local SWAKS_VERSION='20240103.0'
|
||||
local SWAKS_RELEASE="swaks-${SWAKS_VERSION}"
|
||||
curl -sSfL "https://github.com/jetmore/swaks/releases/download/v${SWAKS_VERSION}/${SWAKS_RELEASE}.tar.gz" | tar -xz
|
||||
mv "${SWAKS_RELEASE}/swaks" /usr/local/bin
|
||||
rm -r "${SWAKS_RELEASE}"
|
||||
curl -sSfL "https://github.com/jetmore/swaks/releases/download/v${SWAKS_VERSION}/${SWAKS_RELEASE}.tar.gz" \
|
||||
| tar -xz --directory /usr/local/bin --no-same-owner --strip-components=1 "${SWAKS_RELEASE}/swaks"
|
||||
}
|
||||
|
||||
function _install_postfix() {
|
||||
|
@ -73,9 +101,6 @@ function _install_packages() {
|
|||
clamav clamav-daemon
|
||||
# spamassassin is used only with amavisd-new, while pyzor + razor are used by spamassasin
|
||||
amavisd-new spamassassin pyzor razor
|
||||
# the following packages are all for Fail2Ban
|
||||
# https://github.com/docker-mailserver/docker-mailserver/pull/3403#discussion_r1306581431
|
||||
fail2ban python3-pyinotify python3-dnspython
|
||||
)
|
||||
|
||||
# predominantly for Amavis support
|
||||
|
@ -121,7 +146,7 @@ function _install_packages() {
|
|||
bind9-dnsutils iputils-ping less nano
|
||||
)
|
||||
|
||||
apt-get "${QUIET}" --no-install-recommends install \
|
||||
apt-get "${QUIET}" install --no-install-recommends \
|
||||
"${ANTI_VIRUS_SPAM_PACKAGES[@]}" \
|
||||
"${CODECS_PACKAGES[@]}" \
|
||||
"${MISCELLANEOUS_PACKAGES[@]}" \
|
||||
|
@ -138,46 +163,98 @@ function _install_dovecot() {
|
|||
dovecot-pop3d dovecot-sieve
|
||||
)
|
||||
|
||||
# Dovecot packages for community supported features.
|
||||
# Additional Dovecot packages for supporting the DMS community (docs-only guide contributions).
|
||||
DOVECOT_PACKAGES+=(dovecot-auth-lua)
|
||||
|
||||
# Dovecot's deb community repository only provides x86_64 packages, so do not include it
|
||||
# when building for another architecture.
|
||||
# (Opt-in via ENV) Change repo source for dovecot packages to a third-party repo maintained by Dovecot.
|
||||
# NOTE: AMD64 / x86_64 is the only supported arch from the Dovecot CE repo (thus noDMS built for ARM64 / aarch64)
|
||||
# Repo: https://repo.dovecot.org/ce-2.4-latest/debian/bookworm/dists/bookworm/main/
|
||||
# Docs: https://repo.dovecot.org/#debian
|
||||
if [[ ${DOVECOT_COMMUNITY_REPO} -eq 1 ]] && [[ "$(uname --machine)" == "x86_64" ]]; then
|
||||
_log 'trace' 'Using Dovecot community repository'
|
||||
curl -sSfL https://repo.dovecot.org/DOVECOT-REPO-GPG | gpg --import
|
||||
gpg --export ED409DA1 > /etc/apt/trusted.gpg.d/dovecot.gpg
|
||||
echo "deb https://repo.dovecot.org/ce-2.3-latest/debian/${VERSION_CODENAME} ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/dovecot.list
|
||||
# WARNING: Repo only provides Debian Bookworm package support for Dovecot CE 2.4+.
|
||||
# As Debian Bookworm only packages Dovecot 2.3.x, building DMS with this alternative package repo may not yet be compatible with DMS:
|
||||
# - 2.3.19: https://salsa.debian.org/debian/dovecot/-/tree/stable/bookworm
|
||||
# - 2.3.21: https://salsa.debian.org/debian/dovecot/-/tree/stable/bookworm-backports
|
||||
|
||||
_log 'trace' 'Updating Dovecot package signatures'
|
||||
_log 'trace' 'Adding third-party package repository (Dovecot)'
|
||||
curl -fsSL https://repo.dovecot.org/DOVECOT-REPO-GPG-2.4 | gpg --dearmor > /usr/share/keyrings/upstream-dovecot.gpg
|
||||
echo \
|
||||
"deb [signed-by=/usr/share/keyrings/upstream-dovecot.gpg] https://repo.dovecot.org/ce-2.4-latest/debian/${VERSION_CODENAME} ${VERSION_CODENAME} main" \
|
||||
> /etc/apt/sources.list.d/upstream-dovecot.list
|
||||
|
||||
# Refresh package index:
|
||||
apt-get "${QUIET}" update
|
||||
|
||||
# Additional community package needed for Lua support if the Dovecot community repository is used.
|
||||
# This repo instead provides `dovecot-auth-lua` as a transitional package to `dovecot-lua`,
|
||||
# thus this extra package is required to retain lua support:
|
||||
DOVECOT_PACKAGES+=(dovecot-lua)
|
||||
fi
|
||||
|
||||
_log 'debug' 'Installing Dovecot'
|
||||
apt-get "${QUIET}" --no-install-recommends install "${DOVECOT_PACKAGES[@]}"
|
||||
apt-get "${QUIET}" install --no-install-recommends "${DOVECOT_PACKAGES[@]}"
|
||||
|
||||
# dependency for fts_xapian
|
||||
apt-get "${QUIET}" --no-install-recommends install libxapian30
|
||||
# Runtime dependency for fts_xapian (built via `compile.sh`):
|
||||
apt-get "${QUIET}" install --no-install-recommends libxapian30
|
||||
}
|
||||
|
||||
function _install_rspamd() {
|
||||
_log 'debug' 'Installing Rspamd'
|
||||
_log 'trace' 'Adding Rspamd PPA'
|
||||
curl -sSfL https://rspamd.com/apt-stable/gpg.key | gpg --dearmor >/etc/apt/trusted.gpg.d/rspamd.gpg
|
||||
echo \
|
||||
"deb [signed-by=/etc/apt/trusted.gpg.d/rspamd.gpg] http://rspamd.com/apt-stable/ ${VERSION_CODENAME} main" \
|
||||
>/etc/apt/sources.list.d/rspamd.list
|
||||
# NOTE: DMS only supports the rspamd package via using the third-party repo maintained by Rspamd (AMD64 + ARM64):
|
||||
# Repo: https://rspamd.com/apt-stable/dists/bookworm/main/
|
||||
# Docs: https://rspamd.com/downloads.html#debian-and-ubuntu-linux
|
||||
# NOTE: Debian 12 provides Rspamd 3.4 (too old) and Rspamd discourages it's use
|
||||
|
||||
_log 'trace' 'Updating package index after adding PPAs'
|
||||
_log 'trace' 'Adding third-party package repository (Rspamd)'
|
||||
curl -fsSL https://rspamd.com/apt-stable/gpg.key | gpg --dearmor > /usr/share/keyrings/upstream-rspamd.gpg
|
||||
echo \
|
||||
"deb [signed-by=/usr/share/keyrings/upstream-rspamd.gpg] https://rspamd.com/apt-stable/ ${VERSION_CODENAME} main" \
|
||||
> /etc/apt/sources.list.d/upstream-rspamd.list
|
||||
|
||||
# Refresh package index:
|
||||
apt-get "${QUIET}" update
|
||||
|
||||
_log 'trace' 'Installing actual package'
|
||||
_log 'debug' 'Installing Rspamd'
|
||||
apt-get "${QUIET}" install rspamd redis-server
|
||||
}
|
||||
|
||||
function _install_fail2ban() {
|
||||
local FAIL2BAN_VERSION=1.1.0
|
||||
local FAIL2BAN_DEB_URL="https://github.com/fail2ban/fail2ban/releases/download/${FAIL2BAN_VERSION}/fail2ban_${FAIL2BAN_VERSION}-1.upstream1_all.deb"
|
||||
local FAIL2BAN_DEB_ASC_URL="${FAIL2BAN_DEB_URL}.asc"
|
||||
local FAIL2BAN_GPG_FINGERPRINT='8738 559E 26F6 71DF 9E2C 6D9E 683B F1BE BD0A 882C'
|
||||
local FAIL2BAN_GPG_PUBLIC_KEY_ID='0x683BF1BEBD0A882C'
|
||||
local FAIL2BAN_GPG_PUBLIC_KEY_SERVER='hkps://keyserver.ubuntu.com'
|
||||
|
||||
_log 'debug' 'Installing Fail2ban'
|
||||
# Dependencies (https://github.com/docker-mailserver/docker-mailserver/pull/3403#discussion_r1306581431)
|
||||
apt-get "${QUIET}" install --no-install-recommends python3-pyinotify python3-dnspython python3-systemd
|
||||
|
||||
gpg --keyserver "${FAIL2BAN_GPG_PUBLIC_KEY_SERVER}" --recv-keys "${FAIL2BAN_GPG_PUBLIC_KEY_ID}" 2>&1
|
||||
|
||||
curl -fsSLo fail2ban.deb "${FAIL2BAN_DEB_URL}"
|
||||
curl -fsSLo fail2ban.deb.asc "${FAIL2BAN_DEB_ASC_URL}"
|
||||
|
||||
FINGERPRINT=$(LANG=C gpg --verify fail2ban.deb.asc fail2ban.deb |& sed -n 's#Primary key fingerprint: \(.*\)#\1#p')
|
||||
|
||||
if [[ -z ${FINGERPRINT} ]]; then
|
||||
echo 'ERROR: Invalid GPG signature!' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ${FINGERPRINT} != "${FAIL2BAN_GPG_FINGERPRINT}" ]]; then
|
||||
echo "ERROR: Wrong GPG fingerprint!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dpkg -i fail2ban.deb 2>&1
|
||||
rm fail2ban.deb fail2ban.deb.asc
|
||||
|
||||
_log 'debug' 'Patching Fail2ban to enable network bans'
|
||||
# Enable network bans
|
||||
# https://github.com/docker-mailserver/docker-mailserver/issues/2669
|
||||
# https://github.com/fail2ban/fail2ban/issues/3125
|
||||
sedfile -i -r 's/^_nft_add_set = .+/_nft_add_set = <nftables> add set <table_family> <table> <addr_set> \\{ type <addr_type>\\; flags interval\\; \\}/' /etc/fail2ban/action.d/nftables.conf
|
||||
}
|
||||
|
||||
function _post_installation_steps() {
|
||||
_log 'debug' 'Running post-installation steps (cleanup)'
|
||||
_log 'debug' 'Deleting sensitive files (secrets)'
|
||||
|
@ -189,11 +266,6 @@ function _post_installation_steps() {
|
|||
_log 'trace' 'Removing leftovers from APT'
|
||||
apt-get "${QUIET}" clean
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
_log 'debug' 'Patching Fail2ban to enable network bans'
|
||||
# Enable network bans
|
||||
# https://github.com/docker-mailserver/docker-mailserver/issues/2669
|
||||
sedfile -i -r 's/^_nft_add_set = .+/_nft_add_set = <nftables> add set <table_family> <table> <addr_set> \\{ type <addr_type>\\; flags interval\\; \\}/' /etc/fail2ban/action.d/nftables.conf
|
||||
}
|
||||
|
||||
_pre_installation_steps
|
||||
|
@ -202,4 +274,5 @@ _install_postfix
|
|||
_install_packages
|
||||
_install_dovecot
|
||||
_install_rspamd
|
||||
_install_fail2ban
|
||||
_post_installation_steps
|
||||
|
|
|
@ -135,7 +135,8 @@ function _create_dovecot_alias_dummy_accounts() {
|
|||
fi
|
||||
|
||||
DOVECOT_USERDB_LINE="${ALIAS}:${REAL_ACC[1]}:${DMS_VMAIL_UID}:${DMS_VMAIL_GID}::/var/mail/${REAL_DOMAINNAME}/${REAL_USERNAME}/home::${REAL_ACC[2]:-}"
|
||||
if grep -qi "^${ALIAS}:" "${DOVECOT_USERDB_FILE}"; then
|
||||
# Match a full line with `-xF` to avoid regex patterns introducing false positives matching `ALIAS`:
|
||||
if grep -qixF "${DOVECOT_USERDB_LINE}" "${DOVECOT_USERDB_FILE}"; then
|
||||
_log 'warn' "Alias '${ALIAS}' will not be added to '${DOVECOT_USERDB_FILE}' twice"
|
||||
else
|
||||
echo "${DOVECOT_USERDB_LINE}" >>"${DOVECOT_USERDB_FILE}"
|
||||
|
|
|
@ -44,7 +44,7 @@ function _monitored_files_checksums() {
|
|||
|
||||
# Check whether Rspamd is used and if so, monitor it's changes as well
|
||||
if [[ ${ENABLE_RSPAMD} -eq 1 ]] && [[ -d ${RSPAMD_DMS_D} ]]; then
|
||||
readarray -d '' STAGING_FILES_RSPAMD < <(find "${RSPAMD_DMS_D}" -type f -name "*.sh" -print0)
|
||||
readarray -d '' STAGING_FILES_RSPAMD < <(find "${RSPAMD_DMS_D}" -type f -print0)
|
||||
STAGING_FILES+=("${STAGING_FILES_RSPAMD[@]}")
|
||||
fi
|
||||
fi
|
||||
|
|
|
@ -98,9 +98,14 @@ function __account_already_exists() {
|
|||
|
||||
# Also used by addsaslpassword
|
||||
function _password_request_if_missing() {
|
||||
local PASSWD_CONFIRM
|
||||
if [[ -z ${PASSWD} ]]; then
|
||||
read -r -s -p 'Enter Password: ' PASSWD
|
||||
echo
|
||||
[[ -z ${PASSWD} ]] && _exit_with_error 'Password must not be empty'
|
||||
|
||||
read -r -s -p 'Confirm Password: ' PASSWD_CONFIRM
|
||||
echo
|
||||
[[ ${PASSWD} != "${PASSWD_CONFIRM}" ]] && _exit_with_error 'Passwords do not match!'
|
||||
fi
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
function _exit_with_error() {
|
||||
if [[ -n ${1+set} ]]; then
|
||||
if [[ -n ${1:-} ]]; then
|
||||
_log 'error' "${1}"
|
||||
else
|
||||
_log 'error' "Call to '_exit_with_error' is missing a message to log"
|
||||
|
|
|
@ -43,12 +43,12 @@ RESET=$(echo -ne '\e[0m')
|
|||
# message is logged. Likewise when the second argument
|
||||
# is missing. Both failures will return with exit code '1'.
|
||||
function _log() {
|
||||
if [[ -z ${1+set} ]]; then
|
||||
if [[ -z ${1:-} ]]; then
|
||||
_log 'error' "Call to '_log' is missing a valid log level"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -z ${2+set} ]]; then
|
||||
if [[ -z ${2:-} ]]; then
|
||||
_log 'error' "Call to '_log' is missing a message to log"
|
||||
return 1
|
||||
fi
|
||||
|
@ -116,7 +116,7 @@ function _log() {
|
|||
# variables file. If this does not yield a value either,
|
||||
# use the default log level.
|
||||
function _get_log_level_or_default() {
|
||||
if [[ -n ${LOG_LEVEL+set} ]]; then
|
||||
if [[ -n ${LOG_LEVEL:-} ]]; then
|
||||
echo "${LOG_LEVEL}"
|
||||
elif [[ -e /etc/dms-settings ]] && grep -q -E "^LOG_LEVEL='[a-z]+'" /etc/dms-settings; then
|
||||
grep '^LOG_LEVEL=' /etc/dms-settings | cut -d "'" -f 2
|
||||
|
|
|
@ -111,14 +111,6 @@ function _rspamd_handle_user_modules_adjustments() {
|
|||
fi
|
||||
}
|
||||
|
||||
# We check for usage of the previous location of the commands file.
|
||||
# TODO This can be removed after the release of v14.0.0.
|
||||
local RSPAMD_DMS_CUSTOM_COMMANDS_F_OLD="${RSPAMD_DMS_D}-modules.conf"
|
||||
readonly RSPAMD_DMS_CUSTOM_COMMANDS_F_OLD
|
||||
if [[ -f ${RSPAMD_DMS_CUSTOM_COMMANDS_F_OLD} ]]; then
|
||||
_dms_panic__general "Old custom command file location '${RSPAMD_DMS_CUSTOM_COMMANDS_F_OLD}' is deprecated (use '${RSPAMD_DMS_CUSTOM_COMMANDS_F}' now)" 'Rspamd setup'
|
||||
fi
|
||||
|
||||
if [[ -f "${RSPAMD_DMS_CUSTOM_COMMANDS_F}" ]]; then
|
||||
__rspamd__log 'debug' "Found file '${RSPAMD_DMS_CUSTOM_COMMANDS_F}' - parsing and applying it"
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ function _reload_postfix() {
|
|||
# you can set the environment variable `POSTFIX_README_DIRECTORY='/new/dir/'`
|
||||
# (`POSTFIX_` is an arbitrary prefix, you can choose the one you like),
|
||||
# and then call this function:
|
||||
# `_replace_by_env_in_file 'POSTFIX_' 'PATH TO POSTFIX's main.cf>`
|
||||
# `_replace_by_env_in_file 'POSTFIX_' '<PATH TO POSTFIX's main.cf>`
|
||||
#
|
||||
# ## Panics
|
||||
#
|
||||
|
@ -131,9 +131,9 @@ function _reload_postfix() {
|
|||
# 1. No first and second argument is supplied
|
||||
# 2. The second argument is a path to a file that does not exist
|
||||
function _replace_by_env_in_file() {
|
||||
if [[ -z ${1+set} ]]; then
|
||||
if [[ -z ${1:-} ]]; then
|
||||
_dms_panic__invalid_value 'first argument unset' 'utils.sh:_replace_by_env_in_file'
|
||||
elif [[ -z ${2+set} ]]; then
|
||||
elif [[ -z ${2:-} ]]; then
|
||||
_dms_panic__invalid_value 'second argument unset' 'utils.sh:_replace_by_env_in_file'
|
||||
elif [[ ! -f ${2} ]]; then
|
||||
_dms_panic__invalid_value "file '${2}' does not exist" 'utils.sh:_replace_by_env_in_file'
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
# When 'pipefail' is enabled, the exit status of the pipeline reflects the exit status of the last command that fails.
|
||||
# Without 'pipefail', the exit status of a pipeline is determined by the exit status of the last command in the pipeline.
|
||||
set -o pipefail
|
||||
shopt -s globstar inherit_errexit
|
||||
|
||||
# Allows the usage of '**' in patterns, e.g. ls **/*
|
||||
shopt -s globstar
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# ? >> Sourcing helpers & stacks
|
||||
|
@ -34,13 +38,11 @@ function _register_functions() {
|
|||
# ? >> Checks
|
||||
|
||||
_register_check_function '_check_hostname'
|
||||
_register_check_function '_check_log_level'
|
||||
_register_check_function '_check_spam_prefix'
|
||||
|
||||
# ? >> Setup
|
||||
|
||||
_register_setup_function '_setup_vmail_id'
|
||||
_register_setup_function '_setup_logs_general'
|
||||
_register_setup_function '_setup_timezone'
|
||||
|
||||
if [[ ${SMTP_ONLY} -ne 1 ]]; then
|
||||
|
@ -59,7 +61,6 @@ function _register_functions() {
|
|||
;;
|
||||
|
||||
( 'LDAP' )
|
||||
_environment_variables_ldap
|
||||
_register_setup_function '_setup_ldap'
|
||||
;;
|
||||
|
||||
|
@ -72,15 +73,8 @@ function _register_functions() {
|
|||
;;
|
||||
esac
|
||||
|
||||
if [[ ${ENABLE_OAUTH2} -eq 1 ]]; then
|
||||
_environment_variables_oauth2
|
||||
_register_setup_function '_setup_oauth2'
|
||||
fi
|
||||
|
||||
if [[ ${ENABLE_SASLAUTHD} -eq 1 ]]; then
|
||||
_environment_variables_saslauthd
|
||||
_register_setup_function '_setup_saslauthd'
|
||||
fi
|
||||
[[ ${ENABLE_OAUTH2} -eq 1 ]] && _register_setup_function '_setup_oauth2'
|
||||
[[ ${ENABLE_SASLAUTHD} -eq 1 ]] && _register_setup_function '_setup_saslauthd'
|
||||
|
||||
_register_setup_function '_setup_dovecot_inet_protocols'
|
||||
|
||||
|
@ -94,7 +88,6 @@ function _register_functions() {
|
|||
_register_setup_function '_setup_ssl'
|
||||
_register_setup_function '_setup_docker_permit'
|
||||
_register_setup_function '_setup_mailname'
|
||||
_register_setup_function '_setup_dovecot_hostname'
|
||||
|
||||
_register_setup_function '_setup_postfix_early'
|
||||
|
||||
|
@ -118,20 +111,23 @@ function _register_functions() {
|
|||
_register_setup_function '_setup_logwatch'
|
||||
|
||||
_register_setup_function '_setup_save_states'
|
||||
_register_setup_function '_setup_apply_fixes_after_configuration'
|
||||
_register_setup_function '_environment_variables_export'
|
||||
_register_setup_function '_setup_adjust_state_permissions'
|
||||
|
||||
if [[ ${ENABLE_MTA_STS} -eq 1 ]]; then
|
||||
_register_setup_function '_setup_mta_sts'
|
||||
_register_start_daemon '_start_daemon_mta_sts_daemon'
|
||||
fi
|
||||
|
||||
# ! The following functions must be executed after all other setup functions
|
||||
_register_setup_function '_setup_directory_and_file_permissions'
|
||||
_register_setup_function '_setup_run_user_patches'
|
||||
|
||||
# ? >> Daemons
|
||||
|
||||
_register_start_daemon '_start_daemon_cron'
|
||||
_register_start_daemon '_start_daemon_rsyslog'
|
||||
|
||||
[[ ${SMTP_ONLY} -ne 1 ]] && _register_start_daemon '_start_daemon_dovecot'
|
||||
[[ ${SMTP_ONLY} -ne 1 ]] && _register_start_daemon '_start_daemon_dovecot'
|
||||
|
||||
if [[ ${ENABLE_UPDATE_CHECK} -eq 1 ]]; then
|
||||
if [[ ${DMS_RELEASE} != 'edge' ]]; then
|
||||
|
@ -161,6 +157,7 @@ function _register_functions() {
|
|||
[[ ${ENABLE_CLAMAV} -eq 1 ]] && _register_start_daemon '_start_daemon_clamav'
|
||||
[[ ${ENABLE_AMAVIS} -eq 1 ]] && _register_start_daemon '_start_daemon_amavis'
|
||||
[[ ${ACCOUNT_PROVISIONER} == 'FILE' ]] && _register_start_daemon '_start_daemon_changedetector'
|
||||
[[ ${ENABLE_GETMAIL} -eq 1 ]] && _register_start_daemon '_start_daemon_getmail'
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
|
@ -169,35 +166,42 @@ function _register_functions() {
|
|||
# ? >> Executing all stacks / actual start of DMS
|
||||
# ------------------------------------------------------------
|
||||
|
||||
_early_supervisor_setup
|
||||
_early_variables_setup
|
||||
|
||||
_log 'info' "Welcome to docker-mailserver ${DMS_RELEASE}"
|
||||
|
||||
_register_functions
|
||||
_check
|
||||
|
||||
# Ensure DMS only adjusts config files for a new container.
|
||||
# Container restarts should skip as they retain the modified config.
|
||||
if [[ ! -f /CONTAINER_START ]]; then
|
||||
_early_supervisor_setup
|
||||
_early_variables_setup
|
||||
if [[ -f /CONTAINER_START ]]; then
|
||||
_log 'info' 'Container was restarted. Skipping most setup routines.'
|
||||
# We cannot skip all setup routines because some need to run _after_
|
||||
# the initial setup (and hence, they cannot be moved to the check stack).
|
||||
_setup_directory_and_file_permissions
|
||||
|
||||
_log 'info' "Welcome to docker-mailserver ${DMS_RELEASE}"
|
||||
|
||||
_register_functions
|
||||
_check
|
||||
_setup
|
||||
_run_user_patches
|
||||
# shellcheck source=./startup/setup.d/mail_state.sh
|
||||
source /usr/local/bin/setup.d/mail_state.sh
|
||||
_setup_adjust_state_permissions
|
||||
else
|
||||
# container was restarted
|
||||
_early_variables_setup
|
||||
|
||||
_log 'info' 'Container was restarted. Skipping setup routines.'
|
||||
_log 'info' "Welcome to docker-mailserver ${DMS_RELEASE}"
|
||||
|
||||
_register_functions
|
||||
_setup
|
||||
fi
|
||||
|
||||
# marker to check if container was restarted
|
||||
date >/CONTAINER_START
|
||||
|
||||
# Container logs will receive updates from this log file:
|
||||
MAIN_LOGFILE=/var/log/mail/mail.log
|
||||
# NOTE: rsyslogd would usually create this later during `_start_daemons`, however it would already exist if the container was restarted.
|
||||
touch "${MAIN_LOGFILE}"
|
||||
# Ensure `tail` follows the correct position of the log file for this container start (new logs begin once `_start_daemons` is called)
|
||||
TAIL_START=$(( $(wc -l < "${MAIN_LOGFILE}") + 1 ))
|
||||
|
||||
[[ ${LOG_LEVEL} =~ (debug|trace) ]] && print-environment
|
||||
_start_daemons
|
||||
|
||||
# Container start-up scripts completed. `tail` will now pipe the log updates to stdout:
|
||||
_log 'info' "${HOSTNAME} is up and running"
|
||||
|
||||
touch /var/log/mail/mail.log
|
||||
exec tail -Fn 0 /var/log/mail/mail.log
|
||||
exec tail -Fn "+${TAIL_START}" "${MAIN_LOGFILE}"
|
||||
|
|
|
@ -26,24 +26,6 @@ function _check_hostname() {
|
|||
fi
|
||||
}
|
||||
|
||||
function _check_log_level() {
|
||||
if [[ ${LOG_LEVEL} == 'trace' ]] \
|
||||
|| [[ ${LOG_LEVEL} == 'debug' ]] \
|
||||
|| [[ ${LOG_LEVEL} == 'info' ]] \
|
||||
|| [[ ${LOG_LEVEL} == 'warn' ]] \
|
||||
|| [[ ${LOG_LEVEL} == 'error' ]]
|
||||
then
|
||||
return 0
|
||||
else
|
||||
local DEFAULT_LOG_LEVEL='info'
|
||||
_log 'warn' "Log level '${LOG_LEVEL}' is invalid (falling back to default '${DEFAULT_LOG_LEVEL}')"
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
VARS[LOG_LEVEL]="${DEFAULT_LOG_LEVEL}"
|
||||
LOG_LEVEL="${DEFAULT_LOG_LEVEL}"
|
||||
fi
|
||||
}
|
||||
|
||||
function _check_spam_prefix() {
|
||||
# This check should be independent of ENABLE_POP3 and ENABLE_IMAP
|
||||
if [[ ${MOVE_SPAM_TO_JUNK} -eq 0 ]] \
|
||||
|
|
|
@ -34,6 +34,7 @@ function _start_daemon_clamav { _default_start_daemon 'clamav' ;
|
|||
function _start_daemon_cron { _default_start_daemon 'cron' ; }
|
||||
function _start_daemon_dovecot { _default_start_daemon 'dovecot' ; }
|
||||
function _start_daemon_fail2ban { _default_start_daemon 'fail2ban' ; }
|
||||
function _start_daemon_getmail { _default_start_daemon 'getmail' ; }
|
||||
function _start_daemon_opendkim { _default_start_daemon 'opendkim' ; }
|
||||
function _start_daemon_opendmarc { _default_start_daemon 'opendmarc' ; }
|
||||
function _start_daemon_postgrey { _default_start_daemon 'postgrey' ; }
|
||||
|
|
|
@ -82,7 +82,9 @@ function _setup_timezone() {
|
|||
fi
|
||||
}
|
||||
|
||||
function _setup_apply_fixes_after_configuration() {
|
||||
# Misc checks and fixes migrated here until next refactor:
|
||||
# NOTE: `start-mailserver.sh` runs this along with `mail-state.sh` during container restarts
|
||||
function _setup_directory_and_file_permissions() {
|
||||
_log 'trace' 'Removing leftover PID files from a stop/start'
|
||||
find /var/run/ -not -name 'supervisord.pid' -name '*.pid' -delete
|
||||
touch /dev/shm/supervisor.sock
|
||||
|
@ -101,9 +103,11 @@ function _setup_apply_fixes_after_configuration() {
|
|||
_log 'debug' "Ensuring '${RSPAMD_DMS_DKIM_D}' is owned by '_rspamd:_rspamd'"
|
||||
chown -R _rspamd:_rspamd "${RSPAMD_DMS_DKIM_D}"
|
||||
fi
|
||||
|
||||
__log_fixes
|
||||
}
|
||||
|
||||
function _run_user_patches() {
|
||||
function _setup_run_user_patches() {
|
||||
local USER_PATCHES='/tmp/docker-mailserver/user-patches.sh'
|
||||
|
||||
if [[ -f ${USER_PATCHES} ]]; then
|
||||
|
@ -113,3 +117,32 @@ function _run_user_patches() {
|
|||
_log 'trace' "No optional '${USER_PATCHES}' provided"
|
||||
fi
|
||||
}
|
||||
|
||||
function __log_fixes() {
|
||||
_log 'debug' 'Ensuring /var/log/mail owneership + permissions are correct'
|
||||
|
||||
# File/folder permissions are fine when using docker volumes, but may be wrong
|
||||
# when file system folders are mounted into the container.
|
||||
# Set the expected values and create missing folders/files just in case.
|
||||
mkdir -p /var/log/{mail,supervisor}
|
||||
|
||||
# TODO: Remove these lines in a future release once concerns are resolved:
|
||||
# https://github.com/docker-mailserver/docker-mailserver/pull/4370#issuecomment-2661762043
|
||||
chown syslog:root /var/log/mail
|
||||
|
||||
if [[ ${ENABLE_CLAMAV} -eq 1 ]]; then
|
||||
# TODO: Consider assigning /var/log/mail a writable non-root group for other processes like ClamAV?
|
||||
# - Check if ClamAV is capable of creating files itself when they're missing?
|
||||
# - Alternatively a symlink to /var/log/mail from the original intended location would allow write access
|
||||
# as a user to the symlink location, while keeping ownership as root at /var/log/mail
|
||||
# - `LogSyslog false` for clamd.conf + freshclam.conf could possibly be enabled instead of log files?
|
||||
# However without better filtering in place (once Vector is adopted), this should be avoided.
|
||||
touch /var/log/mail/{clamav,freshclam}.log
|
||||
chown clamav:adm /var/log/mail/{clamav,freshclam}.log
|
||||
fi
|
||||
|
||||
# Volume permissions should be corrected:
|
||||
# https://github.com/docker-mailserver/docker-mailserver-helm/issues/137
|
||||
chmod 755 /var/log/mail/
|
||||
find /var/log/mail/ -type f -exec chmod 640 {} +
|
||||
}
|
||||
|
|
|
@ -23,7 +23,11 @@ function _setup_opendkim() {
|
|||
# check if any keys are available
|
||||
if [[ -e /tmp/docker-mailserver/opendkim/KeyTable ]]; then
|
||||
cp -a /tmp/docker-mailserver/opendkim/* /etc/opendkim/
|
||||
_log 'trace' "DKIM keys added for: $(find /etc/opendkim/keys/ -maxdepth 1 -type f -printf '%f ')"
|
||||
|
||||
local DKIM_DOMAINS
|
||||
DKIM_DOMAINS=$(find /etc/opendkim/keys/ -maxdepth 1 -type f -printf '%f ')
|
||||
_log 'trace' "DKIM keys added for: ${DKIM_DOMAINS}"
|
||||
|
||||
chown -R opendkim:opendkim /etc/opendkim/
|
||||
chmod -R 0700 /etc/opendkim/keys/
|
||||
else
|
||||
|
|
|
@ -3,13 +3,54 @@
|
|||
function _setup_dovecot() {
|
||||
_log 'debug' 'Setting up Dovecot'
|
||||
|
||||
# Protocol support
|
||||
sedfile -i -e 's|include_try /usr/share/dovecot/protocols.d|include_try /etc/dovecot/protocols.d|g' /etc/dovecot/dovecot.conf
|
||||
cp -a /usr/share/dovecot/protocols.d /etc/dovecot/
|
||||
# disable pop3 (it will be eventually enabled later in the script, if requested)
|
||||
# Disable these protocols by default, they can be enabled later via ENV (ENABLE_POP3, ENABLE_IMAP, ENABLE_MANAGESIEVE)
|
||||
mv /etc/dovecot/protocols.d/pop3d.protocol /etc/dovecot/protocols.d/pop3d.protocol.disab
|
||||
# disable imap (it will be eventually enabled later in the script, if requested)
|
||||
mv /etc/dovecot/protocols.d/imapd.protocol /etc/dovecot/protocols.d/imapd.protocol.disab
|
||||
mv /etc/dovecot/protocols.d/managesieved.protocol /etc/dovecot/protocols.d/managesieved.protocol.disab
|
||||
sedfile -i 's|^postmaster_address = .*$|postmaster_address = '"${POSTMASTER_ADDRESS}"'|g' /etc/dovecot/conf.d/15-lda.conf
|
||||
|
||||
# NOTE: While Postfix will deliver to Dovecot via LMTP (Previously LDA until DMS v2),
|
||||
# LDA may be used via other services like Getmail being configured to use /usr/lib/dovecot/deliver
|
||||
# when mail does not need to go through Postfix.
|
||||
# `mail_plugins` is scoped to the `protocol lda` config block of this file.
|
||||
#
|
||||
# TODO: `postmaster_address` + `hostname` appear to be for the general Dovecot config rather than LDA specific?
|
||||
# https://doc.dovecot.org/2.3/settings/core/#core_setting-postmaster_address
|
||||
# https://doc.dovecot.org/2.3/settings/core/#core_setting-hostname
|
||||
# Dovecot 3.0 docs:
|
||||
# https://doc.dovecot.org/main/core/summaries/settings.html#postmaster_address
|
||||
# https://doc.dovecot.org/main/core/summaries/settings.html#postmaster_address
|
||||
# https://doc.dovecot.org/main/core/config/delivery/lmtp.html#common-delivery-settings
|
||||
# https://doc.dovecot.org/main/core/config/delivery/lda.html#common-delivery-settings
|
||||
# https://doc.dovecot.org/main/core/config/sieve/submission.html#postmaster-address
|
||||
# Shows config example with postmaster_address scoped in a `protocol lda { }` block:
|
||||
# https://doc.dovecot.org/main/howto/virtual/simple_install.html#delivering-mails
|
||||
#
|
||||
# DMS initially copied Dovecot example configs, these were removed from Dovecot 2.4 onwards:
|
||||
# https://github.com/dovecot/core/commit/5941699b277d762d98c202928cf5b5c8c70bc359
|
||||
# In favor of a minimal config example:
|
||||
# https://github.com/dovecot/core/commit/9a6a6aef35bb403fa96f0b5efdb0faff85b1471d
|
||||
# 2.3 series example config:
|
||||
# https://github.com/dovecot/core/blob/2.3.21.1/doc/example-config/conf.d/15-lda.conf
|
||||
# Initial config files committed to DMS in April 2016:
|
||||
# TODO: Consider housekeeping on config to only represent relevant changes/support by scripts
|
||||
# https://github.com/docker-mailserver/docker-mailserver/commit/ee0d0853dd672488238eecb0ec2d26719ff45d7d
|
||||
#
|
||||
# TODO: `mail_plugins` appending `sieve` should probably be done for both `15-lda.conf` and `20-lmtp.conf`
|
||||
# Presently DMS replaces the `20-lmtp.conf` from `dovecot-lmtpd` package with our own modified copy from 2016.
|
||||
# The DMS variant only makes this one change to that file, thus we could adjust it as we do below for `15-lda.conf`
|
||||
# Reference: https://github.com/docker-mailserver/docker-mailserver/pull/4350#issuecomment-2646736328
|
||||
|
||||
# shellcheck disable=SC2016
|
||||
sedfile -i -r \
|
||||
-e 's|^(\s*)#?(mail_plugins =).*|\1\2 $mail_plugins sieve|' \
|
||||
-e 's|^#?(lda_mailbox_autocreate =).*|\1 yes|' \
|
||||
-e 's|^#?(lda_mailbox_autosubscribe =).*|\1 yes|' \
|
||||
-e "s|^#?(postmaster_address =).*|\1 ${POSTMASTER_ADDRESS}|" \
|
||||
-e "s|^#?(hostname =).*|\1 ${HOSTNAME}|" \
|
||||
/etc/dovecot/conf.d/15-lda.conf
|
||||
|
||||
if ! grep -q -E '^stats_writer_socket_path=' /etc/dovecot/dovecot.conf; then
|
||||
printf '\n%s\n' 'stats_writer_socket_path=' >>/etc/dovecot/dovecot.conf
|
||||
|
@ -24,6 +65,7 @@ function _setup_dovecot() {
|
|||
sedfile -i -E \
|
||||
"s|^(mail_location =).*|\1 ${DOVECOT_MAILBOX_FORMAT}:/var/mail/%d/%n|" \
|
||||
/etc/dovecot/conf.d/10-mail.conf
|
||||
|
||||
_log 'trace' 'Enabling cron job for dbox purge'
|
||||
mv /etc/cron.d/dovecot-purge.disabled /etc/cron.d/dovecot-purge
|
||||
chmod 644 /etc/cron.d/dovecot-purge
|
||||
|
@ -55,6 +97,12 @@ function _setup_dovecot() {
|
|||
[[ -f /tmp/docker-mailserver/dovecot.cf ]] && cp /tmp/docker-mailserver/dovecot.cf /etc/dovecot/local.conf
|
||||
}
|
||||
|
||||
# The `sieve` plugin is always enabled in DMS, this method handles user supplied sieve scripts + ManageSieve protocol
|
||||
# NOTE: There is a related post-setup step for this sieve support handled at `_setup_post()` (setup-stack.sh)
|
||||
# TODO: Improved sieve support may be needed in DMS to support this use-case:
|
||||
# https://github.com/docker-mailserver/docker-mailserver/issues/3904
|
||||
# TODO: Change detection support + refactor/DRY this sieve logic:
|
||||
# https://github.com/orgs/docker-mailserver/discussions/2633#discussioncomment-11622955
|
||||
function _setup_dovecot_sieve() {
|
||||
mkdir -p /usr/lib/dovecot/sieve-{filter,global,pipe}
|
||||
mkdir -p /usr/lib/dovecot/sieve-global/{before,after}
|
||||
|
@ -192,8 +240,3 @@ function _setup_dovecot_inet_protocols() {
|
|||
function _setup_dovecot_dhparam() {
|
||||
_setup_dhparam 'Dovecot' '/etc/dovecot/dh.pem'
|
||||
}
|
||||
|
||||
function _setup_dovecot_hostname() {
|
||||
_log 'debug' 'Applying hostname to Dovecot'
|
||||
sedfile -i "s|^#hostname =.*$|hostname = '${HOSTNAME}'|g" /etc/dovecot/conf.d/15-lda.conf
|
||||
}
|
||||
|
|
|
@ -4,38 +4,46 @@ function _setup_getmail() {
|
|||
if [[ ${ENABLE_GETMAIL} -eq 1 ]]; then
|
||||
_log 'trace' 'Preparing Getmail configuration'
|
||||
|
||||
local GETMAILRC ID CONFIGS
|
||||
local GETMAIL_RC ID GETMAIL_DIR
|
||||
|
||||
GETMAILRC='/etc/getmailrc.d'
|
||||
CONFIGS=0
|
||||
local GETMAIL_CONFIG_DIR='/tmp/docker-mailserver/getmail'
|
||||
local GETMAIL_RC_DIR='/etc/getmailrc.d'
|
||||
local GETMAIL_RC_GENERAL_CF="${GETMAIL_CONFIG_DIR}/getmailrc_general.cf"
|
||||
local GETMAIL_RC_GENERAL='/etc/getmailrc_general'
|
||||
|
||||
mkdir -p "${GETMAILRC}"
|
||||
# Create the directory /etc/getmailrc.d to place the user config in later.
|
||||
mkdir -p "${GETMAIL_RC_DIR}"
|
||||
|
||||
# Generate getmailrc configs, starting with the `/etc/getmailrc_general` base config,
|
||||
# Add a unique `message_log` config, then append users own config to the end.
|
||||
for FILE in /tmp/docker-mailserver/getmail-*.cf; do
|
||||
if [[ -f ${FILE} ]]; then
|
||||
CONFIGS=1
|
||||
ID=$(cut -d '-' -f 3 <<< "${FILE}" | cut -d '.' -f 1)
|
||||
local GETMAIL_CONFIG="${GETMAILRC}/getmailrc-${ID}"
|
||||
|
||||
cat /etc/getmailrc_general >"${GETMAIL_CONFIG}"
|
||||
echo -e "message_log = /var/log/mail/getmail-${ID}.log\n" >>"${GETMAIL_CONFIG}"
|
||||
cat "${FILE}" >>"${GETMAIL_CONFIG}"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${CONFIGS} -eq 1 ]]; then
|
||||
cat >/etc/cron.d/getmail << EOF
|
||||
*/${GETMAIL_POLL} * * * * root /usr/local/bin/getmail-cron
|
||||
EOF
|
||||
chmod -R 600 "${GETMAILRC}"
|
||||
# Check if custom getmailrc_general.cf file is present.
|
||||
if [[ -f "${GETMAIL_RC_GENERAL_CF}" ]]; then
|
||||
_log 'debug' "Custom 'getmailrc_general.cf' found"
|
||||
cp "${GETMAIL_RC_GENERAL_CF}" "${GETMAIL_RC_GENERAL}"
|
||||
fi
|
||||
|
||||
# Both the debug command and cron job (that runs getmail) for getmail
|
||||
# expect this location to exist.
|
||||
GETMAILDIR=/tmp/docker-mailserver/getmail
|
||||
mkdir -p "${GETMAILDIR}"
|
||||
# If no matching filenames are found, and the shell option nullglob is disabled, the word is left unchanged.
|
||||
# If the nullglob option is set, and no matches are found, the word is removed.
|
||||
shopt -s nullglob
|
||||
|
||||
# Generate getmailrc configs, starting with the `/etc/getmailrc_general` base config, then appending users own config to the end.
|
||||
for FILE in "${GETMAIL_CONFIG_DIR}"/*.cf; do
|
||||
if [[ ${FILE} =~ /getmail/(.+)\.cf ]] && [[ ${FILE} != "${GETMAIL_RC_GENERAL_CF}" ]]; then
|
||||
ID=${BASH_REMATCH[1]}
|
||||
|
||||
_log 'debug' "Processing getmail config '${ID}'"
|
||||
|
||||
GETMAIL_RC=${GETMAIL_RC_DIR}/${ID}
|
||||
cat "${GETMAIL_RC_GENERAL}" "${FILE}" >"${GETMAIL_RC}"
|
||||
fi
|
||||
done
|
||||
# Strip read access from non-root due to files containing secrets:
|
||||
chmod -R 600 "${GETMAIL_RC_DIR}"
|
||||
|
||||
# Directory, where "oldmail" files are stored.
|
||||
# For more information see: https://getmail6.org/faq.html#faq-about-oldmail
|
||||
# The debug command for getmail expects this location to exist.
|
||||
GETMAIL_DIR=/var/lib/getmail
|
||||
_log 'debug' "Creating getmail state-dir '${GETMAIL_DIR}'"
|
||||
mkdir -p "${GETMAIL_DIR}"
|
||||
else
|
||||
_log 'debug' 'Getmail is disabled'
|
||||
fi
|
||||
|
|
|
@ -1,15 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
function _setup_logs_general() {
|
||||
_log 'debug' 'Setting up general log files'
|
||||
|
||||
# File/folder permissions are fine when using docker volumes, but may be wrong
|
||||
# when file system folders are mounted into the container.
|
||||
# Set the expected values and create missing folders/files just in case.
|
||||
mkdir -p /var/log/{mail,supervisor}
|
||||
chown syslog:root /var/log/mail
|
||||
}
|
||||
|
||||
function _setup_logrotate() {
|
||||
_log 'debug' 'Setting up logrotate'
|
||||
|
||||
|
|
|
@ -1,124 +1,138 @@
|
|||
#!/bin/bash
|
||||
|
||||
DMS_STATE_DIR='/var/mail-state'
|
||||
|
||||
# Consolidate all states into a single directory
|
||||
# (/var/mail-state) to allow persistence using docker volumes
|
||||
function _setup_save_states() {
|
||||
local DEST DESTDIR STATEDIR SERVICEDIR SERVICEDIRS SERVICEFILE SERVICEFILES
|
||||
|
||||
STATEDIR='/var/mail-state'
|
||||
|
||||
if [[ -d ${STATEDIR} ]]; then
|
||||
_log 'debug' "Consolidating all state onto ${STATEDIR}"
|
||||
|
||||
# Always enabled features:
|
||||
SERVICEDIRS=(
|
||||
lib/logrotate
|
||||
lib/postfix
|
||||
spool/postfix
|
||||
)
|
||||
|
||||
# Only consolidate state for services that are enabled
|
||||
# Notably avoids copying over 200MB for the ClamAV database
|
||||
[[ ${ENABLE_AMAVIS} -eq 1 ]] && SERVICEDIRS+=('lib/amavis')
|
||||
[[ ${ENABLE_CLAMAV} -eq 1 ]] && SERVICEDIRS+=('lib/clamav')
|
||||
[[ ${ENABLE_FAIL2BAN} -eq 1 ]] && SERVICEDIRS+=('lib/fail2ban')
|
||||
[[ ${ENABLE_FETCHMAIL} -eq 1 ]] && SERVICEDIRS+=('lib/fetchmail')
|
||||
[[ ${ENABLE_MTA_STS} -eq 1 ]] && SERVICEDIRS+=('lib/mta-sts')
|
||||
[[ ${ENABLE_POSTGREY} -eq 1 ]] && SERVICEDIRS+=('lib/postgrey')
|
||||
[[ ${ENABLE_RSPAMD} -eq 1 ]] && SERVICEDIRS+=('lib/rspamd')
|
||||
[[ ${ENABLE_RSPAMD_REDIS} -eq 1 ]] && SERVICEDIRS+=('lib/redis')
|
||||
[[ ${ENABLE_SPAMASSASSIN} -eq 1 ]] && SERVICEDIRS+=('lib/spamassassin')
|
||||
[[ ${ENABLE_SRS} -eq 1 ]] && SERVICEDIRS+=('lib/postsrsd')
|
||||
[[ ${SMTP_ONLY} -ne 1 ]] && SERVICEDIRS+=('lib/dovecot')
|
||||
|
||||
# Single service files
|
||||
[[ ${ENABLE_SRS} -eq 1 ]] && SERVICEFILES+=('/etc/postsrsd.secret')
|
||||
|
||||
for SERVICEFILE in "${SERVICEFILES[@]}"; do
|
||||
DEST="${STATEDIR}/${SERVICEFILE}"
|
||||
DESTDIR="${DEST%/*}"
|
||||
|
||||
mkdir -p "${DESTDIR}"
|
||||
if [[ -f ${DEST} ]]; then
|
||||
_log 'trace' "Destination ${DEST} exists, linking ${SERVICEFILE} to it"
|
||||
# Original content from image no longer relevant, remove it:
|
||||
rm -f "${SERVICEFILE}"
|
||||
elif [[ -f "${SERVICEFILE}" ]]; then
|
||||
_log 'trace' "Moving ${SERVICEFILE} to ${DEST}"
|
||||
# Empty volume was mounted, or new content from enabling a feature ENV:
|
||||
mv "${SERVICEFILE}" "${DEST}"
|
||||
# Apply SELinux security context to match the state directory, so access
|
||||
# is not restricted to the current running container:
|
||||
chcon -R --reference="${STATEDIR}" "${DEST}" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Symlink the original file in the container ($SERVICEFILE) to be
|
||||
# sourced from assocaiated path in /var/mail-state/ ($DEST):
|
||||
ln -s "${DEST}" "${SERVICEFILE}"
|
||||
done
|
||||
|
||||
for SERVICEDIR in "${SERVICEDIRS[@]}"; do
|
||||
DEST="${STATEDIR}/${SERVICEDIR//\//-}"
|
||||
SERVICEDIR="/var/${SERVICEDIR}"
|
||||
|
||||
# If relevant content is found in /var/mail-state (presumably a volume mount),
|
||||
# use it instead. Otherwise copy over any missing directories checked.
|
||||
if [[ -d ${DEST} ]]; then
|
||||
_log 'trace' "Destination ${DEST} exists, linking ${SERVICEDIR} to it"
|
||||
# Original content from image no longer relevant, remove it:
|
||||
rm -rf "${SERVICEDIR}"
|
||||
elif [[ -d ${SERVICEDIR} ]]; then
|
||||
_log 'trace' "Moving contents of ${SERVICEDIR} to ${DEST}"
|
||||
# An empty volume was mounted, or new content dir now exists from enabling a feature ENV:
|
||||
mv "${SERVICEDIR}" "${DEST}"
|
||||
# Apply SELinux security context to match the state directory, so access
|
||||
# is not restricted to the current running container:
|
||||
chcon -R --reference="${STATEDIR}" "${DEST}" 2>/dev/null || true
|
||||
else
|
||||
_log 'error' "${SERVICEDIR} should exist but is missing"
|
||||
fi
|
||||
|
||||
# Symlink the original path in the container ($SERVICEDIR) to be
|
||||
# sourced from assocaiated path in /var/mail-state/ ($DEST):
|
||||
ln -s "${DEST}" "${SERVICEDIR}"
|
||||
done
|
||||
|
||||
# This ensures the user and group of the files from the external mount have their
|
||||
# numeric ID values in sync. New releases where the installed packages order changes
|
||||
# can change the values in the Docker image, causing an ownership mismatch.
|
||||
# NOTE: More details about users and groups added during image builds are documented here:
|
||||
# https://github.com/docker-mailserver/docker-mailserver/pull/3011#issuecomment-1399120252
|
||||
_log 'trace' "Fixing ${STATEDIR}/* permissions"
|
||||
[[ ${ENABLE_AMAVIS} -eq 1 ]] && chown -R amavis:amavis "${STATEDIR}/lib-amavis"
|
||||
[[ ${ENABLE_CLAMAV} -eq 1 ]] && chown -R clamav:clamav "${STATEDIR}/lib-clamav"
|
||||
[[ ${ENABLE_FETCHMAIL} -eq 1 ]] && chown -R fetchmail:nogroup "${STATEDIR}/lib-fetchmail"
|
||||
[[ ${ENABLE_MTA_STS} -eq 1 ]] && chown -R _mta-sts:_mta-sts "${STATEDIR}/lib-mta-sts"
|
||||
[[ ${ENABLE_POSTGREY} -eq 1 ]] && chown -R postgrey:postgrey "${STATEDIR}/lib-postgrey"
|
||||
[[ ${ENABLE_RSPAMD} -eq 1 ]] && chown -R _rspamd:_rspamd "${STATEDIR}/lib-rspamd"
|
||||
[[ ${ENABLE_RSPAMD_REDIS} -eq 1 ]] && chown -R redis:redis "${STATEDIR}/lib-redis"
|
||||
[[ ${ENABLE_SPAMASSASSIN} -eq 1 ]] && chown -R debian-spamd:debian-spamd "${STATEDIR}/lib-spamassassin"
|
||||
|
||||
chown -R root:root "${STATEDIR}/lib-logrotate"
|
||||
chown -R postfix:postfix "${STATEDIR}/lib-postfix"
|
||||
|
||||
# NOTE: The Postfix spool location has mixed owner/groups to take into account:
|
||||
# UID = postfix(101): active, bounce, corrupt, defer, deferred, flush, hold, incoming, maildrop, private, public, saved, trace
|
||||
# UID = root(0): dev, etc, lib, pid, usr
|
||||
# GID = postdrop(103): maildrop, public
|
||||
# GID for all other directories is root(0)
|
||||
# NOTE: `spool-postfix/private/` will be set to `postfix:postfix` when Postfix starts / restarts
|
||||
# Set most common ownership:
|
||||
chown -R postfix:root "${STATEDIR}/spool-postfix"
|
||||
chown root:root "${STATEDIR}/spool-postfix"
|
||||
|
||||
# These two require the postdrop(103) group:
|
||||
chgrp -R postdrop "${STATEDIR}"/spool-postfix/{maildrop,public}
|
||||
|
||||
# These permissions rely on the `postdrop` binary having the SGID bit set.
|
||||
# Ref: https://github.com/docker-mailserver/docker-mailserver/pull/3625
|
||||
chmod 730 "${STATEDIR}/spool-postfix/maildrop"
|
||||
chmod 710 "${STATEDIR}/spool-postfix/public"
|
||||
else
|
||||
_log 'debug' "'${STATEDIR}' is not present; Not consolidating state"
|
||||
if [[ ! -d ${DMS_STATE_DIR} ]]; then
|
||||
_log 'debug' "'${DMS_STATE_DIR}' is not present - not consolidating state"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_log 'debug' "Consolidating all state onto ${DMS_STATE_DIR}"
|
||||
|
||||
local DEST SERVICEDIR SERVICEDIRS SERVICEFILE SERVICEFILES
|
||||
|
||||
# Always enabled features:
|
||||
SERVICEDIRS=(
|
||||
'lib/logrotate'
|
||||
'lib/postfix'
|
||||
'spool/postfix'
|
||||
)
|
||||
|
||||
# Only consolidate state for services that are enabled
|
||||
# Notably avoids copying over 200MB for the ClamAV database
|
||||
[[ ${ENABLE_AMAVIS} -eq 1 ]] && SERVICEDIRS+=('lib/amavis')
|
||||
[[ ${ENABLE_CLAMAV} -eq 1 ]] && SERVICEDIRS+=('lib/clamav')
|
||||
[[ ${ENABLE_FAIL2BAN} -eq 1 ]] && SERVICEDIRS+=('lib/fail2ban')
|
||||
[[ ${ENABLE_FETCHMAIL} -eq 1 ]] && SERVICEDIRS+=('lib/fetchmail')
|
||||
[[ ${ENABLE_GETMAIL} -eq 1 ]] && SERVICEDIRS+=('lib/getmail')
|
||||
[[ ${ENABLE_MTA_STS} -eq 1 ]] && SERVICEDIRS+=('lib/mta-sts')
|
||||
[[ ${ENABLE_POSTGREY} -eq 1 ]] && SERVICEDIRS+=('lib/postgrey')
|
||||
[[ ${ENABLE_RSPAMD} -eq 1 ]] && SERVICEDIRS+=('lib/rspamd')
|
||||
[[ ${ENABLE_RSPAMD_REDIS} -eq 1 ]] && SERVICEDIRS+=('lib/redis')
|
||||
[[ ${ENABLE_SPAMASSASSIN} -eq 1 ]] && SERVICEDIRS+=('lib/spamassassin')
|
||||
[[ ${ENABLE_SRS} -eq 1 ]] && SERVICEDIRS+=('lib/postsrsd')
|
||||
[[ ${SMTP_ONLY} -ne 1 ]] && SERVICEDIRS+=('lib/dovecot')
|
||||
|
||||
# Single service files
|
||||
[[ ${ENABLE_SRS} -eq 1 ]] && SERVICEFILES+=('/etc/postsrsd.secret')
|
||||
|
||||
for SERVICEFILE in "${SERVICEFILES[@]}"; do
|
||||
DEST="${DMS_STATE_DIR}/${SERVICEFILE}"
|
||||
|
||||
# Append service parent dir(s) path to the state dir and ensure it exists:
|
||||
mkdir -p "${DEST%/*}"
|
||||
if [[ -f ${DEST} ]]; then
|
||||
_log 'trace' "Destination ${DEST} exists, linking ${SERVICEFILE} to it"
|
||||
# Original content from image no longer relevant, remove it:
|
||||
rm -f "${SERVICEFILE}"
|
||||
elif [[ -f "${SERVICEFILE}" ]]; then
|
||||
_log 'trace' "Moving ${SERVICEFILE} to ${DEST}"
|
||||
# Empty volume was mounted, or new content from enabling a feature ENV:
|
||||
mv "${SERVICEFILE}" "${DEST}"
|
||||
# Apply SELinux security context to match the state directory, so access
|
||||
# is not restricted to the current running container:
|
||||
chcon -R --reference="${DMS_STATE_DIR}" "${DEST}" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Symlink the original file in the container ($SERVICEFILE) to be
|
||||
# sourced from assocaiated path in /var/mail-state/ ($DEST):
|
||||
ln -s "${DEST}" "${SERVICEFILE}"
|
||||
done
|
||||
|
||||
for SERVICEDIR in "${SERVICEDIRS[@]}"; do
|
||||
DEST="${DMS_STATE_DIR}/${SERVICEDIR//\//-}"
|
||||
SERVICEDIR="/var/${SERVICEDIR}"
|
||||
|
||||
# If relevant content is found in /var/mail-state (presumably a volume mount),
|
||||
# use it instead. Otherwise copy over any missing directories checked.
|
||||
if [[ -d ${DEST} ]]; then
|
||||
_log 'trace' "Destination ${DEST} exists, linking ${SERVICEDIR} to it"
|
||||
# Original content from image no longer relevant, remove it:
|
||||
rm -rf "${SERVICEDIR}"
|
||||
elif [[ -d ${SERVICEDIR} ]]; then
|
||||
_log 'trace' "Moving contents of ${SERVICEDIR} to ${DEST}"
|
||||
# An empty volume was mounted, or new content dir now exists from enabling a feature ENV:
|
||||
mv "${SERVICEDIR}" "${DEST}"
|
||||
# Apply SELinux security context to match the state directory, so access
|
||||
# is not restricted to the current running container:
|
||||
# https://github.com/docker-mailserver/docker-mailserver/pull/3890
|
||||
chcon -R --reference="${DMS_STATE_DIR}" "${DEST}" 2>/dev/null || true
|
||||
else
|
||||
_log 'error' "${SERVICEDIR} should exist but is missing"
|
||||
fi
|
||||
|
||||
# Symlink the original path in the container ($SERVICEDIR) to be
|
||||
# sourced from associated path in /var/mail-state/ ($DEST):
|
||||
ln -s "${DEST}" "${SERVICEDIR}"
|
||||
done
|
||||
}
|
||||
|
||||
# These corrections are to fix changes to UID/GID values between upgrades,
|
||||
# or when ownership/permissions were altered externally on the host (eg: migration or system scripts)
|
||||
function _setup_adjust_state_permissions() {
|
||||
[[ ! -d ${DMS_STATE_DIR} ]] && return 0
|
||||
|
||||
# Parent directories must have executable bit set to descend the file tree for access,
|
||||
# as each service running as a non-root user requires this to access their state directory,
|
||||
# `/var/mail-state` must allow all users `+x`:
|
||||
chmod +x "${DMS_STATE_DIR}"
|
||||
|
||||
# This ensures the user and group of the files from the external mount have their
|
||||
# numeric ID values in sync. New releases where the installed packages order changes
|
||||
# can change the values in the Docker image, causing an ownership mismatch.
|
||||
# NOTE: More details about users and groups added during image builds are documented here:
|
||||
# https://github.com/docker-mailserver/docker-mailserver/pull/3011#issuecomment-1399120252
|
||||
_log 'trace' "Ensuring correct ownership + permissions for DMS state dir: '${DMS_STATE_DIR}'"
|
||||
[[ ${ENABLE_AMAVIS} -eq 1 ]] && chown -R amavis:amavis "${DMS_STATE_DIR}/lib-amavis"
|
||||
[[ ${ENABLE_CLAMAV} -eq 1 ]] && chown -R clamav:clamav "${DMS_STATE_DIR}/lib-clamav"
|
||||
[[ ${ENABLE_FETCHMAIL} -eq 1 ]] && chown -R fetchmail:nogroup "${DMS_STATE_DIR}/lib-fetchmail"
|
||||
[[ ${ENABLE_MTA_STS} -eq 1 ]] && chown -R _mta-sts:_mta-sts "${DMS_STATE_DIR}/lib-mta-sts"
|
||||
[[ ${ENABLE_POSTGREY} -eq 1 ]] && chown -R postgrey:postgrey "${DMS_STATE_DIR}/lib-postgrey"
|
||||
[[ ${ENABLE_RSPAMD} -eq 1 ]] && chown -R _rspamd:_rspamd "${DMS_STATE_DIR}/lib-rspamd"
|
||||
[[ ${ENABLE_RSPAMD_REDIS} -eq 1 ]] && chown -R redis:redis "${DMS_STATE_DIR}/lib-redis"
|
||||
[[ ${ENABLE_SPAMASSASSIN} -eq 1 ]] && chown -R debian-spamd:debian-spamd "${DMS_STATE_DIR}/lib-spamassassin"
|
||||
|
||||
chown -R root:root "${DMS_STATE_DIR}/lib-logrotate"
|
||||
chown -R postfix:postfix "${DMS_STATE_DIR}/lib-postfix"
|
||||
|
||||
# NOTE: The Postfix spool location has mixed owner/groups to take into account:
|
||||
# UID = postfix(101): active, bounce, corrupt, defer, deferred, flush, hold, incoming, maildrop, private, public, saved, trace
|
||||
# UID = root(0): dev, etc, lib, pid, usr
|
||||
# GID = postdrop(103): maildrop, public
|
||||
# GID for all other directories is root(0)
|
||||
# NOTE: `spool-postfix/private/` will be set to `postfix:postfix` when Postfix starts / restarts
|
||||
# Set most common ownership:
|
||||
chown -R postfix:root "${DMS_STATE_DIR}/spool-postfix"
|
||||
chown root:root "${DMS_STATE_DIR}/spool-postfix"
|
||||
|
||||
# These two require the postdrop(103) group:
|
||||
chgrp -R postdrop "${DMS_STATE_DIR}"/spool-postfix/{maildrop,public}
|
||||
|
||||
# These permissions rely on the `postdrop` binary having the SGID bit set.
|
||||
# Ref: https://github.com/docker-mailserver/docker-mailserver/pull/3625
|
||||
chmod 730 "${DMS_STATE_DIR}/spool-postfix/maildrop"
|
||||
chmod 710 "${DMS_STATE_DIR}/spool-postfix/public"
|
||||
}
|
||||
|
|
|
@ -79,6 +79,8 @@ EOF
|
|||
if [[ ${ACCOUNT_PROVISIONER} == 'FILE' ]]; then
|
||||
postconf 'virtual_mailbox_maps = texthash:/etc/postfix/vmailbox'
|
||||
fi
|
||||
# Historical context regarding decision to use LMTP instead of LDA (do not change this):
|
||||
# https://github.com/docker-mailserver/docker-mailserver/issues/4178#issuecomment-2375489302
|
||||
postconf 'virtual_transport = lmtp:unix:/var/run/dovecot/lmtp'
|
||||
fi
|
||||
|
||||
|
@ -91,13 +93,19 @@ EOF
|
|||
function _setup_postfix_late() {
|
||||
_log 'debug' 'Configuring Postfix (late setup)'
|
||||
|
||||
# These two config files are `access` database tables managed via `setup email restrict`:
|
||||
# NOTE: Prepends to existing restrictions, thus has priority over other permit/reject policies that follow.
|
||||
# https://www.postfix.org/postconf.5.html#smtpd_sender_restrictions
|
||||
# https://www.postfix.org/access.5.html
|
||||
__postfix__log 'trace' 'Configuring user access'
|
||||
if [[ -f /tmp/docker-mailserver/postfix-send-access.cf ]]; then
|
||||
sed -i -E 's|(smtpd_sender_restrictions =)|\1 check_sender_access texthash:/tmp/docker-mailserver/postfix-send-access.cf,|' /etc/postfix/main.cf
|
||||
# Prefer to prepend to our specialized variant instead:
|
||||
# https://github.com/docker-mailserver/docker-mailserver/pull/4379
|
||||
sed -i -E 's|^(dms_smtpd_sender_restrictions =)|\1 check_sender_access texthash:/tmp/docker-mailserver/postfix-send-access.cf,|' /etc/postfix/main.cf
|
||||
fi
|
||||
|
||||
if [[ -f /tmp/docker-mailserver/postfix-receive-access.cf ]]; then
|
||||
sed -i -E 's|(smtpd_recipient_restrictions =)|\1 check_recipient_access texthash:/tmp/docker-mailserver/postfix-receive-access.cf,|' /etc/postfix/main.cf
|
||||
sed -i -E 's|^(smtpd_recipient_restrictions =)|\1 check_recipient_access texthash:/tmp/docker-mailserver/postfix-receive-access.cf,|' /etc/postfix/main.cf
|
||||
fi
|
||||
|
||||
__postfix__log 'trace' 'Configuring relay host'
|
||||
|
@ -129,7 +137,7 @@ function __postfix__setup_override_configuration() {
|
|||
# Do not directly output to 'main.cf' as this causes a read-write-conflict.
|
||||
# `postconf` output is filtered to skip expected warnings regarding overrides:
|
||||
# https://github.com/docker-mailserver/docker-mailserver/pull/3880#discussion_r1510414576
|
||||
postconf -n >/tmp/postfix-main-new.cf 2> >(grep -v 'overriding earlier entry')
|
||||
postconf -n >/tmp/postfix-main-new.cf 2> >(grep -v 'overriding earlier entry' >&2)
|
||||
|
||||
mv /tmp/postfix-main-new.cf /etc/postfix/main.cf
|
||||
_adjust_mtime_for_postfix_maincf
|
||||
|
|
|
@ -155,13 +155,6 @@ function __setup__security__clamav() {
|
|||
if [[ ${ENABLE_CLAMAV} -eq 1 ]]; then
|
||||
_log 'debug' 'Enabling and configuring ClamAV'
|
||||
|
||||
local FILE
|
||||
for FILE in /var/log/mail/{clamav,freshclam}.log; do
|
||||
touch "${FILE}"
|
||||
chown clamav:adm "${FILE}"
|
||||
chmod 640 "${FILE}"
|
||||
done
|
||||
|
||||
if [[ ${CLAMAV_MESSAGE_SIZE_LIMIT} != '25M' ]]; then
|
||||
_log 'trace' "Setting ClamAV message scan size limit to '${CLAMAV_MESSAGE_SIZE_LIMIT}'"
|
||||
|
||||
|
|
|
@ -76,8 +76,9 @@ function __rspamd__run_early_setup_and_checks() {
|
|||
mkdir -p /var/lib/rspamd/
|
||||
: >/var/lib/rspamd/stats.ucl
|
||||
|
||||
if [[ -d ${RSPAMD_DMS_OVERRIDE_D} ]]; then
|
||||
cp "${RSPAMD_DMS_OVERRIDE_D}"/* "${RSPAMD_OVERRIDE_D}"
|
||||
# Copy if directory exists and is not empty
|
||||
if [[ -d ${RSPAMD_DMS_OVERRIDE_D} ]] && [[ -z $(find "${RSPAMD_DMS_OVERRIDE_D}" -maxdepth 0 -empty) ]]; then
|
||||
cp "${RSPAMD_DMS_OVERRIDE_D}/"* "${RSPAMD_OVERRIDE_D}"
|
||||
fi
|
||||
|
||||
if [[ ${ENABLE_AMAVIS} -eq 1 ]] || [[ ${ENABLE_SPAMASSASSIN} -eq 1 ]]; then
|
||||
|
@ -319,8 +320,7 @@ function __rspamd__setup_check_authenticated() {
|
|||
local MODULE_FILE="${RSPAMD_LOCAL_D}/settings.conf"
|
||||
readonly MODULE_FILE
|
||||
if _env_var_expect_zero_or_one 'RSPAMD_CHECK_AUTHENTICATED' \
|
||||
&& [[ ${RSPAMD_CHECK_AUTHENTICATED} -eq 0 ]]
|
||||
then
|
||||
&& [[ ${RSPAMD_CHECK_AUTHENTICATED} -eq 0 ]]; then
|
||||
__rspamd__log 'debug' 'Content checks for authenticated users are disabled'
|
||||
else
|
||||
__rspamd__log 'debug' 'Enabling content checks for authenticated users'
|
||||
|
@ -330,34 +330,24 @@ function __rspamd__setup_check_authenticated() {
|
|||
fi
|
||||
}
|
||||
|
||||
# This function performs a simple check: go through DKIM configuration files, acquire
|
||||
# all private key file locations and check whether they exist and whether they can be
|
||||
# accessed by Rspamd.
|
||||
# This function performs a simple check on the queried rspamd DKIM configuration:
|
||||
# - Acquire all private key file locations and check whether they exist and can be accessed by Rspamd.
|
||||
# - We are not checking paths that contain the '$' symbol.
|
||||
function __rspamd__check_dkim_permissions() {
|
||||
local DKIM_CONF_FILES DKIM_KEY_FILES
|
||||
[[ -f ${RSPAMD_LOCAL_D}/dkim_signing.conf ]] && DKIM_CONF_FILES+=("${RSPAMD_LOCAL_D}/dkim_signing.conf")
|
||||
[[ -f ${RSPAMD_OVERRIDE_D}/dkim_signing.conf ]] && DKIM_CONF_FILES+=("${RSPAMD_OVERRIDE_D}/dkim_signing.conf")
|
||||
|
||||
# Here, we populate DKIM_KEY_FILES which we later iterate over. DKIM_KEY_FILES
|
||||
# contains all keys files configured by the user.
|
||||
local FILE
|
||||
for FILE in "${DKIM_CONF_FILES[@]}"; do
|
||||
readarray -t DKIM_KEY_FILES_TMP < <(grep -o -E 'path = .*' "${FILE}" | cut -d '=' -f 2 | tr -d ' ";')
|
||||
DKIM_KEY_FILES+=("${DKIM_KEY_FILES_TMP[@]}")
|
||||
done
|
||||
|
||||
for FILE in "${DKIM_KEY_FILES[@]}"; do
|
||||
if [[ -f ${FILE} ]]; then
|
||||
__rspamd__log 'trace' "Checking DKIM file '${FILE}'"
|
||||
local KEY_FILE
|
||||
while read -r KEY_FILE; do
|
||||
if [[ -f ${KEY_FILE} ]]; then
|
||||
__rspamd__log 'trace' "Checking DKIM file '${KEY_FILE}'"
|
||||
# See https://serverfault.com/a/829314 for an explanation on `-exec false {} +`
|
||||
# We additionally resolve symbolic links to check the permissions of the actual files
|
||||
if find "$(realpath -eL "${FILE}")" \( -user _rspamd -or -group _rspamd -or -perm -o=r \) -exec false {} +; then
|
||||
__rspamd__log 'warn' "Rspamd DKIM private key file '${FILE}' does not appear to have correct permissions/ownership for Rspamd to use it"
|
||||
if find "$(realpath -L "${KEY_FILE}")" \( -user _rspamd -or -group _rspamd -or -perm -o=r \) \
|
||||
-exec false {} +; then
|
||||
__rspamd__log 'warn' "Rspamd DKIM private key file '${KEY_FILE}' does not appear to have correct permissions/ownership for Rspamd to use it"
|
||||
else
|
||||
__rspamd__log 'trace' "DKIM file '${FILE}' permissions and ownership appear correct"
|
||||
__rspamd__log 'trace' "DKIM file '${KEY_FILE}' permissions and ownership appear correct"
|
||||
fi
|
||||
else
|
||||
__rspamd__log 'warn' "Rspamd DKIM private key file '${FILE}' is configured for usage, but does not appear to exist"
|
||||
__rspamd__log 'warn' "Rspamd DKIM private key file '${KEY_FILE}' is configured for usage, but does not appear to exist"
|
||||
fi
|
||||
done
|
||||
done < <(rspamadm configdump dkim_signing | grep 'path =' | grep -v -F '$' | awk '{print $3}' | tr -d ';"')
|
||||
}
|
||||
|
|
|
@ -4,9 +4,16 @@
|
|||
declare -A VARS
|
||||
|
||||
function _early_variables_setup() {
|
||||
__environment_variables_log_level
|
||||
_obtain_hostname_and_domainname
|
||||
__environment_variables_backwards_compatibility
|
||||
__environment_variables_general_setup
|
||||
|
||||
[[ ${ACCOUNT_PROVISIONER} == 'LDAP' ]] && __environment_variables_ldap
|
||||
[[ ${ENABLE_OAUTH2} -eq 1 ]] && __environment_variables_oauth2
|
||||
[[ ${ENABLE_SASLAUTHD} -eq 1 ]] && __environment_variables_saslauthd
|
||||
|
||||
__environment_variables_export
|
||||
}
|
||||
|
||||
# This function handles variables that are deprecated. This allows a
|
||||
|
@ -55,6 +62,8 @@ function __environment_variables_general_setup() {
|
|||
VARS[DMS_VMAIL_UID]="${DMS_VMAIL_UID:=5000}"
|
||||
VARS[DMS_VMAIL_GID]="${DMS_VMAIL_GID:=5000}"
|
||||
|
||||
# user-customizable are last
|
||||
|
||||
_log 'trace' 'Setting anti-spam & anti-virus environment variables'
|
||||
|
||||
VARS[AMAVIS_LOGLEVEL]="${AMAVIS_LOGLEVEL:=0}"
|
||||
|
@ -159,15 +168,27 @@ function __environment_variables_general_setup() {
|
|||
VARS[UPDATE_CHECK_INTERVAL]="${UPDATE_CHECK_INTERVAL:=1d}"
|
||||
}
|
||||
|
||||
function _environment_variables_oauth2() {
|
||||
_log 'debug' 'Setting OAUTH2-related environment variables now'
|
||||
function __environment_variables_log_level() {
|
||||
if [[ ${LOG_LEVEL} == 'trace' ]] \
|
||||
|| [[ ${LOG_LEVEL} == 'debug' ]] \
|
||||
|| [[ ${LOG_LEVEL} == 'info' ]] \
|
||||
|| [[ ${LOG_LEVEL} == 'warn' ]] \
|
||||
|| [[ ${LOG_LEVEL} == 'error' ]]
|
||||
then
|
||||
return 0
|
||||
else
|
||||
local DEFAULT_LOG_LEVEL='info'
|
||||
_log 'warn' "Log level '${LOG_LEVEL}' is invalid (falling back to default '${DEFAULT_LOG_LEVEL}')"
|
||||
|
||||
VARS[OAUTH2_INTROSPECTION_URL]="${OAUTH2_INTROSPECTION_URL:=}"
|
||||
# shellcheck disable=SC2034
|
||||
VARS[LOG_LEVEL]="${DEFAULT_LOG_LEVEL}"
|
||||
LOG_LEVEL="${DEFAULT_LOG_LEVEL}"
|
||||
fi
|
||||
}
|
||||
|
||||
# This function handles environment variables related to LDAP.
|
||||
# NOTE: SASLAuthd and Dovecot LDAP support inherit these common ENV.
|
||||
function _environment_variables_ldap() {
|
||||
function __environment_variables_ldap() {
|
||||
_log 'debug' 'Setting LDAP-related environment variables now'
|
||||
|
||||
VARS[LDAP_BIND_DN]="${LDAP_BIND_DN:=}"
|
||||
|
@ -177,19 +198,26 @@ function _environment_variables_ldap() {
|
|||
VARS[LDAP_START_TLS]="${LDAP_START_TLS:=no}"
|
||||
}
|
||||
|
||||
function __environment_variables_oauth2() {
|
||||
_log 'debug' 'Setting OAUTH2-related environment variables now'
|
||||
|
||||
VARS[OAUTH2_INTROSPECTION_URL]="${OAUTH2_INTROSPECTION_URL:=}"
|
||||
}
|
||||
|
||||
# This function handles environment variables related to SASLAUTHD
|
||||
# LDAP specific ENV handled in: `startup/setup.d/saslauthd.sh:_setup_saslauthd()`
|
||||
function _environment_variables_saslauthd() {
|
||||
function __environment_variables_saslauthd() {
|
||||
_log 'debug' 'Setting SASLAUTHD-related environment variables now'
|
||||
|
||||
# Only used by the supervisor service command (upstream default: `/etc/default/saslauthd`)
|
||||
VARS[SASLAUTHD_MECHANISMS]="${SASLAUTHD_MECHANISMS:=pam}"
|
||||
# This ENV is only used by the supervisor service config `saslauth.conf`:
|
||||
# NOTE: `pam` is set as the upstream default in `/etc/default/saslauthd`
|
||||
VARS[SASLAUTHD_MECHANISMS]="${SASLAUTHD_MECHANISMS:=ldap}"
|
||||
}
|
||||
|
||||
# This function Writes the contents of the `VARS` map (associative array)
|
||||
# to locations where they can be sourced from (e.g. `/etc/dms-settings`)
|
||||
# or where they can be used by Bash directly (e.g. `/root/.bashrc`).
|
||||
function _environment_variables_export() {
|
||||
function __environment_variables_export() {
|
||||
_log 'debug' "Exporting environment variables now (creating '/etc/dms-settings')"
|
||||
|
||||
: >/root/.bashrc # make DMS variables available in login shells and their subprocesses
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue