diff --git a/Makefile b/Makefile index 1570855c..f717e39e 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ clean: # remove running and stopped test containers -@ [[ -d config.bak ]] && { rm -rf config ; mv config.bak 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/ # ----------------------------------------------- diff --git a/target/bin/addmailuser b/target/bin/addmailuser index 657f56b8..0a0a7f76 100755 --- a/target/bin/addmailuser +++ b/target/bin/addmailuser @@ -35,31 +35,41 @@ function __usage [[ ${1:-} == 'help' ]] && { __usage ; exit 0 ; } -USER="${1}" +FULL_EMAIL="${1}" shift PASSWD="${*}" -[[ -z ${USER} ]] && { __usage ; errex 'No username specified' ; } -[[ "${USER}" =~ .*\@.* ]] || { __usage ; errex 'Username must include the domain' ; } +[[ -z ${FULL_EMAIL} ]] && { __usage ; errex 'No username specified' ; } +[[ "${FULL_EMAIL}" =~ .*\@.* ]] || { __usage ; errex 'Username must include the domain' ; } # Protect config file with lock to avoid race conditions touch "${DATABASE}" -( - flock -e 200 +create_lock "$(basename "$0")" +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 - then - echo "User '${USER}' already exists." - exit 1 - fi +if [[ -z ${PASSWD} ]] +then + read -r -s -p "Enter Password: " PASSWD + echo + [[ -z ${PASSWD} ]] && errex "Password must not be empty" +fi - if [[ -z ${PASSWD} ]] - then - read -r -s -p "Enter Password: " PASSWD - echo - [[ -z ${PASSWD} ]] && errex "Password must not be empty" - fi +HASH="$(doveadm pw -s SHA512-CRYPT -u "${FULL_EMAIL}" -p "${PASSWD}")" +echo "${FULL_EMAIL}|${HASH}" >> "${DATABASE}" - HASH="$(doveadm pw -s SHA512-CRYPT -u "${USER}" -p "${PASSWD}")" - echo "${USER}|${HASH}" >> "${DATABASE}" -) 200< "${DATABASE}" +USER="${FULL_EMAIL%@*}" +DOMAIN="${FULL_EMAIL#*@}" + +# 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 diff --git a/target/bin/delmailuser b/target/bin/delmailuser index 97c4cb0f..8c2cdbb3 100755 --- a/target/bin/delmailuser +++ b/target/bin/delmailuser @@ -86,81 +86,77 @@ then fi fi -( - flock -e 200 +create_lock "$(basename "$0")" +for EMAIL in "${@}" +do + ERROR=false - for EMAIL in "${@}" - do - ERROR=false + # very simple plausibility check + [[ ${EMAIL} != *@*.* ]] && errex "No valid email address: ${EMAIL}" - # very simple plausibility check - [[ ${EMAIL} != *@*.* ]] && errex "No valid address: ${EMAIL}" + USER="${EMAIL%@*}" + DOMAIN="${EMAIL#*@}" - USER="${EMAIL%@*}" - DOMAIN="${EMAIL#*@}" + # ${EMAIL} must not contain /s and other syntactic characters + UNESCAPED_EMAIL="${EMAIL}" + EMAIL=$(escape "${EMAIL}") - # ${EMAIL} must not contain /s and other syntactic characters - UNESCAPED_EMAIL="${EMAIL}" - EMAIL=$(escape "${EMAIL}") - - if [[ -f ${DATABASE} ]] + if [[ -f ${DATABASE} ]] + then + if ! sed -i "/^${EMAIL}|/d" "${DATABASE}" then - if ! sed -i "/^${EMAIL}|/d" "${DATABASE}" - 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 + echo "${UNESCAPED_EMAIL} couldn't be deleted in ${DATABASE}." >&2 ERROR=true fi + fi - ${ERROR} && errex 'See the messages above.' - done + 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 -) 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 diff --git a/target/bin/setquota b/target/bin/setquota index f222c78c..0c6db6bd 100755 --- a/target/bin/setquota +++ b/target/bin/setquota @@ -33,24 +33,21 @@ then fi # Protect config file with lock to avoid race conditions +create_lock "$(basename "$0")" + touch "${DATABASE}" -( - flock -e 200 +if [ -z "${QUOTA}" ]; then + 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 - read -r -s "Enter quota (e.g. 10M): " QUOTA - echo - [[ -z "${QUOTA}" ]] && errex "Quota must not be empty. Use 0 for unlimited quota" - 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}" +# 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}" diff --git a/target/bin/updatemailuser b/target/bin/updatemailuser index c50171ef..bd9efabd 100755 --- a/target/bin/updatemailuser +++ b/target/bin/updatemailuser @@ -28,8 +28,7 @@ fi HASH="$(doveadm pw -s SHA512-CRYPT -u "${USER}" -p "${PASSWD}")" # Protect config file with lock to avoid race conditions -( - flock -e 200 - grep -qi "^$(escape "${USER}")|" "${DATABASE}" 2>/dev/null || errex "User \"${USER}\" does not exist" - sed -i "s ^""${USER}""|.* ""${USER}""|""${HASH}"" " "${DATABASE}" -) 200< "${DATABASE}" +touch "${DATABASE}" +create_lock "$(basename "$0")" +grep -qi "^$(escape "${USER}")|" "${DATABASE}" 2>/dev/null || errex "User \"${USER}\" does not exist" +sed -i "s ^""${USER}""|.* ""${USER}""|""${HASH}"" " "${DATABASE}" diff --git a/target/scripts/check-for-changes.sh b/target/scripts/check-for-changes.sh index f36137e1..f089a5cc 100755 --- a/target/scripts/check-for-changes.sh +++ b/target/scripts/check-for-changes.sh @@ -6,7 +6,9 @@ LOG_DATE=$(date +"%Y-%m-%d %H:%M:%S ") _notify 'task' "${LOG_DATE} Start check-for-changes script." -# ? --------------------------------------------- Checks +SCRIPT_NAME="$(basename "$0")" + +# ? ––––––––––––––––––––––––––––––––––––––––––––– Checks cd /tmp/docker-mailserver || exit 1 @@ -43,10 +45,17 @@ while true do 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 _monitored_files_checksums >"${CHKSUM_FILE}.new" - - if ! cmp --silent -- "${CHKSUM_FILE}" "${CHKSUM_FILE}.new" + 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 _notify 'inf' "${LOG_DATE} Change detected" CHANGED=$(grep -Fxvf "${CHKSUM_FILE}" "${CHKSUM_FILE}.new" | sed 's/^[^ ]\+ //') @@ -60,178 +69,175 @@ do # TODO Perform updates below conditionally too -------- # 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 - # Lock configuration while working - ( - flock -e 200 - for FILE in ${CHANGED} - do - case "${FILE}" in - "/etc/letsencrypt/acme.json" ) - 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 + for FILE in ${CHANGED} + do + case "${FILE}" in + "/etc/letsencrypt/acme.json" ) + for CERTDOMAIN in ${SSL_DOMAIN} ${HOSTNAME} ${DOMAINNAME} do - UNAME=$(echo "${FROM}" | cut -d @ -f1) - DOMAIN=$(echo "${FROM}" | cut -d @ -f2) + _extract_certs_from_acme "${CERTDOMAIN}" && break + done + ;; - # 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) + * ) + _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 - 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 - cp -f /tmp/docker-mailserver/postfix-regexp.cf /etc/postfix/regexp - sed -i -e '/^virtual_alias_maps/{ + 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 + 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:\/etc\/postfix\/regexp/ }' /etc/postfix/main.cf - fi fi + fi - if [[ -f /tmp/vhost.tmp ]] - then - sort < /tmp/vhost.tmp | uniq >/etc/postfix/vhost - rm /tmp/vhost.tmp - fi + if [[ -f /tmp/vhost.tmp ]] + then + sort < /tmp/vhost.tmp | uniq >/etc/postfix/vhost + rm /tmp/vhost.tmp + fi - if find /var/mail -maxdepth 3 -a \( \! -user 5000 -o \! -group 5000 \) | read -r - then - chown -R 5000:5000 /var/mail - fi + if find /var/mail -maxdepth 3 -a \( \! -user 5000 -o \! -group 5000 \) | read -r + then + chown -R 5000:5000 /var/mail + fi - supervisorctl restart postfix + supervisorctl restart postfix - # prevent restart of dovecot when smtp_only=1 - [[ ${SMTP_ONLY} -ne 1 ]] && supervisorctl restart dovecot - ) 200 /dev/null && pwd )" +if [[ "$(uname)" == "Darwin" ]] +then + readlink() { + greadlink "${@:+$@}" # Requires coreutils + } +fi +SCRIPT_DIR=$(dirname "$(readlink -f "$0")") REPO_ROOT="$(realpath "${SCRIPT_DIR}"/../../)" HADOLINT_VERSION=2.4.1 @@ -51,7 +57,7 @@ function __log_success function __in_path { - command -v "${@}" &>/dev/null && return 0 ; return 1 ; + command -v "${@:+$@}" &>/dev/null && return 0 ; return 1 ; } function _eclint @@ -142,4 +148,4 @@ function __main esac } -__main "${@}" || exit ${?} +__main "${@:+$@}" || exit ${?}