#!/bin/sh # update-exim4.conf(8) - Generate /var/lib/exim4/config.autogenerated UPEX4C_confdir="/etc/exim4" UPEX4C_sections="main acl router transport retry rewrite auth" EXIM="/usr/sbin/exim4" UPEX4C_verbose=no UPEX4C_autoconfigfile=/var/lib/exim4/config.autogenerated UPEX4C_outputfile="${UPEX4C_autoconfigfile}" UPEX4C_version="4.50-8" UE4CC="$UPEX4C_confdir/update-exim4.conf.conf" usage() { cat <&2 exit 1 fi eval set -- ${TEMP} while test "$1" != "--"; do case $1 in -h|--help) usage exit 0 ;; -v|--verbose) UPEX4C_verbose=yes ;; --keepcomments) UPEX4C_comments=yes ;; --removecomments) UPEX4C_comments=no ;; -o|--output) shift UPEX4C_outputfile="$1" ;; -d|--confdir) shift UPEX4C_confdir="$1" ;; esac shift done shift # No non-option arguments allowed. if [ "$#" -ne 0 ]; then echo "No non option arguments ($@) allowed" >&2 usage >&2 exit 1 fi # exit immediately if /etc/exim4/exim4.conf exists and -o was not specified if [ -e /etc/exim4/exim4.conf ] && \ [ "x${UPEX4C_outputfile}" = "x${UPEX4C_autoconfigfile}" ] ; then exit 0 fi UPEX4C_confd=$UPEX4C_confdir/conf.d [ -d ${UPEX4C_confd} ] || \ { printf "$0: Error, no ${UPEX4C_confd}, exiting.\n" 1>&2 ; exit 1 ; } [ -d `dirname $UPEX4C_outputfile` ] || \ { printf "$0: Error, missing `dirname $UPEX4C_outputfile`, exiting.\n" 1>&2 ; exit 1 ; } if [ -f "$UE4CC" ]; then . $UE4CC else echo >&2 "$0: Error, no $UE4CC, exiting." exit 1 fi [ "x${CFILEMODE}" = "x" ] && CFILEMODE=644 [ "x${dc_use_split_config}" = "x" ] && dc_use_split_config='false' [ "x${dc_localdelivery}" = "x" ] && dc_localdelivery='mail_spool' [ "x${UPEX4C_comments}" = "x" ] && UPEX4C_comments="${ue4c_keepcomments:-no}" mailname=`cat /etc/mailname | head -n 1` # add localhost, get rid of spaces and trailing colons local_domains="`echo localhost:${dc_other_hostnames} | \ sed -e 'sÄ[: ]*$ÄÄ' -e 'sÄ *ÄÄ'`" dc_rewriteemailaddresses_mailname='*@'"$mailname"' ${lookup{${local_part}}lsearch{/etc/email-addresses}{$value}fail} Ffrs' TEMPLATEFILE=${UPEX4C_confdir}/exim4.conf.template UPEX4C_internal_tmp=`tempfile -m600 -p ex4` trap "rm -f ${UPEX4C_internal_tmp}" EXIT INT TERM # test if $1 is user modified, print message unmodifandmessage() { [ "$#" -eq 1 ] || return 1 if unmodified "$1" ; then return 0 else [ "${UPEX4C_verbose}" = "yes" ] && \ echo "ignoring user modified file $1" return 1 fi } # 0123456789abcdef0123456789abcdef # use this as template for new gen_something functions. UPEX4C_skeleton() { UPEX4C_internal_currfile="${UPEX4C_confd}/foo/bar" unmodifandmessage "${UPEX4C_internal_currfile}" || return cat << EOF > "${UPEX4C_internal_tmp}" # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # This is an md5sum. ####################################### # WARNING WARNING WARNING WARNING # This file is dynamically generated by update-exim4.conf(8) using the data # in /etc/exim4/update-exim4.conf.conf. EOF # insert more code that appends to ${UPEX4C_internal_tmp} UPEX4C_internal_md5=`cat "${UPEX4C_internal_tmp}" | md5sum | cut -d\ -f1` { echo "# ${UPEX4C_internal_md5}" ; cat "${UPEX4C_internal_tmp}" ; } > \ "${UPEX4C_internal_currfile}" } # run-parts emulation, stolen from Branden's /etc/X11/Xsession # Addition: Use file.rul instead if file if it exists. run_parts () { # reset LC_COLLATE unset LANG LC_COLLATE LC_ALL if [ -z "$1" ]; then errormessage "$0: internal run_parts called without an argument" fi if [ ! -d "$1" ]; then errormessage "$0: internal run_parts called, but $1 does not exist or is not a directory." fi for F in $(ls $1); do if expr "$F" : '[[:alnum:]_-]\+$' > /dev/null 2>&1; then if [ -f "$1/$F" ] ; then if [ -f "$1/${F}.rul" ] ; then echo "$1/${F}.rul" else echo "$1/$F" fi fi fi done; } # also from Branden errormessage () { # pretty-print messages of arbitrary length (no trailing newline) echo "$*" | fold -s -w ${COLUMNS:-80} >&2; } cat_parts() { if [ -z "$1" ]; then errormessage "$0: internal cat_parts called without an argument" fi if [ ! -d "$1" ]; then errormessage "$0: internal cat_parts called, but $1 does not exist or is not a directory." fi for file in `run_parts $1`; do echo "#####################################################" echo "### $file" echo "#####################################################" cat $file echo echo "#####################################################" echo "### end $file" echo "#####################################################" done } # check whether the file given as argument was modified by the user # by comparing the md5sum in the first line with the real one. unmodified() { [ "$#" -eq 1 ] || return 1 [ -f "$1" ] || return 1 # first line, without the leading '# '. checksum_current=`sed -n -e '1s/^# //' -e '1p;1q' "$1"` # md5sum over the rest of the file. # some versions of md5sum produce # '68b329da9893e34099c7d8ad5cb9c940 -' others don't add the dash. # '68b329da9893e34099c7d8ad5cb9c940' checksum_new=`sed -n '2,$p' "$1" | md5sum | cut -d\ -f1` if [ "${checksum_current}" = "${checksum_new}" ] ; then return 0 else return 1 fi } # update the md5sum given in the first line, return an error if the file does # not have an md5sum header in the first line. updatechecksumheader() { [ "$#" -eq 1 ] || return 1 [ -f "$1" ] || return 1 # check for correct format "# 76a51391da4a0687697224a124b71a17" sed -n -e '1p;1q' "$1" | grep -q -E '^# [[:xdigit:]]{32}$' || \ { echo "incorrect format" ; return 1 ;} NEWFILE=`tempfile -m600 -p ex4` sed -n '2,$p' "$1" | md5sum | cut -d\ -f1 | sed '1s/^/# /' > $NEWFILE sed -n '2,$p' "$1" >> $NEWFILE mv -f $NEWFILE "$1" } gentmpconf() { touch ${UPEX4C_outputfile}.tmp #chown --reference=${TEMPLATEFILE} \ # ${UPEX4C_outputfile}.tmp ${UPEX4C_outputfile} #chmod --reference=${TEMPLATEFILE} \ # ${UPEX4C_outputfile}.tmp ${UPEX4C_outputfile} if [ "`id -u`" = "0" ]; then chown root:Debian-exim ${UPEX4C_outputfile}.tmp [ -e ${UPEX4C_outputfile} ] && \ chown root:Debian-exim ${UPEX4C_outputfile} fi chmod 640 ${UPEX4C_outputfile}.tmp [ -e ${UPEX4C_outputfile} ] && chmod 640 ${UPEX4C_outputfile} } removecomments(){ if [ "x${UPEX4C_comments}" = "xno" ] ; then grep -E -v '^[[:space:]]*#' | sed -e '/^$/N;/\n$/D' ; else cat fi } gentmpconf cat << EOF > ${UPEX4C_outputfile}.tmp ######### # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING # this file is generated dynamically from the files in # CONFDIR/conf.d/ or /etc/exim4/exim4.conf.template respectively and # /etc/exim4/update-exim4.conf.conf # Any changes you make here will be lost. # See /usr/share/doc/exim4-base/README.Debian.gz and update-exim4.conf(8) # for instructions of customization. # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING # WARNING WARNING WARNING ######### EOF case "$dc_eximconfig_configtype" in satellite|smarthost) if [ "${dc_hide_mailname}" = "true" ] && [ -n "${dc_readhost}" ] ; then DEBCONFheaders_rewriteDEBCONF='headers_rewrite = *@+local_domains $1@DCreadhost frs : *@'"$mailname"' $1@DCreadhost frs' DEBCONFreturn_pathDEBCONF='return_path = ${if match_domain{$sender_address_domain}{+local_domains}{${sender_address_local_part}@DCreadhost}{${if match_domain{$sender_address_domain}{'"$mailname"'}{${sender_address_local_part}@DCreadhost}fail}}}' fi ;; local) ;; internet) ;; none|*) if [ "${dc_use_split_config}" = "true" ] ; then for i in ${UPEX4C_sections} ; do cat_parts ${UPEX4C_confd}/$i done | \ removecomments | \ sed -e "s/DEBCONF[^D][^E][^B].*DEBCONF//g" \ >> ${UPEX4C_outputfile}.tmp else LOCALMACROS="" if [ -e "/etc/exim4/exim4.conf.localmacros" ]; then LOCALMACROS="/etc/exim4/exim4.conf.localmacros" fi cat $LOCALMACROS /etc/exim4/exim4.conf.template | \ removecomments | \ sed -e "s/DEBCONF[^D][^E][^B].*DEBCONF//g" \ >> ${UPEX4C_outputfile}.tmp fi mv -f ${UPEX4C_outputfile}.tmp ${UPEX4C_outputfile} chmod ${CFILEMODE} ${UPEX4C_outputfile} [ "${UPEX4C_verbose}" = "yes" ] && \ echo "Not substituting variables since conftype is none (or other)" exit 0 ;; esac if [ "x${dc_local_interfaces}" = "x" ] ; then listenonpublic='# if local_interfaces is unset, we listen on all interfaces' else listenonpublic="local_interfaces = ${dc_local_interfaces}" fi hardcode_primary_hostname="" if [ "x${dc_minimaldns}" = "xtrue" ] ; then UPEX4C_minimaldns='DC_minimaldns = 1' if guessed_name=`hostname --fqdn | grep '\.'` ; then hardcode_primary_hostname="primary_hostname = ${guessed_name}" fi else UPEX4C_minimaldns='' fi case "${dc_use_split_config}" in true) for i in ${UPEX4C_sections} ; do echo "# begin processing $i #####" cat_parts ${UPEX4C_confd}/$i echo "# end of $i #####" done | \ sed -e "sÄDEBCONFlocal_domainsDEBCONFÄ@:${local_domains}Äg" \ -e "sÄDEBCONFrelay_domainsDEBCONFÄ${dc_relay_domains}Äg" \ -e "sÄDEBCONFrelay_netsDEBCONFÄ${dc_relay_nets}Äg" \ -e "sÄDEBCONFvisiblenameDEBCONFÄ${mailname}Äg" \ -e "sÄDEBCONFreadhostDEBCONFÄ${dc_readhost}Äg" \ -e "sÄDEBCONFsmarthostDEBCONFÄ${dc_smarthost}Äg" \ -e "sÄDEBCONFconfigtypeDEBCONFÄ${dc_eximconfig_configtype}Äg" \ -e "sÄDEBCONFlistenonpublicDEBCONFÄ${listenonpublic}Äg" \ -e "sÄDEBCONFpackageversionDEBCONFÄ${UPEX4C_version}Äg" \ -e "sÄDEBCONFminimaldnsDEBCONFÄ${UPEX4C_minimaldns}Äg" \ -e "sÄDEBCONFnever_usersDEBCONFÄÄg" \ -e "sÄDEBCONFheaders_rewriteDEBCONFÄ${DEBCONFheaders_rewriteDEBCONF}Äg" \ -e "sÄDEBCONFreturn_pathDEBCONFÄ${DEBCONFreturn_pathDEBCONF}Äg" \ -e "sÄDEBCONF_hardcode_primary_hostname_DEBCONFÄ${hardcode_primary_hostname}Äg" \ -e "sÄDEBCONFlocaldeliveryDEBCONFÄ${dc_localdelivery}Äg" \ -e "sÄDEBCONFrewriteemailaddresses_mailnameDEBCONFÄ${dc_rewriteemailaddresses_mailname}Äg" \ | removecomments \ >> ${UPEX4C_outputfile}.tmp ;; false) if [ ! -r /etc/exim4/exim4.conf.template ] ; then echo "Error: Unsplit config selected and /etc/exim4/exim4.conf.template missing ... exiting" 1>&2 exit 1 fi LOCALMACROS="" if [ -e "/etc/exim4/exim4.conf.localmacros" ]; then LOCALMACROS="/etc/exim4/exim4.conf.localmacros" fi cat $LOCALMACROS /etc/exim4/exim4.conf.template \ | sed -e "sÄDEBCONFlocal_domainsDEBCONFÄ@:${local_domains}Äg" \ -e "sÄDEBCONFrelay_domainsDEBCONFÄ${dc_relay_domains}Äg" \ -e "sÄDEBCONFrelay_netsDEBCONFÄ${dc_relay_nets}Äg" \ -e "sÄDEBCONFvisiblenameDEBCONFÄ${mailname}Äg" \ -e "sÄDEBCONFreadhostDEBCONFÄ${dc_readhost}Äg" \ -e "sÄDEBCONFsmarthostDEBCONFÄ${dc_smarthost}Äg" \ -e "sÄDEBCONFconfigtypeDEBCONFÄ${dc_eximconfig_configtype}Äg" \ -e "sÄDEBCONFlistenonpublicDEBCONFÄ${listenonpublic}Äg" \ -e "sÄDEBCONFpackageversionDEBCONFÄ${UPEX4C_version}Äg" \ -e "sÄDEBCONFminimaldnsDEBCONFÄ${UPEX4C_minimaldns}Äg" \ -e "sÄDEBCONFnever_usersDEBCONFÄÄg" \ -e "sÄDEBCONFheaders_rewriteDEBCONFÄ${DEBCONFheaders_rewriteDEBCONF}Äg" \ -e "sÄDEBCONFreturn_pathDEBCONFÄ${DEBCONFreturn_pathDEBCONF}Äg" \ -e "sÄDEBCONF_hardcode_primary_hostname_DEBCONFÄ${hardcode_primary_hostname}Äg" \ -e "sÄDEBCONFlocaldeliveryDEBCONFÄ${dc_localdelivery}Äg" \ -e "sÄDEBCONFrewriteemailaddresses_mailnameDEBCONFÄ${dc_rewriteemailaddresses_mailname}Äg" \ | removecomments \ >> ${UPEX4C_outputfile}.tmp ;; esac # test validity if called without -o if [ "x${UPEX4C_outputfile}" = "x${UPEX4C_autoconfigfile}" ] && \ [ -x ${EXIM} ] ; then if ! ${EXIM} -C "${UPEX4C_outputfile}.tmp" -bV > /dev/null ; then # we have an error in the configuration file. Do not install # and activate. However, errors in string expansions inside # the configuration file are not detected by this check! errormessage "Invalid new configfile ${UPEX4C_outputfile}.tmp" errormessage "not installing ${UPEX4C_outputfile}.tmp to ${UPEX4C_outputfile}" exit 1 fi fi mv -f ${UPEX4C_outputfile}.tmp ${UPEX4C_outputfile} chmod ${CFILEMODE} ${UPEX4C_outputfile}