[exim-cvs] cvs commit: exim/exim-conf ABOUT exim/exim-conf/…

トップ ページ
このメッセージを削除
このメッセージに返信
著者: Philip Hazel
日付:  
To: exim-cvs
題目: [exim-cvs] cvs commit: exim/exim-conf ABOUT exim/exim-conf/config.samples C002 C006 C022 C022.tar C037 C042 C043 C044 C045 C046 C047 C049 C050 C051 F001 F002 F003 F004 L001 S001 S002
ph10 2004/10/08 11:50:49 BST

  Added files:
    exim-conf            ABOUT 
    exim-conf/config.samples C002 C006 C022 C022.tar C037 C042 
                             C043 C044 C045 C046 C047 C049 C050 
                             C051 F001 F002 F003 F004 L001 S001 
                             S002 
  Log:
  Start


  Revision  Changes    Path
  1.1       +10 -0     exim/exim-conf/ABOUT (new)
  1.1       +68 -0     exim/exim-conf/config.samples/C002 (new)
  1.1       +39 -0     exim/exim-conf/config.samples/C006 (new)
  1.1       +28 -0     exim/exim-conf/config.samples/C022 (new)
  1.1       +314 -0    exim/exim-conf/config.samples/C022.tar (new)
  1.1       +116 -0    exim/exim-conf/config.samples/C037 (new)
  1.1       +83 -0     exim/exim-conf/config.samples/C042 (new)
  1.1       +551 -0    exim/exim-conf/config.samples/C043 (new)
  1.1       +148 -0    exim/exim-conf/config.samples/C044 (new)
  1.1       +48 -0     exim/exim-conf/config.samples/C045 (new)
  1.1       +35 -0     exim/exim-conf/config.samples/C046 (new)
  1.1       +89 -0     exim/exim-conf/config.samples/C047 (new)
  1.1       +44 -0     exim/exim-conf/config.samples/C049 (new)
  1.1       +124 -0    exim/exim-conf/config.samples/C050 (new)
  1.1       +324 -0    exim/exim-conf/config.samples/C051 (new)
  1.1       +35 -0     exim/exim-conf/config.samples/F001 (new)
  1.1       +98 -0     exim/exim-conf/config.samples/F002 (new)
  1.1       +97 -0     exim/exim-conf/config.samples/F003 (new)
  1.1       +71 -0     exim/exim-conf/config.samples/F004 (new)
  1.1       +185 -0    exim/exim-conf/config.samples/L001 (new)
  1.1       +70 -0     exim/exim-conf/config.samples/S001 (new)
  1.1       +150 -0    exim/exim-conf/config.samples/S002 (new)


Index: ABOUT
====================================================================
$Cambridge: exim/exim-conf/ABOUT,v 1.1 2004/10/08 10:50:49 ph10 Exp $

CVS directory exim/exim-conf
----------------------------

This directory contains sample configurations and similar files that have been
submitted by Exim users. The files are not locally modified, and so do not have
CVS version Ids.

End

Index: C002
====================================================================
Date: Wed, 14 Jan 1998 15:07:22 +0200
From: Vladimir Litovka <doka@???>

[Syntax converted for Exim 4 by PH, 06-Dec-2001. Unchecked.]

Although exim not intended for use in UUCP environment (it doesn't know
anything about bang!path addresses), I'm successfully using it for delivering
mail to UUCP clients. For this purposes I'm using two rewrite rules:

#--------------------- REWRITE CONFIGURATION ------------------------#

  # system!system.domain.net!user
  \N^([^!]+)!((\w+)(\.\w+)+)!(.*)@your\.domain\N \
      "${if eq {$1}{$3}{$5@$2}{$2!$5@$1}}"    Tbcrtq


  # system*!user
  \N^([^!]+)!(.*)@your\.domain\N        $2@$1   Tbcrtq


#--------------------------------------------------------------------#

  The first rule check
    if destination address in form:
      uuname!system.some.domain!user
    and
      uuname == system
    it rewrites address to user@???
    else it rewrites it to system.some.domain!user@uuname
    and QUIT.


  The second rule check
    if destination address in form:
      uuname1!uuname2!FQDN!...!uunameN!user
    it rewrites it to
      uuname2!FQDN!...!uunameN!user@uuname1
    and QUIT.


For successfully delivering mail to uucp domain you must create such
transport:

  #-------------------------------------------------------------------#
  uux:
    driver = pipe;
    command = /usr/bin/uux - -r $host!rmail ($local_part@$domain)
    path = /usr/local/bin:/usr/bin:/bin
    return_fail_output
    user = uucp
  #-------------------------------------------------------------------#


and such router:

  #-------------------------------------------------------------------#
  force_uucp:
    driver = manualroute
    route_data = partial-lsearch;/etc/exim/maps/force.uucp
  #-------------------------------------------------------------------#


and use something similar to this force.uucp:

  # Domain        Relay            Options
  # ------        -----            -------
  system1            system1            uux
  system1.domain        system1            uux
  #
  system2            system2            uux
  system2.domain        system2            uux


(!) Note, that you need unqualified names (system1, system2) because
second rewrite rule don't do qualification (it known nothing about this).

Index: C006
====================================================================
From: Kind@???
Date: Sun, 2 Aug 1998 15:24:05 +0200

[Syntax converted for Exim 4 by PH, 06-Dec-2001. Unchecked.]

This is how I have configured a PP-inspired vacationnote, there is (was?)
such a feature in PP. The user makes a file "tripnote" in his/her
homedirectory, the message is passed to the sender once with a short
leading text.

  ############
  # TRANSPORT
  vacation_reply:
    driver = autoreply
    file = $home/tripnote
    file_expand
    log = $home/tripnote.log
    once = $home/tripnote.db
    from = vacation@???
    to = $sender_address
    subject = "Re: $h_subject"
    text = "\
    Dear $h_from:\n\n\
    This is an automatic reply.  Feel free to send additional\n\
    mail, as only this one notice will be generated.  The following\n\
    is a prerecorded message, sent for $local_part@???:\n\
    ====================================================\n\n\
    "


  # ROUTER
  user_vacation:
    driver = accept
    check_local_user 
    require_files = $local_part:$home/tripnote
    no_verify
    senders = !^.*-request@.* : !^owner-.*@.* : !^postmaster@.* : \
              ! ^listmaster@.* : !^mailer-daemon@.*
    transport = vacation_reply
    unseen


Index: C022
====================================================================
Date: Tue, 14 Sep 1999 00:58:56 +0200
Updated: Fri, 11 Jan 2002 05:13:57 +0200
From: Vadim Vygonets <vadik@???>

This is the Exim configuration file of a machine which delivers mail to several
local domains, where the mail is delivered locally, several hairy domains,
handled as described below, and a half-virtual domain, which is first processed
by its special alias file, then processed as other local domains (including the
processing by the global alias file).

This contribution consists of a number of files that are in the tar archive
C022.tar, which unpacks into a directory called "virtual". See the README file
therein for an explanation of the configuration.

This is the updated virtual domain handling for Exim 4. The
main changes are:

  1. Now there's the alias file admin.raw for privileged aliases
     (such as Postmaster).  It is processed earlier than
     domain-specific files.  The domain is not preserved on
     redirection.


  2. <DOMAIN>.rewrite.raw is gone, and <DOMAIN>.aliases.raw is
     renamed to <DOMAIN>.raw.  The functionality was put into
     entries with keys ending with a '+', and the data are allowed
     to have no domain (which made the rewrite rule slightly more
     complicated).



  Index: C022.tar
  ===================================================================
      <<Binary file>>


Index: C037
====================================================================
Date: Wed, 22 Nov 2000 17:51:42 -0500 (EST)
From: Dave C. <djc@???>

[Syntax converted for Exim 4 by PH, 06-Dec-2001. Unchecked.]

Ok.. Ive come up with something which might be worth including in the
cookbook. Credit where it is due, the idea for this came from Nigel's
C014.

I have a setup to support ETRN for a few small (ok, two) domains.
Currently it just leaves all the mail in the exim spool, and uses the
default exim etrn response to flush it out.

I don't like that - I agree with the opinion expressed on the list that
mail should be delivered somewhere else, and then shoved down an SMTP
session by some other program. Ive searched far and wide for something
suitable to do that shoving, and finally hit upon the only program I
trust to do that, handling errors and rejections correctly - exim
itself.

Nigel's solution for 'situation where a site I MX for has a known
outage', combined with a bit of bash scriptery, seems to form a neat
solution. (An intermittently connected host sort of falls under the
'known outage' category ;)

Without any further fluff, here are the details. Additional comments
appear below..

Either the real (intermittently connected) destination host needs to be
listed as the lowest MX (with the exim server as a less preferred) , or
the exim server needs to be the lowest MX, but have a router before the
lookuphost router which uses route_list or something appropriate to
normally deliver mail to the dialup host. The former is probably better
for a host which is usually connected and is only occasionally
disconnected (since other hosts would be able to delivery directly most
of the time, skipping an extra relay), while the latter would probably
work better for the converse ;) This paragraph actually applies anytime
you are using ETRN..

In either case, the routers below must precede whatever router handles
the normal direct-to-dialup-destination..

--

smtp_etrn_command = /etc/exim/etrn_script $domain

[- Content of /etc/exim/etrn_script: -]
#!/bin/sh

# Where exim lives
EXIM=/usr/sbin/exim

# Something appropriate to generate a temporary unique string
UNIQ=`head -c100 /dev/urandom | md5sum | cut -f 1 -d" "`

arg=$1
domain=`echo $arg | sed 's/^\#//g'`

  if ( test -f /var/spool/etrn/${domain} ); then
   exim_lock -q /var/spool/etrn/${domain} "mv /var/spool/etrn/${domain} /tmp/etrn-bsmtp-${UNIQ}"
   ( cat /tmp/etrn-bsmtp-${UNIQ}
     echo "QUIT" ) | $EXIM -bS -oMr etrn_requeue
   rm -f /tmp/etrn-bsmtp-${UNIQ}
  fi


$EXIM -R $domain

[- end of etrn_script -]

[- exim transport -]

bsmtp_for_etrn:
driver=appendfile
file=/var/spool/etrn/$domain
user=exim
batch_max = 1000
use_bsmtp

[- routers -]
[- You probably would want to put the domains in a file or a dbm and
[- adjused the 'domains' setting appropriately for both of these..

# If any message has already been delivered to the bsmtp file,
# this will detect the existence of the file and all messages will
# go there, regardless of age.
etrn_already:
driver = accept
transport = bsmtp_for_etrn
require_files = /var/spool/etrn/$domain
domains = etrntest.somedomain.com

# If a message has been on the queue for over the specified amount of
# time, this will catch it and drop it into the bsmtp file
etrn_delay:
driver = accept
transport = bsmtp_for_etrn
condition = ${if >{$message_age}{1800} {yes}{no}}
domains = etrntest.somedomain.com

[- -]

Basically, this setup lets exim try to deliver to the real host for up
to whatever time is specified in the \%etrn_delay%\ router. (1800 seconds =
30 minutes), and then delivers all waiting messages, and any further
messages, directly to a BSMTP file. This setup uses one big BSMTP
file per domain, it probably wouldnt be too complex to have it use separate
files.

When the \^etrn_script^\ runs, it locks and renames the BSMTP file, and
reinjects the messages to Exim, which (presumably) will now be able to
deliver them. If it can't, then once they are too old they will again
be sent off to the BSMTP file.. (If for som reason this occurs over and
over without Exim being able to deliver them, eventually the messages
will be returned with \*too many Received headers*\; this is a good
thing, since their age will never get high enough for them to be
returned by any retry rules).

Index: C042
====================================================================
From: Kirill Miazine <lists@???>
Date: Tue, 2 Apr 2002 19:41:24 +0200

Hello,

Since Exim 4 configuration needed to get Mailman work differs a little
bit from Exim 3 and since I still haven't seen a "recipe" for Mailman
with Exim 4, I'm providing my configuration (based heavily on
http://www.exim.org/howto/mailman.html).

Following goes into main config settings:

domainlist lists_domains = lists.krot.org
MAILMAN_HOME=/local/lists
MAILMAN_WRAP=MAILMAN_HOME/mail/wrapper
MAILMAN_UID=mailman
MAILMAN_GID=exim


Following routers are defined:

  list_owner:
      driver = redirect
      domains = +lists_domains
      require_files = MAILMAN_HOME/lists/$local_part/config.db
      local_part_suffix = -owner
      data = ${lc:$local_part}-admin@$domain


  owner_list:
      driver = redirect
      domains = +lists_domains
      require_files = MAILMAN_HOME/lists/$local_part/config.db
      local_part_prefix = owner-
      data = ${lc:$local_part}-admin@$domain


  list_admin:
      driver = accept
      domains = +lists_domains
      require_files = MAILMAN_HOME/lists/$local_part/config.db
      local_part_suffix = -admin
      transport = list_admin


  list_request:
      driver = accept
      domains = +lists_domains
      require_files = MAILMAN_HOME/lists/$local_part/config.db
      local_part_suffix = -request
      transport = list_request


  list:
      driver = accept
      domains = +lists_domains
      require_files = MAILMAN_HOME/lists/$local_part/config.db
      transport = list



And these transports are needed:

  list_admin:
      driver = pipe
      command = MAILMAN_WRAP mailowner ${lc:$local_part}
      current_directory = MAILMAN_HOME
      home_directory = MAILMAN_HOME
      user = MAILMAN_UID
      group = MAILMAN_GID


  list_request:
      driver = pipe
      command = MAILMAN_WRAP mailcmd ${lc:$local_part}
      current_directory = MAILMAN_HOME
      home_directory = MAILMAN_HOME
      user = MAILMAN_UID
      group = MAILMAN_GID


  list:
      driver = pipe
      command = MAILMAN_WRAP post ${lc:$local_part}
      current_directory = MAILMAN_HOME
      home_directory = MAILMAN_HOME
      user = MAILMAN_UID
      group = MAILMAN_GID


Mailman was configured --with-mail-gid=exim.

Index: C043
====================================================================
# Below is an Exim 4 config file which is designed for an Exim server that
# is put in front of an Exchange 5.5 system but which verifies the valid
# addresses that are stored in Exchange via LDAP lookups against the Exchange
# server. The advantage being that I can do much more aggressive spam
# fighting, make my own set of policy decisions etc, using the flexibility of
# Exim while still supporting the Exchange system for final delivery (not my
# ideal situation but the company relies on it). In any case, I thought this
# was sufficiently useful and answers some semi-regular questions on the list,
# that it might be included in either the FAQ or the sample configs.

# From: Tabor J. Wells <twells@???>
# Date: Wed, 21 Aug 2002 11:16:36 -0400




  ######################################################################
  #                  Runtime configuration file for Exim               #
  ######################################################################



# This is a default configuration file which will operate correctly in
# uncomplicated installations. Please see the manual for a complete list
# of all the runtime configuration options that can be included in a
# configuration file. There are many more than are mentioned here. The
# manual is in the file doc/spec.txt in the Exim distribution as a plain
# ASCII file. Other formats (PostScript, Texinfo, HTML, PDF) are available
# from the Exim ftp sites. The manual is also online at the Exim web sites.


# This file is divided into several parts, all but the first of which are
# headed by a line starting with the word "begin". Only those parts that
# are required need to be present. Blank lines, and lines starting with #
# are ignored.


  ########### IMPORTANT ########## IMPORTANT ########### IMPORTANT ###########
  #                                                                          #
  # Whenever you change Exim's configuration file, you *must* remember to    #
  # HUP the Exim daemon, because it will not pick up the new configuration   #
  # until you do. However, any other Exim processes that are started, for    #
  # example, a process started by an MUA in order to send a message, will    #
  # see the new configuration as soon as it is in place.                     #
  #                                                                          #
  # You do not need to HUP the daemon for changes in auxiliary files that    #
  # are referenced from this file. They are read every time they are used.   #
  #                                                                          #
  # It is usually a good idea to test a new configuration for syntactic      #
  # correctness before installing it (for example, by running the command    #
  # "exim -C /config/file.new -bV").                                         #
  #                                                                          #
  ########### IMPORTANT ########## IMPORTANT ########### IMPORTANT ###########




  ######################################################################
  #                    MAIN CONFIGURATION SETTINGS                     #
  ######################################################################


# Specify your host's canonical name here. This should normally be the fully
# qualified "official" name of your host. If this option is not set, the
# uname() function is called to obtain the name. In many cases this does
# the right thing and you need not set anything explicitly.

# primary_hostname =


# The next three settings create two lists of domains and one list of hosts.
# These lists are referred to later in this configuration using the syntax
# +local_domains, +relay_to_domains, and +relay_from_hosts, respectively. They
# are all colon-separated lists:

domainlist local_domains = @ : dbm;/etc/exim/db/localdomains.db
domainlist relay_to_domains =
hostlist relay_from_hosts = 127.0.0.1 : 192.168.1.0/24

# Most straightforward access control requirements can be obtained by
# appropriate settings of the above options. In more complicated situations, you
# may need to modify the Access Control List (ACL) which appears later in this
# file.

# The first setting specifies your local domains, for example:
#
# domainlist local_domains = my.first.domain : my.second.domain
#
# You can use "@" to mean "the name of the local host", as in the default
# setting above. This is the name that is specified by primary_hostname,
# as specified above (or defaulted). If you do not want to do any local
# deliveries, remove the "@" from the setting above. If you want to accept mail
# addressed to your host's literal IP address, for example, mail addressed to
# "user@???", you can add "@[]" as an item in the local domains
# list. You also need to uncomment "allow_domain_literals" below. This is not
# recommended for today's Internet.

# The second setting specifies domains for which your host is an incoming relay.
# If you are not doing any relaying, you should leave the list empty. However,
# if your host is an MX backup or gateway of some kind for some domains, you
# must set relay_to_domains to match those domains. For example:
#
# domainlist relay_to_domains = *.myco.com : my.friend.org
#
# This will allow any host to relay through your host to those domains.
# See the section of the manual entitled "Control of relaying" for more
# information.

# The third setting specifies hosts that can use your host as an outgoing relay
# to any other host on the Internet. Such a setting commonly refers to a
# complete local network as well as the localhost. For example:
#
# hostlist relay_from_hosts = 127.0.0.1 : 192.168.0.0/16
#
# The "/16" is a bit mask (CIDR notation), not a number of hosts. Note that you
# have to include 127.0.0.1 if you want to allow processes on your host to send
# SMTP mail by using the loopback address. A number of MUAs use this method of
# sending mail.


# All three of these lists may contain many different kinds of item, including
# wildcarded names, regular expressions, and file lookups. See the reference
# manual for details. The lists above are used in the access control list for
# incoming messages. The name of this ACL is defined here:

acl_smtp_rcpt = acl_check_rcpt

# You should not change that setting until you understand how ACLs work.


# Specify the domain you want to be added to all unqualified addresses
# here. An unqualified address is one that does not contain an "@" character
# followed by a domain. For example, "caesar@???" is a fully qualified
# address, but the string "caesar" (i.e. just a login name) is an unqualified
# email address. Unqualified addresses are accepted only from local callers by
# default. See the recipient_unqualified_hosts option if you want to permit
# unqualified addresses from remote sources. If this option is not set, the
# primary_hostname value is used for qualification.

# qualify_domain =


# If you want unqualified recipient addresses to be qualified with a different
# domain to unqualified sender addresses, specify the recipient domain here.
# If this option is not set, the qualify_domain value is used.

# qualify_recipient =


# The following line must be uncommented if you want Exim to recognize
# addresses of the form "user@???" that is, with a "domain literal"
# (an IP address) instead of a named domain. The RFCs still require this form,
# but it makes little sense to permit mail to be sent to specific hosts by
# their IP address in the modern Internet. This ancient format has been used
# by those seeking to abuse hosts by using them for unwanted relaying. If you
# really do want to support domain literals, uncomment the following line, and
# see also the "domain_literal" router below.

# allow_domain_literals


# No deliveries will ever be run under the uids of these users (a colon-
# separated list). An attempt to do so causes a panic error to be logged, and
# the delivery to be deferred. This is a paranoic safety catch. Note that the
# default setting means you cannot deliver mail addressed to root as if it
# were a normal user. This isn't usually a problem, as most sites have an alias
# for root that redirects such mail to a human administrator.

never_users = root


# The setting below causes Exim to do a reverse DNS lookup on all incoming
# IP calls, in order to get the true host name. If you feel this is too
# expensive, you can specify the networks for which a lookup is done, or
# remove the setting entirely.

host_lookup = *


# The settings below, which are actually the same as the defaults in the
# code, cause Exim to make RFC 1413 (ident) callbacks for all incoming SMTP
# calls. You can limit the hosts to which these calls are made, and/or change
# the timeout that is used. If you set the timeout to zero, all RFC 1413 calls
# are disabled. RFC 1413 calls are cheap and can provide useful information
# for tracing problem messages, but some hosts and firewalls have problems
# with them. This can result in a timeout instead of an immediate refused
# connection, leading to delays on starting up an SMTP session.

rfc1413_hosts = *
rfc1413_query_timeout = 30s


# By default, Exim expects all envelope addresses to be fully qualified, that
# is, they must contain both a local part and a domain. If you want to accept
# unqualified addresses (just a local part) from certain hosts, you can specify
# these hosts by setting one or both of
#
# sender_unqualified_hosts =
# recipient_unqualified_hosts =
#
# to control sender and recipient addresses, respectively. When this is done,
# unqualified addresses are qualified using the settings of qualify_domain
# and/or qualify_recipient (see above).


# If you want Exim to support the "percent hack" for certain domains,
# uncomment the following line and provide a list of domains. The "percent
# hack" is the feature by which mail addressed to x%y@z (where z is one of
# the domains listed) is locally rerouted to x@y and sent on. If z is not one
# of the "percent hack" domains, x%y is treated as an ordinary local part. This
# hack is rarely needed nowadays; you should not enable it unless you are sure
# that you really need it.
#
# percent_hack_domains =
#
# As well as setting this option you will also need to remove the test
# for local parts containing % in the ACL definition below.


# When Exim can neither deliver a message nor return it to sender, it "freezes"
# the delivery error message (aka "bounce message"). There are also other
# circumstances in which messages get frozen. They will stay on the queue for
# ever unless one of the following options is set.

# This option unfreezes frozen bounce messages after two days, tries
# once more to deliver them, and ignores any delivery failures.

ignore_bounce_errors_after = 2d

# This option cancels (removes) frozen messages that are older than a week.

timeout_frozen_after = 7d

# Defined LDAP default servers
ldap_default_servers = 192.168.1.101



  ######################################################################
  #                       ACL CONFIGURATION                            #
  #         Specifies access control lists for incoming SMTP mail      #
  ######################################################################


begin acl

# This access control list is used for every RCPT command in an incoming
# SMTP message. The tests are run in order until the address is either
# accepted or denied.

acl_check_rcpt:

    # Accept if the source is local SMTP (i.e. not over TCP/IP). We do this by
    # testing for an empty sending host field.


    accept  hosts = :


    # Deny if the local part contains @ or % or / or | or !. These are rarely
    # found in genuine local parts, but are often tried by people looking to
    # circumvent relaying restrictions.


    # Also deny if the local part starts with a dot. Empty components aren't
    # strictly legal in RFC 2822, but Exim allows them because this is common.
    # However, actually starting with a dot may cause trouble if the local part
    # is used as a file name (e.g. for a mailing list).


    deny    local_parts   = ^.*[@%!/|] : ^\\.


    # Accept mail to postmaster in any local domain, regardless of the source,
    # and without verifying the sender.


    accept  local_parts   = postmaster
            domains       = +local_domains


    # Deny unless the sender address can be verified.


    require verify        = sender


    #############################################################################
    # There are no checks on DNS "black" lists because the domains that contain
    # these lists are changing all the time. However, here are two examples of
    # how you could get Exim to perform a DNS black list lookup at this point.
    # The first one denies, while the second just warns.
    #
    # deny    message       = rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
    #         dnslists      = black.list.example
    #
    # warn    message       = X-Warning: $sender_host_address is in a black list at $dnslist_domain
    #         log_message   = found in $dnslist_domain
    #         dnslists      = black.list.example
    #############################################################################


    # Accept if the address is in a local domain, but only if the recipient can
    # be verified. Otherwise deny. The "endpass" line is the border between
    # passing on to the next ACL statement (if tests above it fail) or denying
    # access (if tests below it fail).


    accept  domains       = +local_domains
            endpass
            message       = unknown user
            verify        = recipient


    # Accept if the address is in a domain for which we are relaying, but again,
    # only if the recipient can be verified.


    accept  domains       = +relay_to_domains
            endpass
            message       = unrouteable address
            verify        = recipient


    # If control reaches this point, the domain is neither in +local_domains
    # nor in +relay_to_domains.


    # Accept if the message comes from one of the hosts for which we are an
    # outgoing relay. Recipient verification is omitted here, because in many
    # cases the clients are dumb MUAs that don't cope well with SMTP error
    # responses. If you are actually relaying out from MTAs, you should probably
    # add recipient verification here.


    accept  hosts         = +relay_from_hosts


    # Accept if the message arrived over an authenticated connection, from
    # any host. Again, these messages are usually from MUAs, so recipient
    # verification is omitted.


    accept  authenticated = *


    # Reaching the end of the ACL causes a "deny", but we might as well give
    # an explicit message.


    deny    message       = relay not permitted




  ######################################################################
  #                      ROUTERS CONFIGURATION                         #
  #               Specifies how addresses are handled                  #
  ######################################################################
  #     THE ORDER IN WHICH THE ROUTERS ARE DEFINED IS IMPORTANT!       #
  # An address is passed to each router in turn until it is accepted.  #
  ######################################################################


begin routers

# This router routes to remote hosts over SMTP by explicit IP address,
# when an email address is given in "domain literal" form, for example,
# <user@???>. The RFCs require this facility. However, it is
# little-known these days, and has been exploited by evil people seeking
# to abuse SMTP relays. Consequently it is commented out in the default
# configuration. If you uncomment this router, you also need to uncomment
# allow_domain_literals above, so that Exim can recognize the syntax of
# domain literal addresses.

# domain_literal:
# driver = ipliteral
# domains = ! +local_domains
# transport = remote_smtp


# This router routes addresses that are not in local domains by doing a DNS
# lookup on the domain name. Any domain that resolves to 0.0.0.0 or to a
# loopback interface address (127.0.0.0/8) is treated as if it had no DNS
# entry. Note that 0.0.0.0 is the same as 0.0.0.0/32, which is commonly treated
# as the local host inside the network stack. It is not 0.0.0.0/0, the default
# route. If the DNS lookup fails, no further routers are tried because of
# the no_more setting, and consequently the address is unrouteable.

  dnslookup:
    driver = dnslookup
    domains = ! +local_domains
    transport = remote_smtp
    ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8 : 10.0.0.0/8 : 172.16.0.0/12
    no_more



# The remaining routers handle addresses in the local domain(s).


# This router handles aliasing using a traditional /etc/aliases file.
#
##### NB You must ensure that /etc/aliases exists. It used to be the case
##### NB that every Unix had that file, because it was the Sendmail default.
##### NB These days, there are systems that don't have it. Your aliases
##### NB file should at least contain an alias for "postmaster".
#
# If any of your aliases expand to pipes or files, you will need to set
# up a user and a group for these deliveries to run under. You can do
# this by uncommenting the "user" option below (changing the user name
# as appropriate) and adding a "group" option if necessary. Alternatively, you
# can specify "user" on the transports that are used. Note that the transports
# listed below are the same as are used for .forward files; you might want
# to set up different ones for pipe and file deliveries from aliases.

  system_aliases:
    driver = redirect
    allow_fail
    allow_defer
    data = ${lookup{$local_part}lsearch{/etc/exim/txt/aliases.txt}}
  # user = exim
    file_transport = address_file
    pipe_transport = address_pipe


# This router matches local user mailboxes.
# Domains set to $primary_hostname so that I can route stuff locally as need
# be but prevent user@??? from delivering locally when 'user'
# also matches the Exchange lookup below.

  localuser:
    driver = accept
    check_local_user
    domains = $primary_hostname
    transport = local_delivery
    no_more


# Routers for lookups in LDAP on Exchange if they exist there then punt

# First if it exists as a otherMailbox=smtp$user@??? (Exchange's
# format for aliases then substitute the canonical email address for this user
# as defined by mail=

  exchangeothermailboxlookup:
    driver = redirect
    data = ${lookup ldap {ldap:///?mail?sub?(otherMailbox=smtp\$${quote_ldap:$local_part}@${quote_ldap:$domain})}}
    domains = dbm;/etc/exim/db/localdomains.db
    verify_recipient


# This lookup verifies the mail=user@??? format and if it exists
# Pass to the the manualroute router which is used to punt to the internal
# Exchange server as defined by domain.

  exchangemaillookup:
    driver = redirect
    data = ${lookup ldap {ldap:///?mail?sub?(mail=${quote_ldap:$local_part}@${quote_ldap:$domain})}}
    domains = dbm;/etc/exim/db/localdomains.db
    verify_recipient
    self = pass
    pass_router = exchangeroute
    no_more


# localdomains.db contain entries that look like:
# example.com: 192.168.1.101
# example.net: 192.168.1.102
# etc.

  exchangeroute:
    driver = manualroute
    transport = remote_smtp
    route_data = ${lookup{$domain}dbm{/etc/exim/db/localdomains.db}}


  ######################################################################
  #                      TRANSPORTS CONFIGURATION                      #
  ######################################################################
  #                       ORDER DOES NOT MATTER                        #
  #     Only one appropriate transport is called for each delivery.    #
  ######################################################################


# A transport is used only when referenced from a router that successfully
# handles an address.

begin transports


# This transport is used for delivering messages over SMTP connections.

  remote_smtp:
    driver = smtp



# This transport is used for local delivery to user mailboxes in traditional
# BSD mailbox format. By default it will be run under the uid and gid of the
# local user, and requires the sticky bit to be set on the /var/mail directory.
# Some systems use the alternative approach of running mail deliveries under a
# particular group instead of using the sticky bit. The commented options below
# show how this can be done.

  local_delivery:
    driver = appendfile
    file = /var/mail/$local_part
    delivery_date_add
    envelope_to_add
    return_path_add
  # group = mail
  # mode = 0660



# This transport is used for handling pipe deliveries generated by alias or
# .forward files. If the pipe generates any standard output, it is returned
# to the sender of the message as a delivery error. Set return_fail_output
# instead of return_output if you want this to happen only when the pipe fails
# to complete normally. You can set different transports for aliases and
# forwards if you want to - see the references to address_pipe in the routers
# section above.

  address_pipe:
    driver = pipe
    return_output



# This transport is used for handling deliveries directly to files that are
# generated by aliasing or forwarding.

  address_file:
    driver = appendfile
    delivery_date_add
    envelope_to_add
    return_path_add



# This transport is used for handling autoreplies generated by the filtering
# option of the userforward router.

  address_reply:
    driver = autoreply




  ######################################################################
  #                      RETRY CONFIGURATION                           #
  ######################################################################


begin retry

# This single retry rule applies to all domains and all errors. It specifies
# retries every 15 minutes for 2 hours, then increasing retry intervals,
# starting at 1 hour and increasing each time by a factor of 1.5, up to 16
# hours, then retries every 6 hours until 4 days have passed since the first
# failed delivery.

  # Domain               Error       Retries
  # ------               -----       -------


  *                      *           F,2h,15m; G,16h,1h,1.5; F,4d,6h




  ######################################################################
  #                      REWRITE CONFIGURATION                         #
  ######################################################################


# There are no rewriting specifications in this default configuration file.

begin rewrite



  ######################################################################
  #                   AUTHENTICATION CONFIGURATION                     #
  ######################################################################


# There are no authenticator specifications in this default configuration file.

begin authenticators


# End of Exim configuration file

Index: C044
====================================================================
Date: Mon, 2 Dec 2002 10:35:06 +0000
From: Mike Richardson <doctor@???>

Hiya,

I thought I'd submit this as an example of an authenticated mail hub
configuration. Several people have asked for it so I thought it
might be of interest.

Authenticated mail hubs using LDAP to authenticate against which simply
forward mail to central mailrouters. X headers are added for audit
trail purposes.

Config:
#########################################################################

acl_smtp_rcpt = acl_check_rcpt

ignore_bounce_errors_after = 12h

timeout_frozen_after = 3d

# LDAP server:

hide ldap_default_servers=ldap.your.site

# SSL options. advertise TLS but don't insist on it.

tls_advertise_hosts=*
tls_certificate=/var/cert/securemail.your.site.cert
tls_privatekey=/var/cert/securemail.your.site.key
tls_verify_hosts= *

# Remove the queue runner logs and add logging of the interface, protocols
# and connections. Useful for debugging when users are having difficulty
# configuring and connecting. Many ISPs use Transparent Proxying

log_selector= +incoming_interface -queue_run +smtp_protocol_error
+smtp_syntax_error +smtp_connection

# SMTP input limits. Some connections are reserved for local users.

smtp_accept_max=200
smtp_accept_queue=150
smtp_accept_reserve=10
smtp_reserve_hosts=130.88.0.0/16
smtp_connect_backlog=100

# Overloading

queue_only_load=5
deliver_queue_load_max=7

# Message size limits

message_size_limit=10M
return_size_limit=65535

# Spool space check

check_spool_space=100M

# directory splitting

split_spool_directory

# Parallel remote deliver

remote_max_parallel = 10

# My system filter is to create extra logging info for X-Mailer info.

system_filter=/etc/systemfilter
system_filter_user=exim

# Listen of multiple interfaces to defeat transparent proxying

local_interfaces = 130.88.200.47.25 : 130.88.200.47.465 : 130.88.200.47.587

# Only accept local traffic and authenticated stuff.
# Error message points to useful web page.

acl_check_rcpt:

    accept  hosts = :
    deny    local_parts   = ^.*[@%!/|]
    require verify        = sender


    accept  authenticated = *


    deny    message       = Not authenticated, see http://www.useful.web.page/




  ######################################################################
  #                      ROUTERS CONFIGURATION                         #
  #               Specifies how addresses are handled                  #
  ######################################################################


begin routers

# Manual route to force all traffic through our hubs which handle all
# the alias expansion, domain routing etc.
# I add an X header for audit trail purposes but no more information that
# would be expected from a legitimate email. Don't want to upset the DPA
# people

  smarthost:
    driver = manualroute
    headers_add =X-Authenticated-Sender: ${lookup ldap\
  {ldap:///o=ac,c=uk?cn?sub?(&(uid=$authenticated_id))}{$value}{no}} from \
  ${sender_fullhost}\nX-Authenticated-From: ${lookup ldap\
  {ldap:///o=ac,c=uk?mail?sub?(&(uid=$authenticated_id))}{$value}{no}}
    transport = remote_smtp
    domains = ! +local_domains
    route_list=* mailrouter.your.site 
    ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
    no_more


# All other routes as per normal...


  ######################################################################
  #                   AUTHENTICATION CONFIGURATION                     #
  ######################################################################


# This only supports PLAIN and LOGIN due to the nature of our LDAP server.

begin authenticators

  plain:
    driver= plaintext
    public_name = PLAIN
    server_condition="${lookup ldap {user=\"${lookup \
  ldapdn{ldap:///o=ac,c=uk?sn?sub?(&(uid=$2))}{$value}{no}}\" pass=$3 \
  ldap:///o=ac,c=uk?sn?sub?(&(uid=$2))}{yes}{no}}"
    server_set_id = $2


  login:
    driver = plaintext
    public_name= LOGIN
    server_prompts = "Username:: : Password::"
    server_condition="${lookup ldap {user=\"${lookup \
  ldapdn{ldap:///o=ac,c=uk?sn?sub?(&(uid=$1))}{$value}{no}}\" pass=$2 \
  ldap:///o=ac,c=uk?sn?sub?(&(uid=$1))}{yes}{no}}"
    server_set_id=$1
  # End of Exim configuration file
  ##########################################################################


Index: C045
====================================================================
Date: Tue, 20 Aug 2002 07:33:36 -0700
From: "Kevin P. Fleming" <kpfleming@???>

Here it is, for Exim 4.10 and Cyrus IMAPD 2.1.5 using db3/db4-format
mailbox database. This configuration delivers the messages to Cyrus
IMAPD using LMTP over a TCP/IP socket, so the cyrus.conf file needs to
start lmtpd as "lmtpd -a" so the connection will be pre-authenticated
(given that, it is also important that the cyrus.conf file restrict
lmtpd to listening on 127.0.0.1 _only_, otherwise random users could
submit messages directly to lmtpd).


routers:

  # look in the Cyrus IMAPD mailboxes.db file for local_domains local
  # parts to be verified
  local_user_verify:
     driver = accept
     domains = +local_domains
     local_part_suffix = +*
     local_part_suffix_optional
     condition = ${lookup{user.${local_part}} dbmnz {/storage/imap/mailboxes.db} {yes}{no}}
     verify_only


  # rewrite local_domains local parts to be all lowercase
  lowercase_local:
     driver = redirect
     redirect_router = local_user
     domains = +local_domains
     data = ${lc:${local_part}}


  # deliver local_domains messages
  local_user:
     driver = accept
     domains = +local_domains
     transport = local_delivery



transport:

  # deliver messages to Cyrus IMAPD using LMTP over TCP/IP on the loopback
  interface
  local_delivery:
     driver = smtp
     protocol = lmtp
     allow_localhost = yes
     hosts = 127.0.0.1



Index: C046
====================================================================
Date: Wed, 18 Sep 2002 15:22:44 +0100 (BST)
From: Tony Finch <fanf2@???>

I wanted to be able to preserve the envelope contents (except for the return
path when I'm feeling paranoid about error handling).

Feel free to add this to the examples -- someone else might find it useful. I
also have a complete configuration which I have been recommending to other
people in Cambridge (although it could work elsewhere with tweaks) at
http://www-uxsup.csx.cam.ac.uk/~fanf2/conf4.satellite.

# Deliver a duplicate of some proportion of all messages to a special
# machine specified in the file /MAIL_TAP_HOST, if it exists. The
# probability of sending a message is the reciprocal of the second
# number in the hash part of the condition. The address data is used
# to prevent redirected addresses from being tapped twice. The
# originating host and sender are recorded in extra headers. If the
# delivery fails the bounce goes to a rubbish bin (although this means
# that the traffic seen by the tap is not quite the same as the
# traffic seen here).

  traffic_tap:
    unseen
    no_expn
    no_verify
    transport = smtp
    driver = manualroute
    require_files = /MAIL_TAP_HOST
    route_data = ${readfile{/MAIL_TAP_HOST}{:}}
    address_data = ${if!def:address_data{tapped}fail}
    condition = ${if!eq{a}{${hash_1_1:$message_headers$message_body}}{no}{yes}}
    headers_add = ${if!def:sender_host_address{}{X-Orig-Remote-Host: $sender_host_address}}\n\
                  X-Orig-Return-Path: $return_path
    errors_to = YOUR_RUBBISH_BIN_ADDRESS_HERE



Index: C047
====================================================================
From: Oliver Egginger <Oliver.Egginger@???>
Date: 21 May 2003 10:11:16 +0200

Hi there,

download the spamassassin package. See
http://au.spamassassin.org/downloads.html

Define a router in your Exim configuration file.
For Exim 4 it could look like this:

  # Spam Assassin
  spamcheck_router:
    no_verify
    check_local_user
    # When to scan a message :
    #   -   it isn't already flagged as spam
    #   -   it isn't already scanned
    #   -   comes from ABC.DEF.GHI.JKL or MNO.PQR.STU.VWX
    #   -   .spamcheck exists for this user
    condition = \
    "${if and { {!def:h_X-Spam-Flag:} \
                {!eq {$received_protocol}{spam-scanned}} \
                {or { {eq {$sender_host_address}{ABC.DEF.GHI.JKL}} \
                      {eq {$sender_host_address}{MNO.PQR.STU.VWX}} \
                    }\
                }\
              }\
              {1}{0}\
      }"
    require_files = $home/.spamcheck
    driver = accept
    transport = spamcheck



This router has two advantages (for us):

1. You can define the sender host addresses from which you will scan the spam.
In my example there are ABC.DEF.GHI.JKL and MNO.PQR.STU.VWX (you have to
substiute this by your real IP-Adresses).

2. The spamcheck router only runs in dependency of the existence of the
.spamcheck file. So your users can decide whether or not they wont to use
Spamassassin. Thats important for protection of privacy in germany.

If you don't need this you can simplify the router, for example:

  # Spam Assassin
  spamcheck_router:
    no_verify
    check_local_user
    # When to scan a message :
    #   -   it isn't already flagged as spam
    #   -   it isn't already scanned
    condition = \
    "${if and { {!def:h_X-Spam-Flag:} \
                {!eq {$received_protocol}{spam-scanned}} \
              }\
              {1}{0}\
      }"
    driver = accept
    transport = spamcheck



In the end you will need a spamcheck transport. This one works well for us:

  # Spam Assassin
  spamcheck:
      driver = pipe
      command =  /usr/exim/bin/exim -oMr spam-scanned -bS
      use_bsmtp = true
      transport_filter = /usr/bin/spamc
      home_directory = "/tmp"
      current_directory = "/tmp"
      # must use a privileged user to set $received_protocol on the way
      # back in!
      user = mail
      group = mail
      log_output = true
      return_fail_output = true
      return_path_add = false
      message_prefix =
      message_suffix =



Put the router and the transport on the right places in your exim conf and send
the daemon a HUP signal. Thats all.

- oliver

Index: C049
====================================================================
From: Suresh Ramasubramanian <linux@???>
Date: Mon, 11 Aug 2003 11:57:39 +0530

I've been seeing a whole bunch of IPs that send me spam / virus mail and
HELOing as one of my own IPs, or as HELO one.of.my.own.domains (or maybe
HELO primary_hostname)

On the other hand, I have users relaying through my box with AUTH, using
mozilla, which HELO's as "HELO hserus.net" if a hserus.net user relays.

Here's something to stop this stuff - in acl_check_rcpt:

[snippet in exim configure file]

    accept  hosts = :


    # Accept all authenticated senders
    accept  authenticated = *


    # Spam control


    # Be polite and say HELO. Reject anything from hosts that havn't given
    # a valid HELO/EHLO to us.
    deny condition = ${if \
      or{{!def:sender_helo_name}{eq{$sender_helo_name}{}}}{yes}{no}}
             message = RFCs mandate HELO/EHLO before mail can be sent


    # Forged hostname - HELOs as my own hostname or domain
    deny    message = Forged hostname detected in HELO: $sender_helo_name
      hosts    = !+relay_from_hosts
      log_message = Forged hostname detected in HELO: \
      $sender_helo_name
      condition = ${lookup {$sender_helo_name} \
          lsearch{/usr/local/etc/exim/local_domains}{yes}{no}}


    # Forged hostname -HELOs as one of my own IPs
    deny message = Forged IP detected in HELO: $sender_helo_name
         hosts = !+relay_from_hosts
         log_message = Forged IP detected in HELO: $sender_helo_name
         condition = ${if \
        eq{$sender_helo_name}{$interface_address}{yes}{no}}


[end snippet]


  Index: C050
  ====================================================================
  From: David Woodhouse <dwmw2@???> 
  Date: Thu, 18 Dec 2003 14:25:47 +0000                                          


Given a domain in DNS of the form...

  $ORIGIN vdns.infradead.org.mailtarget.
  fish        604800    IN    TXT    dwmw2@???


(It doesn't _have_ to be in private namespace; you can put it anywhere but I
prefer to have it private)

The following routers use it to implement a virtual domain. You could of course
omit the first and just make sure you have postmaster in all the zones you use
this way...

Rather than hardcoding the DNS domain to use in the router, we can put it into
a flat file with the list of domains for which we should be doing this.

We put this into /etc/exim/dns-virtual-domains:

      vdns.infradead.org: vdns.infradead.org.mailtarget


In the main section of the configuration file we have:

domainlist dns_virtual_domains = lsearch;CONFDIR/dns-virtual-domains

The following routers handle unqualified addresses, multiple TXT records, and
entries of the form '@domain'. Also if we're not primary MX for the virtual
domain in question we'll fall back to forwarding to a higher-priority MX host
if the DNS isn't talking to us....

  virtual_postmaster:
    driver = redirect
    domains = +dns_virtual_domains
    local_parts = postmaster:root:abuse:mailer-daemon
    data = postmaster@$primary_hostname


    # For virtual domains, look up the target in DNS and rewrite...


  dns_virtual_domains:
    driver = redirect
    domains = +dns_virtual_domains
    check_ancestor
    repeat_use
    one_time
    allow_defer
    allow_fail
    forbid_file
    forbid_pipe
    retry_use_local_part
    qualify_preserve_domain


     # Stash the lookup domain root for use in the next router.
    address_data = ${lookup{$domain}lsearch{CONFDIR/dns-virtual-domains}}


    # The lookup failure won't distinguish between absent record, absent
    # domain, or other temporary failures. So we make this router just
    # give up, and sort out the various failure modes later.


    # The ${sg...} bits turn multiple TXT records (which Exim gives us
    # separated by \n) into a comma-separated list, and also rewrite
    # any element of that list of the form '@domain' (i.e. without a
    # local part) to $local_part@domain, using the original local part
    # from the address being routed, at the newly-provided domain.


    # Addresses containing _only_ a localpart are qualified at the
    # same domain as is being looked up, by qualify_preserve_domain
    # above.
    data = ${sg{\
          ${sg{\
             ${lookup dnsdb{txt=$local_part.$address_data}{$value}fail}\
          }{\n}{,}}\
       }{(,|^)[ ]*@}{\$1\$local_part@}}


  dns_virtual_failed:
    driver = redirect
    domains = +dns_virtual_domains
    allow_fail
    allow_defer
    data = ${lookup dnsdb{ns=$address_data}\
      # If NS lookup succeeded, the domain exists and we can find it.
      # Therefore, the above lookup failure meant that the user
          # just doesn't exist. Fail appropriately:
      {:fail:Unknown user at virtual domain}\
      # NS lookup failed. This means there's a DNS problem -- so we
      # shouldn't fail the delivery; let the following routers handle
      # it... Note "fail" not "{:fail:}". It means 'pass'. :)
      fail}



    # We have DNS problems. If we're actually _delivering_, then try to
    # deliver to a higher-priority MX if one exists. Otherwise, we defer and
    # let it stay on the queue until the problem is fixed.
    # You may prefer to freeze or bounce in this situation; I don't.
  dns_virtual_relay:
    driver = dnslookup
    domains = +dns_virtual_domains
    transport = remote_smtp
    self = defer
    no_verify
    no_more


    # On the other hand, if there's a DNS problem and we're only _verifying_,
    # as we do when accepting incoming mail, then accept it for now and
    # it'll get queued for when the DNS works again.
  dns_virtual_verify_fallback:
    driver = accept
    domains = +dns_virtual_domains
    verify_only
    no_more


> Now I just need to investigate DDNS and see if it'll let individual
> users update the TXT records for their own aliases in the DNS... :)


This is remarkably simple to set up -- Google is your friend. I'm now
able to set up HMAC-MD5 keys to 'own' certain mail domains, and the
owners of those virtual mail domains can happily change the TXT records
to their hearts content, without bugging me to make changes and roll out
new alias files to all the MX hosts.

A setuid app which is able to read the key file, and which will update
the alias only for the user it's invoked by, is also fairly trivial to
implement -- inspired by the 'cammail' alias system.


Index: C051
====================================================================
From: Nathan Ollerenshaw <nathan@???>

## I've been working quite hard to come up with a config that reasonably
## matches the qmail-ldap setup, without the warts. I want to submit it
## for inclusion in your config.samples archive, in case anyone else needs
## to do the same as I. I hope its useful.
##
## A few notes; it supports catchalls but not dash extension addressing,
## as I couldn't be bothered, and I'm unsure as to how many people
## actually use the feature. Certainly nobody on my system. It supports
## autoreplies, but not an autoreply on a catchall, because this just
## kills your mailserver when someone does a dictionary spam attack
## against a domain set up this way.


  ######################################################################
  #                  Runtime configuration file for Exim               #
  ######################################################################


#domainlist local_domains = @ : lsearch:/apps/conf/mail/locals
domainlist local_domains = lsearch;/apps/conf/mail/locals
domainlist relay_to_domains =

# the pop-before-smtp package at http://popbsmtp.sourceforge.net/
# creates the /etc/mail/popauth.db file for us. We have to use dbmnz
# lookup type here.

hostlist relay_from_hosts = 127.0.0.1 : net-dbmnz;/etc/mail/popauth.db
primary_hostname = [[[SET THIS TO LOCAL HOST NAME]]]

# LDAP settings

# Set the following to your ldap server(s)
ldap_default_servers = ldap::389
BASEDN = [[[SET THIS TO YOUR BASE DN IN LDAP]]]

acl_smtp_rcpt = acl_check_rcpt
acl_smtp_data = acl_check_data

exim_user = vmail
exim_group = vmail
trusted_users = vmail
never_users = root
host_lookup = *
rfc1413_hosts = *
rfc1413_query_timeout = 0s
ignore_bounce_errors_after = 2d
timeout_frozen_after = 7d
bounce_return_body = false
accept_8bitmime = true
allow_mx_to_ip = true
auto_thaw = 60m
smtp_accept_max = 0
smtp_load_reserve = 20
delay_warning = 4h:8h:24h
dns_again_means_nonexist = !+local_domains : !+relay_to_domains

spamd_address = 127.0.0.1 783
av_scanner = clamd:127.0.0.1 3310

# Spool settings

split_spool_directory = true
check_spool_space = 100M
check_spool_inodes = 1000

# Logging - enable a bunch of extra useful stuff. Never know, could help
# one day, and at least its better than qmail! Har har!

  log_selector = +delivery_size +received_sender +received_recipients \
          +subject +sender_on_delivery


# NOTE TO SELF: Lets use syslog and have all six mail servers log to a
# central location so its easier to do statistics gathering and fault
# analysis.

# MACROS

# Secret for all machines in the cluster. Change it to whatever you feel
# is best.

SECRET = Ni2opNyw2pNM3cmWn21nOSbwdq

  GET_ADDRESS_DATA = ${lookup ldap {\
          ldap:///BASEDN??sub?(&(uid=${quote_ldap:$local_part}@${quote_ldap:$domain}))\
          }\
  }


  GET_CATCHALL_DATA = ${lookup ldap {\
          ldap:///BASEDN??sub?(&(uid=catchall@${quote_ldap:$domain}))\
          }\
  }


MSGCOOKIE = ${hmac{md5}{SECRET}{$body_linecount}}

  ######################################################################
  #                      ROUTERS CONFIGURATION                         #
  #               Specifies how addresses are handled                  #
  ######################################################################


begin routers

  dnslookup:
    driver = dnslookup
    domains = ! +local_domains
    transport = remote_smtp
    ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
    no_more


  system_aliases:
    driver = redirect
    condition = ${if eq {{$primary_hostname}{$domain} {1}{0}} }
    allow_fail
    allow_defer
    data = ${lookup{$local_part}lsearch{/etc/aliases}}
    file_transport = address_file
    pipe_transport = address_pipe


# the forward router does the initial LDAP lookup. It then caches this in
# $address_data for use by any of the other routers. Each router will fall
# through if they then don't meet their condition.

  lookup:
    driver = redirect
    address_data = GET_ADDRESS_DATA
    # data is intentionally left blank so that the router will decline
    # we just want this router to do a lookup so the results are availble
    # for the other routers.
    data = 


# OK, this is where we start supporting crazy qmail-ldap stuff. First, we
# check if the address has a deliveryMode of 'forwardonly'. forwardonly is
# a misnomer, because its possible for and address to be a forward, a mailbox
# and an autoreply. So, we make it do the forward, and check to see if it is
# also a reply or localdelivery, if so we set unseen to yes to make Exim
# copy the message and send it to the next router.

  forward:
    driver = redirect
    condition = ${if match {${extract{deliveryMode}{$address_data}}}{forwardonly} {1}{0}}
    data = ${extract{mailForwardingAddress}{$address_data}}
    unseen = ${if or {{match {${extract{deliveryMode}{$address_data}}}{reply}} \
                      {match {${extract{deliveryMode}{$address_data}}}{localdelivery}}} \
                      {yes}{no}}


# Same deal, check if its a reply, if so we send it to the correct transport.
# After, we see if it needs to go to localdelivery as well.

  reply:
    driver = accept
    condition = ${if match {${extract{deliveryMode}{$address_data}}}{reply} {1}{0}}
    transport = auto_reply
    unseen = ${if match {${extract{deliveryMode}{$address_data}}}{localdelivery} {yes}{no}}


  localdelivery:
    driver = accept
    condition = ${if match {${extract{deliveryMode}{$address_data}}}{localdelivery} {1}{0}}
    transport = local_delivery


# If we've reached this point, the account doesn't exist, so we need to
# check to see if there is a catchall account, and if so do the usual for
# it too. NOTE: we do not support auto-reply in a catch-all.
#
# This could, of course, be abused by someone assigning an auto-reply to
# a forward_catchall.

  # NOTE TO SELF: See if reply router can be failed if an address comes from
  #               a catchall.


  lookup_catchall:
    driver = redirect
    address_data = GET_CATCHALL_DATA
    # data is intentionally left blank so that the router will decline
    # just want this router to do a lookup.
    data =  
    # could probably do a no_more = true based on the result of that LDAP
    # lookup to skip the next few routers, but there is no point as they are
    # not doing anything heavy so I'll just let them fall through and fail.


# The catchall routers are exactly the same as the above routers, except
# they make use of the GET_CATCHALL_DATA address_data to decide what to do
# with the mail.

  forward_catchall:
    driver = redirect
    condition = ${if match {${extract{deliveryMode}{$address_data}}}{forwardonly} {1}{0}}
    data = ${extract{mailForwardingAddress}{$address_data}}
    unseen = ${if match {${extract{deliveryMode}{$address_data}}}{localdelivery} {yes}{no}}


  localdelivery_catchall:
    driver = accept
    condition = ${if match {${extract{deliveryMode}{$address_data}}}{localdelivery} {1}{0}}
    transport = local_delivery


  ######################################################################
  #                      TRANSPORTS CONFIGURATION                      #
  ######################################################################


begin transports

  remote_smtp:
    driver = smtp


# Deliver to the mailbox specified in the LDAP directory. We make sure
# that quota is obeyed, and we try to send a messge to the user if it
# gets to over 85%.

  local_delivery:
    driver = appendfile
    maildir_format
    directory = ${extract{mailMessageStore}{$address_data}}/Maildir
    create_directory
    directory_mode = 0700
    delivery_date_add
    envelope_to_add
    return_path_add
    group = vmail
    user = vmail
    mode = 0600
    quota = ${eval:${sg{${extract{1}{,}{${extract{mailQuota}{$address_data}}}}}{S}{}}/1024}K
    maildir_use_size_file = true
    quota_warn_threshold = 85%


# We set this to iso-2022-jp because we're in japan. Set it to whatever.

  auto_reply:
    driver = autoreply
    subject = "[Auto-Reply] $header_subject"
    headers = "Content-Type: text/plain; charset=iso-2022-jp"
    to = "$sender_address"
    text = ${extract{mailReplyText}{$address_data}}
    from = $local_part@$domain



  ######################################################################
  #                       ACL CONFIGURATION                            #
  #         Specifies access control lists for incoming SMTP mail      #
  ######################################################################


begin acl

# You should probably set up exiscan-acl's mime check here to scan for viruses
# and spam and reject at SMTP time. As I won't be doing that for a while, I've
# left it as an exercise for the reader.

  acl_check_rcpt:
    accept  hosts = :
    deny    message       = Restricted characters in address
            domains       = +local_domains
            local_parts   = ^[.] : ^.*[@%!/|]
    deny    message       = Restricted characters in address
            domains       = !+local_domains
            local_parts   = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
    accept  local_parts   = postmaster
            domains       = +local_domains
    require verify        = sender
    accept  domains       = +local_domains
            endpass
            verify        = recipient
    accept  domains       = +relay_to_domains
            endpass
            verify        = recipient
    accept  hosts         = +relay_from_hosts
    accept  authenticated = *
    deny    message       = relay not permitted


  acl_check_data:
    require verify        = header_syntax
            message       = This message has malformed headers.
    deny    message       = This message contains malformed MIME ($demime_reason).
            demime        = *
            condition     = ${if >{$demime_errorlevel}{2}{1}{0}}
    deny    message       = We do not accept ".$found_extension" attachments here as \
                            they are common file extensions for viruses. If you wish \
                            to send such an attachment, please zip it first.
            demime        = bat:btm:cmd:com:cpl:dll:exe:lnk:msi:pif:prf:reg:scr:vbs:url
    accept


begin retry

  # Address or Domain    Error       Retries
  # -----------------    -----       -------


  *                      *           F,2h,15m; G,16h,1h,1.5; F,4d,6h


  ######################################################################
  #                      REWRITE CONFIGURATION                         #
  ######################################################################


# There are no rewriting specifications in this default configuration file.

begin rewrite

  ######################################################################
  #                   AUTHENTICATION CONFIGURATION                     #
  ######################################################################


# There are no authenticator specifications in this default configuration file.

begin authenticators

  plain:
    driver = plaintext
    public_name = PLAIN
    server_condition = ${if ldapauth {user="uid=${quote_ldap_dn:$2},BASEDN" \
                          pass=${quote:$3} ldap:///}{yes}{no}}
    server_set_id = $2



  login:
    driver = plaintext
    public_name = LOGIN
    server_prompts = Username:: : Password::
    server_condition = ${if ldapauth {user="uid=${quote_ldap_dn:$1},BASEDN" \
                          pass=${quote:$2} ldap:///}{yes}{no}}
    server_set_id = $1


  ######################################################################
  #                   CONFIGURATION FOR local_scan()                   #
  ######################################################################


# begin local_scan

# End of Exim configuration file

Index: F001
====================================================================
From: Ephraim Silverberg <ephraim@???>
Date: Tue, 17 Feb 1998 12:55:55 +0200

We're using Exim 1.82 and have written a message filter to intercept spam
messages that RBL doesn't catch. Since we have met with reasonable success
since installing (and refining) the filter -- 566 genuine spam messages
intercepted during a time period where there were 67 RBL rejections -- I
thought that the rest of the list may be interested in reviewing our filter
as a starting point for their own system message filter.

There are a number of caveats, however:

  1. The suspected spam is not automatically rejected as RBL hosts are, but
     is saved to a folder that should be read/writable by the mail
     administrators.  The reason for this is that the filter catches also
     some legitimate mail and these messages should be bounced to their
     originally intended recipient(s) (ala X-Envelope-To:) and the filter
     refined and/or the databases (described below) updated.


  2. My filter traps blank/non-existent To: lines as well as To: lines
     contained in From: lines, but firsts exempts the following categories
     from this check: mailing lists, local mail, mail originating in the
     country (e.g. in our case *.il) and mail coming from autosupport servers.


Beyond implicit checks, it uses four DBM databases: two that exempt the
message from any spam (beyond RBL) checks (software servers and strange mailing
lists need to be here) -- one based on $sender_address and the other on
$header_to: lines -- and, conversely, two databases for known spammers that
have valid mail headers that aren't caught by implicit checks. All entries
in these databases are lowercase so that we don't need two lines for
'friend@???' and 'Friend@???'.

The sample filter package is at ftp://ftp.cs.huji.ac.il/pub/exim/spam_filter/

Comments and suggestions are welcome.

Index: F002
====================================================================
Date: Tue, 03 Mar 1998 15:45:24 -0500
From: Dan Birchall <djb@???>

History:

In early 1997, I wrote a little PERL program which refused
mail from unknown addresses until they mailed me promising
not to spam me. (This ran on my account as an end-user
solution.) It was very effective, but didn't scale well.

Recently, I'd been thinking of adding some similar
functionality to my Exim filter file. Someone on another
list mentioned that they were going to work on doing the
same in their Sendmail config, and since I'd already
thought through how to do it in Exim, and knew it'd be
slightly easier than falling out of bed, I went ahead and
did it. I mentioned having done it, and Piete bugged me
to send it here too. :)

Structure:

There are two (optionally three) flat files involved, plus
a system-wide filter file and one (optionally two) shell
script(s).

The first flat file contains a list of recipient e-mail
addresses handled by my server, with parameters stating
whether they do or do not wish to be afforded some degree
of protection from spam through various filters. An
excerpt:

djb@???: spam=no
djb@???: spam=no untrusted=no
djb@???: spam=no relay=no untrusted=no

Various filters in my filter file read this, and based
on the values of certain parameters, will take certain
measures to prevent spam from reaching an address. This
particular filter works on the "untrusted" parameter.

The second flat file contains a list of IP addresses for
hosts that the server has been instructed to trust. (At
this point, this is a system-wide list; if a host is
trusted, it's trusted for all addresses. It should be
fairly similar to arrange for some sort of user-specific
list, but I haven't had the need.) An excerpt:

206.214.98.16: good=yes
205.180.57.68: good=yes
204.249.49.75: good=yes

The filter is as follows:

if
${lookup{$recipients:untrusted}lsearch{/usr/exim/lists/shield}{$value}}
is "no"
and
${lookup{$sender_host_address:good}lsearch{/usr/exim/lists/good_hosts}{$value}}
is ""
then freeze endif

Basically, if $recipients is found in the first file, with
an "untrusted=no" parameter, and the sending host's IP
address is *not* in the second file, or does not have a
"good=yes" parameter next to it, the message is frozen.

I then come along as root and run this script, with the
Exim message ID as the only argument:

echo -n `grep host_address /usr/exim/spool/input/$1-H |cut -f2 -d" "` >>
/usr/exim/lists/good_hosts
echo ": good=yes" >> /usr/exim/lists/good_hosts
sendmail -M $1

This adds the sending host's IP to the good_hosts file and
forces delivery of the message.

Options:

The other optional file is a blacklist; the other optional
script puts the sending host's IP in *that* file and deletes
the message.

This is just yet another fun little way to play with spam.
(Looks like meat, tastes like play-doh... or is it the
other way around?)

Bugs:

Yes, there are weaknesses. Specifically:

* multi-address $recipients will probably get by this
* scalability is always a concern
* large ISP's that generate lots of mail _and_ spam...

This is near the top of my filter file, though, and
there are several other filters below it to catch any
stuff it might miss.

Index: F003
====================================================================
Date: Sat, 4 Apr 1998 07:23:39 +0200 (GMT+0200)
From: "F. Jacot Guillarmod" <Jacot@???>

Here's four checks installed in our system wide filter that knock out
a lot of otherwise hard to detect rubbish - and would handle the above
example. The most interesting one is the hotmail.com "validity check".

  # ===========================================================================
  # authenticated sender, but not from pegasus
  #-------------------------------------------
  elif "$h_comments" contains "authenticated sender" and
       "$h_x-mailer" does not contain "pegasus" then


      log "$tod_log $message_id SPAMAUTHS: sender=$sender_address \
       subject=$header_subject: recipients_count=$recipients_count \
       recipients=$recipients"
      save /usr/local/lib/mail/spam


  # claims to be from hotmail.com
  #------------------------------
  elif "$h_from" contains "hotmail.com" and
       "${if !def:header_x-originating-ip {nospam}}" is nospam then


      log "$tod_log $message_id SPAMHOTMAIL: sender=$sender_address \
       subject=$header_subject: recipients_count=$recipients_count \
       recipients=$recipients"
      save /usr/local/lib/mail/spam


  # claims to be from juno.com
  #------------------------------
  elif "$h_from" contains "juno.com" and
       "${if def:header_x-mailer {juno} {spam}}" is spam then


      log "$tod_log $message_id SPAMJUNO: sender=$sender_address \
       subject=$header_subject: recipients_count=$recipients_count \
       recipients=$recipients"
      save /usr/local/lib/mail/spam


# spam X-UIDL header found
# ------------------------
elif "${if def:header_x-uidl {spam}}" is spam then

      log "$tod_log $message_id SPAM-X-UIDL: sender=$sender_address \
       subject=$header_subject: recipients_count=$recipients_count \
       recipients=$recipients"
      save /usr/local/lib/mail/spam
  # ===========================================================================



The following rule seems to work (but I don't use it):

# either To: is contained in From: or there is no To: line
# --------------------------------------------------------
elif $h_from contains $h_to then

       log "$tod_log $message_id SPAM-TOEQFRM: sender=$sender_address \
       subject=$header_subject: recipients_count=$recipients_count \
       recipients=$recipients"
       save /usr/local/lib/mail/spam
  # --------------------------------------------------------




Here's parts of my personal .forward file - I'm relying on the system wide exim
configs to zap spam, and only do the old fashioned stuff to whatever gets
through:

  #==========================================================================
  # Exim filter            <<== do not edit or remove this line


if error_message then finish endif

logfile $home/eximfilter.log

  # Mail from support system
  if   $header_subject contains "[Help #"
  then
    save $home/Mail/in.support


  # Mail from squid mailing list to local newsgroup
  elif   $header_subject contains "squid-users-digest"
  then
    deliver "<ru-list-squid@???>"


  # Mail from exim-users mailing list to local newsgroup
  elif   $return_path contains "exim-users-request"
  then
    deliver "<ru-list-exim-users@???>"


  # Stuff to be thrown away
  if   $header_subject contains "Warning From uucp"
  then
    seen finish
  endif


#==========================================================================


Index: F004
====================================================================
Date: Tue, 23 Nov 1999 02:49:32 +0200
From: Vadim Vygonets <vadik@???>

This is an Exim filter snippet to change locally-generated
Message-Id: and Resent-Message-Id: headers to world-unique values.


# Exim filter

  # Copyright (c) 1999
  #    Hans Matzen <hans@???>,
  #    Vadim Vygonets <vadik@???>.  All rights reserved.


#################################################################
# Change locally-generated Message-Id: and Resent-Message-Id:
# headers to world-unique values.

# Notes:
# Change every occurence of "home.dom" to your home domain.
# Change every occurence of "uniqie.remote.dom" to some unique value.

# Unique values, as Vadik explained in his message to exim-users,
# can be chosen in different ways:

### The ideal way is to choose "hostnames" in existing domains whose
### admins you know, and you will be sure that no hostname ending
### with ".nonexistant.friendly.dom" will ever appear on this planet,
### not even on someone else's message IDs.

### Another ideas include putting after your hostname things like:
### .972.2.6412694.phone
### .29.32.columbia.street.jerusalem.96583.israel.addr
### .1122.3576.3847.1446.visa.01.2002.expiration.date.vadim.vygonets.name.credit.card

# This snippet provides to schemes to do such rewriting. The
# first scheme is to have mapping from local hostnames to unique
# "Message-Id domains". The second scheme is to use one unique
# "Message-Id domain", inserting the original "domain" into the
# "local-part" of the new Message-Id header.

# Precaution
headers remove "X-Vygo-Net-Temporary-Message-Id"

  # Change Message-Id:
  if "${if def:h_Message-Id: {yes}}" is yes and 
      ${lc:${domain:$h_Message-Id:}} is    "home.dom" or
      ${lc:${domain:$h_Message-Id:}} ends ".home.dom" then
  # This is if you want to have a file mapping each hostname to a unique
  # Message-Id domain part, or, if it fails, preserves the original domain part:
  #    headers add "X-Vygo-Net-Temporary-Message-Id: <${local_part:$h_Message-Id:}@${lookup{${domain:$h_Message-Id:}}lsearch{/var/exim/msgid-hosts}{$value}{${domain:$h_Message-Id:}}}>\n"
  # This rewrites Message-Id as <local_part.domain@???>:
      headers add "X-Vygo-Net-Temporary-Message-Id: <${local_part:$h_Message-Id:}.${domain:$h_Message-Id:}@unique.remote.dom>\n"
      headers remove "Message-Id"
      headers add "Message-Id: $h_X-Vygo-Net-Temporary-Message-Id:"
      headers remove "X-Vygo-Net-Temporary-Message-Id"
  endif


  # Change Resent-Message-Id:
  if "${if def:h_Resent-Message-Id: {yes}}" is yes and 
      ${lc:${domain:$h_Resent-Message-Id:}} is    "home.dom" or
      ${lc:${domain:$h_Resent-Message-Id:}} ends ".home.dom" then
  # This is if you want to have a file mapping each hostname to a unique
  # Message-Id domain part, or, if it fails, preserves the original domain part:
  #    headers add "X-Vygo-Net-Temporary-Message-Id: <${local_part:$h_Resent-Message-Id:}@${lookup{${domain:$h_Resent-Message-Id:}}lsearch{/var/exim/msgid-hosts}{$value}{${domain:$h_Resent-Message-Id:}}}>\n"
  # This rewrites Message-Id as <local_part.domain@???>:
      headers add "X-Vygo-Net-Temporary-Message-Id: <${local_part:$h_Resent-Message-Id:}.${domain:$h_Resent-Message-Id:}@unique.remote.dom>\n"
      headers remove "Resent-Message-Id"
      headers add "Resent-Message-Id: $h_X-Vygo-Net-Temporary-Message-Id:"
      headers remove "X-Vygo-Net-Temporary-Message-Id"
  endif



Index: L001
====================================================================
/*
* uvscan local_scan() function for Exim (requires at least Exim v4.14)
* known to work with VirusScan for Linux v4.16.0 (Scan engine v4.2.40)
* but should be OK with other platforms
*
* this file is free software (license=GNU GPLv2) and comes with no
* guarantees--if it breaks, you get to keep the pieces (maybe not the mail)!
*
* by (ie patches / flames to): mb/local_scan@???, 2003-05-02
* (original version on 2002-05-25)
*/

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <string.h>
#include "local_scan.h"

/*
* remember to set LOCAL_SCAN_HAS_OPTIONS=yes in Local/Makefile
* otherwise you get stuck with the compile-time defaults
*/

static uschar *uvscan_binary = US"/usr/local/uvscan/uvscan";
static uschar *data_directory = US"/usr/local/uvscan";

  optionlist local_scan_options[] = { /* alphabetical order */
      { "data_directory", opt_stringptr, &data_directory },
      { "uvscan_binary", opt_stringptr, &uvscan_binary }
  };


int local_scan_options_count = sizeof(local_scan_options)/sizeof(optionlist);

/* log headers in rejectlog or not? */

//#define VIRUS_IN_MAIL LOCAL_SCAN_REJECT
#define VIRUS_IN_MAIL LOCAL_SCAN_REJECT_NOLOGHDR

/*
* buffer is used both for file copying and catching uvscan's output
* BUFSIZE = 1024 should always be fine
*/

#define BUFSIZE 1024

/* some number which uvscan doesn't return */
#define MAGIC 123

/*
* some macros to make the main function more obvious
* NB bailing out might leave tempfiles hanging around
* (and open fds, but no need to be worried about that)
*/

  #define BAIL(btext) { log_write(0, LOG_MAIN, "UVSCAN ERROR: "btext); \
      *return_text = "local scanning problem: please try again later"; \
      return LOCAL_SCAN_TEMPREJECT; }


  #define DEBUG(dtext) if ((debug_selector & D_local_scan) != 0) \
          { debug_printf(dtext); sleep(1); }
      /* sleep useful for running exim -d */


  #define RESULT(rtext) header_add(32, \
      "X-uvscan-result: "rtext" (%s)\n", message_id);


  #define FREEZE(ftext) { header_add(32, \
      "X-uvscan-warning: frozen for manual attention (%s)\n", message_id); \
      RESULT(ftext); *return_text = ftext; return LOCAL_SCAN_ACCEPT_FREEZE; }


/* OK, enough waffle. On with the show! */

  int local_scan(int fd, uschar **return_text)
  {
      char tf[] = "/tmp/local_scan.XXXXXX"; /* should this be tunable? */
      int tmpfd, bytesin, bytesout, pid, status, pipe_fd[2];
      fd_set fds; 
      static uschar buffer[BUFSIZE];


      DEBUG("entered uvscan local_scan() function");


      /*
       * I set majordomo to resend using -oMr lsmtp
           * (and yes, I know majordomo isn't actually using SMTP..)
       * no point in scanning these beasties twice
       */


      if(!strcmp(received_protocol, "lsmtp"))
          return LOCAL_SCAN_ACCEPT;


      /* create a file to copy the data into */


      if ((tmpfd = mkstemp(tf)) == -1)
          BAIL("mkstemp failed");


      DEBUG("made tmp file");


      /* copy said file BUFSIZE at a time */


      while ((bytesin = read(fd, buffer, BUFSIZE)) > 0) {
          bytesout = write(tmpfd, buffer, bytesin);
          if (bytesout < 1)
              BAIL("writing to tmp file");
      }
      if (bytesin < 0)
          BAIL("reading from spool file");


      close(tmpfd);


      if(pipe(pipe_fd) == -1)
          BAIL("making pipe");


      /* fork and scan */    


      if((pid = fork()) == -1)
          BAIL("couldn't fork");


      if(pid == 0) {
          close(1); /* close stdout */
          if(dup2(pipe_fd[1],1) == -1) /* duplicate write as stdout */
              BAIL("dup2 (stdout) failed");
          if(fcntl(1,F_SETFD,0) == -1) /* fd to NOT close on exec() */
              BAIL("fcntl (stdout) failed");


          execl(uvscan_binary, uvscan_binary, "--mime", "--secure",
              "-d", data_directory, tf, NULL);
          DEBUG("execl failed");
          _exit(MAGIC);
      }


      if(waitpid(pid, &status, 0) < 1)
          BAIL("couldn't wait for child");

    
      DEBUG("about to unlink");


      if(unlink(tf) == -1)
          FREEZE("couldn't unlink tmp file");


      DEBUG("unlinked :)");


      /*
       * choose what to do based on the return code of uvscan
       * RESULT() or FREEZE() according to personal taste
       */


      if(WIFEXITED(status) != 0)
          switch(WEXITSTATUS(status)) {
          case 0: RESULT("clean"); break;
          case 2: RESULT("driver integrity check failed"); break;
          case 6: FREEZE("general problem occurred"); break;
          case 8: RESULT("could not find a driver"); break;
          case 12: FREEZE("failed to clean file"); break;
          case 13:
              // RESULT("virus detected"); /* were we to accept */
              DEBUG("about to read from uvscan process");
              FD_ZERO(&fds);
              FD_SET(pipe_fd[0], &fds);
              if(select(pipe_fd[0]+1, &fds, NULL, NULL, NULL)) {
                  /* last NULL above means wait forever! */
                  DEBUG("select returned non-zero");
                  if((bytesin = read(pipe_fd[0], buffer,
                          BUFSIZE - 1)) > 0) {
                      buffer[bytesin] = (uschar)0;
                      *return_text = buffer + 22;
                      /* 22 was empirically found ;) */
                      return VIRUS_IN_MAIL;
                  } else
                      BAIL("reading from uvscan process");
              }
              break;
          case 15: FREEZE("self-check failed"); break;
          case 19: FREEZE("virus detected and cleaned"); break;
          case MAGIC: RESULT("couldn't run uvscan"); break;
          default:
              RESULT("unknown error code");
              header_add(32, "X-uvscan-status: %d\n",
                  WEXITSTATUS(status));
              break;
          }
      else
          BAIL("child exited abnormally");


      return LOCAL_SCAN_ACCEPT;
  }


Index: S001
====================================================================
This script patches an Exim binary in order to change the compiled-in
configuration file name. See FAQ 0065 for a situation in which this might
be a useful thing to do.

============================================================
#!/usr/local/bin/perl
#
# Patch the config file location in exim so as to avoid using
# exim -C and thus having problems with vacation messages etc.
#
# Placed in the public domain.

# This is the default in exim RPMS.
my $oldconf = "/etc/exim/exim4.conf";

die "Usage: $0 infile outfile configfile\n" unless (@ARGV == 3);
my ($in, $out, $newconf) = @ARGV;

  # We mustn't make our string longer than the original!
  die "configfile location must be ".length($oldconf)." chars long or less\n"
      if (length($newconf) > length($oldconf));


# Get original details.
my @stat = (stat($in));
die "stat($in): $!\n" if (@stat == 0);

# Get original binary.
open(F, "<$in") || die "Can't read $in\n";
read(F, $exim, $stat[7]) || die "Can't read $in\n";
die "Didn't read full data\n" unless (length($exim) == $stat[7]);
close(F);

  # Find the old config location.
  my $pos = 0;
  my @positions = ();
  while (($pos = index($exim, $oldconf."\0", $pos)) >= 0)
  {
      print "Config file name found at byte offset $pos\n";
      push(@positions, $pos);
      $pos++;
  }


die "Old config location ($oldconf) not found\n" if (@positions == 0);

# We could be clever here and try to isolate the correct instance,
# but for now I'm going to assume it's the only instance.
die "Too many possible config locations found\n" if (@positions > 1);

# Patch in the new config location
substr($exim, $positions[0], length($newconf)+1) = $newconf."\0";

# Write out the patched version.
open(F, ">$out") || die "Can't write $out\n";
print F $exim;
close(F);

# Set permissions on new copy to match old.
chmod($stat[2] & 07777, $out);

# Print the config file path.
$out = "./".$out unless ($out =~ m#/#);
print <<EOF;

Trying to run '$out -bP configure_file'. If it has worked
either it will be printed below or you will get a LOG: MAIN PANIC
about it (if the config file doesn't already exist)

EOF
system($out, "-bP", "configure_file");
============================================================

Index: S002
====================================================================
From: John Jetmore <jetmore@???>
Date: Wed, 24 Sep 2003 13:12:58 -0500 (CDT)

I'm sure that everyone who's interested in something like this has already
come up with their own way to do this, but here's my solution:

When I moved from smail to exim I built a program that took individual
config pieces stripped all the comments and built a config file. As a
bonus, it also runs exim -C <testfile> -bV on the new file and reports any
config errors before copying it over the old config. In addition to just
being familiar in general w/ all the files being broken up according to
their major categories, I also got the benfit of being able to have config
pieces that were easily updatable (just replace the whole file and rebuild
the configure file).

  The script has some site-specific stuff hard coded, but it's easily
  fixable.  Essentially in my exim configd I have a directory called
  subconfigure, which can contain directories named \d\d.\w+.  Mine
  currently contains:
  10.general/  30.routers/     50.retry/    70.authenticators/
  20.acls/     40.transports/  60.rewrite/  80.local_scan/


  Each of these directories can contain files in the form \d\d.\w+.  For
  instance, my 30.routers contains:
  00.begin              80.l_user_delivery_normal   _50.l_mx
  10.r_forcepaths       _12.r_static_route_junk     _60.l_psp
  15.r_stalemail        _17.r_internal_route        _72.l_aliases_list
  33.r_mailrtrd_router  _20.r_conditionalforce      _74.l_aliases_isp
  40.r_standard         _31.r_mailrtrd_bypass_spam  _76.l_aliases_mer
  70.l_aliases          _39.r_smarthost             _80.l_user_delivery_isp


those files prefixed by "_" will not be used to build the live configure
file. They are "turned off". This allows me to keep a general list of
configure pieces that are easily updatable but not necessarily every rule
is used on every machine. Not every file contains a single router - for
instance 60.l_psp is our virtual hosting solution and contains 10 routers.
They're just grouped by logical role.

All of these sub pieces are built in to the configure file w/ a shell
script called mkconfigure, inline below. Again, my assumption is that
anyone who wants a system like this built it for themselves, but it
would be kind of fun to flesh this script out to be more generic.
Maybe post it and some samples on a webpage. Or no one responds to this
and I shut up about it =).

This system is way overkill for some people (for instance, my home machine
uses a single configure file because I don't do that much special with
it), but it's useful in a larger system role.

--John

mkconfigure:

#!/bin/ksh

# I have found that our custom set up of exim's configure file is overly
# confusing. To help alleviate this, I have broken the file out into its
# core pieces (general, tansports, directors, routers, retry, rewrite, and
# authentication), and then each of those into logical sub-pieces (SIS,
# for instance. This program is to take all of those sub pieces and put
# them back together into the file that exim understands.

# No one should every touch the 'configure' file from now on, one should
# instead manipulate the files in the subconfigure directory and run this
# program

# jetmore 20011119

EXIMD=$1
CONFIGSUFF=$2

  if [ "X$EXIMD" == "X" ] ; then
    EXIMD=/local/exim
  fi
  if [ ! -d "$EXIMD" ] ; then
    echo "$EXIMD is not a directory" >&2
    exit 1
  fi
  ETCD=$EXIMD/etc
  SUBCD=$ETCD/subconfigure$CONFIGSUFF
  CONFIGF=$ETCD/configure$CONFIGSUFF


  if [ ! -d $SUBCD ] ; then
    echo "$SUBCD is not a directory" >&2
    exit 1
  fi


GREP=/bin/grep

# initialize the temporary config file in case some trash got left around
cat /dev/null > $CONFIGF.t

  # print the banner to the temp config file
  echo                                                             >> $CONFIGF.t
  echo "#########################################################" >> $CONFIGF.t
  echo "# DO NOT DIRECTLY MANIPULATE THIS FILE                   " >> $CONFIGF.t
  echo "#                                                        " >> $CONFIGF.t
  echo "# if you need to make configuration change, do so in     " >> $CONFIGF.t
  echo "# $SUBCD and run the mkconfigure"                          >> $CONFIGF.t
  echo "# command.  Changes made to this file will be lost       " >> $CONFIGF.t
  echo "#                                                        " >> $CONFIGF.t
  echo "# See jetmore w/ questions                               " >> $CONFIGF.t
  echo "#########################################################" >> $CONFIGF.t
  echo                                                             >> $CONFIGF.t


  # get the major categories
  for CAT in $SUBCD/[0-9]*
  do
      # print which category we're in
      echo                                                         >> $CONFIGF.t
      echo "## major category $CAT"                                >> $CONFIGF.t
      echo                                                         >> $CONFIGF.t


      # get the subcategories
      for SUBCAT in $CAT/[0-9]*
      do
          # print which sub category we're in
          echo "## sub category $SUBCAT"                           >> $CONFIGF.t
          echo                                                     >> $CONFIGF.t


          # place the contents of any non-comment line into the configure file
          $GREP -v "^ *#" $SUBCAT                                  >> $CONFIGF.t
          echo                                                     >> $CONFIGF.t
      done
  done


  # check and make sure there aren't any typos in the new config file
  $EXIMD/bin/exim -C $CONFIGF.t -bV > $CONFIGF.test 2>&1
  if [ "$?" -eq "1" ] ; then
      #/bin/rm $CONFIGF.t
      echo
      echo "There is a problem with the configure file.  "
      echo "moving paniclog to paniclog.mkfail"
      echo "$CONFIGF.test has details:"
      echo
      echo #####################################################################
      cat $CONFIGF.test
      echo #####################################################################
      echo
      echo "$CONFIGF not changed!"
      /bin/mv -f /log/exim/paniclog /log/exim/paniclog.mkfail
      exit 1
  fi
  /bin/rm $CONFIGF.test


/bin/mv $CONFIGF.t $CONFIGF
echo "$CONFIGF updated successfully."
echo "Don't forget to HUP the mail daemon"
exit 0