Exemple #1
0
    def writeConfig(self, *a):

        try:
            serverIP = Utils.getLanIPs(config)[0]
        except:
            # We aren't sure what our IP is.. oh dear
            serverIP = "127.0.0.1"

        # This all needs to happen first
        hosts = """127.0.0.1       localhost
127.0.1.1       %(host)s.%(domain)s   %(host)s

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts\n""" % {
            'host': config.Hostname,
            'domain': config.Domain
        }

        l = open('/etc/hosts', 'wt')
        l.write(hosts)
        l.close()

        if config.General.get('sysresolv', []):
            ns = ""
            for i in config.General['sysresolv']:
                ns += 'nameserver %s\n' % i
        else:
            if serverIP == "127.0.0.1":
                ns = ""
            else:
                ns = 'nameserver 127.0.0.1\n'

        resolv = """search %s
domain %s
%s\n""" % (config.Domain, config.Domain, ns)
        l = open('/etc/resolv.conf', 'wt')
        l.write(resolv)
        l.close()

        os.system('mkdir -p /etc/bind/pri > /dev/null 2>&1')
        SOA = """@ 86400         IN      SOA    %s. postmaster.%s. (
                                    1               ; Serial
                                    28800           ; Refresh
                                    7200            ; Retry
                                    604800          ; Expire
                                    3600)          ; Minimum TTL\n"""
        zones = ""
        ipv6addr = ""
        ipv6listen = ""
        ipv6query = ""

        if Utils.getLanIP6s(config):
            ipv6addr = Utils.getLanIP6s(config)

            ipv6listen = "listen-on-v6 {\n        %s;\n    };" % ';'.join(
                [n.split('/')[0] for n in ipv6addr])

            ipv6query = "%s;" % Utils.getV6Network(ipv6addr[0])

        TSOA = SOA % ("%s.%s" %
                      (config.Hostname, config.Domain), config.Domain)
        TSOA += "                            NS      %s.%s.\n" % (
            config.Hostname, config.Domain)
        if not config.General.get('zones', {}).get(config.Domain, None):
            if not serverIP:
                serverIP = "127.0.0.1"

            forward = TSOA + "                        A       %s\n" % serverIP

            for cname in config.TCSAliases:
                spaces = ''.join([" " for i in range(20 - len(cname))])
                forward += "%s %s   CNAME   %s\n" % (cname, spaces,
                                                     config.Hostname)

            forward += "%s                  A       %s\n" % (config.Hostname,
                                                             serverIP)

            if ipv6addr:
                forward += "%s                  AAAA    %s\n" % (
                    config.Hostname, ipv6addr[0])

            Utils.writeConf('/etc/bind/pri/%s.zone' % (config.Domain, ),
                            forward, ';')
            zones += """    zone "%s" in {
        type master;
        allow-update {
            127.0.0.1;
        };
        notify no;
        file "pri/%s.zone";
    };\n\n""" % (config.Domain, config.Domain)

        if config.General.get('zones', None):
            for domain, info in config.General['zones'].items():
                zones += "    zone \"%s\" in {\n" % domain

                # Get options
                if info.get('options', None):
                    for opt in info['options']:
                        zones += "        %s;\n" % opt
                else:
                    # Use defaults
                    zones += "        type master;\n        notify no;\n"

                if 'type forward' not in info.get('options'):
                    # check updaters
                    if info.get('update', None):
                        zones += "        allow-update {\n"
                        for update in info['update']:
                            zones += "            %s;\n" % update
                        zones += "        };\n"

                    else:
                        # Use default localhost.
                        zones += "        allow-update {\n            127.0.0.1;\n        };"

                ns = info.get('ns', [])
                if len(ns) < 1:
                    print "ERROR!! Domain %s requires at least 1 name server!" % domain
                    sys.exit()

                # Create zone data
                zonedata = ""

                for i in ns:
                    zonedata += "                        NS      %s.\n" % i

                if info.get('records'):
                    maxRec = max([
                        len(rec.split()[0]) for rec in info.get('records', [])
                    ]) + 5
                else:
                    maxRec = 4

                colspace = [maxRec, 8]
                first = ""
                for rec in info.get('records', []):
                    if "MX" in rec:
                        host, type, prio, data = rec.split()
                        type = "%s %s" % (type, prio)
                    else:
                        host, type, data = tuple(rec.split())

                    theseSpaces = [
                        colspace[c] - len(i)
                        for c, i in enumerate([host, type])
                    ]
                    recLine = "%s%s%s%s%s\n" % (host, " " * theseSpaces[0],
                                                type, " " * theseSpaces[1],
                                                data)
                    if type == "NS" or "MX" in rec:
                        first += recLine
                    else:
                        zonedata += recLine

                if 'type forward' in info.get('options'):
                    zones += "        forwarders {\n           %s;\n        };\n" % info.get(
                        'forward')

                if 'type slave' in info.get('options'):
                    uservs = []

                    for i in info.get('update'):
                        if i != "127.0.0.1":
                            uservs.append(i)

                    zones += "        masters {\n           %s;\n        };\n" % ';'.join(
                        uservs)

                if 'type master' in info.get('options'):
                    zones += "        file \"pri/%s.zone\";\n" % domain
                # Terminate entry
                zones += "    };\n"

                l = open('/etc/bind/pri/%s.zone' % domain, 'wt')
                l.write(SOA % (ns[0], domain))
                l.write(first)
                l.write(zonedata)
                l.close()

        reverse = TSOA + "%s                     PTR     %s.%s.\n" % (
            serverIP.split('.')[-1], config.Hostname, config.Domain)

        os.system('chown -R bind:bind /etc/bind/pri ')
        Utils.writeConf('/etc/bind/pri/reverse.zone', reverse, ';')

        lanv4Ips = Utils.getLanIPs(config)
        if lanv4Ips:
            listenv4 = ';'.join(lanv4Ips) + ';'
        else:
            listenv4 = ""

        options = """options {
    listen-on {
        127.0.0.1;
        %s
    };

    %s

    allow-query {
        %s
        127.0.0.1;
        0.0.0.0/0;
    };

    forwarders {
%s    };

    directory "/var/bind";
    pid-file "/var/run/named/named.pid";
    forward first;\n};\n\n""" % (listenv4, ipv6listen, ipv6query, ''.join(
            ["        %s;\n" % i for i in config.ForwardingNameservers]))

        zones = """zone "." in {
        type hint;
        file "named.ca";
    };

    zone "0.0.127.in-addr.arpa" in {
        type master;
        file "pri/127.zone";
        notify no;
    };

    zone "localhost" in {
        type master;
        file "pri/localhost.zone";
        notify no;
    };

    zone "%s.in-addr.arpa" in {
        type master;
        file "pri/reverse.zone";
        notify no;
        allow-update { 127.0.0.1; };
    };

%s\n""" % ('.'.join([i for i in reversed(serverIP.split('.')[:3])]), zones)

        # Debian modifications
        zones = zones.replace('named.ca', 'db.root')
        zones = zones.replace('pri/localhost.zone', 'db.local')
        zones = zones.replace('pri/127.zone', 'db.127')
        options = options.replace('pid-file "/var/run/named/named.pid";', '')
        options = options.replace('directory "/var/bind";',
                                  'directory "/etc/bind";')

        # Rechown
        os.system('chown -R bind:bind /etc/bind/*')

        bindFile = options + zones

        Utils.writeConf('/etc/bind/named.conf', bindFile, '//')

        os.system('rm /etc/bind/pri/*.jnl > /dev/null 2>&1')
Exemple #2
0
    def writeConfig(self, *a):
        # VERY IMPORTANT NOTICE! 
        #
        #  All lines are lead by 8 spaces. These spaces are stripped out at the end.
        #  If you have less than 8 spaces before any new line written to the config
        #  then it will be broken
        #  This is done to make the source semi readable 
        # 
        # END OF IMPORTANT NOTICE

        # Setup local delivery domains
        locals = "\n".join(config.LocalDomains)

        # A list of servers we redeliver or hub mail to
        serverhosts = ['127.0.0.1']

        # Configure hubbed hosts and relay domains
        relayDoms = config.Mail.get('relay', [])
        hubs = ""
        mailReroute = ""
        for dom, dest in config.Mail.get('hubbed', []):
            if dest not in serverhosts:
                serverhosts.append(dest)
            if "@" in dom:
                mailReroute += "%s       %s        byname\n" % (dom,dest)
                dom = dom.split('@')[-1]
            else:
                hubs += "%s        %s        byname\n" % (dom, dest)

            if dom not in relayDoms:
                relayDoms.append(dom)

        # Branch configuration 
        branches = config.Mail.get('branchtopology', {})
        branchMap = {}
        for r in config.Mail.get('branches', []):

            # if the items in branches are not lists, we assume an old datastructure
            if not isinstance(r, list):
                branchMap[r] = None
                continue

            svr, relay = r


            branchMap[svr] = None

            if relay:
                branchMap[svr] = relay.replace(' ', '').replace(';', ',').replace(':', ',').split(',')

        branchReroute = ""
        for branch, addrs in branches.items():
            for addr in addrs:
                # Extend relay domains to handle this remote server too
                dom = addr.split('@')[-1]
                if dom not in relayDoms:
                    relayDoms.append(dom)

                if branchMap[branch]:
                    relay = ':'.join(branchMap[branch])
                else:
                    relay = branch
                
                if relay not in serverhosts:
                    serverhosts.append(relay)

                # Add the address to mail reroute
                branchReroute += "%s       %s        byname\n" % (
                    addr,
                    relay
                )
                
        # Setup our relay list
        relays = "\n".join(relayDoms)

        # Initialise blacklists
        blacklistSender = ""
        blacklistHost = ""
        blacklistDom  = ""
        
        for b in config.Mail.get('blacklist', []):
            if "@" in b:
                blacklistSender += b + '\n'
            else:
                try:
                    int(b.split('.')[0])
                    blacklistHost += b + '\n'
                except:
                    blacklistDom += b + '\n'

        whitelistSender = ""
        whitelistHost = ""
        whitelistDom = ""
        for w in config.Mail.get('whitelist', []):
            if "@" in w:
                whitelistSender += w + "\n"
            else:
                try:
                    int(w.split('.')[0])
                    whitelistHost += w + '\n'
                except:
                    whitelistDom += w + '\n'

        catchall = ""
        for c in config.Mail.get('catchall', []):
            catchall += c + "\n"

        # System filters
        copyTo = "#System Filter\nif error_message then finish endif\n\n"

        if config.Mail.get('copytoall', None):
            copyTo += "if first_delivery then\n"
            copyTo += "    unseen deliver %s errors_to postmaster@%s\n" % (config.Mail['copytoall'], config.Domain)
            copyTo += "endif\n\n"

        for addr, dest in config.Mail.get('copys', []):
            copyTo += "if $recipients contains %s then\n" % addr
            copyTo += "    unseen deliver %s errors_to postmaster@%s\n" % (dest, config.Domain)
            copyTo += "endif\n\n"

        # Global system filter
        if os.path.exists('/usr/local/tcs/tums/filter.db'):
            filterCont = open('/usr/local/tcs/tums/filter.db').read()
            copyTo += filterCont
            copyTo += "\n"
        
        allowsend = ""
        if config.Mail.get('allowsend', None):
            allowsend = "\n".join(config.Mail['allowsend'])

        if config.Mail.get('disableratelimit', None):
            rateLimit = ""
        else:
            rateLimit = """
        # System-wide rate limit for dodgey senders
          defer message = Connection limited: Sender rate $sender_rate / $sender_rate_period.
                hosts            = +relay_hosts
                !sender_domains  = +local_domains : +relay_domains
                !senders         = :
                ratelimit = 50 / 1h / strict\n"""

        if config.Mail.get('disablerpfilter', None):
            senderRpFilter = ""
        else:
            senderRpFilter = """
        # Block mail from forged address on the local side. 
          deny message  =  Vulani has rejected this message from $sender_address because it is not local to this site. http://vulani.net/
                !sender_domains  = +local_domains : +relay_domains
                !senders         = :
                !senders         = +acl_allowed_senders
                hosts            = +relay_hosts
                !hosts           = +server_hosts\n"""


        Utils.writeConf('/etc/exim4/sender_whitelist', whitelistSender, '#')
        Utils.writeConf('/etc/exim4/host_whitelist', whitelistHost, '#')
        Utils.writeConf('/etc/exim4/domain_whitelist', whitelistDom, '#')

        Utils.writeConf('/etc/exim4/sender_blacklist', blacklistSender, '#')
        Utils.writeConf('/etc/exim4/host_blacklist', blacklistHost, '#')
        Utils.writeConf('/etc/exim4/domain_blacklist', blacklistDom, '#')

        Utils.writeConf('/etc/exim4/allowed_senders', allowsend, '#')

        Utils.writeConf('/etc/exim4/host_noavscan', "", '#')

        Utils.writeConf('/etc/exim4/local_domains', locals, '#')
        Utils.writeConf('/etc/exim4/relay_domains', relays, '#')
        Utils.writeConf('/etc/exim4/hubbed_hosts', hubs, '#')
        Utils.writeConf('/etc/exim4/mail_reroute', mailReroute, '#')
        Utils.writeConf('/etc/exim4/branch_reroute', branchReroute, '#')
        Utils.writeConf('/etc/exim4/system_filter', copyTo, '#')
        Utils.writeConf('/etc/exim4/catchall_domains', catchall, '#')

        # Get rid of the autogenerated tag so aptitude doesn't break us
        os.system('rm /var/lib/exim4/config.autogenerated > /dev/null 2>&1')
        systemFilter = "system_filter = /etc/exim4/system_filter\n"
 
        if config.Mail.get('noavscan'):
            avScan = ""
            avscanacl = ""
            print "Antivirus scanning disabled!"
        else:
            avScan = "av_scanner = clamd:/var/run/clamav/clamd.sock"
            avscanacl = """            accept condition  = ${if <={$message_size}{250k}{yes}{no}}
            deny message      = This message contains a virus ($malware_name)
                !hosts        = +acl_host_noavscan
                malware       = *\n"""

        primaryDomain = config.Domain
        hostname = config.ExternalName  # Must be externally lookupable(?!?) name
        mailSize = config.Mail.get('mailsize', '')
        localNet = " : ".join([v for k,v in Utils.getLanNetworks(config).items()])
        
        for n in Utils.getLanIP6s(config):
            localNet += ' : %s ' % n.replace(':', '::')

        # fill in allowed hosts (config.Mail.relay-from)
        if config.Mail.get('relay-from'):
            localNet += ' : ' + ' : '.join(config.Mail['relay-from'])
        extensionBlock = ""

        # Blocked file extensions
        if config.Mail.get('blockedfiles', []):
            extensionBlock = "            deny  message     = We do not accept \".$found_extension\" attachments here.\n"
            extensionBlock += "                 demime      = %s\n" % ':'.join(config.Mail['blockedfiles'])

        # Mail rewrite rules
        rewriteRules = ""
        for fromm,too,flags in config.Mail.get('rewrites', []):
            # flags is one of TtFfbcr
            rewriteRules+='        *@%s    $1@%s   %s\n' % (fromm, too, flags)

        # Get any mailman settings
        mm_router, mm_transport, mm_main = self.MailMan()

        # SpamAssassin required score
        spamscore = config.Mail.get('spamscore', 70)

        # Get greylisting ACLS (if greylisting is enabled)
        aclCheckSenderGreylist, aclCheckDataGreylist = self.Greylisting()

        ### Enable tweaked performance
        performanceTweak = ""
        if config.Mail.get('performance', False):
            performanceTweak =  "        # use muliple directories (default false)\n"
            performanceTweak += "        split_spool_directory\n"
            performanceTweak += "        # queue incoming if load high (no default)\n"
            performanceTweak += "        queue_only_load = 4\n"
            performanceTweak += "        # maximum simultaneous queue runners (default 5)\n"
            performanceTweak += "        queue_run_max = 0\n"
            performanceTweak += "        # parallel delivery of one message to a number of remote hosts (default 2)\n"
            performanceTweak += "        remote_max_parallel = 30\n"
            performanceTweak += "        # simultaneous connections from a single host (default 10)\n"
            performanceTweak += "        smtp_accept_max_per_connection = 20\n"
            performanceTweak += "        # maximum number of waiting SMTP connections (default 20)\n"
            performanceTweak += "        smtp_connect_backlog = 50\n"
            performanceTweak += "        # maximum number of simultaneous incoming SMTP calls that Exim will accept (default 20)\n"
            performanceTweak += "        smtp_accept_max = 0\n"

        if config.Mail.get('rbls'):
            RBL = config.Mail.get('rbls')
        else:
            RBL = [
                "dsn.rfc-ignorant.org/$sender_address_domain",
                "zen.spamhaus.org",
                "dnsbl.njabl.org",
                "bhnc.njabl.org",
                "combined.njabl.org",
                "bl.spamcop.net",
                "psbl-mirror.surriel.com",
                "blackholes.mail-abuse.org",
                "dialup.mail-abuse.org"
            ]


        ### Exim main configuration

        eximMain = """
        ######################################################################
        #                    MAIN CONFIGURATION SETTINGS                     #
        ######################################################################
        ldap_default_servers = %(ldap)s
        primary_hostname = %(hostname)s
        %(avScan)s
        spamd_address = 127.0.0.1 783
        %(systemFilter)s
        
        domainlist local_domains = @ : lsearch;/etc/exim4/local_domains
        domainlist relay_domains = lsearch;/etc/exim4/relay_domains
        hostlist   relay_hosts = 127.0.0.1 : %(hostlist)s
        hostlist   server_hosts = %(serverhosts)s
        
        domainlist acl_domain_whitelist = lsearch;/etc/exim4/domain_whitelist
        hostlist acl_host_whitelist = net-iplsearch;/etc/exim4/host_whitelist
        addresslist acl_sender_whitelist = lsearch*@;/etc/exim4/sender_whitelist
        domainlist acl_domain_blacklist = lsearch;/etc/exim4/domain_blacklist
        hostlist acl_host_blacklist = net-iplsearch;/etc/exim4/host_blacklist
        addresslist acl_sender_blacklist = lsearch*@;/etc/exim4/sender_blacklist
        addresslist acl_allowed_senders = /etc/exim4/allowed_senders

        hostlist acl_host_noavscan = net-iplsearch;/etc/exim4/host_noavscan

        acl_smtp_connect = acl_check_host
        acl_smtp_helo = acl_check_helo
        acl_smtp_mail = acl_check_sender
        acl_smtp_rcpt = acl_check_rcpt
        acl_smtp_data = acl_check_data
        acl_smtp_etrn = acl_check_etrn

        qualify_domain = %(domain)s
        trusted_users = mail
        message_size_limit = %(mailSize)s
        helo_allow_chars = _
        host_lookup = *
        smtp_enforce_sync = false 
        helo_accept_junk_hosts = *
        strip_excess_angle_brackets
        strip_trailing_dot
        delay_warning_condition = "\\
                ${if match{$h_precedence:}{(?i)bulk|list|junk}{no}{yes}}"
        #rfc1413_hosts = ${if eq{$interface_port}{SMTP_PORT} {*}{! *}}
        rfc1413_query_timeout = 0s
        sender_unqualified_hosts = %(hostlist)s
        recipient_unqualified_hosts = %(hostlist)s
        ignore_bounce_errors_after = 2d
        timeout_frozen_after = 7d
        recipients_max = 0
        # SSL/TLS cert and key
        tls_certificate = /etc/exim4/exim.cert
        tls_privatekey = /etc/exim4/exim.key
        # Advertise TLS to anyone
        tls_advertise_hosts = *
        smtp_etrn_command = /etc/exim4/etrn_script $domain

        LDAP_AUTH_CHECK_LOGIN = ${lookup ldap { \\
            user="******"cn=Manager,o=%(base)s" pass=%(pass)s ldap:///?dn?sub?(&(accountStatus=active)(mail=${quote_ldap:$1}))}}" \\
            pass="******" ldap:///?mail?sub?(&(accountStatus=active)(mail=${quote_ldap:$1}))}{yes}{no}}
        
        LDAP_AUTH_CHECK_PLAIN = ${lookup ldap { \\
            user="******"cn=Manager,o=%(base)s" pass=%(pass)s ldap:///?dn?sub?(&(accountStatus=active)(mail=${quote_ldap:$2}))}}" \\
            pass="******" ldap:///?mail?sub?(&(accountStatus=active)(mail=${quote_ldap:$2}))}{yes}{no}}
        

%(extra)s
        """ % {
            'ldap':         '127.0.0.1',
            'hostname':     hostname,
            'hostlist':     localNet,
            'serverhosts':  ' : '.join(serverhosts),
            'domain':       primaryDomain,
            'mailSize':     mailSize,
            'extra':        performanceTweak + mm_main,
            'systemFilter': systemFilter,
            'avScan':       avScan,
            'base':config.LDAPBase,
            'pass':config.LDAPPassword
        }

        eximACL="""
        ######################################################################
        #                       ACL CONFIGURATION                            #
        #         Specifies access control lists for incoming SMTP mail      #
        ######################################################################

        begin acl

        ######################################################################
        # Check connecting host (DNSBL's checked in acl_check_rcpt to ensure no reconnect attempt)
        ######################################################################
        acl_check_host:
            deny hosts        = +acl_host_blacklist
            accept

        ######################################################################
        # Check conencting host is not pretending to be the localhost
        ######################################################################
        acl_check_helo:

            accept hosts         = +relay_hosts
        # If the HELO pretend to be this host
            deny condition       = ${if or { \\
                                  {eq {${lc:$sender_helo_name}}{%(hostname)s}} \\
                                  {eq {${lc:$sender_helo_name}}{%(domain)s}} \\
                                  } {true}{false} }
            accept


        ######################################################################
        # Check sender address
        ######################################################################
        acl_check_sender:
            deny message      = sender envelope address $sender_address is locally blacklisted here.
                senders         = +acl_sender_blacklist

            accept


        ######################################################################
        # Check incoming messages
        ######################################################################
        acl_check_rcpt:

        # Accept if source is local SMTP
          accept hosts      = :
        # Deny if illegal characters in email address
          deny local_parts  = ^.*[@%%!/|] : ^\\\\.

%(ratelimit)s

        # Accept mail to postmaster at any local domain without any checks
          accept local_parts = postmaster
                domains    = +local_domains

%(senderRpFilter)s

        # Accept local, authenticated, whitelisted and dnswl'd hosts
          accept hosts      = +relay_hosts
          accept authenticated = *
          accept dnslists   = list.dnswl.org
          accept hosts      = +acl_host_whitelist
          accept domains    = +acl_domain_whitelist
          accept senders    = +acl_sender_whitelist

        # Deny if domain is locally blacklisted
          deny message        = rejected because $sender_domain is locally blacklisted here
                domains             = +acl_domain_blacklist

        # Deny if listed in a DNSBL
          deny message      = rejected because $sender_host_address is in a blacklist \\
                              at $dnslist_domain\\n$dnslist_text
            !senders        = :
            domains         = +local_domains : +relay_domains
            dnslists        = %(rbl)s

        # Accept if this is a local domain
          accept domains    = +local_domains
            endpass
            message         = unknown user
            verify          = recipient

        # Accept if this is a relay domain
          accept domains    = +relay_domains
            endpass
            message         = unrouteable address
            verify          = recipient

%(senderGreylist)s

        # Deny everything else
            deny message    = relay not permitted

        ######################################################################
        # Check contents of email
        ######################################################################
        acl_check_data:
%(dataGreylist)s

        # ClamAV virus scanning
            deny message      = Vulani has rejected this message because it contains a virus: ($malware_name) http://vulani.net
                log_message   = rejected VIRUS ($malware_name) from $sender_address to $recipients
                !hosts        = +acl_host_noavscan
                demime        = *
                malware       = */defer_ok

        # Reject messages that have serious MIME errors. This calls the demime
        # condition again, but will return cached results.
            deny message      = Vulani has rejected this message because it contains a broken MIME container ($demime_reason) http://vulani.net
                log_message   = rejected broken MIME container ($demime_reason) from $sender_address to $recipients
                condition     = ${if >{$demime_errorlevel}{2}{1}{0}}
                demime        = *

        # SpamAssassin Content Filtering
        # Include Spam Score in Header
            warn message      = X-Spam-Score: $spam_score\\n\\
                                X-Spam-Score-Int: $spam_score_int\\n\\
                                X-Spam-Bar: $spam_bar
                condition     = ${if <{$message_size}{250k}{1}{0}}
                !hosts        = +relay_hosts
                spam          = nobody:true/defer_ok

        # Reject spam messages with score over 7, using an extra condition.
            deny message      = Vulani has rejected this message because it scored $spam_score spam points and is considered to be unsolicited http://vulani.net
                log_message   = rejected SPAM score above threshhold in message from $sender_address to $recipients
                !hosts        = +acl_host_noavscan
                condition     = ${if >{$spam_score_int}{70}{1}{0}}
                spam          = nobody:true

%(extblock)s

            accept

        ######################################################################
        # Check ETRN requests
        ######################################################################
        acl_check_etrn:
            accept hosts = 0.0.0.0/0

        """ % {
            'rbl':              ' : '.join(RBL),        # DNS block lists
            'spamlow':          int(spamscore)-20,      # Warn spam score
            'spamhigh':         int(spamscore),         # Drop spam score.
            'senderGreylist':   aclCheckSenderGreylist, # Greylisting configuration
            'dataGreylist':     aclCheckDataGreylist,   #
            'extblock':         extensionBlock,         # Blocked file extensions
            'hostname':         hostname,
            'domain':       primaryDomain,
            'senderRpFilter': senderRpFilter,
            'ratelimit':    rateLimit,
            'avscan':       avscanacl
        }

        # Trigger our disclaimer transport 
        if config.Mail.get('disclaimer'):
            transport = "remote_smtp_filter"
        else:
            transport = "remote_smtp"

        # Set the external router depending on how the relay is set
        if config.SMTPRelay:
            externalRouter = """
        gateway:
            driver = manualroute
            domains = ! +local_domains
            route_list = * %s bydns
            transport = %s
           """ % (config.SMTPRelay, transport)
        else:
            externalRouter = """
        dnslookup:
            driver = dnslookup
            domains = ! +local_domains
            transport = %s
            ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
            no_more
            """ % transport

        eximRouters = """
        ######################################################################
        #                      ROUTERS CONFIGURATION                         #
        ######################################################################

        begin routers

        etrn_already:
            driver = accept
            transport = bsmtp_for_etrn
            require_files = /var/spool/mail/etrn/$domain
            domains = lsearch;/etc/exim/etrn_domains

        etrn_delay:
            driver = accept
            transport = bsmtp_for_etrn
            condition = ${if >{$message_age}{1800} {yes}{no}}
            domains = lsearch;/etc/exim/etrn_domains

        mail_reroute:
            driver = manualroute
            route_data = ${lookup{$local_part@$domain}lsearch{/etc/exim4/mail_reroute}}
            transport = remote_smtp

        branch_reroute:
            driver = manualroute
            route_data = ${lookup{$local_part@$domain}lsearch{/etc/exim4/branch_reroute}}
            transport = remote_smtp

        hubbed_hosts:
            driver = manualroute
            domains = ! +local_domains
            route_data = ${lookup{$domain}lsearch{/etc/exim/hubbed_hosts}}
            transport = remote_smtp

%(extro)s

        userforward:
            driver = redirect
            domains = +local_domains
            file = /var/spool/mail/forward/${local_part}@${domain}
            no_verify
            no_expn
            check_ancestor
            file_transport = address_file
            pipe_transport = address_pipe
            reply_transport = address_reply

        alias_user_vacation:
            driver = redirect
            domains = +local_domains
            allow_defer
            allow_fail
            data = ${lookup ldap {user="******" pass=%(ldappass)s \\
                   ldap:///?mail?sub?(mailAlternateAddress=${local_part}@${domain})}}
            redirect_router = user_vacation
            retry_use_local_part

        user_vacation:
            driver = accept
            domains = +local_domains
            require_files = /var/spool/mail/vacation/${local_part}@${domain}.txt
            no_verify
            user = apache
            senders = !^.*-request@.* : !^owner-.*@.* : !^postmaster@.* : \\
                      ! ^listmaster@.* : !^mailer-daemon@.* : !^noreply@.* : \\
                      !^.*-bounces@.*
            transport = vacation_reply
            unseen

        ldap_aliases:
            driver = redirect
            domains = +local_domains
            allow_defer
            allow_fail
            data = ${lookup ldap {user="******" pass=%(ldappass)s \\
                   ldap:///?mail?sub?(mailAlternateAddress=${local_part}@${domain})}}
            redirect_router = ldap_forward
            retry_use_local_part

        ldap_forward:
            driver = redirect
            domains = +local_domains
            allow_defer
            allow_fail
            data = ${lookup ldap {user="******" pass=%(ldappass)s \\
                    ldap:///?mailForwardingAddress?sub?\\
                    (&(accountStatus=active)(mail=${local_part}@${domain}))}{$value}fail}
            no_expn
            retry_use_local_part
            no_verify

        ldap_user:
            driver = accept
            domains = +local_domains
            condition =   ${if eq {}{${lookup ldap {user="******" pass=%(ldappass)s \\
                          ldap:///?mail?sub?(&(accountStatus=active)(mail=${local_part}@${domain}))}}}{no}{yes}}
            group = users
            retry_use_local_part
            transport = local_delivery

        catchall:
            domains = lsearch;/etc/exim/catchall_domains
            driver = redirect
            data = catchall@${domain}

%(router)s

        #localuser:
        #    driver = accept
        #    domains = +local_domains
        #    check_local_user
        #    transport = local_delivery
        """ % {
            'router': mm_router,
            'ldapbase': config.LDAPBase,
            'ldappass': config.LDAPPassword,
            'extro': externalRouter,
        }

        ## Prevent bounce of failed hosts? (Maximum send timeout reached)
        hostfailBounce = ""
        if config.Mail.get('hostfailbounce', False):
            hostfailBounce += "    delay_after_cutoff = false\n"

        if config.Mail.get('smtpinterface'):
            hostfailBounce += "    interface = %s\n" % config.Mail.get('smtpinterface')

        eximTransports = """
        ######################################################################
        #                      TRANSPORTS CONFIGURATION                      #
        ######################################################################

        begin transports

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

        vacation_reply:
            debug_print = "T: vacation_reply for $local_part@$domain"
            driver = autoreply
            file = /var/spool/mail/vacation/${local_part}@${domain}.txt
            file_expand
            log = /var/spool/mail/vacation/${local_part}@${domain}.log
            once_repeat = 7d
            once = /var/spool/mail/vacation/${local_part}@${domain}.db
            from = ${local_part}@${domain}
            to = $sender_address
            subject = "Re: $h_subject"
            text = "\\
            This is an automated response for $local_part@${domain}:\\n\\
            ====================================================\\n\\n"

        remote_smtp:
            driver = smtp
            %(iface)s

        remote_smtp_filter:
            driver = smtp
            transport_filter = /usr/local/tcs/tums/bin/remime
            %(iface)s

        local_delivery:
            driver = appendfile
            create_directory
            delivery_date_add
            directory = ${lookup ldap {user="******" pass=%(wpass)s \\
                        ldap:///?mailMessageStore?sub?(&(accountStatus=active)\\
                        (mail=${local_part}@${domain}))}}
            directory_mode = 770
            envelope_to_add
            group = mail
            maildir_format
            mode = 660
            return_path_add
            user = mail

        address_pipe:
            driver = pipe
            return_output

        address_file:
            driver = appendfile
            delivery_date_add
            envelope_to_add
            return_path_add

        address_reply:
            driver = autoreply

        %(mm)s\n""" % {
            'iface': hostfailBounce, 
            'basedn': config.LDAPBase, 
            'wpass': config.LDAPPassword, 
            'mm': mm_transport
        }

        eximOther = """
        ######################################################################
        #                      RETRY CONFIGURATION                           #
        ######################################################################

        begin retry
        *        *   senders=:      F,2m,1m
        *        *                  F,2h,15m; G,16h,1h,1.5; F,7d,4h

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

        begin rewrite
%(rewrite)s
        ######################################################################
        #                   AUTHENTICATION CONFIGURATION                     #
        ######################################################################

        begin authenticators

        login:
            driver = plaintext
            public_name = LOGIN
            server_prompts = "Username:: : Password::"
            server_advertise_condition = yes
            server_condition = ${if match_ip{$sender_host_address}{+relay_hosts}{yes}{LDAP_AUTH_CHECK_LOGIN}}
            server_set_id = $1
        plain:
            driver = plaintext
            public_name = PLAIN
            server_prompts = :
            server_advertise_condition = yes
            server_condition = ${if match_ip{$sender_host_address}{+relay_hosts}{yes}{LDAP_AUTH_CHECK_PLAIN}}
            server_set_id = $2 
        """ % {
            'base':config.LDAPBase,
            'pass':config.LDAPPassword,
            'rewrite': rewriteRules
        }

        confFile = eximMain + eximACL + eximRouters + eximTransports + eximOther
        os.system('mkdir -p /var/spool/mail/forward/')
        os.system('mkdir -p /var/spool/mail/etrn/')

        # Reprocess the config file
        lp = confFile.split('\n')
        confFile = ""
        for i in lp:
            confFile += i[8:] + '\n'

        confFile = confFile.replace('/etc/exim/', '/etc/exim4/').replace('apache', 'www-data')
        # Patches user names
        confFile = confFile.replace('user=mail', 'user=Debian-exim')
        Utils.writeConf('/etc/exim4/exim4.conf', confFile, '#')
        os.system('chmod a+r /etc/exim4/*')
        os.system('chmod -R a+r /usr/local/tcs/tums/data')
        os.system('chmod a+x /etc/exim4/etrn_script >/dev/null 2>&1')
        os.system('chmod a+rx /var/mail/vacation >/dev/null 2>&1')
        os.system('chown Debian-exim:Debian-exim /var/spool/mail/etrn')
        os.system('mkdir /var/cache/vulani/ >/dev/null 2>&1')

        ### Mailname
        mailname = "%s.%s\n" % ( config.Hostname, config.Domain )
        l = open('/etc/mailname', 'wt')
        l.write(mailname)
        l.close()