File entrypoint.sles.sh of Package postfix-image

#!/bin/bash

DEBUG=${DEBUG:-"0"}

[ "${DEBUG}" = "1" ] && set -x

VIRTUAL_MBOX=${VIRTUAL_MBOX:-"0"}
USE_LDAP=${USE_LDAP:-"0"}
NULLCLIENT=${NULLCLIENT:-"1"}
ENABLE_SUBMISSION=${ENABLE_SUBMISSION:-"0"}
ENABLE_SUBMISSIONS=${ENABLE_SUBMISSIONS:-"0"}

export PATH=/usr/sbin:/sbin:${PATH}

setup_timezone() {
    if [ -n "$TZ" ]; then
	TZ_FILE="/usr/share/zoneinfo/$TZ"
	if [ -f "$TZ_FILE" ]; then
	    echo "Setting container timezone to: $TZ"
	    ln -snf "$TZ_FILE" /etc/localtime
	else
	    echo "Cannot set timezone \"$TZ\": timezone does not exist."
	fi
    fi
}

set_config_value() {
    local failed
    key=${1}
    value=${2}

    echo "Setting configuration option \"${key}\" with value \"${value}\""
    postconf -e "${key} = ${value}" || failed=1
    if [ "$failed" ]; then
	echo "ERROR: postconf -e ${key} ${value} failed!"
	exit 1
    fi
}

# usage: file_env VAR [DEFAULT]
#    ie: file_env 'SMTP_PASSWORD' 'example'
# (will allow for "$SMTP_PASSWORD_FILE" to fill in the value of
#  "$SMTP_PASSWORD" from a file, especially for Docker's secrets feature)
file_env() {
    var="$1"
    fileVar="${var}_FILE"
    def="${2:-}"
    if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
        echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
        exit 1
    fi
    val="$def"
    if [ "${!var:-}" ]; then
        val="${!var}"
    elif [ "${!fileVar:-}" ]; then
        val="$(< "${!fileVar}")"
    fi
    export "$var"="$val"
    unset "$fileVar"
}

update_db() {
    local failed

    while test "x$1" != "x" ; do
        pfmap=/etc/postfix/${1}
        test -e "${pfmap}" && \
            if test "${pfmap}" -nt "${pfmap}.lmdb" -o ! -e "${pfmap}.lmdb" ; then
		echo "rebuilding ${pfmap}.lmdb"
		postmap "${pfmap}" || failed=1
		if [ "$failed" ]; then
		    echo "ERROR: postmap ${pfmap} failed!"
		    exit 1
		fi
            fi
        shift
    done
}

setup_aliases() {
    local failed

    get_alias_maps() {
	test -d /etc/aliases.d && test "$(echo /etc/aliases.d/*)" != "/etc/aliases.d/*" && \
            for i in $(find /etc/aliases.d -maxdepth 1 -type f \
			    '!' -regex ".*\.\(db\|rpmsave\|rpmorig\)" \
			    '!' -regex ".*/\(\.\|#\).*" \
			    '!' -regex ".*~$") ; do
		echo -n "$i ";
	    done
    }

    echo "Building /etc/aliases.lmdb."
    set_config_value "alias_database" "lmdb:/etc/aliases"
    /usr/bin/newaliases

    ALLMAPS="lmdb:/etc/aliases"
    for i in $(get_alias_maps); do
        ALLMAPS="${ALLMAPS}, lmdb:$i"
	echo "Building $i.lmdb"
	postalias "${i}" || failed=1
	if [ "${failed}" ]; then
	    echo "ERROR: postalias ${i} failed!"
	    exit 1
	fi
    done
    set_config_value "alias_maps" "${ALLMAPS}"
}

setup_network() {
    if [ -n "${INET_PROTOCOLS}" ]; then
        set_config_value "inet_protocols" "{$INET_PROTOCOLS}"
    else
        # XXX Containers have ipv6 addresses, but not routeable
        #if ip addr show dev lo | grep -q inet6 ; then
        #    set_config_value "inet_protocols" "all"
        #else
             set_config_value "inet_protocols" "ipv4"
        #fi
    fi

    # Always allow private networks, we are running in a container...
    networks='127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16'
    if [ -n "${SMTP_NETWORKS}" ]; then
        networks+=", ${SMTP_NETWORKS}"
    fi
    set_config_value "mynetworks" "${networks}"
}

setup_relayhost() {
    if [ -n "${SMTP_RELAYHOST}" ]; then
        SMTP_PORT="${SMTP_PORT:-587}"
        set_config_value "relayhost" "${SMTP_RELAYHOST}:${SMTP_PORT}"

	if [ "${NULLCLIENT}" -eq "1" ] && [ -z "${MYDESTINATION}" ] ; then
	    set_config_value "mydestination" ""
	fi
    fi

    if [ -n "${SMTP_USERNAME}" ]; then
        file_env 'SMTP_PASSWORD'
        if [ -z "${SMTP_PASSWORD}" ]; then
            echo "SMTP_PASSWORD is not set"
            exit 1
        fi
        # Add auth credentials to sasl_passwd
        echo "Adding SASL authentication configuration"
        echo "${SMTP_RELAYHOST} ${SMTP_USERNAME}:${SMTP_PASSWORD}" >> /etc/postfix/sasl_passwd
        update_db sasl_passwd
        set_config_value "smtp_sasl_password_maps" "lmdb:/etc/postfix/sasl_passwd"
        set_config_value "smtp_sasl_auth_enable" "yes"
        set_config_value "smtp_sasl_security_options" "noanonymous"
    fi

    if [ -n "${MASQUERADE_DOMAINS}" ]; then
        set_config_value "masquerade_domains" "${MASQUERADE_DOMAINS}"
        # Requires since postfix 2.2
        set_config_value "local_header_rewrite_clients" "static:all"
    fi
}

setup_submission() {
    SMTPD_USE_TLS=${SMTPD_USE_TLS:-"0"}

    if [ "${ENABLE_SUBMISSION}" -eq "1" ]; then
	echo "Enable submission port"

	echo "submission inet n       -       n       -       -       smtpd" >> /etc/postfix/master.cf

	if [ "${SMTPD_USE_TLS}" -eq "1" ]; then
	    echo " -o smtpd_tls_security_level=encrypt" >> /etc/postfix/master.cf
	    echo " -o smtpd_sasl_auth_enable=no" >> /etc/postfix/master.cf
	    #echo " -o smtpd_client_restrictions=permit_sasl_authenticated,reject" >> /etc/postfix/master.cf
	fi
    fi

    if [ "${ENABLE_SUBMISSIONS}" -eq "1" ]; then
	if [ "${SMTPD_USE_TLS}" -eq "1" ]; then
	    echo "Enable submissions port"

	    echo "smtps inet n       -       n       -       -       smtpd" >> /etc/postfix/master.cf
	    echo " -o smtpd_tls_wrappermode=yes" >> /etc/postfix/master.cf
	    echo " -o smtpd_sasl_auth_enable=no" >> /etc/postfix/master.cf
	else
	    echo "WARNING: ENABLE_SUBMISSIONS requires SMTPD_USE_TLS, ignoring!"
	fi
    fi

    if [ "${SMTPD_USE_TLS}" -eq "1" ]; then
	echo "Enable TLS for smtpd"

	SMTPD_TLS_CRT=${SMTPD_TLS_CRT:-"/etc/postfix/ssl/certs/tls.crt"}
	SMTPD_TLS_KEY=${SMTPD_TLS_KEY:-"/etc/postfix/ssl/certs/tls.key"}

	# smtpd_use_tls is deprecated and only for compatibility
	set_config_value "smtpd_use_tls" "yes"
	set_config_value "smtpd_tls_security_level" "may"
	set_config_value "smtpd_tls_CApath" "/etc/ssl/certs"
	set_config_value "smtpd_tls_cert_file" "${SMTPD_TLS_CRT}"
	set_config_value "smtpd_tls_key_file" "${SMTPD_TLS_KEY}"
    fi
}

setup_vhosts() {
    if [ "${USE_LDAP}" -eq "1" ]; then
	LDAP_BASE_DN=${LDAP_BASE_DN:-"dc=example,dc=org"}
	LDAP_SERVER_URL=${LDAP_SERVER_URL:-"ldap://localhost"}
        LDAP_USE_TLS=${LDAP_USE_TLS:-"1"}
        LDAP_BIND_DN=${LDAP_BIND_DN:-"cn=mailAccountReader,ou=Manager,${LDAP_BASE_DN}"}
	file_env LDAP_BIND_PASSWORD
        if [ -z "${LDAP_BIND_PASSWORD}" ]; then
            echo "LDAP_BIND_PASSWORD is not set"
            exit 1
        fi

	# Adjust LDAP variables
	mkdir -p /etc/postfix/ldap
	for map in smtpd_sender_login_maps virtual_alias_domains virtual_alias_maps virtual_gid_maps virtual_mailbox_maps virtual_uid_maps ; do
	    sed -e "s|@LDAP_BASE_DN@|${LDAP_BASE_DN}|g" \
		-e "s|@LDAP_SERVER_URL@|${LDAP_SERVER_URL}|g" \
		-e "s|@LDAP_BIND_DN@|${LDAP_BIND_DN}|g" \
		-e "s|@LDAP_BIND_PASSWORD@|${LDAP_BIND_PASSWORD}|g" \
		"/entrypoint/ldap/${map}" > "/etc/postfix/ldap/${map}"
             if [ "${LDAP_USE_TLS}" = "1" ]; then
                 sed -i -e 's|^start_tls.*|start_tls = yes|g' "/etc/postfix/ldap/${map}"
             else
                 sed -i -e 's|^start_tls.*|start_tls = no|g' "/etc/postfix/ldap/${map}"
	     fi
	     if [ -n "${LDAP_TLS_CA_CRT}" ]; then
		 sed -i -e "s|^#tls_ca_cert_file =.*|tls_ca_cert_file = ${LDAP_TLS_CA_CRT}|g" "/etc/postfix/ldap/${map}"
	     fi
	done

	# Don't use VIRUAL_DOMAINS and ldap:virtual_alias_domains at the same time, postfix does
	# not like this
	if [ -z "${VIRTUAL_DOMAINS}" ]; then
	    set_config_value "virtual_alias_domains" "ldap:/etc/postfix/ldap/virtual_alias_domains"
	fi
	set_config_value "virtual_alias_maps" "ldap:/etc/postfix/ldap/virtual_alias_maps"
	set_config_value "virtual_mailbox_maps" "ldap:/etc/postfix/ldap/virtual_mailbox_maps"
	set_config_value "smtpd_sender_login_maps" "ldap:/etc/postfix/ldap/smtpd_sender_login_maps"
    else
	set_config_value "virtual_mailbox_maps" "lmdb:/etc/postfix/vmaps"
	set_config_value "virtual_mailbox_limit_maps" "lmdb:/etc/postfix/vquota"

	# Only create vmaps if not provided by admin
	if [ ! -f /etc/postfix/vmaps ]; then
	    for mail in ${VIRTUAL_USERS} ; do
		user=${mail%@*}
		domain=${mail#*@}
		echo "${mail} ${domain}/${user}/" >> /etc/postfix/vmaps
		echo "${mail} 0" >> /etc/postfix/vquota
	    done
	fi
	update_db vquota
    fi

    set_config_value "virtual_mailbox_domains" "/etc/postfix/vhosts"
    # Only create vhosts if not provided by admin
    if [ ! -f /etc/postfix/vhosts ]; then
        if [ -n "${VIRTUAL_DOMAINS}" ]; then
	    for d in ${VIRTUAL_DOMAINS}; do
		echo "$d" >> /etc/postfix/vhosts
	    done
        elif [ -n "${SERVER_DOMAIN}" ]; then
	    echo "${SERVER_DOMAIN}" > /etc/postfix/vhosts
	else
	    touch /etc/postfix/vhosts
        fi
    fi
    update_db vmaps

    if [ -n "${LMTP}" ]; then
	# Use LMTP to deliver the mail to the user

	set_config_value "virtual_transport" "lmtp:${LMTP}:24"
    else
	# Store mails local below /var/spool/vmail

	# Create the vmail user with the requested UID, else 5000
	VMAIL_UID="${VMAIL_UID:-5000}"
	if [ -x /usr/sbin/adduser ]; then
	    adduser -D -h /var/spool/vmail -g "Virtual Mail User" -u "${VMAIL_UID}" -s /sbin/nologin vmail
	else
            useradd -d /var/spool/vmail -U -c "Virtual Mail User" -u "${VMAIL_UID}" vmail
	fi
	if [ $? -ne 0 ]; then
            echo "ERROR: creating of vmail user failed! Aborting."
            exit 1
	fi

	if [ ! -d /var/spool/vmail ]; then
            mkdir -p /var/spool/vmail
            chown vmail:vmail /var/spool/vmail
            chmod 775 /var/spool/vmail
	fi

	set_config_value "virtual_mailbox_base" "/var/spool/vmail"
	set_config_value "virtual_minimum_uid" "1000"
	set_config_value "virtual_uid_maps" "static:${VMAIL_UID}"
	set_config_value "virtual_gid_maps" "static:${VMAIL_UID}"
	set_config_value "home_mailbox" "Maildir/"
	# XXX make this configureable and adjust message_size_limit
	set_config_value "virtual_mailbox_limit" "0"
	set_config_value "mailbox_size_limit" "0" # "51200000"
	set_config_value "message_size_limit" "0" # "10240000"
    fi
}

configure_postfix() {

    setup_network

    if [ -n "${SERVER_HOSTNAME}" ]; then
	if [ -z "${SERVER_DOMAIN}" ]; then
	    SERVER_DOMAIN=$(echo "${SERVER_HOSTNAME}" | cut -d"." -f2-)
	fi
	set_config_value "myhostname" "${SERVER_HOSTNAME}"
        set_config_value "mydomain" "${SERVER_DOMAIN}"
    fi

    # Generic settings
    ## Use lmdb instead of "hash" to get rid of BDB
    set_config_value "default_database_type" "lmdb"
    sed -i -e 's|hash:|lmdb:|g' /etc/postfix/main.cf
    ## TLS
    if [ -n "${SMTP_TLS_WRAPPERMODE}" ]; then
       set_config_value "smtp_tls_wrappermode" "${SMTP_TLS_WRAPPERMODE}"
    fi
    SMTP_TLS_SECURITY_LEVEL=${SMTP_TLS_SECURITY_LEVEL:-"may"}
    set_config_value "smtp_tls_security_level" "${SMTP_TLS_SECURITY_LEVEL}"
    set_config_value "smtp_tls_CApath" "/etc/postfix/ssl/cacerts"
    ## Debug only:
    # set_config_value "smtp_tls_loglevel" "2"

    if [ "${VIRTUAL_MBOX}" -eq "1" ]; then
        setup_vhosts
    fi
    if [ -n "${MYDESTINATION}" ]; then
	set_config_value "mydestination" "${MYDESTINATION}"
    else
	set_config_value "mydestination" "\$myhostname, localhost.\$mydomain, localhost"
    fi
    setup_submission
    setup_relayhost

    # Add maps to config and create database
    for i in canonical relocated sender_canonical transport virtual; do
	set_config_value "${i}_maps" "lmdb:/etc/postfix/${i}"
	update_db "${i}"
    done
    set_config_value "smtpd_sender_restrictions" "lmdb:/etc/postfix/access"

    # Log to stdout
    set_config_value "maillog_file" "/dev/stdout"

    # Generate and update maps
    update_db access relay relay_recipients

    setup_aliases
}

terminate() {
    base=$(basename "$1")
    pid=$(/usr/bin/ps -aux | /usr/bin/grep "$base" | /usr/bin/grep -v grep | /usr/bin/awk '{print $2}' | /usr/bin/tr '\n' ' ')

    if [ -n "$pid" ]; then
	echo "Terminating $base..."
	if kill "$pid" ; then
	    echo "Terminating $base failed!"
	fi
    else
	echo "Failure determining PID of $base"
    fi
}

init_trap() {
    trap stop_daemons TERM INT
}

stop_postfix() {

    typeset -i sec=$1
    typeset -i ms=$((sec*100))

    (   while ! (ps -aux | grep qmgr | grep -v grep | awk '{print $2}' | tr '\n' ' ') > /dev/null 2>&1; do
            ((ms-- <= 0)) && break
            usleep 10000
	done
	exec postfix flush
    ) > /dev/null 2>&1 &

    postfix stop
}

stop_daemons() {
    stop_postfix "$@"
}

#
# Main
#

# if command starts with an option, prepend postfix
if [ "${1:0:1}" = '-' ]; then
        set -- postfix start-fg "$@"
fi

init_trap
setup_timezone
# Update certificates if /etc/pki is mounted from the host
update-ca-certificates
# configure postfix even if postfix will not be started, to
# allow to see the result with postconf for debugging/testing.
configure_postfix

# If host mounting /var/spool/postfix, we need to delete the old pid file
# before starting services
rm -f /var/spool/postfix/pid/master.pid

echo "[info] refer to postfix manual pages at https://www.postfix.org/postfix-manuals.html"
exec "$@"
openSUSE Build Service is sponsored by