From 185b5456076ca86959643ce2f19c98c0f82f281e Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Sun, 29 Dec 2013 19:39:09 +0000 Subject: [PATCH] Initial commit. --- .gitignore | 3 + Makefile | 86 ++++++++++++++++++ README | 188 ++++++++++++++++++++++++++++++++++++++ auth.m4 | 132 +++++++++++++++++++++++++++ base.m4 | 289 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ config.m4 | 80 +++++++++++++++++ defs.m4 | 106 ++++++++++++++++++++++ divmap.m4 | 128 ++++++++++++++++++++++++++ exchange.m4 | 92 +++++++++++++++++++ lists.m4 | 57 ++++++++++++ local.m4 | 113 +++++++++++++++++++++++ satellite.m4 | 39 ++++++++ spam.m4 | 186 ++++++++++++++++++++++++++++++++++++++ vhost.m4 | 69 ++++++++++++++ 14 files changed, 1568 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README create mode 100644 auth.m4 create mode 100644 base.m4 create mode 100644 config.m4 create mode 100644 defs.m4 create mode 100644 divmap.m4 create mode 100644 exchange.m4 create mode 100644 lists.m4 create mode 100644 local.m4 create mode 100644 satellite.m4 create mode 100644 spam.m4 create mode 100644 vhost.m4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2c7cb1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.conf +hacks.m4 +local.mk diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a88c324 --- /dev/null +++ b/Makefile @@ -0,0 +1,86 @@ +### -*-makefile-*- +### +### Build script for Exim configuration +### +### (c) 2012 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +V = 0 +v_tag = $(call v_tag_$V,$1) +v_tag_0 = @printf " %-6s %s\n" $1 $@; + +V_GEN = $(call v_tag,GEN) +V_AT = $(V_AT_$V) +V_AT_0 = @ + +dir-nosl = $(patsubst %/,%,$(dir $1)) + +all: +.SECONDEXPANSION: # sorry + +CLEANFILES += $(TARGETS) + +EARLY = defs.m4 divmap.m4 config.m4 +MAIN = lists.m4 base.m4 + +MODES = + +MODES += satellite +OPTIONS_satellite = satellite.m4 + +MODES += hub +OPTIONS_hub = auth.m4 exchange.m4 local.m4 spam.m4 vhost.m4 + +MODES += usersat +OPTIONS_usersat = auth.m4 local.m4 satellite.m4 + +-include local.mk + +HOST_MODES += $(foreach m, $(MODES), \ + $(foreach h, $(HOSTS_$m), $h/$m)) + +CONFIGS = $(foreach m, $(MODES), exim4-$m.conf) +TARGETS += $(CONFIGS) +$(CONFIGS): exim4-%.conf: $(EARLY) $$(HOOKS_$$*) $(MAIN) $$(OPTIONS_$$*) + $(V_GEN)m4 -P -DMODE=$* $^ >$@.new + $(V_AT)exim4 -C$@.new -bV >/dev/null + $(V_AT)mv $@.new $@ + +all: $(TARGETS) + +THISHOST = $(shell hostname) + +ROOT = sudo + +INSTALL_TARGETS = $(addprefix install-, $(HOST_MODES)) + +$(filter install-$(THISHOST)/%, $(INSTALL_TARGETS)): \ +install-$(THISHOST)/%: exim4-%.conf + $(ROOT) install -m644 $< /etc/exim4/exim4.conf + $(ROOT) service exim4 reload + +$(filter-out install-$(THISHOST)/%, $(INSTALL_TARGETS)): \ +install-%: exim4-$$(notdir $$*).conf + $(ROOT) scp $< root@$(call dir-nosl,$*):/etc/exim4/exim4.conf + $(ROOT) ssh root@$(call dir-nosl,$*) service exim4 reload + +install: $(INSTALL_TARGETS) + +clean:; rm -f $(CLEANFILES) +.PHONY: clean diff --git a/README b/README new file mode 100644 index 0000000..25149fd --- /dev/null +++ b/README @@ -0,0 +1,188 @@ +The =distorted.org.uk= mail system + +* Delivery + +The mail delivery agent is Exim. If you don't do anything special, mail +is delivered into =/var/mail/USER= on stratocaster, in mbox format. + +There are a number of ways you can affect mail delivery. + +** The =~/.forward= file + +In traditional Unix style, you can write delivery instructions into a +file named =.forward= in your home directory. This file can contain a +comma-separated list of email address and/or file or directory names to +which your mail should be sent. Mail is written to files in traditional +Unix `mbox' format, and to directories in `Maildir' format. The +=:fail:= and =:defer:= items are permitted, but may not be very useful. + +This file can instead be an Exim or Sieve filter file, as marked by a +special comment on the first line. See the document `Exim's interfaces +to mail filtering', available via the command =info filter=, for details +about these files. + +** The =~/.mail/forward= file + +If you prefer, you can write delivery instructions to =~/.mail/forward= +instead. If you have lots of mail configuration files, you may find it +tidier to keep them all together in =~/.mail=. + +** The =~/.mail/forward.suffix= file + +You will receive mail sent to =USER@distorted.org.uk=. You can also +receive mail sent to =USER-SUFFIX@distorted.org.uk= or +=USER+SUFFIX@distorted.org.uk=, for any =SUFFIX= string if you create a +file =~/.mail/forward.suffix=. While this can be a simple forward file, +it's probably much more useful to write an Exim filter file to analyse +the suffix string and take appropriate action. + +If this file exists, it should be world-readable, because it will be +used by the mail server at SMTP time in order to decide whether a +particular =SUFFIX= string is valid. + + +* Reading mail + +** Reading mail locally + +The servers =stratocaster= and =jem= have a few mail user agents +installed, most notably trad BSD =mail=, =mutt=, and Emacs's various +mail-reading interfaces; more can be added. + +** Fetching mail through IMAP + +There's an IMAP server running on =mail.distorted.org.uk=. ... + +** Forwarding mail off-site + + +* Spam filtering + +The mail server checks incoming mail using SpamAssassin at SMTP time. +Suspected spam is rejected immediately. There are no `junk' mail +folders. Legitimate senders will likely receive bounces; spammers will +probably ignore the error and continue. + +** SpamAssassin + +SpamAssassin works by having a large collection of rules: it tests an +incoming message against these rules, and adds up the /scores/ for the +rules that match. If the total score is above a given threshold then +the message is declared to be probably spam, and rejected. + +If the mail server accepts a message, it adds two headers to it. + + + =X-SpamAssassin-Score= has the form =SCORE/LIMIT (BAR)=, where + =SCORE= is the actual score for the message, =LIMIT= is the maximum + score allowed, and =BAR= is a little bar chart showing the score in + a way which can be matched easily using regular expressions. The + bar chart uses =+= or =-= signs, depending on whether the score is + positive or negative, or consists of a single =/= sign if it's close + to zero. + + + =X-SpamAssassin-Status= consists of space-separated =KEY=VAUE= + pairs. The keys currently are: =score= and =limit=, which are the + message's score and limit again; and =tests=, which lists the rules + which matched the message and their individual scores, as a + comma-separated list of items of the form =RULE:SCORE=. + +** Custom spam limits + +The default spam limit is currently 5 points. However, you can override +this limit for mail sent to you by creating a world-readable file +=~/.mail/spam-limit= in your home directory on stratocaster. This file +should contain lines of the form + +: PATTERN: LIMIT + +where =PATTERN= is an Exim =nwildlsearch= pattern matched against a +string of the form =RECIPIENT/SENDER=, and the =LIMIT= is ten times the +maximum SpamAssassin score you're willing to tolerate for this message. +See the Exim manual for full details; in short, the pattern may be a +literal string, a string beginning with a =*= to match a particular +suffix (usually a sender address or domain, which is why the sender is +on the right), or a Perl-style regular expression starting with =^=. + +You may not want information about who is sending you spam (or honest +but spamlike mail) to be public knowledge, so instead you can make a +file =~/.mail/spam-limit.userv= of the same format. This file need not +be readable by anyone other than you. + +Be careful with this facility: if a single incoming message has multiple +recipients, and they assign it different spam score limits (either +explicitly, or implicitly by accepting the system default) then the +sender will be told to defer delivery to some recipients. It's +therefore probably a bad idea to apply custom spam score limits for mail +for popular mailing lists, for example. + +** SAUCE + +I'm not currently running SAUCE, but I'm giving it some consideration. +If you have comments on the matter, either way, I'm interested. + + +* Sending mail + +** Submission mechanisms + +Mail can be sent in a number of ways. + + + The =sendmail= program. This is really Exim in disguise. + + + SMTP to =localhost= port 25. This doesn't require explicit + authentication, since it relies on an identd, which is running on + all =distorted.org.uk= hosts. + + + SMTP to =mail.distorted.org.uk= port 587. You must establish TLS, + and authenticate using a username and password; the server uses a + short-lived certificate signed by the =distorted.org.uk= certificate + authority, whose root certificate is at =/etc/ca/ca.cert= on all + servers. Use [[https://www.distorted.org.uk/chpwd/][Chopwood]] to set or change this password. + +** Sender authenticity + +It is my intention that it be very hard for one =distorted.org.uk= user +to impersonate another to a third. To this end, the mail server is +rather picky about envelope sender addresses. + + + It won't accept an apparently local sender address from an external + mail server at all. + + + It will check locally submitted mail against the submitter's user + name. The precise details vary according to the submission + mechanism: mail submitted through =sendmail= will have additional + headers added; mail submitted through SMTP will be rejected unless + the envelope sender is acceptable. + +If I see something like DKIM catching on then this will also provide +external users with some kind of (probably fairly weak) sender +authenticity. + +On the other hand, the mail server is aware of vanity domains, extension +addresses, and so on, and should let you send mail apparently from an +such an address that you control. If you think the mail server is being +unnecessarily strict about something then I'm willing to discuss your +requirements. + +If I'm hosting your mail domain for you then you get to decide the +appropriate policy. + + +* Mail hosting and custom domains + +I think I have a fairly sane way to set up stratocaster (or some other +server, but strat is the obvious choice) to receive mail for domains +other than =distorted.org.uk=. I can easily arrange to accept mail for +such domains and deliver them locally or to other hosts. Pester me if +this sounds useful to you. + + +* Quick reference + + + +* COMMENT Emacs cruft + +### Local variables: +### mode: org +### End: diff --git a/auth.m4 b/auth.m4 new file mode 100644 index 0000000..d4729c0 --- /dev/null +++ b/auth.m4 @@ -0,0 +1,132 @@ +### -*-m4-*- +### +### Client authentication for distorted.org.uk Exim configuration +### +### (c) 2012 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +###-------------------------------------------------------------------------- +### Authenticators. + +m4_define(<:CHECK_PASSWD:>, +<:${lookup {$1} lsearch {CONF_sysconf_dir/passwd} \ + {${if crypteq {$2} {$value}}} \ + {false}}:>) + +m4_define(<:ALLOW_PLAINTEXT_AUTH_P:>, +<:or {{match_ip {$sender_host_address}{+localnet}} \ + {and {{def:tls_cipher} {eq{$acl_c_mode}{submission}}}}}:>) + +SECTION(auth)m4_dnl +plain: + driver = plaintext + public_name = PLAIN + server_advertise_condition = ${if ALLOW_PLAINTEXT_AUTH_P} + server_prompts = : + server_condition = CHECK_PASSWD($auth2, $auth3) + server_set_id = $auth2 + +login: + driver = plaintext + public_name = LOGIN + server_advertise_condition = ${if ALLOW_PLAINTEXT_AUTH_P} + server_prompts = <; Username: ; Password: + server_condition = CHECK_PASSWD($auth1, $auth2) + server_set_id = $auth1 + +DIVERT(null) +###-------------------------------------------------------------------------- +### Verification of sender address. + +SECTION(global, acl)m4_dnl +acl_not_smtp_start = not_smtp_start +SECTION(acl, misc)m4_dnl +not_smtp_start: + ## Record the user's name. + warn set acl_c_user = $sender_ident + +SECTION(acl, mail-hooks)m4_dnl + ## Check that a submitted message's sender address is allowable. + require acl = mail_check_auth + +SECTION(acl, misc)m4_dnl +mail_check_auth: + + ## If this isn't a submission then it doesn't need checking. + accept condition = ${if !eq{$acl_c_mode}{submission}} + + ## If the caller hasn't formally authenticated, but this is a + ## loopback connection, then we can trust identd to tell us the right + ## answer. So we should stash the right name somewhere consistent. + warn set acl_c_user = $authenticated_id + hosts = +localnet + !authenticated = * + set acl_c_user = $sender_ident + + ## User must be authenticated. + deny message = Sender not authenticated + !hosts = +localnet + !authenticated = * + + ## Make sure that the local part is one that the authenticated sender + ## is allowed to claim. + deny message = Sender address forbidden to calling user + !condition = ${LOOKUP_DOMAIN($sender_address_domain, + {${if and {{match_local_part \ + {$acl_c_user} \ + {+dom_users}} \ + {match_local_part \ + {$sender_address_local_part} \ + {+dom_locals}}}}}, + {${if and {{match_local_part \ + {$sender_address_local_part} \ + {+user_extaddr}} \ + {or {{eq {$sender_address_domain} \ + {}} \ + {match_domain \ + {$sender_address_domain} \ + {+public}}}}}}})} + + ## All done. + accept + +DIVERT(null) +###-------------------------------------------------------------------------- +### Dealing with `AUTH' parameters and relaying. + +SECTION(global, acl)m4_dnl +acl_smtp_mailauth = mailauth +SECTION(acl, misc)m4_dnl +## Check the `AUTH=...' parameter to a `MAIL' command. +mailauth: + ## If the client has authenticated using TLS then we're OK. The + ## sender was presumably checked upstream, and we can believe that + ## the name has been transmitted honestly. + accept condition = ${if def:tls_peerdn} + + ## If this is submission, and the client has authenticated, then we + ## check that the name matches the user. + accept condition = ${if eq {$authenticated_sender} \ + {$authenticated_id@CONF_master_domain}} + + ## Otherwise we can't tell who really sent it. + deny message = Authenticated user not authoritative for claimed sender. + +DIVERT(null) +###----- That's all, folks -------------------------------------------------- diff --git a/base.m4 b/base.m4 new file mode 100644 index 0000000..887a132 --- /dev/null +++ b/base.m4 @@ -0,0 +1,289 @@ +### -*-m4-*- +### +### Basic settings for distorted.org.uk Exim configuration +### +### (c) 2012 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +###-------------------------------------------------------------------------- +### Global settings. + +SECTION(global, priv)m4_dnl +prod_requires_admin = false + +SECTION(global, logging)m4_dnl +log_file_path = : syslog +log_selector = \ + +smtp_confirmation \ + +tls_peerdn +log_timezone = true +syslog_duplication = false +syslog_timestamp = false + +SECTION(global, daemon)m4_dnl +local_interfaces = <; CONF_interfaces +extra_local_interfaces = <; 0.0.0.0 ; :: + +SECTION(global, resource)m4_dnl +deliver_queue_load_max = 8 +queue_only_load = 12 +smtp_accept_max = 16 +smtp_accept_queue = 32 +smtp_accept_reserve = 4 +smtp_load_reserve = 10 +smtp_reserve_hosts = +trusted + +SECTION(global, policy)m4_dnl +host_lookup = * + +SECTION(global, users)m4_dnl +gecos_name = $1 +gecos_pattern = ([^,:]*) + +SECTION(global, incoming)m4_dnl +received_header_text = Received: \ + ${if def:sender_rcvhost {from $sender_rcvhost\n\t} \ + {${if def:sender_ident \ + {from ${quote_local_part:$sender_ident} }}\ + ${if def:sender_helo_name \ + {(helo=$sender_helo_name)\n\t}}}}\ + by $primary_hostname \ + ${if def:received_protocol \ + {with $received_protocol \ + ${if def:tls_cipher {(cipher=$tls_cipher)\n\t}}}}\ + (Exim $version_number)\n\t\ + ${if def:sender_address \ + {(envelope-from <$sender_address>\ + ${if def:authenticated_id \ + {; auth=$authenticated_id}})\n\t}}\ + id $message_exim_id\ + ${if def:received_for {\n\tfor $received_for}} + +SECTION(global, smtp)m4_dnl +smtp_return_error_details = true +accept_8bitmime = true + +SECTION(global, process)m4_dnl +extract_addresses_remove_arguments = false +headers_charset = utf-8 +qualify_domain = CONF_master_domain + +SECTION(global, bounce)m4_dnl +delay_warning = 1h : 24h : 2d + +DIVERT(null) +###-------------------------------------------------------------------------- +### Access control lists. + +SECTION(global, acl-after) +SECTION(global, acl)m4_dnl +acl_smtp_helo = helo +SECTION(acl, misc)m4_dnl +helo: + require message = The other one has bells on + verify = helo + + accept + +SECTION(global, acl)m4_dnl +acl_smtp_mail = mail +SECTION(acl, mail)m4_dnl +mail: + + ## Always allow the empty sender, so that we can receive bounces. + accept senders = : + + ## Ensure that the sender is routable. This is important to prevent + ## undeliverable bounces. + require message = Invalid sender; \ + ($sender_verify_failure; $acl_verify_message) + verify = sender + + ## If this is directly from a client then hack on it for a while. + warn condition = ${if eq{$acl_c_mode}{submission}} + control = submission + +SECTION(acl, mail-tail)m4_dnl + ## And we're done. + accept + +SECTION(global, acl)m4_dnl +acl_smtp_connect = connect +SECTION(acl, connect)m4_dnl +connect: +SECTION(acl, connect-tail)m4_dnl + warn acl = check_submission + accept + +check_submission: + ## See whether this message needs hacking on. + accept !hosts = +localnet + !condition = ${if ={$received_port}{CONF_submission_port}} + set acl_c_mode = relay + + ## Remember to apply submission controls. + warn set acl_c_mode = submission + + ## Done. + accept + +SECTION(global, acl)m4_dnl +acl_smtp_rcpt = rcpt +SECTION(acl, rcpt)m4_dnl +rcpt: + + ## Reject if the client isn't allowed to relay and the recipient + ## isn't in one of our known domains. + deny message = Relaying not permitted + !hosts = CONF_relay_clients + !authenticated = * + !domains = +known + + ## Ensure that the recipient is routable. + require message = Invalid recipient \ + ($recipient_verify_failure; $acl_verify_message) + verify = recipient + +SECTION(acl, rcpt-tail)m4_dnl + ## Everything checks out OK: let this one go through. + accept + +SECTION(global, acl)m4_dnl +acl_smtp_data = data +SECTION(acl, data)m4_dnl +data: + +SECTION(acl, data-tail)m4_dnl + accept + +SECTION(global, acl)m4_dnl +acl_smtp_expn = expn_vrfy +acl_smtp_vrfy = expn_vrfy +SECTION(acl)m4_dnl +expn_vrfy: + accept hosts = +trusted + deny message = Suck it and see + +DIVERT(null) +###-------------------------------------------------------------------------- +### Common options for forwarding routers. + +## We're pretty permissive here. +m4_define(<:FILTER_BASE:>, + <:driver = redirect + modemask = 002 + check_owner = false + check_group = false + allow_filter = true + allow_defer = true + allow_fail = true + forbid_blackhole = false + check_ancestor = true:>) + +## Common options for forwarding routers at verification time. +m4_define(<:FILTER_VERIFY:>, + <:verify_only = true + user = CONF_filter_user + forbid_filter_dlfunc = true + forbid_filter_logwrite = true + forbid_filter_perl = true + forbid_filter_readsocket = true + forbid_filter_run = true + file_transport = dummy + directory_transport = dummy + pipe_transport = dummy + reply_transport = dummy:>) + +## Transports for redirection filters. +m4_define(<:FILTER_TRANSPORTS:>, + <:file_transport = mailbox + directory_transport = maildir + pipe_transport = pipe + reply_transport = reply:>) + +DIVERT(null) +###-------------------------------------------------------------------------- +### Some standard transports. + +m4_define(<:USER_DELIVERY:>, + <:delivery_date_add = true + envelope_to_add = true + return_path_add = true:>) + +SECTION(transports)m4_dnl +## A standard transport for remote delivery. Try to do TLS, and don't worry +## too much if it's not very secure: the alternative is sending in plaintext +## anyway. +smtp: + driver = smtp + tls_require_ciphers = CONF_acceptable_ciphers + tls_dh_min_bits = 1020 + tls_tempfail_tryclear = true + +## Transport to a local SMTP server; use TLS and perform client +## authentication. +smtp_local: + driver = smtp + hosts_require_tls = * + tls_certificate = CONF_sysconf_dir/client.cert + tls_privatekey = CONF_sysconf_dir/client.key + tls_verify_certificates = CONF_ca_dir/ca.cert + tls_require_ciphers = CONF_good_ciphers + tls_dh_min_bits = 3070 + tls_tempfail_tryclear = false + authenticated_sender = ${if def:authenticated_id \ + ${authenticated_id@CONF_master_domain} \ + fail} + +## A standard transport for local delivery. +deliver: + driver = appendfile + file = /var/mail/$local_part + USER_DELIVERY + +## Transports for user filters. +mailbox: + driver = appendfile + USER_DELIVERY + +maildir: + driver = appendfile + maildir_format = true + USER_DELIVERY + +pipe: + driver = pipe + return_output = true + +## A special dummy transport for use during address verification. +dummy: + driver = appendfile + file = /dev/null + +DIVERT(null) +###-------------------------------------------------------------------------- +### Retry configuration. + +SECTION(retry, default)m4_dnl +## Default. +* * \ + F,2h,15m; G,16h,2h,1.5; F,4d,6h + +DIVERT(null) +###----- That's all, folks -------------------------------------------------- diff --git a/config.m4 b/config.m4 new file mode 100644 index 0000000..5901edc --- /dev/null +++ b/config.m4 @@ -0,0 +1,80 @@ +### -*-m4-*- +### +### Basic configuration settings for distorted.org.uk Exim configuration +### +### (c) 2012 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## Master domain name. +DEFCONF(master_domain, distorted.org.uk) + +## The smarthost for satellite hosts. +DEFCONF(smarthost, mail.distorted.org.uk) + +## The user who runs verification filters. +DEFCONF(filter_user, Debian-exim) + +## Where the spam filter is. +DEFCONF(spamd_address, 172.29.199.179) +DEFCONF(spamd_port, 783) + +## Default spam limit for incoming mail (multiplied by ten). +DEFCONF(spam_max, 50) + +## Which interfaces to listen on. Exim checks for the literal string `::0' +## when setting things up: don't use `::', or we'll be tripped up by Linux's +## demented non-`IPV6_V6ONLY' behaviour. +DEFCONF(interfaces, m4_ifelse(MODE, satellite, 127.0.0.1 ; ::1, + 0.0.0.0 ; ::0)) + +## Submission port number. (This is sometimes tweaked for testing.) +DEFCONF(submission_port, 587) + +## Locations of other configuration files. +DEFCONF(sysconf_dir, /etc/mail) +DEFCONF(userconf_dir, $home/.mail) +DEFCONF(alias_file, /etc/aliases) +DEFCONF(ca_dir, /etc/ca) + +## User address suffix handling. +DEFCONF(user_suffix_list, -* : +*) +DEFCONF(user_extaddr_regexp, $acl_c_user([-+@]|\$)) +DEFCONF(user_extaddr_fixup, ${sg {$local_part_suffix}{^[-+]}{}}) + +## Other hosts allowed to relay mail through us. +DEFCONF(relay_clients, +trusted) + +## TLS-related settings. We're assuming GNUTLS here, rather than OpenSSL. +## For local connections we are very strict. For random clients, we try +## fairly hard to encourage any kind of crypto on the grounds that probably +## nobody can verify our certificate anyway. +DEFCONF(good_ciphers, NONE<::>m4_dnl +:+VERS-TLS1.2:+VERS-TLS1.1<::>m4_dnl +:+DHE-RSA:+DHE-DSS<::>m4_dnl +:+AES-256-CBC:+AES-128-CBC<::>m4_dnl +:+SHA256<::>m4_dnl +:+SIGN-RSA-SHA512:+SIGN-RSA-SHA384:+SIGN-RSA-SHA256:+SIGN-DSA-SHA256<::>m4_dnl +:+CTYPE-X.509<::>m4_dnl +:+COMP-NULL<::>m4_dnl +) +DEFCONF(acceptable_ciphers, NORMAL<::>m4_dnl +:-MD5<::>m4_dnl +) + +###----- That's all, folks -------------------------------------------------- diff --git a/defs.m4 b/defs.m4 new file mode 100644 index 0000000..f9b3333 --- /dev/null +++ b/defs.m4 @@ -0,0 +1,106 @@ +m4_divert(-1)m4_dnl ### -*-m4-*- +### +### Basic definitions for distorted.org.uk Exim configuration +### +### (c) 2012 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +m4_changequote(<:, :>) +m4_changecom(<:#:#:>) + +###-------------------------------------------------------------------------- +### Output file preamble and postamble. + +m4_divert(0)m4_dnl +### -*-conf-*- GENERATED FROM /etc/mail/m4/*.m4: DO NOT EDIT! +### +### Exim configuration for distorted.org.uk. + +m4_divert(1000)m4_dnl +### GENERATED FROM exim4.conf.m4: DO NOT EDIT! +m4_divert(-1) + +###-------------------------------------------------------------------------- +### Useful macros. + +## ONEOF(arg, ...) +## +## Output the first of its arguments that is non-empty. +m4_define(<:ONEOF:>, <:m4_ifelse(<:$#:>, <:1:>, <:$1:>, + <:$1:>, <::>, <:ONEOF(m4_shift($@)):>, <:$1:>):>) + +## DEFCONF(CONF, DEFAULT) +## +## Define config variable CONF, assigning it the DEFAULT value if not +## overridden by `SETCONF'. +m4_define(<:DEFCONF:>, +<:m4_ifdef(<:CONF_$1:>, <::>, +<:m4_define(<:CONF_$1:>, <:$2:>):>):>) + +## SETCONF(CONF, VALUE) +## +## Set config variable VALUE. +m4_define(<:SETCONF:>, <:m4_define(<:CONF_$1:>, <:$2:>):>) + +## FOREACH(what, list) +## +## The LIST is a comma-separated list of things, like an m4 argument list. +## For each item in the list, expand WHAT as if it's the body of a macro with +## the list item as its arguments. In other words, the list item itself can +## be a list of comma-separated items, which are available as $1, $2, ..., +## within WHAT. +m4_define(<:_FOREACH:>, <:m4_dnl +m4_ifelse(<:$#:>, <:1:>, <:_foreach_func($1):>, + <:_foreach_func($1)<::>_FOREACH(m4_shift($@)):>):>) +m4_define(<:FOREACH:>, <:m4_dnl +m4_pushdef(<:_foreach_func:>, <:$1:>)m4_dnl +_FOREACH($2)<::>m4_dnl +m4_popdef(<:_foreach_func:>):>) + +m4_define(<:DIVERT:>, <:m4_dnl +m4_divert(m4_indir(<:_div:$1:>))m4_dnl +:>) + +m4_define(<:SECTION:>, <:m4_dnl +DIVERT(<:$1:>)m4_dnl +m4_ifdef(<:_done:$1:>, <::>, <:m4_dnl +###-------------------------------------------------------------------------- +m4_ifdef(<:_head:$1:>, <:m4_indir(<:_head:$1:>):>, <:begin $1:>) + +m4_define(<:_done:$1:>, <:1:>):>)m4_dnl +m4_ifelse(<:$2:>, <::>, <::>, <:m4_dnl +DIVERT(<:$1/$2:>)m4_dnl +m4_ifdef(<:_done:$1/$2:>, <::>, <:m4_dnl +m4_ifdef(<:_head:$1/$2:>, <:<:##:> m4_indir(<:_head:$1/$2:>) +:>)m4_define(<:_done:$1/$2:>):>):>):>) + +m4_define(<:LOOKUP_DOMAIN:>, + <:if exists{CONF_sysconf_dir/domains.conf} \ + {${lookup {$1}partial0-lsearch{CONF_sysconf_dir/domains.conf} \ + m4_ifelse(<:$2$3:>, <::>, <::>, + <:$2:>, <::>, <:{$value}$3:>, + <:$2$3:>)}} \ + $3:>) + +m4_define(<:KV:>, <:${extract {$1}{$value}$2}:>) +m4_define(<:DOMKV:>, <:${extract {$1}{$domain_data}$2}:>) + +m4_divert(999)m4_dnl +###----- That's all, folks -------------------------------------------------- +m4_divert(-1) diff --git a/divmap.m4 b/divmap.m4 new file mode 100644 index 0000000..c7ed1d7 --- /dev/null +++ b/divmap.m4 @@ -0,0 +1,128 @@ +### -*-m4-*- +### +### Diversion map for distorted.org.uk Exim configuration. +### +### (c) 2012 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +###-------------------------------------------------------------------------- +### Numbering machinery. + +## Rather than maintain the diversion numbers by hand, this chunk of Emacs +## Lisp will recompute them when they've been edited. All you have to do is +## declare the diversions in the correct order. +(save-excursion + (save-match-data + (goto-char (point-min)) + (let ((next-div 0) div) + (while (re-search-forward (concat "\\(DEFDIVERSION(\\)" ;1 + "\\([^,]+\\)" ;2 = diversion + "\\(,\\s-*\\)" ;3 + "\\([0-9]+\\)" ;4 = number + "\\([,)]\\)") ;5 + nil t) + (setq div (match-string 2)) + (if (not (string-match-p "/" div)) + (setq next-div (* 100 (/ (+ next-div 100) 100)))) + (replace-match (concat "\\1\\2\\3" + (int-to-string next-div) + "\\5")) + (setq next-div (+ next-div 2)))))) + +m4_define(<:_div:null:>, <:-1:>) + +m4_define(<:DEFDIVERSION:>, <:m4_dnl + m4_define(<:_div:$1:>, <:$2:>)m4_dnl + m4_ifelse(<:$3:>, <::>, <::>, <:m4_dnl + m4_define(<:_head:$1:>, <:$3:>):>):>) + +###-------------------------------------------------------------------------- +### The diversion map. + +## header 0 + +DEFDIVERSION(global, 100, ### Global settings.) +DEFDIVERSION(global/logging, 102, Logging.) + +DEFDIVERSION(global/lists, 104) + +DEFDIVERSION(global/misc, 106, Miscellaneous.) +DEFDIVERSION(global/param, 108, Exim parameters.) +DEFDIVERSION(global/priv, 110, Privilege controls.) +DEFDIVERSION(global/frozen, 112, Frozen messages.) +DEFDIVERSION(global/lookups, 114, Data lookups.) +DEFDIVERSION(global/msgid, 116, Message ids.) +DEFDIVERSION(global/perl, 118, Embedded Perl startup.) +DEFDIVERSION(global/daemon, 120, Daemon.) +DEFDIVERSION(global/resource, 122, Resource control.) +DEFDIVERSION(global/policy, 124, Policy controls.) +DEFDIVERSION(global/callout, 126, Callout cache.) +DEFDIVERSION(global/tls, 128, TLS.) +DEFDIVERSION(global/users, 130, Local user handling.) +DEFDIVERSION(global/incoming, 132, + All incoming messages (SMTP and non-SMTP).) +DEFDIVERSION(global/non-smtp, 134, Non-SMTP incoming messages.) +DEFDIVERSION(global/smtp, 136, Incoming SMTP messages.) +DEFDIVERSION(global/process, 138, Processing messages.) +DEFDIVERSION(global/filter, 140, System filter.) +DEFDIVERSION(global/routing, 142, Routing and delivery.) +DEFDIVERSION(global/bounce, 144, Bounce and warning messages.) +DEFDIVERSION(global/acl, 146, Access control lists.) +DEFDIVERSION(global/acl-after, 148) + +DEFDIVERSION(acl, 200) +DEFDIVERSION(acl/connect, 202) +DEFDIVERSION(acl/connect-hooks, 204) +DEFDIVERSION(acl/connect-tail, 206) +DEFDIVERSION(acl/mail, 208) +DEFDIVERSION(acl/mail-hooks, 210) +DEFDIVERSION(acl/mail-tail, 212) +DEFDIVERSION(acl/rcpt, 214) +DEFDIVERSION(acl/rcpt-hooks, 216) +DEFDIVERSION(acl/rcpt-tail, 218) +DEFDIVERSION(acl/data, 220) +DEFDIVERSION(acl/data-spam, 222) +DEFDIVERSION(acl/data-tail, 224) +DEFDIVERSION(acl/misc, 226) + +DEFDIVERSION(auth, 300, begin authenticators) + +DEFDIVERSION(routers, 400) +DEFDIVERSION(routers/route, 402) +DEFDIVERSION(routers/remote, 404) +DEFDIVERSION(routers/virtual, 406) +DEFDIVERSION(routers/real, 408) +DEFDIVERSION(routers/alias, 410) +DEFDIVERSION(routers/allspam, 412) +DEFDIVERSION(routers/dispatch, 414) +DEFDIVERSION(routers/forward, 416) +DEFDIVERSION(routers/deliver, 418) + +DEFDIVERSION(transports, 500) + +DEFDIVERSION(retry, 600) +DEFDIVERSION(retry/misc, 602) +DEFDIVERSION(retry/default, 604) + +DEFDIVERSION(rewrite, 700) + +## warning trailer 1000 + +DIVERT(null) +###----- That's all, folks -------------------------------------------------- diff --git a/exchange.m4 b/exchange.m4 new file mode 100644 index 0000000..08fe4a0 --- /dev/null +++ b/exchange.m4 @@ -0,0 +1,92 @@ +### -*-m4-*- +### +### Transmission to remote hosts for distorted.org.uk Exim configuration. +### +### (c) 2012 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +###-------------------------------------------------------------------------- +### Listen for incoming connections. + +SECTION(global, tls)m4_dnl +tls_certificate = CONF_sysconf_dir/server.cert +tls_privatekey = CONF_sysconf_dir/server.key +tls_advertise_hosts = * +tls_dhparam = CONF_ca_dir/dh-param.pem +tls_require_ciphers = ${if or {{={$received_port}{CONF_submission_port}} \ + {match_ip {$sender_host_address}{+trusted}}} \ + {CONF_good_ciphers} \ + {CONF_acceptable_ciphers}} +tls_verify_certificates = CONF_ca_dir/ca.cert +tls_verify_hosts = ${if eq{$acl_c_mode}{submission} {} {+allnets}} + +DIVERT(null) +###-------------------------------------------------------------------------- +### Check source addresses for apparently local senders. + +SECTION(acl, mail-hooks)m4_dnl + ## Check that a submitted message's sender address is allowable. + require acl = mail_client_addr + + ## Insist that a local client connect through TLS. + deny message = Hosts within CONF_master_domain must use TLS + !condition = ${if eq{$acl_c_mode}{submission}} + hosts = +allnets + !encrypted = * + +SECTION(acl, misc)m4_dnl +mail_client_addr: + + ## If this is a message submission then that's handled elsewhere. + accept condition = ${if eq{$acl_c_mode}{submission}} + + ## Make sure that the sender matches the client address. + require message = Client host invalid for sender domain + hosts = ${LOOKUP_DOMAIN($sender_address_domain, + {KV(hosts, {$value}{+allnets})}, + {${if match_domain {$sender_address_domain} \ + {+public} \ + {+allnets}{! +allnets}}})} + + ## OK. + accept + +DIVERT(null) +###-------------------------------------------------------------------------- +### The obvious trivial router. + +SECTION(routers, remote)m4_dnl +## Send mail on to a host in our own network. We must apply extra security. +local: + driver = dnslookup + domains = ! +known : *.CONF_master_domain + self = fail + transport = smtp_local + no_more + +## Send mail on to unknown hosts. +remote: + driver = dnslookup + domains = ! +known + self = fail + transport = smtp + no_more + +DIVERT(null) +###----- That's all, folks -------------------------------------------------- diff --git a/lists.m4 b/lists.m4 new file mode 100644 index 0000000..85d48c2 --- /dev/null +++ b/lists.m4 @@ -0,0 +1,57 @@ +### -*-m4-*- +### +### Lists of addresses and suchlike for distorted.org.uk Exim configuration +### +### (c) 2012 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +SECTION(global, lists)m4_dnl +## Definitions for known networks. +hostlist localnet = <; \ + 127.0.0.0/8 ; ::1 +hostlist border = <; \ + 62.49.204.144/28 ; 2001:470:1f09:1b98::/64 ; \ + 212.13.198.64/28 ; 2001:ba8:0:1d9::/64 +hostlist trusted = <; \ + +localnet ; +border ; \ + 172.29.199.0/24 ; 2001:ba8:1d9::/49 ; 2001:470:9740::/49 +hostlist allnets = <; \ + +localnet ; +border ; \ + 172.29.198.0/23 ; 2001:ba8:1d9::/48 ; 2001:470:9740::/48 + +## Domains we're authoritative for. +domainlist thishost = @ : @[] : \ + ${map {${extract {${extract {1}{.}{$primary_hostname}}} \ + { telecaster=tele \ + stratocaster=strat }}} \ + {$item.$qualify_domain}} +domainlist public = +thishost : distorted.org.uk +domainlist known = +public : \ + ${if exists{CONF_sysconf_dir/domains.conf} \ + {partial0-lsearch; CONF_sysconf_dir/domains.conf} \ + {}} + +## Some magic lists used because `match_local_parts' and friends don't expand +## their right-hand sides. +localpartlist dom_users = ${expand:KV(users, {$value}{*})} +localpartlist dom_locals = ${expand:KV(locals, {$value}{+user_extaddr})} +localpartlist user_extaddr = ^CONF_user_extaddr_regexp + +DIVERT(null) +###----- That's all, folks -------------------------------------------------- diff --git a/local.m4 b/local.m4 new file mode 100644 index 0000000..78b3e64 --- /dev/null +++ b/local.m4 @@ -0,0 +1,113 @@ +### -*-m4-*- +### +### Local senders and recipients for distorted.org.uk Exim configuration +### +### (c) 2012 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +m4_define(<:FILTER_LOCALUSER:>, + <:FILTER_BASE + check_local_user + ignore_enotdir + sieve_useraddress = $local_part + sieve_subaddress = CONF_user_extaddr_fixup + sieve_vacation_directory = CONF_userconf_dir/vacation + condition = ${if exists {<:$1:>}} + file = <:$1:>:>) + +###-------------------------------------------------------------------------- +### Be flexible about originator addresses, as long as they probably work. + +SECTION(global, priv)m4_dnl +local_from_suffix = CONF_user_suffix_list + +SECTION(global, process)m4_dnl +## Restrict users to plausible envelope sender addresses. This is +## surprisingly fiddly. What I actually want to say is that the local part +## must match ^$sender_ident(\$|-) and the domain part must match an +## appropriate domain; but writing a conjunction is rather tricky. And so we +## must burn some addresslist variables. +addresslist wrong_local = ! +user_extaddr +addresslist wrong_domain = ! *@+public +addresslist wrong_address = +wrong_local : +wrong_domain +untrusted_set_sender = : \ + ${LOOKUP_DOMAIN($sender_address_domain, + {${if and {{match_local_part {$sender_ident} {+dom_users}} \ + {match_local_part {$sender_address_local_part} \ + {+dom_locals}}} \ + {*}}})} : \ + ! +wrong_address + +###-------------------------------------------------------------------------- +### Forwarding and redirection for incoming mail. + +SECTION(routers, alias)m4_dnl +## Look up the local part in the address map. +alias: + driver = redirect + allow_fail = true + allow_defer = true + user = CONF_filter_user + FILTER_TRANSPORTS + data = ${lookup {$local_part} lsearch {CONF_alias_file}} + +SECTION(routers, real)m4_dnl +## A special hack to get mail to a user who has a forward file. Only for +## special effects. +real: + driver = accept + check_local_user + local_part_prefix = real- + transport = deliver + condition = ${if match_ip {$sender_host_address} \ + {<; ; 127.0.0.1 ; ::1}} + +SECTION(routers, forward)m4_dnl +## Handle user forward files. Each user is granted an arbitrary number of +## additional mailboxes named USER-SUFFIX. Such addresses are handled by a +## filter file `~/.mail/forward.suffix' in the USER's home directory. The +## filter may reject the incoming message (which is reported as an SMTP +## rejection if possible). Mail sent directly to the user is handled through +## `~/.mail/forward', or `~/.forward', or if neither of those exists, by +## writing the message to `/var/mail/USER'. +filter_verify: + FILTER_LOCALUSER(CONF_userconf_dir/forward.suffix) + FILTER_VERIFY + local_part_suffix = CONF_user_suffix_list +filter_suffix: + FILTER_LOCALUSER(CONF_userconf_dir/forward.suffix) + local_part_suffix = CONF_user_suffix_list + FILTER_TRANSPORTS +filter: + FILTER_LOCALUSER(CONF_userconf_dir/forward) + FILTER_TRANSPORTS +dot_forward: + FILTER_LOCALUSER($home/.forward) + FILTER_TRANSPORTS + +SECTION(routers, deliver)m4_dnl +## Deliver mail to a user, in the absence of any other instructions. +deliver: + driver = accept + check_local_user + transport = deliver + cannot_route_message = Unknown local part + +DIVERT(null) +###----- That's all, folks -------------------------------------------------- diff --git a/satellite.m4 b/satellite.m4 new file mode 100644 index 0000000..088dded --- /dev/null +++ b/satellite.m4 @@ -0,0 +1,39 @@ +### -*-m4-*- +### +### Satellite hosts for distorted.org.uk Exim configuration +### +### (c) 2012 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +SECTION(acl, connect-hooks)m4_dnl + ## Check the caller. + deny message = This is not a public mail server + hosts = ! +allnets + +SECTION(routers, remote)m4_dnl +satellite: + driver = manualroute + transport = smtp_local + domains = ! +thishost + host_find_failed = defer + same_domain_copy_routing = true + route_list = {$spam_score_int}{$acl_m_spam_limit} \ + {true}{false}} + + ## Insert headers from the spam check now that we've decided to + ## accept the message. + warn + ## Convert the limit (currently 10x fixed point) into a + ## decimal for presentation. + set acl_m_spam_limit_presentation = \ + ${sg{$acl_m_spam_limit}{\N(\d)$\N}{.\$1}} + + ## Convert the report into something less obnoxious. Plain + ## old SpamAssassin has an `X-Spam-Status' header which + ## lists the matched rules and provides some other basic + ## information. Try to extract something similar from the + ## report. + ## + ## This is rather fiddly. + + ## Firstly, escape angle brackets, because we'll be using + ## them for our own purposes. + set acl_m_spam_tests = ${sg{$spam_report}{([!<>])}{!\$1}} + + ## Trim off the blurb paragraph and the preview. The rest + ## should be fairly well behaved. Wrap double angle- + ## brackets around the remainder; these can't appear in the + ## body because we escaped them all earlier. + set acl_m_spam_tests = \ + ${sg{$acl_m_spam_tests} \ + {\N^(?s).*\n Content analysis details:(.*)$\N} \ + {<<\$1>>}} + + ## Extract the information about the matching rules and + ## their scores. Leave `<<...>>' around everything else. + set acl_m_spam_tests = \ + ${sg{$acl_m_spam_tests} \ + {\N(?s)\n\s*([\d.]+)\s+([-\w]+)\s\N} \ + {>>\$2:\$1,<<}} + + ## Strip everything still in `<<...>>' pairs, including any + ## escaped characters inside. + set acl_m_spam_tests = \ + ${sg{$acl_m_spam_tests}{\N(?s)<<([^!>]+|!.)*>>\N}{}} + + ## Trim off a trailing comma. + set acl_m_spam_tests = ${sg{$acl_m_spam_tests}{,\s*\$}{}} + + ## Undo the escaping. + set acl_m_spam_tests = ${sg{$acl_m_spam_tests}{!(.)}{\$1}} + + ## Insert the headers. + add_header = X-SpamAssassin-Score: \ + $spam_score/$acl_m_spam_limit_presentation \ + ($spam_bar) + add_header = X-SpamAssassin-Status: \ + score=$spam_score, \ + limit=$acl_m_spam_limit_presentation, \n\t\ + tests=$acl_m_spam_tests + + + ## We're good. + accept + +DIVERT(null) +###----- That's all, folks -------------------------------------------------- diff --git a/vhost.m4 b/vhost.m4 new file mode 100644 index 0000000..07ca79e --- /dev/null +++ b/vhost.m4 @@ -0,0 +1,69 @@ +### -*-m4-*- +### +### Virtual host support for distorted.org.uk Exim configuration +### +### (c) 2012 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +m4_define(<:VHOST:>, + <:domains = partial0-lsearch; CONF_sysconf_dir/domains.conf + condition = DOMKV($1):>) +m4_define(<:VHOST_FILTER:>, + <:FILTER_BASE + VHOST(<:$1:>) + $2 = ${expand:DOMKV($1, {$value} fail)}:>) +m4_define(<:VHOST_USER:>, + <:user = DOMKV(owner, {$value}{CONF_filter_user}) + errors_to = DOMKV(errors_to, {$value} fail):>) + +###-------------------------------------------------------------------------- +### Routers and transports for virtual hosting. + +SECTION(routers, route)m4_dnl +## If we're a front-end for some other domain, or we have special information +## about the domain, then pass stuff along as instructed. +route: + driver = manualroute + self = fail + VHOST(route) + route_data = DOMKV(route, {$value} fail) + same_domain_copy_routing = true + transport = smtp + no_more + +SECTION(routers, virtual)m4_dnl +## Remap recipients according to the virtual host's instructions. This must +## be done in two passes, so that we can identify the correct user's spam +## threshold during address verification. +virtual_verify_data: + VHOST_FILTER(redirect, data) + FILTER_VERIFY +virtual_verify_file: + VHOST_FILTER(filter, file) + FILTER_VERIFY + +virtual_filter_data: + VHOST_FILTER(redirect, data) + VHOST_USER +virtual_filter_file: + VHOST_FILTER(filter, file) + VHOST_USER + +DIVERT(null) +###----- That's all, folks -------------------------------------------------- -- 2.11.0