From 5d7783753232a2f964e6ee2603c83881384c6a7a Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 21 Dec 2016 11:34:29 +0100 Subject: [PATCH 01/22] Added travis_wait in config to increase build time to 20min --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4f945c21..d85c94e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ sudo: required services: - docker script: -- make all +- travis_wait make all notifications: slack: secure: TTo1z9nbZCWcIdfPwypubNa3y+pwvfgDGlzEVAGEuK7uuIpmEoAcAUNSSPTnbewDGHnDl8t/ml93MtvP+a+IVuAKytMqF39PHyoZO7aUl9J62V+G75OmnyGjXGJm40pQosCS6LzqoRRYXotl9+fwH568Kf4ifXCrMZX1d+ir7Ww= From c5af8d32a95c025c2e52069fec89f96baec2ede5 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 21 Dec 2016 11:52:51 +0100 Subject: [PATCH 02/22] Changed configuration in 2 different lines --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d85c94e7..e846c4fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,9 @@ sudo: required services: - docker script: -- travis_wait make all +- travis_wait make build-no-cache +- make generate-accounts run fixtures tests clean + notifications: slack: secure: TTo1z9nbZCWcIdfPwypubNa3y+pwvfgDGlzEVAGEuK7uuIpmEoAcAUNSSPTnbewDGHnDl8t/ml93MtvP+a+IVuAKytMqF39PHyoZO7aUl9J62V+G75OmnyGjXGJm40pQosCS6LzqoRRYXotl9+fwH568Kf4ifXCrMZX1d+ir7Ww= From b71a48c33fb61cfd3fc04abf9b601c7f913ffe60 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 21 Dec 2016 12:39:28 +0100 Subject: [PATCH 03/22] Refactored config --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index e846c4fc..ec3bc887 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,12 @@ language: bash sudo: required services: - docker -script: +install: - travis_wait make build-no-cache -- make generate-accounts run fixtures tests clean - +script: +- make generate-accounts run fixtures tests +after_script: +- make clean notifications: slack: secure: TTo1z9nbZCWcIdfPwypubNa3y+pwvfgDGlzEVAGEuK7uuIpmEoAcAUNSSPTnbewDGHnDl8t/ml93MtvP+a+IVuAKytMqF39PHyoZO7aUl9J62V+G75OmnyGjXGJm40pQosCS6LzqoRRYXotl9+fwH568Kf4ifXCrMZX1d+ir7Ww= From 83c0095e003a1ad7106b2e3783b0aa63d4b7aef6 Mon Sep 17 00:00:00 2001 From: Influencer Date: Wed, 21 Dec 2016 14:12:05 -0500 Subject: [PATCH 04/22] Script to update users password, made test and updated setup.sh (#413) * Added script to update users password, made test and updated setup.sh * Moved update password test to tests.bat * Fixed test for update password --- setup.sh | 5 +++++ target/bin/updatemailuser | 29 +++++++++++++++++++++++++++++ test/tests.bats | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100755 target/bin/updatemailuser diff --git a/setup.sh b/setup.sh index bfdc9da4..2050d755 100755 --- a/setup.sh +++ b/setup.sh @@ -43,6 +43,7 @@ SUBCOMMANDS: email: $0 email add + $0 email update $0 email del $0 email list @@ -115,6 +116,10 @@ case $1 in shift _docker_image addmailuser $@ ;; + update) + shift + _docker_image updatemailuser + ;; del) shift _docker_image delmailuser $@ diff --git a/target/bin/updatemailuser b/target/bin/updatemailuser new file mode 100755 index 00000000..b97ced1f --- /dev/null +++ b/target/bin/updatemailuser @@ -0,0 +1,29 @@ +#!/bin/bash + +DATABASE=/tmp/docker-mailserver/postfix-accounts.cf + +function usage { + echo 'Usage: updatemailuser [password]' + exit 1 +} + +if [ ! -z "$1" ]; then + USER=$1 + if [ -e "$DATABASE" ] && [ -z "$(grep $USER -i $DATABASE)" ]; then + echo "User doesn't exist" + exit 1 + fi + if [ ! -z "$2" ]; then + PASS="$2" + else + read -s -p "Enter Password: " PASS + if [ -z "$PASS" ]; then + echo "Password can't be empty" + exit 1 + fi + fi + ENTRY=$(echo "$USER|$(doveadm pw -s SHA512-CRYPT -u "$USER" -p "$PASS")") + sed -i.bak "s%^$USER.*%$ENTRY%g" $DATABASE +else + usage +fi diff --git a/test/tests.bats b/test/tests.bats index 2fa82550..88790db4 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -645,6 +645,27 @@ [ -z "$output" ] } +@test "checking user updating password for user in /tmp/docker-mailserver/postfix-accounts.cf" { + docker exec mail /bin/sh -c "addmailuser user3@domain.tld mypassword" + + initialpass=$(run docker exec mail /bin/sh -c "grep user3@domain.tld -i /tmp/docker-mailserver/postfix-accounts.cf") + sleep 2 + docker exec mail /bin/sh -c "updatemailuser user3@domain.tld mynewpassword" + sleep 2 + changepass=$(run docker exec mail /bin/sh -c "grep user3@domain.tld -i /tmp/docker-mailserver/postfix-accounts.cf") + + if [ initialpass != changepass ]; then + status="0" + else + status="1" + fi + + docker exec mail /bin/sh -c "delmailuser user3@domain.tld" + + [ "$status" -eq 0 ] +} + + @test "checking accounts: listmailuser" { run docker exec mail /bin/sh -c "listmailuser | head -n 1" [ "$status" -eq 0 ] @@ -730,6 +751,17 @@ run ./setup.sh -c mail email list [ "$status" -eq 0 ] } +@test "checking setup.sh: setup.sh email update" { + initialpass=$(cat ./config/postfix-accounts.cf | grep lorem@impsum.org | awk -F '|' '{print $2}') + run ./setup.sh -c mail email update lorem@impsum.org consectetur + updatepass=$(cat ./config/postfix-accounts.cf | grep lorem@impsum.org | awk -F '|' '{print $2}') + if [ initialpass != changepass ]; then + status="0" + else + status="1" + fi + [ "$status" -eq 0 ] +} @test "checking setup.sh: setup.sh email del" { run ./setup.sh -c mail email del lorem@impsum.org [ "$status" -eq 0 ] From 2a15ac619e5d3de81c3ff4d6620c2a3a0f8e4f11 Mon Sep 17 00:00:00 2001 From: Daniele Bellavista Date: Fri, 23 Dec 2016 19:14:02 +0100 Subject: [PATCH 05/22] Secure TLS protocols (#418) --- target/dovecot/10-ssl.conf | 4 ++-- target/postfix/main.cf | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target/dovecot/10-ssl.conf b/target/dovecot/10-ssl.conf index f6937d11..ef1bfb6e 100644 --- a/target/dovecot/10-ssl.conf +++ b/target/dovecot/10-ssl.conf @@ -46,10 +46,10 @@ ssl_key = Date: Fri, 23 Dec 2016 23:56:39 +0100 Subject: [PATCH 06/22] Improved start-mailserver output (#420) * Improved start-mailserver output * Fixed rework to make tests work again * Improved output and updated SSL certs for LE --- Dockerfile | 3 +- Makefile | 4 +- README.md | 5 + target/start-mailserver.sh | 322 ++++++++++++++++++++++--------------- test/tests.bats | 13 +- 5 files changed, 202 insertions(+), 145 deletions(-) diff --git a/Dockerfile b/Dockerfile index f13df638..089c3a11 100644 --- a/Dockerfile +++ b/Dockerfile @@ -117,8 +117,7 @@ RUN sed -i -r "/^#?compress/c\compress\ncopytruncate" /etc/logrotate.conf && \ sed -i -r 's|/var/log/mail|/var/log/mail/mail|g' /etc/logrotate.d/rsyslog # Get LetsEncrypt signed certificate -RUN curl -s https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem > /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem && \ - curl -s https://letsencrypt.org/certs/lets-encrypt-x2-cross-signed.pem > /etc/ssl/certs/lets-encrypt-x2-cross-signed.pem +RUN curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > /etc/ssl/certs/lets-encrypt-x3-cross-signed.pem COPY ./target/bin /usr/local/bin # Start-mailserver script diff --git a/Makefile b/Makefile index 1156a37c..29c4d8d8 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,8 @@ run: -e VIRUSMAILS_DELETE_DELAY=7 \ -e SASL_PASSWD="external-domain.com username:password" \ -e ENABLE_MANAGESIEVE=1 \ - -e PERMIT_DOCKER=host\ + -e PERMIT_DOCKER=host \ + -e DMS_DEBUG=0 \ -h mail.my-domain.com -t $(NAME) sleep 20 docker run -d --name mail_pop3 \ @@ -36,6 +37,7 @@ run: -v "`pwd`/test":/tmp/docker-mailserver-test \ -v "`pwd`/test/config/letsencrypt":/etc/letsencrypt/live \ -e ENABLE_POP3=1 \ + -e DMS_DEBUG=1 \ -e SSL_TYPE=letsencrypt \ -h mail.my-domain.com -t $(NAME) sleep 20 diff --git a/README.md b/README.md index f3d78ae4..f8a48c3b 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,11 @@ Please check [how the container starts](https://github.com/tomav/docker-mailserv Value in **bold** is the default value. +##### DMS_DEBUG + + - **empty** (0) => Debug disabled + - 1 => Enables debug on startup + ##### ENABLE_POP3 - **empty** => POP3 service disabled diff --git a/target/start-mailserver.sh b/target/start-mailserver.sh index 45aef988..778e4a4a 100644 --- a/target/start-mailserver.sh +++ b/target/start-mailserver.sh @@ -8,6 +8,7 @@ ########################################################################## declare -A DEFAULT_VARS DEFAULT_VARS["VIRUSMAILS_DELETE_DELAY"]="${VIRUSMAILS_DELETE_DELAY:="7"}" +DEFAULT_VARS["DMS_DEBUG"]="${DMS_DEBUG:="0"}" ########################################################################## # << DEFAULT VARS ########################################################################## @@ -34,7 +35,8 @@ DEFAULT_VARS["VIRUSMAILS_DELETE_DELAY"]="${VIRUSMAILS_DELETE_DELAY:="7"}" # Implement them in the section-group: {check,setup,fix,start} ########################################################################## function register_functions() { - notify 'taskgrp' 'Registering check,setup,fix,misc and start-daemons functions' + notify 'taskgrp' 'Initializing setup' + notify 'task' 'Registering check,setup,fix,misc and start-daemons functions' ################### >> check funcs @@ -75,7 +77,10 @@ function register_functions() { _register_setup_function "_setup_security_stack" _register_setup_function "_setup_postfix_aliases" _register_setup_function "_setup_postfix_vhost" - _register_setup_function "_setup_postfix_relay_amazon_ses" + + if [ ! -z "$AWS_SES_HOST" -a ! -z "$AWS_SES_USERPASS" ]; then + _register_setup_function "_setup_postfix_relay_amazon_ses" + fi ################### << setup funcs @@ -93,7 +98,8 @@ function register_functions() { ################### >> daemon funcs - _register_start_daemon "_start_daemons_sys" + _register_start_daemon "_start_daemons_cron" + _register_start_daemon "_start_daemons_rsyslog" if [ "$ENABLE_ELK_FORWARDER" = 1 ]; then _register_start_daemon "_start_daemons_filebeat" @@ -191,45 +197,78 @@ function _register_misc_function() { function notify () { c_red="\e[0;31m" c_green="\e[0;32m" + c_brown="\e[0;33m" c_blue="\e[0;34m" c_bold="\033[1m" c_reset="\e[0m" notification_type=$1 notification_msg=$2 + notification_format=$3 + msg="" case "${notification_type}" in - 'inf') - msg="${c_green} * ${c_reset}${notification_msg}" - ;; - 'err') - msg="${c_red} * ${c_reset}${notification_msg}" - ;; - 'warn') - msg="${c_blue} * ${c_reset}${notification_msg}" - ;; - 'task') - msg=" >>>> ${notification_msg}" - ;; 'taskgrp') msg="${c_bold}${notification_msg}${c_reset}" ;; + 'task') + if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then + msg=" ${notification_msg}${c_reset}" + fi + ;; + 'inf') + if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then + msg="${c_green} * ${notification_msg}${c_reset}" + fi + ;; + 'started') + msg="${c_green} ${notification_msg}${c_reset}" + ;; + 'warn') + msg="${c_brown} * ${notification_msg}${c_reset}" + ;; + 'err') + msg="${c_red} * ${notification_msg}${c_reset}" + ;; 'fatal') - msg="${c_bold} >>>> ${notification_msg} <<<<${c_reset}" + msg="${c_red}Error: ${notification_msg}${c_reset}" ;; *) msg="" ;; esac - [[ ! -z "${msg}" ]] && echo -e "${msg}" + case "${notification_format}" in + 'n') + options="-ne" + ;; + *) + options="-e" + ;; + esac + + [[ ! -z "${msg}" ]] && echo $options "${msg}" } function defunc() { - notify 'fatal' "Please fix the failures. Exiting ..." + notify 'fatal' "Please fix your configuration. Exiting..." exit 1 } +function display_startup_daemon() { + $1 &>/dev/null + res=$? + if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then + if [ $res = 0 ]; then + notify 'started' " [ OK ]" + else + echo "false" + notify 'err' " [ FAILED ]" + fi + fi + return $res +} + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # ! CARE --> DON'T CHANGE, except you know exactly what you are doing # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -243,7 +282,7 @@ function defunc() { # Description: Place functions for initial check of container sanity ########################################################################## function check() { - notify 'taskgrp' 'Checking configuration sanity:' + notify 'taskgrp' 'Checking configuration' for _func in "${FUNCS_CHECK[@]}";do $_func [ $? != 0 ] && defunc @@ -253,11 +292,11 @@ function check() { function _check_hostname() { notify "task" "Check that hostname/domainname is provided (no default docker hostname) [$FUNCNAME]" - if ( ! echo $(hostname) | grep -E '^(\S+[.]\S+)$' ); then + if ( ! echo $(hostname) | grep -E '^(\S+[.]\S+)$' > /dev/null ); then notify 'err' "Setting hostname/domainname is required" return 1 else - notify 'inf' "Hostname has been set" + notify 'inf' "Hostname has been set to $(hostname)" return 0 fi } @@ -277,11 +316,9 @@ function _check_environment_variables() { # Description: Place functions for functional configurations here ########################################################################## function setup() { - notify 'taskgrp' 'Setting up the Container:' - + notify 'taskgrp' 'Configuring mail server' for _func in "${FUNCS_SETUP[@]}";do $_func - [ $? != 0 ] && defunc done } @@ -291,14 +328,14 @@ function _setup_default_vars() { for var in ${!DEFAULT_VARS[@]}; do echo "export $var=${DEFAULT_VARS[$var]}" >> /root/.bashrc [ $? != 0 ] && notify 'err' "Unable to set $var=${DEFAULT_VARS[$var]}" && return 1 - notify 'inf' "$var=${DEFAULT_VARS[$var]} set" + notify 'inf' "Set $var=${DEFAULT_VARS[$var]}" done } function _setup_mailname() { notify 'task' 'Setting up Mailname' - echo "Creating /etc/mailname" + notify 'inf' "Creating /etc/mailname" echo $(hostname -d) > /etc/mailname } @@ -317,7 +354,7 @@ function _setup_dovecot() { # Enable Managesieve service by setting the symlink # to the configuration file Dovecot will actually find if [ "$ENABLE_MANAGESIEVE" = 1 ]; then - echo "Sieve management enabled" + notify 'inf' "Sieve management enabled" mv /etc/dovecot/protocols.d/managesieved.protocol.disab /etc/dovecot/protocols.d/managesieved.protocol fi } @@ -327,9 +364,9 @@ function _setup_dovecot_local_user() { echo -n > /etc/postfix/vmailbox echo -n > /etc/dovecot/userdb if [ -f /tmp/docker-mailserver/postfix-accounts.cf -a "$ENABLE_LDAP" != 1 ]; then - echo "Checking file line endings" + notify 'inf' "Checking file line endings" sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf - echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" + notify 'inf' "Regenerating postfix user list" 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 @@ -349,7 +386,7 @@ function _setup_dovecot_local_user() { user=$(echo ${login} | cut -d @ -f1) domain=$(echo ${login} | cut -d @ -f2) # Let's go! - echo "user '${user}' for domain '${domain}' with password '********'" + notify 'inf' "user '${user}' for domain '${domain}' with password '********'" echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox # User database for dovecot has the following format: # user:password:uid:gid:(gecos):home:(shell):extra_fields @@ -370,7 +407,7 @@ function _setup_dovecot_local_user() { echo ${domain} >> /tmp/vhost.tmp done < /tmp/docker-mailserver/postfix-accounts.cf else - echo "==> Warning: 'config/docker-mailserver/postfix-accounts.cf' is not provided. No mail account created." + notify 'warn' "'config/docker-mailserver/postfix-accounts.cf' is not provided. No mail account created." fi } @@ -384,7 +421,7 @@ function _setup_ldap() { /etc/postfix/ldap-${i}.cf done - echo "Configuring dovecot LDAP authentification" + notify 'inf' "Configuring dovecot LDAP authentification" sed -i -e 's|^hosts.*|hosts = '${LDAP_SERVER_HOST:="mail.domain.com"}'|g' \ -e 's|^base.*|base = '${LDAP_SEARCH_BASE:="ou=people,dc=domain,dc=com"}'|g' \ -e 's|^dn\s*=.*|dn = '${LDAP_BIND_DN:="cn=admin,dc=domain,dc=com"}'|g' \ @@ -394,18 +431,18 @@ function _setup_ldap() { # Add domainname to vhost. echo $(hostname -d) >> /tmp/vhost.tmp - echo "Enabling dovecot LDAP authentification" + notify 'inf' "Enabling dovecot LDAP authentification" 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 - echo "Configuring LDAP" + notify 'inf' "Configuring LDAP" [ -f /etc/postfix/ldap-users.cf ] && \ postconf -e "virtual_mailbox_maps = ldap:/etc/postfix/ldap-users.cf" || \ - echo '==> Warning: /etc/postfix/ldap-user.cf not found' + notify 'inf' "==> Warning: /etc/postfix/ldap-user.cf not found" [ -f /etc/postfix/ldap-aliases.cf -a -f /etc/postfix/ldap-groups.cf ] && \ postconf -e "virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf, ldap:/etc/postfix/ldap-groups.cf" || \ - echo '==> Warning: /etc/postfix/ldap-aliases.cf or /etc/postfix/ldap-groups.cf not found' + notify 'inf' "==> Warning: /etc/postfix/ldap-aliases.cf or /etc/postfix/ldap-groups.cf not found" [ ! -f /etc/postfix/sasl/smtpd.conf ] && cat > /etc/postfix/sasl/smtpd.conf << EOF pwcheck_method: saslauthd @@ -415,9 +452,9 @@ return 0 } function _setup_saslauthd() { - notify 'task' 'Setting up Saslauthd' + notify 'task' "Setting up Saslauthd" - echo "Configuring Cyrus SASL" + notify 'inf' "Configuring Cyrus SASL" # checking env vars and setting defaults [ -z $SASLAUTHD_MECHANISMS ] && SASLAUTHD_MECHANISMS=pam [ -z $SASLAUTHD_LDAP_SEARCH_BASE ] && SASLAUTHD_MECHANISMS=pam @@ -426,7 +463,7 @@ function _setup_saslauthd() { ([ -z $SASLAUTHD_LDAP_SSL ] || [ $SASLAUTHD_LDAP_SSL == 0 ]) && SASLAUTHD_LDAP_PROTO='ldap://' || SASLAUTHD_LDAP_PROTO='ldaps://' if [ ! -f /etc/saslauthd.conf ]; then - echo "Creating /etc/saslauthd.conf" + notify 'inf' "Creating /etc/saslauthd.conf" cat > /etc/saslauthd.conf << EOF ldap_servers: ${SASLAUTHD_LDAP_PROTO}${SASLAUTHD_LDAP_SERVER} @@ -477,11 +514,11 @@ function _setup_postfix_aliases() { test "$uname" != "$domain" && echo ${domain} >> /tmp/vhost.tmp done < /tmp/docker-mailserver/postfix-virtual.cf else - echo "==> Warning: 'config/postfix-virtual.cf' is not provided. No mail alias/forward created." + notify 'inf' "Warning 'config/postfix-virtual.cf' is not provided. No mail alias/forward created." fi if [ -f /tmp/docker-mailserver/postfix-regexp.cf ]; then # Copying regexp alias file - echo "Adding regexp alias file postfix-regexp.cf" + notify 'inf' "Adding regexp alias file postfix-regexp.cf" cp -f /tmp/docker-mailserver/postfix-regexp.cf /etc/postfix/regexp sed -i -e '/^virtual_alias_maps/{ s/ regexp:.*// @@ -493,18 +530,18 @@ function _setup_postfix_aliases() { function _setup_dkim() { notify 'task' 'Setting up DKIM' + mkdir -p /etc/opendkim && touch /etc/opendkim/SigningTable + # Check if keys are already available if [ -e "/tmp/docker-mailserver/opendkim/KeyTable" ]; then - mkdir -p /etc/opendkim cp -a /tmp/docker-mailserver/opendkim/* /etc/opendkim/ - echo "DKIM keys added for: `ls -C /etc/opendkim/keys/`" - echo "Changing permissions on /etc/opendkim" - # chown entire directory + notify 'inf' "DKIM keys added for: `ls -C /etc/opendkim/keys/`" + notify 'inf' "Changing permissions on /etc/opendkim" chown -R opendkim:opendkim /etc/opendkim/ # And make sure permissions are right chmod -R 0700 /etc/opendkim/keys/ else - echo "No DKIM key provided. Check the documentation to find how to get your keys." + notify 'warn' "No DKIM key provided. Check the documentation to find how to get your keys." fi } @@ -524,7 +561,7 @@ function _setup_ssl() { KEY="key" fi if [ -n "$KEY" ]; then - echo "Adding $(hostname) SSL certificate" + notify 'inf' "Adding $(hostname) SSL certificate" # Postfix configuration sed -i -r 's~smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem~smtpd_tls_cert_file=/etc/letsencrypt/live/'$(hostname)'/fullchain.pem~g' /etc/postfix/main.cf @@ -534,14 +571,14 @@ function _setup_ssl() { sed -i -e 's~ssl_cert = Warning: 'SASL_PASSWD' is not provided. /etc/postfix/sasl_passwd not created." + notify 'inf' "Warning: 'SASL_PASSWD' is not provided. /etc/postfix/sasl_passwd not created." fi } function _setup_postfix_relay_amazon_ses() { notify 'task' 'Setting up Postfix Relay Amazon SES' - - if [ ! -z "$AWS_SES_HOST" -a ! -z "$AWS_SES_USERPASS" ]; then - if [ -z "$AWS_SES_PORT" ];then - AWS_SES_PORT=25 - fi - echo "Setting up outgoing email via AWS SES host $AWS_SES_HOST:$AWS_SES_PORT" - echo "[$AWS_SES_HOST]:$AWS_SES_PORT $AWS_SES_USERPASS" >> /etc/postfix/sasl_passwd - postconf -e \ - "relayhost = [$AWS_SES_HOST]:$AWS_SES_PORT" \ - "smtp_sasl_auth_enable = yes" \ - "smtp_sasl_security_options = noanonymous" \ - "smtp_sasl_password_maps = texthash:/etc/postfix/sasl_passwd" \ - "smtp_use_tls = yes" \ - "smtp_tls_security_level = encrypt" \ - "smtp_tls_note_starttls_offer = yes" \ - "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt" + if [ -z "$AWS_SES_PORT" ];then + AWS_SES_PORT=25 fi + notify 'inf' "Setting up outgoing email via AWS SES host $AWS_SES_HOST:$AWS_SES_PORT" + echo "[$AWS_SES_HOST]:$AWS_SES_PORT $AWS_SES_USERPASS" >> /etc/postfix/sasl_passwd + postconf -e \ + "relayhost = [$AWS_SES_HOST]:$AWS_SES_PORT" \ + "smtp_sasl_auth_enable = yes" \ + "smtp_sasl_security_options = noanonymous" \ + "smtp_sasl_password_maps = texthash:/etc/postfix/sasl_passwd" \ + "smtp_use_tls = yes" \ + "smtp_tls_security_level = encrypt" \ + "smtp_tls_note_starttls_offer = yes" \ + "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt" } - function _setup_security_stack() { - notify 'task' 'Setting up Security Stack' + notify 'task' "Setting up Security Stack" - echo "Configuring Spamassassin" + notify 'inf' "Configuring Spamassassin" SA_TAG=${SA_TAG:="2.0"} && sed -i -r 's/^\$sa_tag_level_deflt (.*);/\$sa_tag_level_deflt = '$SA_TAG';/g' /etc/amavis/conf.d/20-debian_defaults SA_TAG2=${SA_TAG2:="6.31"} && sed -i -r 's/^\$sa_tag2_level_deflt (.*);/\$sa_tag2_level_deflt = '$SA_TAG2';/g' /etc/amavis/conf.d/20-debian_defaults SA_KILL=${SA_KILL:="6.31"} && sed -i -r 's/^\$sa_kill_level_deflt (.*);/\$sa_kill_level_deflt = '$SA_KILL';/g' /etc/amavis/conf.d/20-debian_defaults test -e /tmp/docker-mailserver/spamassassin-rules.cf && cp /tmp/docker-mailserver/spamassassin-rules.cf /etc/spamassassin/ if [ "$ENABLE_FAIL2BAN" = 1 ]; then - echo "Fail2ban enabled" + notify 'inf' "Fail2ban enabled" test -e /tmp/docker-mailserver/fail2ban-jail.cf && cp /tmp/docker-mailserver/fail2ban-jail.cf /etc/fail2ban/jail.local else # Disable logrotate config for fail2ban if not enabled @@ -737,7 +766,7 @@ function _setup_elk_forwarder() { ELK_PORT=${ELK_PORT:="5044"} ELK_HOST=${ELK_HOST:="elk"} - echo "Enabling log forwarding to ELK ($ELK_HOST:$ELK_PORT)" + notify 'inf' "Enabling log forwarding to ELK ($ELK_HOST:$ELK_PORT)" cat /etc/filebeat/filebeat.yml.tmpl \ | sed "s@\$ELK_HOST@$ELK_HOST@g" \ | sed "s@\$ELK_PORT@$ELK_PORT@g" \ @@ -754,7 +783,7 @@ function _setup_elk_forwarder() { # Description: Place functions for temporary workarounds and fixes here ########################################################################## function fix() { - notify 'taskgrg' "Starting to fix:" + notify 'taskgrg' "Post-configuration checks..." for _func in "${FUNCS_FIX[@]}";do $_func [ $? != 0 ] && defunc @@ -766,10 +795,10 @@ function _fix_var_mail_permissions() { # Fix permissions, but skip this if 3 levels deep the user id is already set if [ `find /var/mail -maxdepth 3 -a \( \! -user 5000 -o \! -group 5000 \) | grep -c .` != 0 ]; then + notify 'inf' "Fixing /var/mail permissions" chown -R 5000:5000 /var/mail - echo "/var/mail permissions fixed" else - echo "Permissions in /var/mail look OK" + notify 'inf' "Permissions in /var/mail look OK" fi } ########################################################################## @@ -783,11 +812,11 @@ function _fix_var_mail_permissions() { # Description: Place functions that do not fit in the sections above here ########################################################################## function misc() { - notify 'taskgrp' 'Starting Misc:' + notify 'taskgrp' 'Starting Misc' for _func in "${FUNCS_MISC[@]}";do $_func - [ $? != 0 ] && defunc + [ $? != 0 ] && defunc done } @@ -796,19 +825,19 @@ function _misc_save_states() { # directory statedir=/var/mail-state if [ "$ONE_DIR" = 1 -a -d $statedir ]; then - echo "Consolidating all state onto $statedir" + notify 'inf' "Consolidating all state onto $statedir" for d in /var/spool/postfix /var/lib/postfix /var/lib/amavis /var/lib/clamav /var/lib/spamassasin /var/lib/fail2ban; do dest=$statedir/`echo $d | sed -e 's/.var.//; s/\//-/g'` if [ -d $dest ]; then - echo " Destination $dest exists, linking $d to it" + notify 'inf' " Destination $dest exists, linking $d to it" rm -rf $d ln -s $dest $d elif [ -d $d ]; then - echo " Moving contents of $d to $dest:" `ls $d` + notify 'inf' " Moving contents of $d to $dest:" `ls $d` mv $d $dest ln -s $dest $d else - echo " Linking $d to $dest" + notify 'inf' " Linking $d to $dest" mkdir -p $dest ln -s $dest $d fi @@ -821,65 +850,66 @@ function _misc_save_states() { # >> Start Daemons ########################################################################## function start_daemons() { - notify 'taskgrp' 'Starting Daemons' + notify 'taskgrp' 'Starting mail server' for _func in "${DAEMONS_START[@]}";do $_func - [ $? != 0 ] && defunc + [ $? != 0 ] && defunc done } -function _start_daemons_sys() { - notify 'task' 'Starting Cron' - cron +function _start_daemons_cron() { + notify 'task' 'Starting cron' 'n' + display_startup_daemon "cron" +} - notify 'task' 'Starting rsyslog' - /etc/init.d/rsyslog start +function _start_daemons_rsyslog() { + notify 'task' 'Starting rsyslog' 'n' + display_startup_daemon "/etc/init.d/rsyslog start" } function _start_daemons_saslauthd() { - notify "task" "Starting saslauthd" - /etc/init.d/saslauthd start + notify 'task' 'Starting saslauthd' 'n' + display_startup_daemon "/etc/init.d/saslauthd start" } function _start_daemons_fail2ban() { - notify 'task' 'Starting fail2ban' + notify 'task' 'Starting fail2ban' 'n' touch /var/log/auth.log # Delete fail2ban.sock that probably was left here after container restart if [ -e /var/run/fail2ban/fail2ban.sock ]; then rm /var/run/fail2ban/fail2ban.sock fi - /etc/init.d/fail2ban start + display_startup_daemon "/etc/init.d/fail2ban start" } function _start_daemons_opendkim() { - notify 'task' 'Starting opendkim' - /etc/init.d/opendkim start + notify 'task' 'Starting opendkim' 'n' + display_startup_daemon "/etc/init.d/opendkim start" } function _start_daemons_opendmarc() { - notify 'task' 'Starting opendmarc' - /etc/init.d/opendmarc start + notify 'task' 'Starting opendmarc' 'n' + display_startup_daemon "/etc/init.d/opendmarc start" } function _start_daemons_postfix() { - notify 'task' 'Starting postfix' - /etc/init.d/postfix start + notify 'task' 'Starting postfix' 'n' + display_startup_daemon "/etc/init.d/postfix start" } function _start_daemons_dovecot() { # Here we are starting sasl and imap, not pop3 because it's disabled by default - notify 'task' "Starting dovecot services" - /usr/sbin/dovecot -c /etc/dovecot/dovecot.conf + notify 'task' 'Starting dovecot services' 'n' + display_startup_daemon "/usr/sbin/dovecot -c /etc/dovecot/dovecot.conf" if [ "$ENABLE_POP3" = 1 ]; then - echo "Starting POP3 services" + notify 'task' 'Starting pop3 services' 'n' mv /etc/dovecot/protocols.d/pop3d.protocol.disab /etc/dovecot/protocols.d/pop3d.protocol - /usr/sbin/dovecot reload + display_startup_daemon "/usr/sbin/dovecot reload" fi if [ -f /tmp/docker-mailserver/dovecot.cf ]; then - echo 'Adding file "dovecot.cf" to the Dovecot configuration' cp /tmp/docker-mailserver/dovecot.cf /etc/dovecot/local.conf /usr/sbin/dovecot reload fi @@ -895,25 +925,24 @@ function _start_daemons_dovecot() { } function _start_daemons_filebeat() { - notify 'task' 'Starting FileBeat' - /etc/init.d/filebeat start + notify 'task' 'Starting filebeat' 'n' + display_startup_daemon "/etc/init.d/filebeat start" } function _start_daemons_fetchmail() { - notify 'task' 'Starting fetchmail' + notify 'task' 'Starting fetchmail' 'n' /usr/local/bin/setup-fetchmail - echo "Fetchmail enabled" - /etc/init.d/fetchmail start + display_startup_daemon "/etc/init.d/fetchmail start" } function _start_daemons_clamav() { - notify 'task' "Starting clamav" - /etc/init.d/clamav-daemon start + notify 'task' 'Starting clamav' 'n' + display_startup_daemon "/etc/init.d/clamav-daemon start" } function _start_daemons_amavis() { - notify 'task' 'Starting Daemon Amavis' - /etc/init.d/amavis start + notify 'task' 'Starting amavis' 'n' + display_startup_daemon "/etc/init.d/amavis start" # @TODO fix: on integration test of mail_with_ldap amavis fails because of: # Starting amavisd: The value of variable $myhostname is "ldap", but should have been @@ -922,7 +951,7 @@ function _start_daemons_amavis() { # in /etc/amavis/conf.d/05-node_id, or fix what uname(3) provides as a host's # network name! - # > temporary workaround to passe integration test + # > temporary workaround to pass integration test return 0 } ########################################################################## @@ -938,6 +967,24 @@ function _start_daemons_amavis() { # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # >> +if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then +notify 'taskgrp' "" +notify 'taskgrp' "#" +notify 'taskgrp' "#" +notify 'taskgrp' "# ENV" +notify 'taskgrp' "#" +notify 'taskgrp' "#" +notify 'taskgrp' "" +printenv +fi + +notify 'taskgrp' "" +notify 'taskgrp' "#" +notify 'taskgrp' "#" +notify 'taskgrp' "# docker-mailserver" +notify 'taskgrp' "#" +notify 'taskgrp' "#" +notify 'taskgrp' "" register_functions @@ -947,7 +994,14 @@ fix misc start_daemons -tail -f /var/log/mail/mail.log +notify 'taskgrp' "" +notify 'taskgrp' "#" +notify 'taskgrp' "# $(hostname) is up and running" +notify 'taskgrp' "#" +notify 'taskgrp' "" + + +tail -fn 0 /var/log/mail/mail.log # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/test/tests.bats b/test/tests.bats index 88790db4..a0811ee1 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -402,13 +402,8 @@ [ "$status" -eq 0 ] } -@test "checking ssl: lets-encrypt-x1-cross-signed.pem is installed" { - run docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem - [ "$status" -eq 0 ] -} - -@test "checking ssl: lets-encrypt-x2-cross-signed.pem is installed" { - run docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x2-cross-signed.pem +@test "checking ssl: lets-encrypt-x3-cross-signed.pem is installed" { + run docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x3-cross-signed.pem [ "$status" -eq 0 ] } @@ -483,7 +478,7 @@ # Getting mail_fail2ban container IP MAIL_FAIL2BAN_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' mail_fail2ban) - # Create a container which will send wront authentications and should banned + # Create a container which will send wrong authentications and should banned docker run --name fail-auth-mailer -e MAIL_FAIL2BAN_IP=$MAIL_FAIL2BAN_IP -v "$(pwd)/test":/tmp/docker-mailserver-test -d $(docker inspect --format '{{ .Config.Image }}' mail) tail -f /var/log/faillog docker exec fail-auth-mailer /bin/sh -c 'nc $MAIL_FAIL2BAN_IP 25 < /tmp/docker-mailserver-test/auth/smtp-auth-login-wrong.txt' @@ -577,6 +572,8 @@ [ "$status" -eq 1 ] run docker exec mail grep -i 'permission denied' /var/log/mail/mail.log [ "$status" -eq 1 ] + run docker exec mail grep -i '(!)connect' /var/log/mail/mail.log + [ "$status" -eq 1 ] run docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail/mail.log [ "$status" -eq 1 ] run docker exec mail_pop3 grep ': error:' /var/log/mail/mail.log From 328661283120da429f33c1b8ddac96428510ac86 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 24 Dec 2016 14:24:29 +0100 Subject: [PATCH 07/22] Should fix #426 (#427) --- target/dovecot/10-ssl.conf | 4 ++-- target/postfix/main.cf | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target/dovecot/10-ssl.conf b/target/dovecot/10-ssl.conf index ef1bfb6e..77f60c5c 100644 --- a/target/dovecot/10-ssl.conf +++ b/target/dovecot/10-ssl.conf @@ -46,10 +46,10 @@ ssl_key = Date: Sat, 24 Dec 2016 14:52:00 +0100 Subject: [PATCH 08/22] Fixes #423 (#428) --- CONTRIBUTING.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..e1b107ad --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,32 @@ +# Contributing + +`docker-mailserver` is OpenSource. That means that you can contribute on enhancements, bug fixing or improving the documentation in the Wiki. + +## Open an issue + +When opening an issue, please provide details use case to let the community reproduce your problem. +Please start the mail server with env `DMS_DEBUG=1` and paste the ouput into the issue. + +## Pull Requests + +#### Project architecture + + ├── config # User: personal configurations + ├── target # Developer: default server configuration, used when building the image + └── test # Developer: integration tests to check that everything keeps working + +#### Development Workflow + +The development workflow is the following: + +- Fork project and clone your fork +- Create a branch using `git checkout -b branch_name` (you can use `issue-xxx` if fixing an existing issue) +- Code :-) +- Add integration tests in `test/tests.bats` +- Use `make` to build image locally and run tests +- Document your improvements +- [Commit](https://help.github.com/articles/closing-issues-via-commit-messages/), push and make a pull-request +- Pull-request is automatically tested on Travis +- When tests are green, your branch is merged into `master` +- `master` is automatically tested on Travis +- Docker builds a new `latest` image From 63cf0f9965ff7c90661baedbb6aff2e9396584fc Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 25 Dec 2016 15:41:02 +0100 Subject: [PATCH 09/22] Disables clamav config in amavis when DISABLE_CLAMAV=1. Fixes #378 (#431) --- Makefile | 1 + target/start-mailserver.sh | 13 +++++++++++++ test/tests.bats | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/Makefile b/Makefile index 29c4d8d8..a8e7b8a8 100644 --- a/Makefile +++ b/Makefile @@ -123,6 +123,7 @@ fixtures: docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-catchall-local.txt" docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/sieve-spam-folder.txt" docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/non-existing-user.txt" + docker exec mail_disabled_clamav /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user.txt" # Wait for mails to be analyzed sleep 10 diff --git a/target/start-mailserver.sh b/target/start-mailserver.sh index 778e4a4a..df24bb1c 100644 --- a/target/start-mailserver.sh +++ b/target/start-mailserver.sh @@ -744,6 +744,19 @@ function _setup_security_stack() { SA_KILL=${SA_KILL:="6.31"} && sed -i -r 's/^\$sa_kill_level_deflt (.*);/\$sa_kill_level_deflt = '$SA_KILL';/g' /etc/amavis/conf.d/20-debian_defaults test -e /tmp/docker-mailserver/spamassassin-rules.cf && cp /tmp/docker-mailserver/spamassassin-rules.cf /etc/spamassassin/ + if [ "$DISABLE_CLAMAV" = 1 ]; then + notify 'inf' "Disabling clamav" + cat > /etc/amavis/conf.d/50-user-security <<- EOM +use strict; +@bypass_virus_checks_maps = (); +$undecipherable_subject_tag = undef; +1; + EOM + else + notify 'inf' "Enabling clamav" + echo "" > /etc/amavis/conf.d/50-user-security + fi + if [ "$ENABLE_FAIL2BAN" = 1 ]; then notify 'inf' "Fail2ban enabled" test -e /tmp/docker-mailserver/fail2ban-jail.cf && cp /tmp/docker-mailserver/fail2ban-jail.cf /etc/fail2ban/jail.local diff --git a/test/tests.bats b/test/tests.bats index a0811ee1..1e3879c5 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -292,6 +292,25 @@ [ "$status" -eq 0 ] } +# +# clamav +# + +@test "checking clamav: should be listed in amavis when enabled" { + run docker exec mail grep -i 'Found secondary av scanner ClamAV-clamscan' /var/log/mail/mail.log + [ "$status" -eq 0 ] +} + +@test "checking clamav: should not be listed in amavis when disabled" { + run docker exec mail_disabled_clamav grep -i 'Found secondary av scanner ClamAV-clamscan' /var/log/mail/mail.log + [ "$status" -eq 1 ] +} + +@test "checking clamav: should not be called when disabled" { + run docker exec mail_disabled_clamav grep -i 'connect to /var/run/clamav/clamd.ctl failed' /var/log/mail/mail.log + [ "$status" -eq 1 ] +} + # # opendkim # From ae9eaae68ed59a4dbb5ff8f0bc37419c84c48b02 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 25 Dec 2016 15:56:35 +0100 Subject: [PATCH 10/22] Empty /etc/aliases to avoid error in log regarding format (we use virtual aliases in this image). (#429) Fixes #425 --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 089c3a11..b9fa1c1b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -102,6 +102,7 @@ RUN sed -i 's/START_DAEMON=no/START_DAEMON=yes/g' /etc/default/fetchmail # Configures Postfix COPY target/postfix/main.cf target/postfix/master.cf /etc/postfix/ +RUN echo "" > /etc/aliases # Configuring Logs RUN sed -i -r "/^#?compress/c\compress\ncopytruncate" /etc/logrotate.conf && \ From df752280e0aad08e0603ac91c6ac58fea0f792b0 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 25 Dec 2016 22:54:37 +0100 Subject: [PATCH 11/22] BREAKING CHANGES: (#432) * Removed DISABLE_AMAVIS * Renamed DISABLE_* to ENABLE_* with 0 as default value. (this must be explicit) * Added missing tests for ENABLE_* * Improved readme and docker-compose example Should fix #256 and #386 --- Makefile | 36 ++++++++---------- README.md | 75 ++++++++++++++++++++++++++------------ docker-compose.yml.dist | 9 ++++- target/start-mailserver.sh | 55 ++++++++++++++++++---------- test/tests.bats | 23 +++++++----- 5 files changed, 124 insertions(+), 74 deletions(-) diff --git a/Makefile b/Makefile index a8e7b8a8..a8022d1c 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,8 @@ run: -v "`pwd`/test/config":/tmp/docker-mailserver \ -v "`pwd`/test":/tmp/docker-mailserver-test \ -v "`pwd`/test/onedir":/var/mail-state \ + -e ENABLE_CLAMAV=1 \ + -e ENABLE_SPAMASSASSIN=1 \ -e SA_TAG=1.0 \ -e SA_TAG2=2.0 \ -e SA_KILL=3.0 \ @@ -31,7 +33,7 @@ run: -e PERMIT_DOCKER=host \ -e DMS_DEBUG=0 \ -h mail.my-domain.com -t $(NAME) - sleep 20 + sleep 15 docker run -d --name mail_pop3 \ -v "`pwd`/test/config":/tmp/docker-mailserver \ -v "`pwd`/test":/tmp/docker-mailserver-test \ @@ -40,40 +42,35 @@ run: -e DMS_DEBUG=1 \ -e SSL_TYPE=letsencrypt \ -h mail.my-domain.com -t $(NAME) - sleep 20 + sleep 15 docker run -d --name mail_smtponly \ -v "`pwd`/test/config":/tmp/docker-mailserver \ -v "`pwd`/test":/tmp/docker-mailserver-test \ -e SMTP_ONLY=1 \ -e PERMIT_DOCKER=network\ -h mail.my-domain.com -t $(NAME) - sleep 20 + sleep 15 docker run -d --name mail_fail2ban \ -v "`pwd`/test/config":/tmp/docker-mailserver \ -v "`pwd`/test":/tmp/docker-mailserver-test \ -e ENABLE_FAIL2BAN=1 \ --cap-add=NET_ADMIN \ -h mail.my-domain.com -t $(NAME) - sleep 20 + sleep 15 docker run -d --name mail_fetchmail \ -v "`pwd`/test/config":/tmp/docker-mailserver \ -v "`pwd`/test":/tmp/docker-mailserver-test \ -e ENABLE_FETCHMAIL=1 \ --cap-add=NET_ADMIN \ -h mail.my-domain.com -t $(NAME) - sleep 20 - docker run -d --name mail_disabled_amavis \ + sleep 15 + docker run -d --name mail_disabled_clamav_spamassassin \ -v "`pwd`/test/config":/tmp/docker-mailserver \ -v "`pwd`/test":/tmp/docker-mailserver-test \ - -e DISABLE_AMAVIS=1 \ + -e ENABLE_CLAMAV=0 \ + -e ENABLE_SPAMASSASSIN=0 \ -h mail.my-domain.com -t $(NAME) - sleep 20 - docker run -d --name mail_disabled_clamav \ - -v "`pwd`/test/config":/tmp/docker-mailserver \ - -v "`pwd`/test":/tmp/docker-mailserver-test \ - -e DISABLE_CLAMAV=1 \ - -h mail.my-domain.com -t $(NAME) - sleep 20 + sleep 15 docker run -d --name mail_manual_ssl \ -v "`pwd`/test/config":/tmp/docker-mailserver \ -v "`pwd`/test":/tmp/docker-mailserver-test \ @@ -81,11 +78,11 @@ run: -e SSL_CERT_PATH=/tmp/docker-mailserver/letsencrypt/mail.my-domain.com/fullchain.pem \ -e SSL_KEY_PATH=/tmp/docker-mailserver/letsencrypt/mail.my-domain.com/privkey.pem \ -h mail.my-domain.com -t $(NAME) - sleep 20 + sleep 15 docker run -d --name ldap_for_mail \ -e LDAP_DOMAIN="localhost.localdomain" \ -h mail.my-domain.com -t ldap - sleep 20 + sleep 15 docker run -d --name mail_with_ldap \ -v "`pwd`/test/config":/tmp/docker-mailserver \ -v "`pwd`/test":/tmp/docker-mailserver-test \ @@ -103,7 +100,7 @@ run: --link ldap_for_mail:ldap \ -h mail.my-domain.com -t $(NAME) # Wait for containers to fully start - sleep 20 + sleep 15 fixtures: cp config/postfix-accounts.cf config/postfix-accounts.cf.bak @@ -123,7 +120,7 @@ fixtures: docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-catchall-local.txt" docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/sieve-spam-folder.txt" docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/non-existing-user.txt" - docker exec mail_disabled_clamav /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user.txt" + docker exec mail_disabled_clamav_spamassassin /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user.txt" # Wait for mails to be analyzed sleep 10 @@ -140,8 +137,7 @@ clean: mail_fail2ban \ mail_fetchmail \ fail-auth-mailer \ - mail_disabled_amavis \ - mail_disabled_clamav \ + mail_disabled_clamav_spamassassin \ mail_manual_ssl \ ldap_for_mail \ mail_with_ldap diff --git a/README.md b/README.md index f8a48c3b..1788669e 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Includes: - fetchmail - basic [sieve support](https://github.com/tomav/docker-mailserver/wiki/Configure-Sieve-filters) using dovecot - [LetsEncrypt](https://letsencrypt.org/) and self-signed certificates +- persistent data and state (but think about backups!) - [integration tests](https://travis-ci.org/tomav/docker-mailserver) - [automated builds on docker hub](https://hub.docker.com/r/tvial/docker-mailserver/) @@ -42,23 +43,33 @@ version: '2' services: mail: - image: tvial/docker-mailserver:latest - # build: . + image: tvial/docker-mailserver:v2.1 hostname: mail domainname: domain.com container_name: mail ports: - - "25:25" - - "143:143" - - "587:587" - - "993:993" + - "25:25" + - "143:143" + - "587:587" + - "993:993" volumes: - - maildata:/var/mail - - ./config/:/tmp/docker-mailserver/ + - maildata:/var/mail + - mailstate:/var/mail-state + - ./config/:/tmp/docker-mailserver/ + environment: + - ENABLE_SPAMASSASSIN=1 + - ENABLE_CLAMAV=1 + - ENABLE_FAIL2BAN=1 + - ONE_DIR=1 + - DMS_DEBUG=0 + cap_add: + - NET_ADMIN volumes: maildata: driver: local + mailstate: + driver: local ``` #### Create your mail accounts @@ -95,9 +106,37 @@ Value in **bold** is the default value. ##### DMS_DEBUG - - **empty** (0) => Debug disabled + - **0** => Debug disabled - 1 => Enables debug on startup +#### ENABLE_CLAMAV + + - **0** => Clamav is disabled + - 1 => Clamav is enabled + +#### ENABLE_SPAMASSASSIN + + - **0** => Spamassassin is disabled + - 1 => Spamassassin is enabled + +##### SA_TAG + + - **2.0** => add spam info headers if at, or above that level + +Note: this spamassassin setting needs `ENABLE_SPAMASSASSIN=1` + +##### SA_TAG2 + + - **6.31** => add 'spam detected' headers at that level + +Note: this spamassassin setting needs `ENABLE_SPAMASSASSIN=1` + +##### SA_KILL + + - **6.31** => triggers spam evasive actions + +Note: this spamassassin setting needs `ENABLE_SPAMASSASSIN=1` + ##### ENABLE_POP3 - **empty** => POP3 service disabled @@ -105,7 +144,7 @@ Value in **bold** is the default value. ##### ENABLE_FAIL2BAN - - **empty** => fail2ban service disabled + - **0** => fail2ban service disabled - 1 => Enables fail2ban service If you enable Fail2Ban, don't forget to add the following lines to your `docker-compose.yml`: @@ -121,7 +160,7 @@ Otherwise, `iptables` won't be able to ban IPs. - 1 => Enables Managesieve on port 4190 ##### ENABLE_FETCHMAIL - - **empty** => `fetchmail` disabled + - **0** => `fetchmail` disabled - 1 => `fetchmail` enabled ##### ENABLE_LDAP @@ -158,21 +197,9 @@ Otherwise, `iptables` won't be able to ban IPs. - **empty** => postmaster@domain.com - => Specify the postmaster address -##### SA_TAG - - - **2.0** => add spam info headers if at, or above that level - -##### SA_TAG2 - - - **6.31** => add 'spam detected' headers at that level - -##### SA_KILL - - - **6.31** => triggers spam evasive actions - ##### ENABLE_SASLAUTHD - - **empty** => `saslauthd` is disabled + - **0** => `saslauthd` is disabled - 1 => `saslauthd` is enabled ##### SASLAUTHD_MECHANISMS diff --git a/docker-compose.yml.dist b/docker-compose.yml.dist index 4eb13770..0666438a 100644 --- a/docker-compose.yml.dist +++ b/docker-compose.yml.dist @@ -2,7 +2,7 @@ version: '2' services: mail: - image: tvial/docker-mailserver:v2 + image: tvial/docker-mailserver:v2.1 hostname: mail domainname: domain.com container_name: mail @@ -13,12 +13,19 @@ services: - "993:993" volumes: - maildata:/var/mail + - mailstate:/var/mail-state - ./config/:/tmp/docker-mailserver/ environment: + - ENABLE_SPAMASSASSIN=1 + - ENABLE_CLAMAV=1 - ENABLE_FAIL2BAN=1 + - ONE_DIR=1 + - DMS_DEBUG=0 cap_add: - NET_ADMIN volumes: maildata: driver: local + mailstate: + driver: local diff --git a/target/start-mailserver.sh b/target/start-mailserver.sh index df24bb1c..cb7afb49 100644 --- a/target/start-mailserver.sh +++ b/target/start-mailserver.sh @@ -7,6 +7,13 @@ # Example: DEFAULT_VARS["KEY"]="VALUE" ########################################################################## declare -A DEFAULT_VARS +DEFAULT_VARS["ENABLE_CLAMAV"]="${ENABLE_CLAMAV:="0"}" +DEFAULT_VARS["ENABLE_SPAMASSASSIN"]="${ENABLE_SPAMASSASSIN:="0"}" +DEFAULT_VARS["ENABLE_FAIL2BAN"]="${ENABLE_FAIL2BAN:="0"}" +DEFAULT_VARS["ENABLE_MANAGESIEVE"]="${ENABLE_MANAGESIEVE:="0"}" +DEFAULT_VARS["ENABLE_FETCHMAIL"]="${ENABLE_FETCHMAIL:="0"}" +DEFAULT_VARS["ENABLE_LDAP"]="${ENABLE_LDAP:="0"}" +DEFAULT_VARS["ENABLE_SASLAUTHD"]="${ENABLE_SASLAUTHD:="0"}" DEFAULT_VARS["VIRUSMAILS_DELETE_DELAY"]="${VIRUSMAILS_DELETE_DELAY:="7"}" DEFAULT_VARS["DMS_DEBUG"]="${DMS_DEBUG:="0"}" ########################################################################## @@ -127,13 +134,11 @@ function register_functions() { _register_start_daemon "_start_daemons_fetchmail" fi - if ! [ "$DISABLE_CLAMAV" = 1 ]; then + if [ "$ENABLE_CLAMAV" = 1 ]; then _register_start_daemon "_start_daemons_clamav" fi - if ! [ "$DISABLE_AMAVIS" = 1 ]; then - _register_start_daemon "_start_daemons_amavis" - fi + _register_start_daemon "_start_daemons_amavis" ################### << daemon funcs } ########################################################################## @@ -738,25 +743,35 @@ function _setup_postfix_relay_amazon_ses() { function _setup_security_stack() { notify 'task' "Setting up Security Stack" - notify 'inf' "Configuring Spamassassin" - SA_TAG=${SA_TAG:="2.0"} && sed -i -r 's/^\$sa_tag_level_deflt (.*);/\$sa_tag_level_deflt = '$SA_TAG';/g' /etc/amavis/conf.d/20-debian_defaults - SA_TAG2=${SA_TAG2:="6.31"} && sed -i -r 's/^\$sa_tag2_level_deflt (.*);/\$sa_tag2_level_deflt = '$SA_TAG2';/g' /etc/amavis/conf.d/20-debian_defaults - SA_KILL=${SA_KILL:="6.31"} && sed -i -r 's/^\$sa_kill_level_deflt (.*);/\$sa_kill_level_deflt = '$SA_KILL';/g' /etc/amavis/conf.d/20-debian_defaults - test -e /tmp/docker-mailserver/spamassassin-rules.cf && cp /tmp/docker-mailserver/spamassassin-rules.cf /etc/spamassassin/ + # recreate auto-generated file + dms_amavis_file="/etc/amavis/conf.d/51-dms_auto_generated" + echo "# WARNING: this file is auto-generated." > $dms_amavis_file + echo "use strict;" >> $dms_amavis_file - if [ "$DISABLE_CLAMAV" = 1 ]; then - notify 'inf' "Disabling clamav" - cat > /etc/amavis/conf.d/50-user-security <<- EOM -use strict; -@bypass_virus_checks_maps = (); -$undecipherable_subject_tag = undef; -1; - EOM - else - notify 'inf' "Enabling clamav" - echo "" > /etc/amavis/conf.d/50-user-security + # Spamassassin + if [ "$ENABLE_SPAMASSASSIN" = 0 ]; then + notify 'warn' "Spamassassin is disabled. You can enable it with 'ENABLE_SPAMASSASSIN=1'" + echo "@bypass_spam_checks_maps = (1);" >> $dms_amavis_file + elif [ "$ENABLE_SPAMASSASSIN" = 1 ]; then + notify 'inf' "Enabling and configuring spamassassin" + SA_TAG=${SA_TAG:="2.0"} && sed -i -r 's/^\$sa_tag_level_deflt (.*);/\$sa_tag_level_deflt = '$SA_TAG';/g' /etc/amavis/conf.d/20-debian_defaults + SA_TAG2=${SA_TAG2:="6.31"} && sed -i -r 's/^\$sa_tag2_level_deflt (.*);/\$sa_tag2_level_deflt = '$SA_TAG2';/g' /etc/amavis/conf.d/20-debian_defaults + SA_KILL=${SA_KILL:="6.31"} && sed -i -r 's/^\$sa_kill_level_deflt (.*);/\$sa_kill_level_deflt = '$SA_KILL';/g' /etc/amavis/conf.d/20-debian_defaults + test -e /tmp/docker-mailserver/spamassassin-rules.cf && cp /tmp/docker-mailserver/spamassassin-rules.cf /etc/spamassassin/ fi + # Clamav + if [ "$ENABLE_CLAMAV" = 0 ]; then + notify 'warn' "Clamav is disabled. You can enable it with 'ENABLE_CLAMAV=1'" + echo "@bypass_virus_checks_maps = (1);" >> $dms_amavis_file + elif [ "$ENABLE_CLAMAV" = 1 ]; then + notify 'inf' "Enabling clamav" + fi + + echo "1; # ensure a defined return" >> $dms_amavis_file + + + # Fail2ban if [ "$ENABLE_FAIL2BAN" = 1 ]; then notify 'inf' "Fail2ban enabled" test -e /tmp/docker-mailserver/fail2ban-jail.cf && cp /tmp/docker-mailserver/fail2ban-jail.cf /etc/fail2ban/jail.local diff --git a/test/tests.bats b/test/tests.bats index 1e3879c5..c9cd111a 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -56,13 +56,8 @@ [ "$status" -eq 0 ] } -@test "checking process: amavis (amavis disabled by DISABLE_AMAVIS)" { - run docker exec mail_disabled_amavis /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/amavisd-new'" - [ "$status" -eq 1 ] -} - -@test "checking process: clamav (clamav disabled by DISABLE_CLAMAV)" { - run docker exec mail_disabled_clamav /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/clamd'" +@test "checking process: clamav (clamav disabled by ENABLED_CLAMAV=0)" { + run docker exec mail_disabled_clamav_spamassassin /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/clamd'" [ "$status" -eq 1 ] } @@ -274,6 +269,16 @@ # spamassassin # +@test "checking spamassassin: should be listed in amavis when enabled" { + run docker exec mail /bin/sh -c "grep -i 'ANTI-SPAM-SA code' /var/log/mail/mail.log | grep 'NOT loaded'" + [ "$status" -eq 1 ] +} + +@test "checking spamassassin: should not be listed in amavis when disabled" { + run docker exec mail_disabled_clamav_spamassassin /bin/sh -c "grep -i 'ANTI-SPAM-SA code' /var/log/mail/mail.log | grep 'NOT loaded'" + [ "$status" -eq 0 ] +} + @test "checking spamassassin: docker env variables are set correctly (default)" { run docker exec mail_pop3 /bin/sh -c "grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'" [ "$status" -eq 0 ] @@ -302,12 +307,12 @@ } @test "checking clamav: should not be listed in amavis when disabled" { - run docker exec mail_disabled_clamav grep -i 'Found secondary av scanner ClamAV-clamscan' /var/log/mail/mail.log + run docker exec mail_disabled_clamav_spamassassin grep -i 'Found secondary av scanner ClamAV-clamscan' /var/log/mail/mail.log [ "$status" -eq 1 ] } @test "checking clamav: should not be called when disabled" { - run docker exec mail_disabled_clamav grep -i 'connect to /var/run/clamav/clamd.ctl failed' /var/log/mail/mail.log + run docker exec mail_disabled_clamav_spamassassin grep -i 'connect to /var/run/clamav/clamd.ctl failed' /var/log/mail/mail.log [ "$status" -eq 1 ] } From 03a0c92e6fb2387454129193701090ce42472dc2 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 25 Dec 2016 23:10:06 +0100 Subject: [PATCH 12/22] Fixed docker version from "v2.1" to "2.1" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1788669e..555eccb5 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ version: '2' services: mail: - image: tvial/docker-mailserver:v2.1 + image: tvial/docker-mailserver:2.1 hostname: mail domainname: domain.com container_name: mail From 40ae75112b205272a007f722b45c4309faedbf2b Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 27 Dec 2016 15:55:41 +0100 Subject: [PATCH 13/22] Fixed #437 setting ENABLE_POP3 to 0 by default (#438) --- target/start-mailserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/target/start-mailserver.sh b/target/start-mailserver.sh index cb7afb49..a7862537 100644 --- a/target/start-mailserver.sh +++ b/target/start-mailserver.sh @@ -9,6 +9,7 @@ declare -A DEFAULT_VARS DEFAULT_VARS["ENABLE_CLAMAV"]="${ENABLE_CLAMAV:="0"}" DEFAULT_VARS["ENABLE_SPAMASSASSIN"]="${ENABLE_SPAMASSASSIN:="0"}" +DEFAULT_VARS["ENABLE_POP3"]="${ENABLE_POP3:="0"}" DEFAULT_VARS["ENABLE_FAIL2BAN"]="${ENABLE_FAIL2BAN:="0"}" DEFAULT_VARS["ENABLE_MANAGESIEVE"]="${ENABLE_MANAGESIEVE:="0"}" DEFAULT_VARS["ENABLE_FETCHMAIL"]="${ENABLE_FETCHMAIL:="0"}" From de70a155f2a78744360f0c055751081d46fd457a Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 27 Dec 2016 16:09:16 +0100 Subject: [PATCH 14/22] Fixed Issue #437 (#439) * Also fixed SMTP_ONLY --- target/start-mailserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/target/start-mailserver.sh b/target/start-mailserver.sh index a7862537..c7fc4b7b 100644 --- a/target/start-mailserver.sh +++ b/target/start-mailserver.sh @@ -15,6 +15,7 @@ DEFAULT_VARS["ENABLE_MANAGESIEVE"]="${ENABLE_MANAGESIEVE:="0"}" DEFAULT_VARS["ENABLE_FETCHMAIL"]="${ENABLE_FETCHMAIL:="0"}" DEFAULT_VARS["ENABLE_LDAP"]="${ENABLE_LDAP:="0"}" DEFAULT_VARS["ENABLE_SASLAUTHD"]="${ENABLE_SASLAUTHD:="0"}" +DEFAULT_VARS["SMTP_ONLY"]="${SMTP_ONLY:="0"}" DEFAULT_VARS["VIRUSMAILS_DELETE_DELAY"]="${VIRUSMAILS_DELETE_DELAY:="7"}" DEFAULT_VARS["DMS_DEBUG"]="${DMS_DEBUG:="0"}" ########################################################################## From 461c88e6aee0240281389519a3fa0687a53e024a Mon Sep 17 00:00:00 2001 From: Wolfgang Ocker Date: Fri, 30 Dec 2016 20:06:44 +0100 Subject: [PATCH 15/22] Fix mailuser tools (#441) * Add some checks for user name matching in mail user scripts * Fix user matching problems in mail user scripts ** fix matching problems at several places: "delmailuser a@example.com" deletes also user "aa@example.com" "delmailuser a@sub.example.com" deletes also user "a@sub-example.com" ** similar problems when inserting ** refactor and clean up --- target/bin/addmailuser | 51 +++++++++++++++++++++------------------ target/bin/delmailuser | 34 +++++++++++++++----------- target/bin/listmailuser | 21 +++++++--------- target/bin/updatemailuser | 48 ++++++++++++++++++------------------ test/tests.bats | 39 +++++++++++++++++++++++------- 5 files changed, 109 insertions(+), 84 deletions(-) diff --git a/target/bin/addmailuser b/target/bin/addmailuser index f6a29ec6..c9e83d9c 100755 --- a/target/bin/addmailuser +++ b/target/bin/addmailuser @@ -1,29 +1,32 @@ -#!/bin/bash +#! /bin/bash -DATABASE=/tmp/docker-mailserver/postfix-accounts.cf +DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf} -function usage { - echo 'Usage: addmailuser [password]' - exit 1 +USER="$1" +PASSWD="$2" + +usage() { + echo "Usage: addmailuser []" } -if [ ! -z "$1" ]; then - USER=$1 - if [ -e "$DATABASE" ] && [ ! -z "$(grep $USER -i $DATABASE)" ]; then - echo "User already exists" - exit 1 - fi - if [ ! -z "$2" ]; then - PASS="$2" - else - read -s -p "Enter Password: " PASS - if [ -z "$PASS" ]; then - echo "Password can't be empty" - exit 1 - fi - fi - ENTRY=$(echo "$USER|$(doveadm pw -s SHA512-CRYPT -u "$USER" -p "$PASS")") - echo "$ENTRY" >> $DATABASE -else - usage +errex() { + echo "$@" 1>&2 + exit 1 +} + +escape() { + echo "${1//./\\.}" +} + +[ -z "$USER" ] && { usage; errex "no username specified"; } + +grep -qi "^$(escape "$USER")|" $DATABASE 2>/dev/null && + errex "User \"$USER\" already exists" + +if [ -z "$PASSWD" ]; then + read -s -p "Enter Password: " PASSWD + echo + [ -z "$PASSWD" ] && errex "Password must not be empty" fi + +echo "$USER|$(doveadm pw -s SHA512-CRYPT -u "$USER" -p "$PASSWD")" >>$DATABASE diff --git a/target/bin/delmailuser b/target/bin/delmailuser index 9638b026..e0d5762d 100755 --- a/target/bin/delmailuser +++ b/target/bin/delmailuser @@ -1,18 +1,24 @@ -#!/bin/bash +#! /bin/bash -DATABASE=/tmp/docker-mailserver/postfix-accounts.cf +DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf} -function usage { - echo "Usage: delmailuser " - exit 1 +USER="$1" + +usage() { + echo "Usage: delmailuser " } -if [ ! -z "$1" ]; then - USER=$1 - if [ -f "$DATABASE" ]; then - ENTRIES=$(grep "$USER" -vi $DATABASE) - echo "$ENTRIES" > $DATABASE - fi -else - usage -fi +errex() { + echo "$@" 1>&2 + exit 1 +} + +escape() { + echo "${1//./\\.}" +} + +[ -z "$USER" ] && { usage; errex "No user specifed"; } +[ -s "$DATABASE" ] || exit 0 + +# XXX $USER must not contain /s and other syntactic characters +sed -i "/^$(escape "$USER")|/d" $DATABASE diff --git a/target/bin/listmailuser b/target/bin/listmailuser index 0004b547..04352a5d 100755 --- a/target/bin/listmailuser +++ b/target/bin/listmailuser @@ -1,16 +1,13 @@ -#! /bin/sh +#! /bin/bash -DATABASE=/tmp/docker-mailserver/postfix-accounts.cf +DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf} -if [ ! -f "$DATABASE" ]; then - echo "The configuration file 'postfix-accounts.cf' doesn't exist. Until now no email addresses have been added." - exit 1 -fi +errex() { + echo "$@" 1>&2 + exit 1 +} -if [ ! -s "$DATABASE" ]; then - echo "No email addresses have been added." - exit 1 -fi - -cat "$DATABASE" | awk -F '|' '{print $1}' +[ -f $DATABASE ] || errex "No postfix-accounts.cf file" +[ -s $DATABASE ] || errex "Empty postfix-accounts.cf - no users have been added" +awk -F '|' '{ print $1; }' $DATABASE diff --git a/target/bin/updatemailuser b/target/bin/updatemailuser index b97ced1f..a302891c 100755 --- a/target/bin/updatemailuser +++ b/target/bin/updatemailuser @@ -1,29 +1,27 @@ -#!/bin/bash +#! /bin/bash -DATABASE=/tmp/docker-mailserver/postfix-accounts.cf +DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf} -function usage { - echo 'Usage: updatemailuser [password]' - exit 1 +USER="$1" +PASSWD="$2" + +usage() { + echo "Usage: updatemailuser [password]" } -if [ ! -z "$1" ]; then - USER=$1 - if [ -e "$DATABASE" ] && [ -z "$(grep $USER -i $DATABASE)" ]; then - echo "User doesn't exist" - exit 1 - fi - if [ ! -z "$2" ]; then - PASS="$2" - else - read -s -p "Enter Password: " PASS - if [ -z "$PASS" ]; then - echo "Password can't be empty" - exit 1 - fi - fi - ENTRY=$(echo "$USER|$(doveadm pw -s SHA512-CRYPT -u "$USER" -p "$PASS")") - sed -i.bak "s%^$USER.*%$ENTRY%g" $DATABASE -else - usage -fi +errex() { + echo "$@" 1>&2 + exit 1 +} + +escape() { + echo "${1//./\\.}" +} + +[ -z "$USER" ] && { usage; errex "no username specified"; } + +grep -qi "^$(escape "$USER")|" $DATABASE 2>/dev/null || + errex "User \"$USER\" does not exist" + +delmailuser "$USER" +addmailuser "$USER" "$PASSWD" diff --git a/test/tests.bats b/test/tests.bats index c9cd111a..d1beb76e 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -565,7 +565,7 @@ } @test "checking amavis: VIRUSMAILS_DELETE_DELAY override works as expected" { - run docker run -ti --rm -e VIRUSMAILS_DELETE_DELAY=2 `docker inspect --format '{{ .Config.Image }}' mail` /bin/bash -c 'echo $VIRUSMAILS_DELETE_DELAY | grep 2' + run docker run -ti --rm -e VIRUSMAILS_DELETE_DELAY=2 `docker inspect --format '{{ .Config.Image }}' mail` /bin/bash -c 'echo $VIRUSMAILS_DELETE_DELAY | grep 2' [ "$status" -eq 0 ] } @@ -653,27 +653,47 @@ @test "checking accounts: user3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf" { docker exec mail /bin/sh -c "addmailuser user3@domain.tld mypassword" - run docker exec mail /bin/sh -c "grep user3@domain.tld -i /tmp/docker-mailserver/postfix-accounts.cf" + run docker exec mail /bin/sh -c "grep '^user3@domain\.tld|' -i /tmp/docker-mailserver/postfix-accounts.cf" [ "$status" -eq 0 ] [ ! -z "$output" ] } -@test "checking accounts: user3 should have been removed from /tmp/docker-mailserver/postfix-accounts.cf" { +@test "checking accounts: auser3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf" { + docker exec mail /bin/sh -c "addmailuser auser3@domain.tld mypassword" + + run docker exec mail /bin/sh -c "grep '^auser3@domain\.tld|' -i /tmp/docker-mailserver/postfix-accounts.cf" + [ "$status" -eq 0 ] + [ ! -z "$output" ] +} + +@test "checking accounts: a.ser3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf" { + docker exec mail /bin/sh -c "addmailuser a.ser3@domain.tld mypassword" + + run docker exec mail /bin/sh -c "grep '^a\.ser3@domain\.tld|' -i /tmp/docker-mailserver/postfix-accounts.cf" + [ "$status" -eq 0 ] + [ ! -z "$output" ] +} + +@test "checking accounts: user3 should have been removed from /tmp/docker-mailserver/postfix-accounts.cf but not auser3" { docker exec mail /bin/sh -c "delmailuser user3@domain.tld" - run docker exec mail /bin/sh -c "grep user3@domain.tld -i /tmp/docker-mailserver/postfix-accounts.cf" + run docker exec mail /bin/sh -c "grep '^user3@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf" [ "$status" -eq 1 ] [ -z "$output" ] + + run docker exec mail /bin/sh -c "grep '^auser3@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf" + [ "$status" -eq 0 ] + [ ! -z "$output" ] } @test "checking user updating password for user in /tmp/docker-mailserver/postfix-accounts.cf" { - docker exec mail /bin/sh -c "addmailuser user3@domain.tld mypassword" + docker exec mail /bin/sh -c "addmailuser user4@domain.tld mypassword" - initialpass=$(run docker exec mail /bin/sh -c "grep user3@domain.tld -i /tmp/docker-mailserver/postfix-accounts.cf") + initialpass=$(run docker exec mail /bin/sh -c "grep '^user4@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf") sleep 2 - docker exec mail /bin/sh -c "updatemailuser user3@domain.tld mynewpassword" + docker exec mail /bin/sh -c "updatemailuser user4@domain.tld mynewpassword" sleep 2 - changepass=$(run docker exec mail /bin/sh -c "grep user3@domain.tld -i /tmp/docker-mailserver/postfix-accounts.cf") + changepass=$(run docker exec mail /bin/sh -c "grep '^user4@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf") if [ initialpass != changepass ]; then status="0" @@ -681,7 +701,7 @@ status="1" fi - docker exec mail /bin/sh -c "delmailuser user3@domain.tld" + docker exec mail /bin/sh -c "delmailuser auser3@domain.tld" [ "$status" -eq 0 ] } @@ -705,6 +725,7 @@ run docker run --rm \ -v "$(pwd)/test/config/without-accounts/":/tmp/docker-mailserver/ \ `docker inspect --format '{{ .Config.Image }}' mail` /bin/sh -c 'addmailuser user3@domain.tld mypassword' + [ "$status" -eq 0 ] run docker run --rm \ -v "$(pwd)/test/config/without-accounts/":/tmp/docker-mailserver/ \ `docker inspect --format '{{ .Config.Image }}' mail` /bin/sh -c 'grep user3@domain.tld -i /tmp/docker-mailserver/postfix-accounts.cf' From fd8ad784d103198069551f75181a8cca1804510d Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 2 Jan 2017 13:39:46 +0100 Subject: [PATCH 16/22] Fixes #424, suggested by @alinmear (#447) --- target/start-mailserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/target/start-mailserver.sh b/target/start-mailserver.sh index c7fc4b7b..e0e1eaa5 100644 --- a/target/start-mailserver.sh +++ b/target/start-mailserver.sh @@ -829,6 +829,7 @@ function _fix_var_mail_permissions() { chown -R 5000:5000 /var/mail else notify 'inf' "Permissions in /var/mail look OK" + return 0 fi } ########################################################################## From 9095ba380352f10024153ea29ee56631979426d9 Mon Sep 17 00:00:00 2001 From: Wolfgang Ocker Date: Tue, 3 Jan 2017 10:55:03 +0100 Subject: [PATCH 17/22] Fix #443 - RIMAP support (#448) * Add unit tests for #443 (rimap auth) * Fix #443 - configure rimap for saslauth * Fix #443 - reuse smtp-auth-login.txt when testing rimap auth --- Makefile | 12 +++++++++++- target/start-mailserver.sh | 16 ++++++++++++++-- test/tests.bats | 27 +++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a8022d1c..f01a1c63 100644 --- a/Makefile +++ b/Makefile @@ -99,6 +99,15 @@ run: -e POSTMASTER_ADDRESS=postmaster@localhost.localdomain \ --link ldap_for_mail:ldap \ -h mail.my-domain.com -t $(NAME) + sleep 15 + docker run -d --name mail_with_imap \ + -v "`pwd`/test/config":/tmp/docker-mailserver \ + -v "`pwd`/test":/tmp/docker-mailserver-test \ + -e ENABLE_SASLAUTHD=1 \ + -e SASLAUTHD_MECHANISMS=rimap \ + -e SASLAUTHD_MECH_OPTIONS=127.0.0.1 \ + -e POSTMASTER_ADDRESS=postmaster@localhost.localdomain \ + -h mail.my-domain.com -t $(NAME) # Wait for containers to fully start sleep 15 @@ -140,7 +149,8 @@ clean: mail_disabled_clamav_spamassassin \ mail_manual_ssl \ ldap_for_mail \ - mail_with_ldap + mail_with_ldap \ + mail_with_imap @if [ -f config/postfix-accounts.cf.bak ]; then\ rm -f config/postfix-accounts.cf ;\ diff --git a/target/start-mailserver.sh b/target/start-mailserver.sh index e0e1eaa5..bbe739a1 100644 --- a/target/start-mailserver.sh +++ b/target/start-mailserver.sh @@ -73,6 +73,7 @@ function register_functions() { if [ "$ENABLE_SASLAUTHD" = 1 ];then _register_setup_function "_setup_saslauthd" + _register_setup_function "_setup_postfix_sasl" fi _register_setup_function "_setup_dkim" @@ -451,11 +452,15 @@ function _setup_ldap() { postconf -e "virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf, ldap:/etc/postfix/ldap-groups.cf" || \ notify 'inf' "==> Warning: /etc/postfix/ldap-aliases.cf or /etc/postfix/ldap-groups.cf not found" + return 0 +} + +function _setup_postfix_sasl() { [ ! -f /etc/postfix/sasl/smtpd.conf ] && cat > /etc/postfix/sasl/smtpd.conf << EOF pwcheck_method: saslauthd mech_list: plain login EOF -return 0 + return 0 } function _setup_saslauthd() { @@ -464,7 +469,7 @@ function _setup_saslauthd() { notify 'inf' "Configuring Cyrus SASL" # checking env vars and setting defaults [ -z $SASLAUTHD_MECHANISMS ] && SASLAUTHD_MECHANISMS=pam - [ -z $SASLAUTHD_LDAP_SEARCH_BASE ] && SASLAUTHD_MECHANISMS=pam + [ "$SASLAUTHD_MECHANISMS" = ldap -a -z $SASLAUTHD_LDAP_SEARCH_BASE ] && SASLAUTHD_MECHANISMS=pam [ -z $SASLAUTHD_LDAP_SERVER ] && SASLAUTHD_LDAP_SERVER=localhost [ -z $SASLAUTHD_LDAP_FILTER ] && SASLAUTHD_LDAP_FILTER='(&(uniqueIdentifier=%u)(mailEnabled=TRUE))' ([ -z $SASLAUTHD_LDAP_SSL ] || [ $SASLAUTHD_LDAP_SSL == 0 ]) && SASLAUTHD_LDAP_PROTO='ldap://' || SASLAUTHD_LDAP_PROTO='ldaps://' @@ -496,6 +501,13 @@ EOF -e "s|^MECHANISMS=.*|MECHANISMS="\"$SASLAUTHD_MECHANISMS\""|g" \ -e "s|^MECH_OPTIONS=.*|MECH_OPTIONS="\"$SASLAUTHD_MECH_OPTIONS\""|g" \ /etc/default/saslauthd + + if [ "$SASLAUTHD_MECHANISMS" = rimap ]; then + sed -i \ + -e 's|^OPTIONS="|OPTIONS="-r |g' \ + /etc/default/saslauthd + fi + sed -i \ -e "/smtpd_sasl_path =.*/d" \ -e "/smtpd_sasl_type =.*/d" \ diff --git a/test/tests.bats b/test/tests.bats index d1beb76e..3872111a 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -66,6 +66,11 @@ [ "$status" -eq 0 ] } +@test "checking process: saslauthd (saslauthd server enabled)" { + run docker exec mail_with_imap /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/saslauthd'" + [ "$status" -eq 0 ] +} + # # imap # @@ -881,3 +886,25 @@ run docker exec mail_with_ldap /bin/sh -c "nc -w 5 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/sasl-ldap-smtp-auth.txt | grep 'Authentication successful'" [ "$status" -eq 0 ] } + + +# +# RIMAP +# + +# dovecot +@test "checking dovecot: ldap rimap connection and authentication works" { + run docker exec mail_with_imap /bin/sh -c "nc -w 1 0.0.0.0 143 < /tmp/docker-mailserver-test/auth/imap-auth.txt" + [ "$status" -eq 0 ] +} + +# saslauthd +@test "checking saslauthd: sasl rimap authentication works" { + run docker exec mail_with_imap bash -c "testsaslauthd -u user1@localhost.localdomain -p mypassword" + [ "$status" -eq 0 ] +} + +@test "checking saslauthd: rimap smtp authentication" { + run docker exec mail_with_imap /bin/sh -c "nc -w 5 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/smtp-auth-login.txt | grep 'Authentication successful'" + [ "$status" -eq 0 ] +} From cfd7fde1eafb733835945975fe98fe1d3fad8c37 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 4 Jan 2017 10:05:02 +0100 Subject: [PATCH 18/22] Added config information Added information regarding were config files must be mounted. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 555eccb5..4904c97e 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ Before you open an issue, please have a look this `README`, the [Wiki](https://g Adapt this file with your FQDN. Install [docker-compose](https://docs.docker.com/compose/) in the version `1.6` or higher. +Your configs must be mounted in `/tmp/docker-mailserver/`. To understand how things work on boot, please have a look to [start-mailserver.sh](https://github.com/tomav/docker-mailserver/blob/master/target/start-mailserver.sh) + ```yaml version: '2' From 9cebc503073b73c9efc35552c38728f5dfe28c38 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Wed, 4 Jan 2017 10:09:03 +0100 Subject: [PATCH 19/22] #445: mention the setup.sh convenience script (#453) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4904c97e..e9ec0eb3 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,8 @@ Don't forget to adapt MAIL_USER and MAIL_PASS to your needs Now the keys are generated, you can configure your DNS server by just pasting the content of `config/opendkim/keys/domain.tld/mail.txt` in your `domain.tld.hosts` zone. +Note: you can also manage email accounts, DKIM keys and more with the [setup.sh convenience script](https://github.com/tomav/docker-mailserver/wiki/Setup-docker-mailserver-using-the-script-setup.sh). + #### Start the container docker-compose up -d mail From 89aa42d658b615c0087bad051424f25dda34a18e Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 4 Jan 2017 10:39:43 +0100 Subject: [PATCH 20/22] Added Gitter webhook --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index ec3bc887..cf62d9bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,3 +14,9 @@ after_script: notifications: slack: secure: TTo1z9nbZCWcIdfPwypubNa3y+pwvfgDGlzEVAGEuK7uuIpmEoAcAUNSSPTnbewDGHnDl8t/ml93MtvP+a+IVuAKytMqF39PHyoZO7aUl9J62V+G75OmnyGjXGJm40pQosCS6LzqoRRYXotl9+fwH568Kf4ifXCrMZX1d+ir7Ww= + webhooks: + urls: + - https://webhooks.gitter.im/e/7c5e56a8257cdec003ab + on_success: always + on_failure: always + on_start: never From 8eb53438cecf01e8c596065606e9b9ce7054ecea Mon Sep 17 00:00:00 2001 From: Guillaume Simon Date: Thu, 5 Jan 2017 09:24:45 +0100 Subject: [PATCH 21/22] Docker tag fix (#455) --- docker-compose.yml.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml.dist b/docker-compose.yml.dist index 0666438a..d965a9a6 100644 --- a/docker-compose.yml.dist +++ b/docker-compose.yml.dist @@ -2,7 +2,7 @@ version: '2' services: mail: - image: tvial/docker-mailserver:v2.1 + image: tvial/docker-mailserver:2.1 hostname: mail domainname: domain.com container_name: mail From 0216ce84a25fa0e66ae07e24270a2e7fde50355c Mon Sep 17 00:00:00 2001 From: Dominik Date: Mon, 9 Jan 2017 16:27:20 +0100 Subject: [PATCH 22/22] Fix update in setup.sh (#456) The updatemailuser needs parameters --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 2050d755..40e29ead 100755 --- a/setup.sh +++ b/setup.sh @@ -118,7 +118,7 @@ case $1 in ;; update) shift - _docker_image updatemailuser + _docker_image updatemailuser $@ ;; del) shift