chore(scripts): Removing flock so NFS works (#1980)
Co-authored-by: Casper <casperklein@users.noreply.github.com> Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
This commit is contained in:
parent
ba32943986
commit
5becce8064
2
Makefile
2
Makefile
|
@ -25,7 +25,7 @@ clean:
|
||||||
# remove running and stopped test containers
|
# remove running and stopped test containers
|
||||||
-@ [[ -d config.bak ]] && { rm -rf config ; mv config.bak config ; } || :
|
-@ [[ -d config.bak ]] && { rm -rf config ; mv config.bak config ; } || :
|
||||||
-@ [[ -d testconfig.bak ]] && { sudo rm -rf test/config ; mv testconfig.bak test/config ; } || :
|
-@ [[ -d testconfig.bak ]] && { sudo rm -rf test/config ; mv testconfig.bak test/config ; } || :
|
||||||
-@ for container in $$(docker ps -a | grep -E "mail|ldap_for_mail|mail_overri.*|hadolint|eclint|shellcheck" | cut -f 1-1 -d ' '); do docker rm -f $$container; done
|
-@ for container in $$(docker ps -a --filter name='^/mail$$|^ldap_for_mail$$|^mail_override_hostname$$|^open-dkim$$|^hadolint$$|^eclint$$|^shellcheck$$' | sed 1d | cut -f 1-1 -d ' '); do docker rm -f $$container; done
|
||||||
-@ sudo rm -rf test/onedir test/alias test/quota test/relay test/config/dovecot-lmtp/userdb test/config/key* test/config/opendkim/keys/domain.tld/ test/config/opendkim/keys/example.com/ test/config/opendkim/keys/localdomain2.com/ test/config/postfix-aliases.cf test/config/postfix-receive-access.cf test/config/postfix-receive-access.cfe test/config/dovecot-quotas.cf test/config/postfix-send-access.cf test/config/postfix-send-access.cfe test/config/relay-hosts/chksum test/config/relay-hosts/postfix-aliases.cf test/config/dhparams.pem test/config/dovecot-lmtp/dh.pem test/config/relay-hosts/dovecot-quotas.cf test/config/user-patches.sh test/alias/config/postfix-virtual.cf test/quota/config/dovecot-quotas.cf test/quota/config/postfix-accounts.cf test/relay/config/postfix-relaymap.cf test/relay/config/postfix-sasl-password.cf test/duplicate_configs/
|
-@ sudo rm -rf test/onedir test/alias test/quota test/relay test/config/dovecot-lmtp/userdb test/config/key* test/config/opendkim/keys/domain.tld/ test/config/opendkim/keys/example.com/ test/config/opendkim/keys/localdomain2.com/ test/config/postfix-aliases.cf test/config/postfix-receive-access.cf test/config/postfix-receive-access.cfe test/config/dovecot-quotas.cf test/config/postfix-send-access.cf test/config/postfix-send-access.cfe test/config/relay-hosts/chksum test/config/relay-hosts/postfix-aliases.cf test/config/dhparams.pem test/config/dovecot-lmtp/dh.pem test/config/relay-hosts/dovecot-quotas.cf test/config/user-patches.sh test/alias/config/postfix-virtual.cf test/quota/config/dovecot-quotas.cf test/quota/config/postfix-accounts.cf test/relay/config/postfix-relaymap.cf test/relay/config/postfix-sasl-password.cf test/duplicate_configs/
|
||||||
|
|
||||||
# -----------------------------------------------
|
# -----------------------------------------------
|
||||||
|
|
|
@ -35,31 +35,41 @@ function __usage
|
||||||
|
|
||||||
[[ ${1:-} == 'help' ]] && { __usage ; exit 0 ; }
|
[[ ${1:-} == 'help' ]] && { __usage ; exit 0 ; }
|
||||||
|
|
||||||
USER="${1}"
|
FULL_EMAIL="${1}"
|
||||||
shift
|
shift
|
||||||
PASSWD="${*}"
|
PASSWD="${*}"
|
||||||
|
|
||||||
[[ -z ${USER} ]] && { __usage ; errex 'No username specified' ; }
|
[[ -z ${FULL_EMAIL} ]] && { __usage ; errex 'No username specified' ; }
|
||||||
[[ "${USER}" =~ .*\@.* ]] || { __usage ; errex 'Username must include the domain' ; }
|
[[ "${FULL_EMAIL}" =~ .*\@.* ]] || { __usage ; errex 'Username must include the domain' ; }
|
||||||
|
|
||||||
# Protect config file with lock to avoid race conditions
|
# Protect config file with lock to avoid race conditions
|
||||||
touch "${DATABASE}"
|
touch "${DATABASE}"
|
||||||
(
|
create_lock "$(basename "$0")"
|
||||||
flock -e 200
|
if grep -qi "^$(escape "${FULL_EMAIL}")|" "${DATABASE}"
|
||||||
|
then
|
||||||
|
echo "User '${FULL_EMAIL}' already exists."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if grep -qi "^$(escape "${USER}")|" "${DATABASE}" 2>/dev/null
|
if [[ -z ${PASSWD} ]]
|
||||||
then
|
then
|
||||||
echo "User '${USER}' already exists."
|
read -r -s -p "Enter Password: " PASSWD
|
||||||
exit 1
|
echo
|
||||||
fi
|
[[ -z ${PASSWD} ]] && errex "Password must not be empty"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -z ${PASSWD} ]]
|
HASH="$(doveadm pw -s SHA512-CRYPT -u "${FULL_EMAIL}" -p "${PASSWD}")"
|
||||||
then
|
echo "${FULL_EMAIL}|${HASH}" >> "${DATABASE}"
|
||||||
read -r -s -p "Enter Password: " PASSWD
|
|
||||||
echo
|
|
||||||
[[ -z ${PASSWD} ]] && errex "Password must not be empty"
|
|
||||||
fi
|
|
||||||
|
|
||||||
HASH="$(doveadm pw -s SHA512-CRYPT -u "${USER}" -p "${PASSWD}")"
|
USER="${FULL_EMAIL%@*}"
|
||||||
echo "${USER}|${HASH}" >> "${DATABASE}"
|
DOMAIN="${FULL_EMAIL#*@}"
|
||||||
) 200< "${DATABASE}"
|
|
||||||
|
# Tests fail if the creation of /var/mail/${DOMAIN}/${USER} doesn't happen fast enough after addmailuser executes (check-for-changes.sh race-condition)
|
||||||
|
if [[ -e "/tmp/docker-mailserver-config-chksum" ]] # Prevent infinite loop in tests like "checking accounts: user3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf even when that file does not exist"
|
||||||
|
then
|
||||||
|
while [[ ! -d "/var/mail/${DOMAIN}/${USER}" ]]
|
||||||
|
do
|
||||||
|
echo "Waiting for dovecot to create /var/mail/${DOMAIN}/${USER}..."
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
|
@ -86,81 +86,77 @@ then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
(
|
create_lock "$(basename "$0")"
|
||||||
flock -e 200
|
for EMAIL in "${@}"
|
||||||
|
do
|
||||||
|
ERROR=false
|
||||||
|
|
||||||
for EMAIL in "${@}"
|
# very simple plausibility check
|
||||||
do
|
[[ ${EMAIL} != *@*.* ]] && errex "No valid email address: ${EMAIL}"
|
||||||
ERROR=false
|
|
||||||
|
|
||||||
# very simple plausibility check
|
USER="${EMAIL%@*}"
|
||||||
[[ ${EMAIL} != *@*.* ]] && errex "No valid address: ${EMAIL}"
|
DOMAIN="${EMAIL#*@}"
|
||||||
|
|
||||||
USER="${EMAIL%@*}"
|
# ${EMAIL} must not contain /s and other syntactic characters
|
||||||
DOMAIN="${EMAIL#*@}"
|
UNESCAPED_EMAIL="${EMAIL}"
|
||||||
|
EMAIL=$(escape "${EMAIL}")
|
||||||
|
|
||||||
# ${EMAIL} must not contain /s and other syntactic characters
|
if [[ -f ${DATABASE} ]]
|
||||||
UNESCAPED_EMAIL="${EMAIL}"
|
then
|
||||||
EMAIL=$(escape "${EMAIL}")
|
if ! sed -i "/^${EMAIL}|/d" "${DATABASE}"
|
||||||
|
|
||||||
if [[ -f ${DATABASE} ]]
|
|
||||||
then
|
then
|
||||||
if ! sed -i "/^${EMAIL}|/d" "${DATABASE}"
|
echo "${UNESCAPED_EMAIL} couldn't be deleted in ${DATABASE}." >&2
|
||||||
then
|
|
||||||
echo "${UNESCAPED_EMAIL} couldn't be deleted in ${DATABASE}." >&2
|
|
||||||
ERROR=true
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -f ${ALIAS_DATABASE} ]]
|
|
||||||
then
|
|
||||||
# delete all aliases where the user is the only recipient( " ${EMAIL}" )
|
|
||||||
# delete user only for all aliases that deliver to multiple recipients ( ",${EMAIL}" "${EMAIL,}" )
|
|
||||||
if sed -i \
|
|
||||||
-e "/ ${EMAIL}$/d" -e "s/,${EMAIL}//g" -e "s/${EMAIL},//g" \
|
|
||||||
"${ALIAS_DATABASE}"
|
|
||||||
then
|
|
||||||
echo "${UNESCAPED_EMAIL} and potential aliases deleted."
|
|
||||||
else
|
|
||||||
echo "Aliases for ${UNESCAPED_EMAIL} couldn't be deleted in ${ALIAS_DATABASE}." >&2
|
|
||||||
ERROR=true
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# remove quota directives
|
|
||||||
if [[ -f ${QUOTA_DATABASE} ]]
|
|
||||||
then
|
|
||||||
if ! sed -i -e "/^${EMAIL}:.*$/d" "${QUOTA_DATABASE}"
|
|
||||||
then
|
|
||||||
echo "Quota for ${UNESCAPED_EMAIL} couldn't be deleted in ${QUOTA_DATABASE}." >&2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! ${MAILDEL}
|
|
||||||
then
|
|
||||||
echo "Leaving the mailbox untouched.
|
|
||||||
If you want to delete it at a later point,
|
|
||||||
use 'sudo docker exec mailserver rm -R /var/mail/${DOMAIN}/${USER}'"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -e "/var/mail/${DOMAIN}/${USER}" ]]
|
|
||||||
then
|
|
||||||
if rm -R "/var/mail/${DOMAIN}/${USER}"
|
|
||||||
then
|
|
||||||
echo "Mailbox deleted."
|
|
||||||
else
|
|
||||||
echo "Mailbox couldn't be deleted." >&2
|
|
||||||
ERROR=true
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "Mailbox directory '/var/mail/${DOMAIN}/${USER}' did not exist." >&2
|
|
||||||
ERROR=true
|
ERROR=true
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
${ERROR} && errex 'See the messages above.'
|
if [[ -f ${ALIAS_DATABASE} ]]
|
||||||
done
|
then
|
||||||
|
# delete all aliases where the user is the only recipient( " ${EMAIL}" )
|
||||||
|
# delete user only for all aliases that deliver to multiple recipients ( ",${EMAIL}" "${EMAIL,}" )
|
||||||
|
if sed -i \
|
||||||
|
-e "/ ${EMAIL}$/d" -e "s/,${EMAIL}//g" -e "s/${EMAIL},//g" \
|
||||||
|
"${ALIAS_DATABASE}"
|
||||||
|
then
|
||||||
|
echo "${UNESCAPED_EMAIL} and potential aliases deleted."
|
||||||
|
else
|
||||||
|
echo "Aliases for ${UNESCAPED_EMAIL} couldn't be deleted in ${ALIAS_DATABASE}." >&2
|
||||||
|
ERROR=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
) 200< "${DATABASE}"
|
# remove quota directives
|
||||||
|
if [[ -f ${QUOTA_DATABASE} ]]
|
||||||
|
then
|
||||||
|
if ! sed -i -e "/^${EMAIL}:.*$/d" "${QUOTA_DATABASE}"
|
||||||
|
then
|
||||||
|
echo "Quota for ${UNESCAPED_EMAIL} couldn't be deleted in ${QUOTA_DATABASE}." >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! ${MAILDEL}
|
||||||
|
then
|
||||||
|
echo "Leaving the mailbox untouched.
|
||||||
|
If you want to delete it at a later point,
|
||||||
|
use 'sudo docker exec mailserver rm -R /var/mail/${DOMAIN}/${USER}'"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -e "/var/mail/${DOMAIN}/${USER}" ]]
|
||||||
|
then
|
||||||
|
if rm -R "/var/mail/${DOMAIN}/${USER}"
|
||||||
|
then
|
||||||
|
echo "Mailbox deleted."
|
||||||
|
else
|
||||||
|
echo "Mailbox couldn't be deleted." >&2
|
||||||
|
ERROR=true
|
||||||
|
fi
|
||||||
|
rmdir "/var/mail/${DOMAIN}" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
echo "Mailbox directory '/var/mail/${DOMAIN}/${USER}' did not exist." >&2
|
||||||
|
ERROR=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
${ERROR} && errex 'See the messages above.'
|
||||||
|
done
|
||||||
exit 0
|
exit 0
|
||||||
|
|
|
@ -33,24 +33,21 @@ then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Protect config file with lock to avoid race conditions
|
# Protect config file with lock to avoid race conditions
|
||||||
|
create_lock "$(basename "$0")"
|
||||||
|
|
||||||
touch "${DATABASE}"
|
touch "${DATABASE}"
|
||||||
(
|
if [ -z "${QUOTA}" ]; then
|
||||||
flock -e 200
|
read -r -s "Enter quota (e.g. 10M): " QUOTA
|
||||||
|
echo
|
||||||
|
[[ -z "${QUOTA}" ]] && errex "Quota must not be empty. Use 0 for unlimited quota"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z "${QUOTA}" ]; then
|
# check quota
|
||||||
read -r -s "Enter quota (e.g. 10M): " QUOTA
|
if [[ -n ${QUOTA} ]] && ! echo "${QUOTA}" | grep -qE "^([0-9]+(B|k|M|G|T)|0)\$"
|
||||||
echo
|
then
|
||||||
[[ -z "${QUOTA}" ]] && errex "Quota must not be empty. Use 0 for unlimited quota"
|
usage
|
||||||
fi
|
errex "invalid quota format. e.g. 302M (B (byte), k (kilobyte), M (megabyte), G (gigabyte) or T (terabyte))"
|
||||||
|
fi
|
||||||
# check quota
|
|
||||||
if [[ -n ${QUOTA} ]] && ! echo "${QUOTA}" | grep -qE "^([0-9]+(B|k|M|G|T)|0)\$"
|
|
||||||
then
|
|
||||||
usage
|
|
||||||
errex "invalid quota format. e.g. 302M (B (byte), k (kilobyte), M (megabyte), G (gigabyte) or T (terabyte))"
|
|
||||||
fi
|
|
||||||
|
|
||||||
delquota "${USER}"
|
|
||||||
echo "${USER}:${QUOTA}" >>"${DATABASE}"
|
|
||||||
) 200< "${DATABASE}"
|
|
||||||
|
|
||||||
|
delquota "${USER}"
|
||||||
|
echo "${USER}:${QUOTA}" >>"${DATABASE}"
|
||||||
|
|
|
@ -28,8 +28,7 @@ fi
|
||||||
HASH="$(doveadm pw -s SHA512-CRYPT -u "${USER}" -p "${PASSWD}")"
|
HASH="$(doveadm pw -s SHA512-CRYPT -u "${USER}" -p "${PASSWD}")"
|
||||||
|
|
||||||
# Protect config file with lock to avoid race conditions
|
# Protect config file with lock to avoid race conditions
|
||||||
(
|
touch "${DATABASE}"
|
||||||
flock -e 200
|
create_lock "$(basename "$0")"
|
||||||
grep -qi "^$(escape "${USER}")|" "${DATABASE}" 2>/dev/null || errex "User \"${USER}\" does not exist"
|
grep -qi "^$(escape "${USER}")|" "${DATABASE}" 2>/dev/null || errex "User \"${USER}\" does not exist"
|
||||||
sed -i "s ^""${USER}""|.* ""${USER}""|""${HASH}"" " "${DATABASE}"
|
sed -i "s ^""${USER}""|.* ""${USER}""|""${HASH}"" " "${DATABASE}"
|
||||||
) 200< "${DATABASE}"
|
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
LOG_DATE=$(date +"%Y-%m-%d %H:%M:%S ")
|
LOG_DATE=$(date +"%Y-%m-%d %H:%M:%S ")
|
||||||
_notify 'task' "${LOG_DATE} Start check-for-changes script."
|
_notify 'task' "${LOG_DATE} Start check-for-changes script."
|
||||||
|
|
||||||
# ? --------------------------------------------- Checks
|
SCRIPT_NAME="$(basename "$0")"
|
||||||
|
|
||||||
|
# ? ––––––––––––––––––––––––––––––––––––––––––––– Checks
|
||||||
|
|
||||||
cd /tmp/docker-mailserver || exit 1
|
cd /tmp/docker-mailserver || exit 1
|
||||||
|
|
||||||
|
@ -43,10 +45,17 @@ while true
|
||||||
do
|
do
|
||||||
LOG_DATE=$(date +"%Y-%m-%d %H:%M:%S ")
|
LOG_DATE=$(date +"%Y-%m-%d %H:%M:%S ")
|
||||||
|
|
||||||
|
# Lock configuration while working
|
||||||
|
create_lock "${SCRIPT_NAME}"
|
||||||
|
|
||||||
# get chksum and check it, no need to lock config yet
|
# get chksum and check it, no need to lock config yet
|
||||||
_monitored_files_checksums >"${CHKSUM_FILE}.new"
|
_monitored_files_checksums >"${CHKSUM_FILE}.new"
|
||||||
|
cmp --silent -- "${CHKSUM_FILE}" "${CHKSUM_FILE}.new"
|
||||||
if ! cmp --silent -- "${CHKSUM_FILE}" "${CHKSUM_FILE}.new"
|
# cmp return codes
|
||||||
|
# 0 – files are identical
|
||||||
|
# 1 – files differ
|
||||||
|
# 2 – inaccessible or missing argument
|
||||||
|
if [ $? -eq 1 ]
|
||||||
then
|
then
|
||||||
_notify 'inf' "${LOG_DATE} Change detected"
|
_notify 'inf' "${LOG_DATE} Change detected"
|
||||||
CHANGED=$(grep -Fxvf "${CHKSUM_FILE}" "${CHKSUM_FILE}.new" | sed 's/^[^ ]\+ //')
|
CHANGED=$(grep -Fxvf "${CHKSUM_FILE}" "${CHKSUM_FILE}.new" | sed 's/^[^ ]\+ //')
|
||||||
|
@ -60,178 +69,175 @@ do
|
||||||
# TODO Perform updates below conditionally too --------
|
# TODO Perform updates below conditionally too --------
|
||||||
# Also note that changes are performed in place and are not atomic
|
# Also note that changes are performed in place and are not atomic
|
||||||
# We should fix that and write to temporary files, stop, swap and start
|
# We should fix that and write to temporary files, stop, swap and start
|
||||||
# Lock configuration while working
|
|
||||||
(
|
|
||||||
flock -e 200
|
|
||||||
|
|
||||||
for FILE in ${CHANGED}
|
for FILE in ${CHANGED}
|
||||||
do
|
do
|
||||||
case "${FILE}" in
|
case "${FILE}" in
|
||||||
"/etc/letsencrypt/acme.json" )
|
"/etc/letsencrypt/acme.json" )
|
||||||
for CERTDOMAIN in ${SSL_DOMAIN} ${HOSTNAME} ${DOMAINNAME}
|
for CERTDOMAIN in ${SSL_DOMAIN} ${HOSTNAME} ${DOMAINNAME}
|
||||||
do
|
|
||||||
_extract_certs_from_acme "${CERTDOMAIN}" && break
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
|
|
||||||
* )
|
|
||||||
_notify 'warn' 'File not found for certificate in check_for_changes.sh'
|
|
||||||
;;
|
|
||||||
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# regenerate postix aliases
|
|
||||||
echo "root: ${PM_ADDRESS}" >/etc/aliases
|
|
||||||
if [[ -f /tmp/docker-mailserver/postfix-aliases.cf ]]
|
|
||||||
then
|
|
||||||
cat /tmp/docker-mailserver/postfix-aliases.cf >>/etc/aliases
|
|
||||||
fi
|
|
||||||
postalias /etc/aliases
|
|
||||||
|
|
||||||
# regenerate postfix accounts
|
|
||||||
: >/etc/postfix/vmailbox
|
|
||||||
: >/etc/dovecot/userdb
|
|
||||||
|
|
||||||
if [[ -f /tmp/docker-mailserver/postfix-accounts.cf ]] && [[ ${ENABLE_LDAP} -ne 1 ]]
|
|
||||||
then
|
|
||||||
sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf
|
|
||||||
echo "# WARNING: this file is auto-generated. Modify config/postfix-accounts.cf to edit user list." >/etc/postfix/vmailbox
|
|
||||||
|
|
||||||
# Checking that /tmp/docker-mailserver/postfix-accounts.cf ends with a newline
|
|
||||||
# shellcheck disable=SC1003
|
|
||||||
sed -i -e '$a\' /tmp/docker-mailserver/postfix-accounts.cf
|
|
||||||
chown dovecot:dovecot /etc/dovecot/userdb
|
|
||||||
chmod 640 /etc/dovecot/userdb
|
|
||||||
sed -i -e '/\!include auth-ldap\.conf\.ext/s/^/#/' /etc/dovecot/conf.d/10-auth.conf
|
|
||||||
sed -i -e '/\!include auth-passwdfile\.inc/s/^#//' /etc/dovecot/conf.d/10-auth.conf
|
|
||||||
|
|
||||||
# rebuild relay host
|
|
||||||
if [[ -n ${RELAY_HOST} ]]
|
|
||||||
then
|
|
||||||
# keep old config
|
|
||||||
: >/etc/postfix/sasl_passwd
|
|
||||||
if [[ -n ${SASL_PASSWD} ]]
|
|
||||||
then
|
|
||||||
echo "${SASL_PASSWD}" >>/etc/postfix/sasl_passwd
|
|
||||||
fi
|
|
||||||
|
|
||||||
# add domain-specific auth from config file
|
|
||||||
if [[ -f /tmp/docker-mailserver/postfix-sasl-password.cf ]]
|
|
||||||
then
|
|
||||||
while read -r LINE
|
|
||||||
do
|
|
||||||
if ! grep -q -e "\s*#" <<< "${LINE}"
|
|
||||||
then
|
|
||||||
echo "${LINE}" >>/etc/postfix/sasl_passwd
|
|
||||||
fi
|
|
||||||
done < <(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-sasl-password.cf || true)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# add default relay
|
|
||||||
if [[ -n "${RELAY_USER}" ]] && [[ -n "${RELAY_PASSWORD}" ]]
|
|
||||||
then
|
|
||||||
echo "[${RELAY_HOST}]:${RELAY_PORT} ${RELAY_USER}:${RELAY_PASSWORD}" >>/etc/postfix/sasl_passwd
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# creating users ; 'pass' is encrypted
|
|
||||||
# comments and empty lines are ignored
|
|
||||||
while IFS=$'|' read -r LOGIN PASS USER_ATTRIBUTES
|
|
||||||
do
|
|
||||||
USER=$(echo "${LOGIN}" | cut -d @ -f1)
|
|
||||||
DOMAIN=$(echo "${LOGIN}" | cut -d @ -f2)
|
|
||||||
|
|
||||||
# test if user has a defined quota
|
|
||||||
if [[ -f /tmp/docker-mailserver/dovecot-quotas.cf ]]
|
|
||||||
then
|
|
||||||
declare -a USER_QUOTA
|
|
||||||
IFS=':' ; read -r -a USER_QUOTA < <(grep "${USER}@${DOMAIN}:" -i /tmp/docker-mailserver/dovecot-quotas.cf)
|
|
||||||
unset IFS
|
|
||||||
|
|
||||||
[[ ${#USER_QUOTA[@]} -eq 2 ]] && USER_ATTRIBUTES="${USER_ATTRIBUTES} userdb_quota_rule=*:bytes=${USER_QUOTA[1]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "${LOGIN} ${DOMAIN}/${USER}/" >>/etc/postfix/vmailbox
|
|
||||||
|
|
||||||
# user database for dovecot has the following format:
|
|
||||||
# user:password:uid:gid:(gecos):home:(shell):extra_fields
|
|
||||||
# example :
|
|
||||||
# ${LOGIN}:${PASS}:5000:5000::/var/mail/${DOMAIN}/${USER}::userdb_mail=maildir:/var/mail/${DOMAIN}/${USER}
|
|
||||||
echo "${LOGIN}:${PASS}:5000:5000::/var/mail/${DOMAIN}/${USER}::${USER_ATTRIBUTES}" >>/etc/dovecot/userdb
|
|
||||||
mkdir -p "/var/mail/${DOMAIN}/${USER}"
|
|
||||||
|
|
||||||
if [[ -e /tmp/docker-mailserver/${LOGIN}.dovecot.sieve ]]
|
|
||||||
then
|
|
||||||
cp "/tmp/docker-mailserver/${LOGIN}.dovecot.sieve" "/var/mail/${DOMAIN}/${USER}/.dovecot.sieve"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "${DOMAIN}" >>/tmp/vhost.tmp
|
|
||||||
done < <(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-accounts.cf)
|
|
||||||
fi
|
|
||||||
|
|
||||||
[[ -n ${RELAY_HOST} ]] && _populate_relayhost_map
|
|
||||||
|
|
||||||
|
|
||||||
if [[ -f /etc/postfix/sasl_passwd ]]
|
|
||||||
then
|
|
||||||
chown root:root /etc/postfix/sasl_passwd
|
|
||||||
chmod 0600 /etc/postfix/sasl_passwd
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -f postfix-virtual.cf ]]
|
|
||||||
then
|
|
||||||
# regenerate postfix aliases
|
|
||||||
: >/etc/postfix/virtual
|
|
||||||
: >/etc/postfix/regexp
|
|
||||||
|
|
||||||
if [[ -f /tmp/docker-mailserver/postfix-virtual.cf ]]
|
|
||||||
then
|
|
||||||
cp -f /tmp/docker-mailserver/postfix-virtual.cf /etc/postfix/virtual
|
|
||||||
|
|
||||||
# the `to` seems to be important; don't delete it
|
|
||||||
# shellcheck disable=SC2034
|
|
||||||
while read -r FROM TO
|
|
||||||
do
|
do
|
||||||
UNAME=$(echo "${FROM}" | cut -d @ -f1)
|
_extract_certs_from_acme "${CERTDOMAIN}" && break
|
||||||
DOMAIN=$(echo "${FROM}" | cut -d @ -f2)
|
done
|
||||||
|
;;
|
||||||
|
|
||||||
# if they are equal it means the line looks like: "user1 other@domain.tld"
|
* )
|
||||||
[ "${UNAME}" != "${DOMAIN}" ] && echo "${DOMAIN}" >>/tmp/vhost.tmp
|
_notify 'warn' 'File not found for certificate in check_for_changes.sh'
|
||||||
done < <(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-virtual.cf || true)
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# regenerate postix aliases
|
||||||
|
echo "root: ${PM_ADDRESS}" >/etc/aliases
|
||||||
|
if [[ -f /tmp/docker-mailserver/postfix-aliases.cf ]]
|
||||||
|
then
|
||||||
|
cat /tmp/docker-mailserver/postfix-aliases.cf >>/etc/aliases
|
||||||
|
fi
|
||||||
|
postalias /etc/aliases
|
||||||
|
|
||||||
|
# regenerate postfix accounts
|
||||||
|
: >/etc/postfix/vmailbox
|
||||||
|
: >/etc/dovecot/userdb
|
||||||
|
|
||||||
|
if [[ -f /tmp/docker-mailserver/postfix-accounts.cf ]] && [[ ${ENABLE_LDAP} -ne 1 ]]
|
||||||
|
then
|
||||||
|
sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf
|
||||||
|
echo "# WARNING: this file is auto-generated. Modify config/postfix-accounts.cf to edit user list." >/etc/postfix/vmailbox
|
||||||
|
|
||||||
|
# Checking that /tmp/docker-mailserver/postfix-accounts.cf ends with a newline
|
||||||
|
# shellcheck disable=SC1003
|
||||||
|
sed -i -e '$a\' /tmp/docker-mailserver/postfix-accounts.cf
|
||||||
|
chown dovecot:dovecot /etc/dovecot/userdb
|
||||||
|
chmod 640 /etc/dovecot/userdb
|
||||||
|
sed -i -e '/\!include auth-ldap\.conf\.ext/s/^/#/' /etc/dovecot/conf.d/10-auth.conf
|
||||||
|
sed -i -e '/\!include auth-passwdfile\.inc/s/^#//' /etc/dovecot/conf.d/10-auth.conf
|
||||||
|
|
||||||
|
# rebuild relay host
|
||||||
|
if [[ -n ${RELAY_HOST} ]]
|
||||||
|
then
|
||||||
|
# keep old config
|
||||||
|
: >/etc/postfix/sasl_passwd
|
||||||
|
if [[ -n ${SASL_PASSWD} ]]
|
||||||
|
then
|
||||||
|
echo "${SASL_PASSWD}" >>/etc/postfix/sasl_passwd
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f /tmp/docker-mailserver/postfix-regexp.cf ]]
|
# add domain-specific auth from config file
|
||||||
|
if [[ -f /tmp/docker-mailserver/postfix-sasl-password.cf ]]
|
||||||
then
|
then
|
||||||
cp -f /tmp/docker-mailserver/postfix-regexp.cf /etc/postfix/regexp
|
while read -r LINE
|
||||||
sed -i -e '/^virtual_alias_maps/{
|
do
|
||||||
|
if ! grep -q -e "\s*#" <<< "${LINE}"
|
||||||
|
then
|
||||||
|
echo "${LINE}" >>/etc/postfix/sasl_passwd
|
||||||
|
fi
|
||||||
|
done < <(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-sasl-password.cf || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# add default relay
|
||||||
|
if [[ -n "${RELAY_USER}" ]] && [[ -n "${RELAY_PASSWORD}" ]]
|
||||||
|
then
|
||||||
|
echo "[${RELAY_HOST}]:${RELAY_PORT} ${RELAY_USER}:${RELAY_PASSWORD}" >>/etc/postfix/sasl_passwd
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# creating users ; 'pass' is encrypted
|
||||||
|
# comments and empty lines are ignored
|
||||||
|
while IFS=$'|' read -r LOGIN PASS USER_ATTRIBUTES
|
||||||
|
do
|
||||||
|
USER=$(echo "${LOGIN}" | cut -d @ -f1)
|
||||||
|
DOMAIN=$(echo "${LOGIN}" | cut -d @ -f2)
|
||||||
|
|
||||||
|
# test if user has a defined quota
|
||||||
|
if [[ -f /tmp/docker-mailserver/dovecot-quotas.cf ]]
|
||||||
|
then
|
||||||
|
declare -a USER_QUOTA
|
||||||
|
IFS=':' ; read -r -a USER_QUOTA < <(grep "${USER}@${DOMAIN}:" -i /tmp/docker-mailserver/dovecot-quotas.cf)
|
||||||
|
unset IFS
|
||||||
|
|
||||||
|
[[ ${#USER_QUOTA[@]} -eq 2 ]] && USER_ATTRIBUTES="${USER_ATTRIBUTES} userdb_quota_rule=*:bytes=${USER_QUOTA[1]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${LOGIN} ${DOMAIN}/${USER}/" >>/etc/postfix/vmailbox
|
||||||
|
|
||||||
|
# user database for dovecot has the following format:
|
||||||
|
# user:password:uid:gid:(gecos):home:(shell):extra_fields
|
||||||
|
# example :
|
||||||
|
# ${LOGIN}:${PASS}:5000:5000::/var/mail/${DOMAIN}/${USER}::userdb_mail=maildir:/var/mail/${DOMAIN}/${USER}
|
||||||
|
echo "${LOGIN}:${PASS}:5000:5000::/var/mail/${DOMAIN}/${USER}::${USER_ATTRIBUTES}" >>/etc/dovecot/userdb
|
||||||
|
mkdir -p "/var/mail/${DOMAIN}/${USER}"
|
||||||
|
|
||||||
|
if [[ -e /tmp/docker-mailserver/${LOGIN}.dovecot.sieve ]]
|
||||||
|
then
|
||||||
|
cp "/tmp/docker-mailserver/${LOGIN}.dovecot.sieve" "/var/mail/${DOMAIN}/${USER}/.dovecot.sieve"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${DOMAIN}" >>/tmp/vhost.tmp
|
||||||
|
done < <(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-accounts.cf)
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -n ${RELAY_HOST} ]] && _populate_relayhost_map
|
||||||
|
|
||||||
|
|
||||||
|
if [[ -f /etc/postfix/sasl_passwd ]]
|
||||||
|
then
|
||||||
|
chown root:root /etc/postfix/sasl_passwd
|
||||||
|
chmod 0600 /etc/postfix/sasl_passwd
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -f postfix-virtual.cf ]]
|
||||||
|
then
|
||||||
|
# regenerate postfix aliases
|
||||||
|
: >/etc/postfix/virtual
|
||||||
|
: >/etc/postfix/regexp
|
||||||
|
|
||||||
|
if [[ -f /tmp/docker-mailserver/postfix-virtual.cf ]]
|
||||||
|
then
|
||||||
|
cp -f /tmp/docker-mailserver/postfix-virtual.cf /etc/postfix/virtual
|
||||||
|
|
||||||
|
# the `to` seems to be important; don't delete it
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
while read -r FROM TO
|
||||||
|
do
|
||||||
|
UNAME=$(echo "${FROM}" | cut -d @ -f1)
|
||||||
|
DOMAIN=$(echo "${FROM}" | cut -d @ -f2)
|
||||||
|
|
||||||
|
# if they are equal it means the line looks like: "user1 other@domain.tld"
|
||||||
|
[ "${UNAME}" != "${DOMAIN}" ] && echo "${DOMAIN}" >>/tmp/vhost.tmp
|
||||||
|
done < <(grep -v "^\s*$\|^\s*\#" /tmp/docker-mailserver/postfix-virtual.cf || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -f /tmp/docker-mailserver/postfix-regexp.cf ]]
|
||||||
|
then
|
||||||
|
cp -f /tmp/docker-mailserver/postfix-regexp.cf /etc/postfix/regexp
|
||||||
|
sed -i -e '/^virtual_alias_maps/{
|
||||||
s/ regexp:.*//
|
s/ regexp:.*//
|
||||||
s/$/ regexp:\/etc\/postfix\/regexp/
|
s/$/ regexp:\/etc\/postfix\/regexp/
|
||||||
}' /etc/postfix/main.cf
|
}' /etc/postfix/main.cf
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -f /tmp/vhost.tmp ]]
|
if [[ -f /tmp/vhost.tmp ]]
|
||||||
then
|
then
|
||||||
sort < /tmp/vhost.tmp | uniq >/etc/postfix/vhost
|
sort < /tmp/vhost.tmp | uniq >/etc/postfix/vhost
|
||||||
rm /tmp/vhost.tmp
|
rm /tmp/vhost.tmp
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if find /var/mail -maxdepth 3 -a \( \! -user 5000 -o \! -group 5000 \) | read -r
|
if find /var/mail -maxdepth 3 -a \( \! -user 5000 -o \! -group 5000 \) | read -r
|
||||||
then
|
then
|
||||||
chown -R 5000:5000 /var/mail
|
chown -R 5000:5000 /var/mail
|
||||||
fi
|
fi
|
||||||
|
|
||||||
supervisorctl restart postfix
|
supervisorctl restart postfix
|
||||||
|
|
||||||
# prevent restart of dovecot when smtp_only=1
|
# prevent restart of dovecot when smtp_only=1
|
||||||
[[ ${SMTP_ONLY} -ne 1 ]] && supervisorctl restart dovecot
|
[[ ${SMTP_ONLY} -ne 1 ]] && supervisorctl restart dovecot
|
||||||
) 200<postfix-accounts.cf # end lock
|
|
||||||
|
|
||||||
# mark changes as applied
|
|
||||||
mv "${CHKSUM_FILE}.new" "${CHKSUM_FILE}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# mark changes as applied
|
||||||
|
mv "${CHKSUM_FILE}.new" "${CHKSUM_FILE}"
|
||||||
|
remove_lock "${SCRIPT_NAME}"
|
||||||
|
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,22 @@ function escape
|
||||||
echo "${1//./\\.}"
|
echo "${1//./\\.}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ? --------------------------------------------- IP & CIDR
|
function create_lock
|
||||||
|
{
|
||||||
|
SCRIPT_NAME="$1"
|
||||||
|
LOCK_FILE="/tmp/docker-mailserver/${SCRIPT_NAME}.lock"
|
||||||
|
[[ -e "${LOCK_FILE}" ]] && errex "Lock file ${LOCK_FILE} exists. Another $1 execution is happening. Try again later."
|
||||||
|
trap remove_lock EXIT # This won't work if the script is, for example, check-for-changes.sh which uses a while loop to stay running; you'll need to include a remove_lock call at the end of your logic
|
||||||
|
touch "${LOCK_FILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove_lock
|
||||||
|
{
|
||||||
|
SCRIPT_NAME=${SCRIPT_NAME:-$1}
|
||||||
|
rm -f "/tmp/docker-mailserver/${SCRIPT_NAME}.lock"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ? ––––––––––––––––––––––––––––––––––––––––––––– IP & CIDR
|
||||||
|
|
||||||
function _mask_ip_digit
|
function _mask_ip_digit
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,13 @@
|
||||||
|
|
||||||
SCRIPT="lint.sh"
|
SCRIPT="lint.sh"
|
||||||
|
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
if [[ "$(uname)" == "Darwin" ]]
|
||||||
|
then
|
||||||
|
readlink() {
|
||||||
|
greadlink "${@:+$@}" # Requires coreutils
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
|
||||||
REPO_ROOT="$(realpath "${SCRIPT_DIR}"/../../)"
|
REPO_ROOT="$(realpath "${SCRIPT_DIR}"/../../)"
|
||||||
|
|
||||||
HADOLINT_VERSION=2.4.1
|
HADOLINT_VERSION=2.4.1
|
||||||
|
@ -51,7 +57,7 @@ function __log_success
|
||||||
|
|
||||||
function __in_path
|
function __in_path
|
||||||
{
|
{
|
||||||
command -v "${@}" &>/dev/null && return 0 ; return 1 ;
|
command -v "${@:+$@}" &>/dev/null && return 0 ; return 1 ;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _eclint
|
function _eclint
|
||||||
|
@ -142,4 +148,4 @@ function __main
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
__main "${@}" || exit ${?}
|
__main "${@:+$@}" || exit ${?}
|
||||||
|
|
Loading…
Reference in New Issue