mirror of
https://github.com/docker-mailserver/docker-mailserver.git
synced 2025-08-02 00:54:54 +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
|
@ -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 ';"')
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue