proto.m4 revision 110647
138032Speterdivert(-1) 238032Speter# 394334Sgshapiro# Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. 464562Sgshapiro# All rights reserved. 538032Speter# Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. 638032Speter# Copyright (c) 1988, 1993 738032Speter# The Regents of the University of California. All rights reserved. 838032Speter# 938032Speter# By using this file, you agree to the terms and conditions set 1038032Speter# forth in the LICENSE file which can be found at the top level of 1138032Speter# the sendmail distribution. 1238032Speter# 1338032Speter# 1438032Speterdivert(0) 1538032Speter 16110647SgshapiroVERSIONID(`$Id: proto.m4,v 8.649.2.14 2002/12/30 15:46:02 ca Exp $') 1738032Speter 1864562Sgshapiro# level CF_LEVEL config file format 1964562SgshapiroV`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley') 2038032Speterdivert(-1) 2138032Speter 2290792Sgshapirodnl if MAILER(`local') not defined: do it ourself; be nice 2390792Sgshapirodnl maybe we should issue a warning? 2490792Sgshapiroifdef(`_MAILER_local_',`', `MAILER(local)') 2590792Sgshapiro 2638032Speter# do some sanity checking 2738032Speterifdef(`__OSTYPE__',, 2864562Sgshapiro `errprint(`*** ERROR: No system type defined (use OSTYPE macro) 2964562Sgshapiro')') 3038032Speter 3138032Speter# pick our default mailers 3238032Speterifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')') 3338032Speterifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')') 3438032Speterifdef(`confRELAY_MAILER',, 3538032Speter `define(`confRELAY_MAILER', 3638032Speter `ifdef(`_MAILER_smtp_', `relay', 3738032Speter `ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')') 3838032Speterifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')') 3938032Speterdefine(`_SMTP_', `confSMTP_MAILER')dnl for readability only 4038032Speterdefine(`_LOCAL_', `confLOCAL_MAILER')dnl for readability only 4138032Speterdefine(`_RELAY_', `confRELAY_MAILER')dnl for readability only 4238032Speterdefine(`_UUCP_', `confUUCP_MAILER')dnl for readability only 4338032Speter 4438032Speter# back compatibility with old config files 4538032Speterifdef(`confDEF_GROUP_ID', 4664562Sgshapiro`errprint(`*** confDEF_GROUP_ID is obsolete. 4764562Sgshapiro Use confDEF_USER_ID with a colon in the value instead. 4864562Sgshapiro')') 4938032Speterifdef(`confREAD_TIMEOUT', 5064562Sgshapiro`errprint(`*** confREAD_TIMEOUT is obsolete. 5164562Sgshapiro Use individual confTO_<timeout> parameters instead. 5264562Sgshapiro')') 5338032Speterifdef(`confMESSAGE_TIMEOUT', 5438032Speter `define(`_ARG_', index(confMESSAGE_TIMEOUT, /)) 5538032Speter ifelse(_ARG_, -1, 5638032Speter `define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)', 5738032Speter `define(`confTO_QUEUERETURN', 5838032Speter substr(confMESSAGE_TIMEOUT, 0, _ARG_)) 5938032Speter define(`confTO_QUEUEWARN', 6038032Speter substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')') 6138032Speterifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,, 6264562Sgshapiro`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete. 6364562Sgshapiro Use confMAX_MESSAGE_SIZE for the second part of the value. 6464562Sgshapiro')')') 6538032Speter 6664562Sgshapiro 6764562Sgshapiro# Sanity check on ldap_routing feature 6864562Sgshapiro# If the user doesn't specify a new map, they better have given as a 6964562Sgshapiro# default LDAP specification which has the LDAP base (and most likely the host) 7064562Sgshapiroifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(` 7164562SgshapiroWARNING: Using default FEATURE(ldap_routing) map definition(s) 7264562Sgshapirowithout setting confLDAP_DEFAULT_SPEC option. 7364562Sgshapiro')')')dnl 7464562Sgshapiro 7538032Speter# clean option definitions below.... 7664562Sgshapirodefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl 7738032Speter 7864562Sgshapirodnl required to "rename" the check_* rulesets... 7964562Sgshapirodefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_')) 8064562Sgshapirodnl default relaying denied message 8190792Sgshapiroifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG', 8290792Sgshapiroifdef(`_USE_AUTH_', `"550 Relaying denied. Proper authentication required."', `"550 Relaying denied"'))') 8390792Sgshapiroifdef(`confRCPTREJ_MSG', `', `define(`confRCPTREJ_MSG', `"550 Mailbox disabled for this recipient"')') 8490792Sgshapirodefine(`_CODE553', `553') 8538032Speterdivert(0)dnl 8638032Speter 8764562Sgshapiro# override file safeties - setting this option compromises system security, 8864562Sgshapiro# addressing the actual file configuration problem is preferred 8964562Sgshapiro# need to set this before any file actions are encountered in the cf file 9064562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe') 9138032Speter 9264562Sgshapiro# default LDAP map specification 9364562Sgshapiro# need to set this now before any LDAP maps are defined 9464562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost') 9564562Sgshapiro 9638032Speter################## 9738032Speter# local info # 9838032Speter################## 9938032Speter 10090792Sgshapiro# my LDAP cluster 10190792Sgshapiro# need to set this before any LDAP lookups are done (including classes) 10290792Sgshapiroifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m') 10390792Sgshapiro 10438032SpeterCwlocalhost 10538032Speterifdef(`USE_CW_FILE', 10638032Speter`# file containing names of hosts for which we receive email 10738032SpeterFw`'confCW_FILE', 10838032Speter `dnl') 10938032Speter 11038032Speter# my official domain name 11138032Speter# ... `define' this only if sendmail cannot automatically determine your domain 11238032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM') 11338032Speter 11438032SpeterCP. 11538032Speter 11638032Speterifdef(`UUCP_RELAY', 11738032Speter`# UUCP relay host 11838032SpeterDY`'UUCP_RELAY 11938032SpeterCPUUCP 12038032Speter 12138032Speter')dnl 12238032Speterifdef(`BITNET_RELAY', 12338032Speter`# BITNET relay host 12438032SpeterDB`'BITNET_RELAY 12538032SpeterCPBITNET 12638032Speter 12738032Speter')dnl 12838032Speterifdef(`DECNET_RELAY', 12938032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl 13038032Speter# DECnet relay host 13138032SpeterDC`'DECNET_RELAY 13238032SpeterCPDECNET 13338032Speter 13438032Speter')dnl 13538032Speterifdef(`FAX_RELAY', 13638032Speter`# FAX relay host 13738032SpeterDF`'FAX_RELAY 13838032SpeterCPFAX 13938032Speter 14038032Speter')dnl 14138032Speter# "Smart" relay host (may be null) 14290792SgshapiroDS`'ifdef(`SMART_HOST', `SMART_HOST') 14338032Speter 14438032Speterifdef(`LUSER_RELAY', `dnl 14538032Speter# place to which unknown users should be forwarded 14638032SpeterKuser user -m -a<> 14738032SpeterDL`'LUSER_RELAY', 14838032Speter`dnl') 14938032Speter 15038032Speter# operators that cannot be in local usernames (i.e., network indicators) 15138032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!') 15238032Speter 15338032Speter# a class with just dot (for identifying canonical names) 15438032SpeterC.. 15538032Speter 15638032Speter# a class with just a left bracket (for identifying domain literals) 15738032SpeterC[[ 15838032Speter 15964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 16064562Sgshapiro# access_db acceptance class 16164562SgshapiroC{Accept}OK RELAY 16290792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl 16364562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl 16464562Sgshapiro# possible access_db RHS for spam friends/haters 16564562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')', 16638032Speter`dnl') 16738032Speter 16890792Sgshapirodnl mark for "domain is ok" (resolved or accepted anyway) 16990792Sgshapirodefine(`_RES_OK_', `OKR')dnl 17038032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl 17138032Speter# Resolve map (to check if a host exists in check_mail) 17290792SgshapiroKresolve host -a<_RES_OK_> -T<TEMP>') 17390792SgshapiroC{ResOk}_RES_OK_ 17438032Speter 17580785Sgshapiroifdef(`_NEED_MACRO_MAP_', `dnl 17680785Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map 17780785Sgshapirodefine(`_MACRO_MAP_', `1')dnl 17880785SgshapiroKmacro macro')', `dnl') 17966494Sgshapiro 18038032Speterifdef(`confCR_FILE', `dnl 18166494Sgshapiro# Hosts for which relaying is permitted ($=R) 18238032SpeterFR`'confCR_FILE', 18338032Speter`dnl') 18438032Speter 18590792Sgshapirodefine(`TLS_SRV_TAG', `"TLS_Srv"')dnl 18690792Sgshapirodefine(`TLS_CLT_TAG', `"TLS_Clt"')dnl 18790792Sgshapirodefine(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl 18890792Sgshapirodefine(`TLS_TRY_TAG', `"Try_TLS"')dnl 18990792Sgshapirodefine(`SRV_FEAT_TAG', `"Srv_Features"')dnl 19064562Sgshapirodnl this may be useful in other contexts too 19164562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map 19264562Sgshapirodefine(`_ARITH_MAP_', `1')dnl 19364562SgshapiroKarith arith') 19464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 19590792Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map 19690792Sgshapirodefine(`_MACRO_MAP_', `1')dnl 19790792SgshapiroKmacro macro') 19890792Sgshapiro# possible values for TLS_connection in access map 19964562SgshapiroC{tls}VERIFY ENCR', `dnl') 20064562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 20164562Sgshapiro# extract relevant part from cert issuer 20264562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl') 20364562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 20464562Sgshapiro# extract relevant part from cert subject 20564562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl') 20664562Sgshapiro 20790792Sgshapiroifdef(`LOCAL_RELAY', `dnl 208110647Sgshapiro# who I send unqualified names to if `FEATURE(stickyhost)' is used 209110560Sgshapiro# (null means deliver locally) 21090792SgshapiroDR`'LOCAL_RELAY') 21138032Speter 21290792Sgshapiroifdef(`MAIL_HUB', `dnl 213110560Sgshapiro# who gets all local email traffic 214110647Sgshapiro# ($R has precedence for unqualified names if `FEATURE(stickyhost)' is used) 21590792SgshapiroDH`'MAIL_HUB') 21638032Speter 21738032Speter# dequoting map 21890792SgshapiroKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `') 21938032Speter 22038032Speterdivert(0)dnl # end of nullclient diversion 22138032Speter# class E: names that should be exposed as from this host, even if we masquerade 22264562Sgshapiro# class L: names that should be delivered locally, even if we have a relay 22338032Speter# class M: domains that should be converted to $M 22464562Sgshapiro# class N: domains that should not be converted to $M 22538032Speter#CL root 22638032Speterundivert(5)dnl 22764562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl') 22838032Speter 22990792Sgshapiroifdef(`MASQUERADE_NAME', `dnl 23038032Speter# who I masquerade as (null for no masquerading) (see also $=M) 23190792SgshapiroDM`'MASQUERADE_NAME') 23238032Speter 23338032Speter# my name for error messages 23438032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON') 23538032Speter 23664562Sgshapiroundivert(6)dnl LOCAL_CONFIG 23738032Speterinclude(_CF_DIR_`m4/version.m4') 23838032Speter 23938032Speter############### 24038032Speter# Options # 24138032Speter############### 24290792Sgshapiroifdef(`confAUTO_REBUILD', 24390792Sgshapiro`errprint(WARNING: `confAUTO_REBUILD' is no longer valid. 24490792Sgshapiro There was a potential for a denial of service attack if this is set. 24590792Sgshapiro)')dnl 24638032Speter 24738032Speter# strip message body to 7 bits on input? 24864562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False') 24938032Speter 25038032Speter# 8-bit data handling 25177349Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8') 25238032Speter 25338032Speter# wait for alias file rebuild (default units: minutes) 25464562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m') 25538032Speter 25638032Speter# location of alias file 25764562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases') 25864562Sgshapiro 25938032Speter# minimum number of free blocks on filesystem 26064562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100') 26138032Speter 26238032Speter# maximum message size 26364562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000') 26438032Speter 26538032Speter# substitution for space (blank) characters 26664562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_') 26738032Speter 26838032Speter# avoid connecting to "expensive" mailers on initial submission? 26964562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False') 27038032Speter 27138032Speter# checkpoint queue runs after every N successful deliveries 27264562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10') 27338032Speter 27438032Speter# default delivery mode 27564562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background') 27638032Speter 27738032Speter# error message header/file 27864562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header') 27938032Speter 28038032Speter# error mode 28164562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print') 28238032Speter 28338032Speter# save Unix-style "From_" lines at top of header? 28464562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False') 28538032Speter 28690792Sgshapiro# queue file mode (qf files) 28790792Sgshapiro_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600') 28890792Sgshapiro 28938032Speter# temporary file mode 29064562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600') 29138032Speter 29238032Speter# match recipients against GECOS field? 29364562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False') 29438032Speter 29538032Speter# maximum hop count 29690792Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `25') 29738032Speter 29838032Speter# location of help file 29964562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile') 30038032Speter 30138032Speter# ignore dots as terminators in incoming messages? 30264562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False') 30338032Speter 30438032Speter# name resolver options 30564562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY') 30638032Speter 30738032Speter# deliver MIME-encapsulated error messages? 30864562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True') 30938032Speter 31038032Speter# Forward file search path 31164562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward') 31238032Speter 31338032Speter# open connection cache size 31464562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2') 31538032Speter 31638032Speter# open connection cache timeout 31764562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m') 31838032Speter 31938032Speter# persistent host status directory 32064562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat') 32138032Speter 32238032Speter# single thread deliveries (requires HostStatusDirectory)? 32364562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False') 32438032Speter 32538032Speter# use Errors-To: header? 32664562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False') 32738032Speter 32838032Speter# log level 32964562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10') 33038032Speter 33138032Speter# send to me too, even in an alias expansion? 33264562Sgshapiro_OPTION(MeToo, `confME_TOO', `True') 33338032Speter 33438032Speter# verify RHS in newaliases? 33564562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False') 33638032Speter 33738032Speter# default messages to old style headers if no special punctuation? 33864562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False') 33938032Speter 34038032Speter# SMTP daemon options 34164562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl', 34294334Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. 34394334Sgshapiro Use `DAEMON_OPTIONS()'; see cf/README. 34464562Sgshapiro)'dnl 34564562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')') 34666494Sgshapiroifelse(defn(`_DPO_'), `', 34790792Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet 34890792SgshapiroO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_') 34964562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E') 35038032Speter 35164562Sgshapiro# SMTP client options 35290792Sgshapiroifelse(defn(`confCLIENT_OPTIONS'), `', `dnl', 35390792Sgshapiro`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid. See cf/README for more information. 35490792Sgshapiro)'dnl 35590792Sgshapiro`CLIENT_OPTIONS(`confCLIENT_OPTIONS')') 35690792Sgshapiroifelse(defn(`_CPO_'), `', 35790792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_') 35864562Sgshapiro 35990792Sgshapiro# Modifiers to `define' {daemon_flags} for direct submissions 36090792Sgshapiro_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `') 36190792Sgshapiro 36290792Sgshapiro# Use as mail submission program? See sendmail/SECURITY 36390792Sgshapiro_OPTION(UseMSP, `confUSE_MSP', `') 36490792Sgshapiro 36538032Speter# privacy flags 36664562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings') 36738032Speter 36838032Speter# who (if anyone) should get extra copies of error messages 36964562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster') 37038032Speter 37138032Speter# slope of queue-only function 37264562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000') 37338032Speter 37490792Sgshapiro# limit on number of concurrent queue runners 37590792Sgshapiro_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `') 37690792Sgshapiro 37790792Sgshapiro# maximum number of queue-runners per queue-grouping with multiple queues 37890792Sgshapiro_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1') 37990792Sgshapiro 38090792Sgshapiro# priority of queue runners (nice(3)) 38190792Sgshapiro_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `') 38290792Sgshapiro 38390792Sgshapiro# shall we sort the queue by hostname first? 38490792Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority') 38590792Sgshapiro 38690792Sgshapiro# minimum time in queue before retry 38790792Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m') 38890792Sgshapiro 38990792Sgshapiro# how many jobs can you process in the queue? 39090792Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000') 39190792Sgshapiro 39290792Sgshapiro# perform initial split of envelope without checking MX records 39390792Sgshapiro_OPTION(FastSplit, `confFAST_SPLIT', `1') 39490792Sgshapiro 39538032Speter# queue directory 39664562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue') 39738032Speter 39890792Sgshapiro# key for shared memory; 0 to turn off 39990792Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0') 40090792Sgshapiro 40194334Sgshapiroifdef(`confSHARED_MEMORY_KEY_FILE', `dnl 40294334Sgshapiro# file to store key for shared memory (if SharedMemoryKey = -1) 40394334SgshapiroO SharedMemoryKeyFile=confSHARED_MEMORY_KEY_FILE') 40494334Sgshapiro 40538032Speter# timeouts (many of these) 40664562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m') 40764562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m') 40890792Sgshapiro_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s') 40964562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m') 41064562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m') 41164562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m') 41264562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h') 41364562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m') 41464562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h') 41564562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h') 41664562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m') 41764562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m') 41864562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m') 41964562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h') 42064562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s') 42164562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s') 42264562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m') 42364562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d') 42464562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d') 42564562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d') 42664562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d') 42764562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h') 42864562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h') 42964562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h') 43064562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h') 43164562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m') 43264562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s') 43364562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s') 43464562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s') 43564562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4') 43664562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4') 43764562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4') 43890792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m') 43990792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m') 44090792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h') 44138032Speter 44290792Sgshapiro# time for DeliverBy; extension disabled if less than 0 44390792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0') 44490792Sgshapiro 44538032Speter# should we not prune routes in route-addr syntax addresses? 44664562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False') 44738032Speter 44838032Speter# queue up everything before forking? 44964562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True') 45038032Speter 45138032Speter# status file 45264562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics') 45338032Speter 45438032Speter# time zone handling: 45538032Speter# if undefined, use system default 45638032Speter# if defined but null, use TZ envariable passed in 45738032Speter# if defined and non-null, use that info 45838032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=', 45938032Speter confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=', 46038032Speter `O TimeZoneSpec=confTIME_ZONE') 46138032Speter 46238032Speter# default UID (can be username or userid:groupid) 46364562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull') 46438032Speter 46538032Speter# list of locations of user database file (null means no lookup) 46664562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb') 46738032Speter 46838032Speter# fallback MX host 46964562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net') 47038032Speter 47138032Speter# if we are the best MX host for a site, try it directly instead of config err 47264562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False') 47338032Speter 47438032Speter# load average at which we just queue messages 47564562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8') 47638032Speter 47738032Speter# load average at which we refuse connections 47864562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12') 47938032Speter 48090792Sgshapiro# load average at which we delay connections; 0 means no limit 48190792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0') 48290792Sgshapiro 48338032Speter# maximum number of children we allow at one time 48498841Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0') 48538032Speter 48638032Speter# maximum number of new connections per second 48771345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0') 48838032Speter 48938032Speter# work recipient factor 49064562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') 49138032Speter 49238032Speter# deliver each queued job in a separate process? 49364562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False') 49438032Speter 49538032Speter# work class factor 49664562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800') 49738032Speter 49838032Speter# work time factor 49964562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000') 50038032Speter 50138032Speter# default character set 50264562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1') 50338032Speter 50490792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others) 50564562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch') 50638032Speter 50738032Speter# hosts file (normally /etc/hosts) 50864562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts') 50938032Speter 51038032Speter# dialup line delay on connection failure 51164562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s') 51238032Speter 51338032Speter# action to take if there are no recipients in the message 51464562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed') 51538032Speter 51638032Speter# chrooted environment for writing to files 51764562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch') 51838032Speter 51938032Speter# are colons OK in addresses? 52064562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True') 52138032Speter 52238032Speter# shall I avoid expanding CNAMEs (violates protocols)? 52364562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False') 52438032Speter 52538032Speter# SMTP initial login message (old $e macro) 52664562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b') 52738032Speter 52838032Speter# UNIX initial From header format (old $l macro) 52964562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d') 53038032Speter 53138032Speter# From: lines that have embedded newlines are unwrapped onto one line 53264562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False') 53338032Speter 53438032Speter# Allow HELO SMTP command that does not `include' a host name 53564562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False') 53638032Speter 53738032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic) 53864562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.') 53938032Speter 54038032Speter# delimiter (operator) characters (old $o macro) 54164562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]') 54238032Speter 54338032Speter# shall I avoid calling initgroups(3) because of high NIS costs? 54464562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False') 54538032Speter 54638032Speter# are group-writable `:include:' and .forward files (un)trustworthy? 54790792Sgshapiro# True (the default) means they are not trustworthy. 54864562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True') 54990792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES', 55090792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL. 55190792Sgshapiro')') 55238032Speter 55338032Speter# where do errors that occur when sending errors get sent? 55464562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster') 55538032Speter 55664562Sgshapiro# where to save bounces if all else fails 55764562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter') 55864562Sgshapiro 55938032Speter# what user id do we assume for the majority of the processing? 56064562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail') 56138032Speter 56238032Speter# maximum number of recipients per SMTP envelope 56364562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100') 56438032Speter 56590792Sgshapiro# limit the rate recipients per SMTP envelope are accepted 56690792Sgshapiro# once the threshold number of recipients have been rejected 56790792Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20') 56890792Sgshapiro 56938032Speter# shall we get local names from our installed interfaces? 57064562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 57138032Speter 57264562Sgshapiro# Return-Receipt-To: header implies DSN request 57364562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 57464562Sgshapiro 57564562Sgshapiro# override connection address (for testing) 57664562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 57764562Sgshapiro 57864562Sgshapiro# Trusted user for file ownership and starting the daemon 57964562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root') 58064562Sgshapiro 58164562Sgshapiro# Control socket for daemon management 58264562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 58364562Sgshapiro 58464562Sgshapiro# Maximum MIME header length to protect MUAs 58564562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0') 58664562Sgshapiro 58764562Sgshapiro# Maximum length of the sum of all headers 58864562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768') 58964562Sgshapiro 59064562Sgshapiro# Maximum depth of alias recursion 59164562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10') 59264562Sgshapiro 59364562Sgshapiro# location of pid file 59464562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid') 59564562Sgshapiro 59664562Sgshapiro# Prefix string for the process title shown on 'ps' listings 59764562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix') 59864562Sgshapiro 59964562Sgshapiro# Data file (df) memory-buffer file maximum size 60064562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096') 60164562Sgshapiro 60264562Sgshapiro# Transcript file (xf) memory-buffer file maximum size 60364562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096') 60464562Sgshapiro 60590792Sgshapiro# lookup type to find information about local mailboxes 60690792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw') 60790792Sgshapiro 60864562Sgshapiro# list of authentication mechanisms 60990792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5') 61064562Sgshapiro 61164562Sgshapiro# default authentication information for outgoing connections 61264562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info') 61364562Sgshapiro 61464562Sgshapiro# SMTP AUTH flags 61564562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `') 61664562Sgshapiro 61790792Sgshapiro# SMTP AUTH maximum encryption strength 61890792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `') 61990792Sgshapiro 62090792Sgshapiro# SMTP STARTTLS server options 62190792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `') 62290792Sgshapiro 62364562Sgshapiro# Input mail filters 62464562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 62564562Sgshapiro 62698841Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl 62764562Sgshapiro# Milter options 62890792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `') 62964562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 63064562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') 63164562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') 63264562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')') 63364562Sgshapiro 63464562Sgshapiro# CA directory 635110560Sgshapiro_OPTION(CACertPath, `confCACERT_PATH', `') 63664562Sgshapiro# CA file 637110560Sgshapiro_OPTION(CACertFile, `confCACERT', `') 63864562Sgshapiro# Server Cert 63964562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `') 64064562Sgshapiro# Server private key 64164562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `') 64264562Sgshapiro# Client Cert 64364562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `') 64464562Sgshapiro# Client private key 64564562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 64664562Sgshapiro# DHParameters (only required if DSA/DH is used) 64764562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `') 64864562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL) 64964562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `') 65064562Sgshapiro 65190792Sgshapiro############################ 65290792Sgshapiro`# QUEUE GROUP DEFINITIONS #' 65390792Sgshapiro############################ 65490792Sgshapiro_QUEUE_GROUP_ 65542575Speter 65638032Speter########################### 65738032Speter# Message precedences # 65838032Speter########################### 65938032Speter 66038032SpeterPfirst-class=0 66138032SpeterPspecial-delivery=100 66238032SpeterPlist=-30 66338032SpeterPbulk=-60 66438032SpeterPjunk=-100 66538032Speter 66638032Speter##################### 66738032Speter# Trusted users # 66838032Speter##################### 66938032Speter 67038032Speter# this is equivalent to setting class "t" 67164562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 67238032SpeterTroot 67338032SpeterTdaemon 67438032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp') 67538032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 67638032Speter 67738032Speter######################### 67838032Speter# Format of headers # 67938032Speter######################### 68038032Speter 68138032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl 68238032SpeterH?P?Return-Path: <$g> 68338032SpeterHReceived: confRECEIVED_HEADER 68438032SpeterH?D?Resent-Date: $a 68538032SpeterH?D?Date: $a 68638032SpeterH?F?Resent-From: confFROM_HEADER 68738032SpeterH?F?From: confFROM_HEADER 68838032SpeterH?x?Full-Name: $x 68938032Speter# HPosted-Date: $a 69038032Speter# H?l?Received-Date: $b 69138032SpeterH?M?Resent-Message-Id: <$t.$i@$j> 69238032SpeterH?M?Message-Id: <$t.$i@$j> 69364562Sgshapiro 69438032Speter# 69538032Speter###################################################################### 69638032Speter###################################################################### 69738032Speter##### 69838032Speter##### REWRITING RULES 69938032Speter##### 70038032Speter###################################################################### 70138032Speter###################################################################### 70238032Speter 70338032Speter############################################ 70438032Speter### Ruleset 3 -- Name Canonicalization ### 70538032Speter############################################ 70664562SgshapiroScanonify=3 70738032Speter 70838032Speter# handle null input (translate to <@> special case) 70938032SpeterR$@ $@ <@> 71038032Speter 71138032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon 71238032SpeterR$* $: $1 <@> mark addresses 71338032SpeterR$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> 71438032SpeterR@ $* <@> $: @ $1 unmark @host:... 71590792SgshapiroR$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr 71638032SpeterR$* :: $* <@> $: $1 :: $2 unmark node::addr 71738032SpeterR:`include': $* <@> $: :`include': $1 unmark :`include':... 71838032SpeterR$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon 71938032SpeterR$* : $* <@> $: $2 strip colon if marked 72038032SpeterR$* <@> $: $1 unmark 72138032SpeterR$* ; $1 strip trailing semi 72271345SgshapiroR$* < $+ :; > $* $@ $2 :; <@> catch <list:;> 72338032SpeterR$* < $* ; > $1 < $2 > bogus bracketed semi 72438032Speter 72538032Speter# null input now results from list:; syntax 72638032SpeterR$@ $@ :; <@> 72738032Speter 72838032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item 72938032SpeterR$* $: < $1 > housekeeping <> 73038032SpeterR$+ < $* > < $2 > strip excess on left 73138032SpeterR< $* > $+ < $1 > strip excess on right 73238032SpeterR<> $@ < @ > MAIL FROM:<> case 73338032SpeterR< $+ > $: $1 remove housekeeping <> 73438032Speter 73564562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 73638032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 73738032SpeterR@ $+ , $+ @ $1 : $2 change all "," to ":" 73838032Speter 73938032Speter# localize and dispose of route-based addresses 74090792Sgshapirodnl XXX: IPv6 colon conflict 74190792Sgshapiroifdef(`NO_NETINET6', `dnl', 74290792Sgshapiro`R@ [$+] : $+ $@ $>Canonify2 < @ [$1] > : $2 handle <route-addr>') 74364562SgshapiroR@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 74464562Sgshapirodnl',`dnl 74564562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d> 74664562SgshapiroR@ $+ , $+ $2 74790792Sgshapiroifdef(`NO_NETINET6', `dnl', 74890792Sgshapiro`R@ [ $* ] : $+ $2') 74964562SgshapiroR@ $+ : $+ $2 75064562Sgshapirodnl') 75138032Speter 75238032Speter# find focus for list syntax 75364562SgshapiroR $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 75438032SpeterR $+ : $* ; $@ $1 : $2; list syntax 75538032Speter 75638032Speter# find focus for @ syntax addresses 75738032SpeterR$+ @ $+ $: $1 < @ $2 > focus on domain 75838032SpeterR$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 75964562SgshapiroR$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 76038032Speter 76190792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here. 76290792Sgshapirodnl # do some sanity checking 76390792Sgshapirodnl R$* < @ $~[ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 76438032Speter 76538032Speterifdef(`_NO_UUCP_', `dnl', 76638032Speter`# convert old-style addresses to a domain-based address 76764562SgshapiroR$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 76864562SgshapiroR$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 76964562SgshapiroR$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 77038032Speter') 77138032Speterifdef(`_USE_DECNET_SYNTAX_', 77238032Speter`# convert node::user addresses into a domain-based address 77364562SgshapiroR$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 77464562SgshapiroR$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 77538032Speter', 77638032Speter `dnl') 77738032Speter# if we have % signs, take the rightmost one 77838032SpeterR$* % $* $1 @ $2 First make them all @s. 77938032SpeterR$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 78064562SgshapiroR$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 78138032Speter 78238032Speter# else we must be a local name 78364562SgshapiroR$* $@ $>Canonify2 $1 78438032Speter 78538032Speter 78638032Speter################################################ 78738032Speter### Ruleset 96 -- bottom half of ruleset 3 ### 78838032Speter################################################ 78938032Speter 79064562SgshapiroSCanonify2=96 79138032Speter 79238032Speter# handle special cases for local names 79338032SpeterR$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 79438032SpeterR$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 79538032Speterifdef(`_NO_UUCP_', `dnl', 79638032Speter`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 79764562Sgshapiro 79890792Sgshapiro# check for IPv4/IPv6 domain literal 79990792SgshapiroR$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr] 80038032SpeterR$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 80138032SpeterR$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 80238032Speter 80364562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl 80438032Speter# look up domains in the domain table 80538032SpeterR$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 80638032Speter 80764562Sgshapiroundivert(2)dnl LOCAL_RULE_3 80838032Speter 80964562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl 81038032Speter# handle BITNET mapping 81138032SpeterR$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 81238032Speter 81364562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl 81438032Speter# handle UUCP mapping 81538032SpeterR$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 81638032Speter 81738032Speterifdef(`_NO_UUCP_', `dnl', 81838032Speter`ifdef(`UUCP_RELAY', 81938032Speter`# pass UUCP addresses straight through 82038032SpeterR$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 82138032Speter`# if really UUCP, handle it immediately 82238032Speterifdef(`_CLASS_U_', 82338032Speter`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82438032Speterifdef(`_CLASS_V_', 82538032Speter`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82638032Speterifdef(`_CLASS_W_', 82738032Speter`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82838032Speterifdef(`_CLASS_X_', 82938032Speter`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 83038032Speterifdef(`_CLASS_Y_', 83138032Speter`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 83238032Speter 83338032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl 83438032Speter# try UUCP traffic as a local address 83538032SpeterR$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 83638032SpeterR$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 83738032Speter')') 83864562Sgshapiro# hostnames ending in class P are always canonical 83964562SgshapiroR$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 84064562Sgshapirodnl apply the next rule only for hostnames not in class P 84164562Sgshapirodnl this even works for phrases in class P since . is in class P 84264562Sgshapirodnl which daemon flags are set? 84364562SgshapiroR$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 84464562Sgshapirodnl the other rules in this section only apply if the hostname 84564562Sgshapirodnl does not end in class P hence no further checks are done here 84664562Sgshapirodnl if this ever changes make sure the lookups are "protected" again! 84764562Sgshapiroifdef(`_NO_CANONIFY_', `dnl 84864562Sgshapirodnl do not canonify unless: 84964562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection 85064562Sgshapirodnl with class P is non-empty) 85164562Sgshapirodnl or {daemon_flags} has c set 85264562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify} 85364562SgshapiroR$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 85464562Sgshapiro# pass to name server to make hostname canonical if requested 85564562SgshapiroR$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 85664562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 85764562SgshapiroR$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 85864562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work 85964562SgshapiroR$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 86064562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl 86164562Sgshapirodnl this should only apply to unqualified hostnames 86264562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar 86364562Sgshapirodnl then $- does not work. 86464562Sgshapiro# lookup unqualified hostnames 86590792SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 86664562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless: 86764562Sgshapirodnl {daemon_flags} contains CC (do not canonify) 86871345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work 86971345Sgshapirodnl should we do this for every hostname: even unqualified? 87071345SgshapiroR$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 87164562SgshapiroR$* CC $* $| $* $: $3 87290792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl 87390792Sgshapiro# do not canonify header addresses 87490792SgshapiroR$* $| $* < @ $* $~P > $* $: $&{addr_type} $| $2 < @ $3 $4 > $5 87590792SgshapiroR$* h $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 87690792SgshapiroR$* h $* $| $* $: $3', `dnl') 87738032Speter# pass to name server to make hostname canonical 87864562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 87964562Sgshapirodnl remove {daemon_flags} for other cases 88064562SgshapiroR$* $| $* $: $2 88138032Speter 88238032Speter# local host aliases and pseudo-domains are always canonical 88338032SpeterR$* < @ $=w > $* $: $1 < @ $2 . > $3 88438032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 88538032Speter`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 88638032Speter`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 88764562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 88864562Sgshapirodnl virtual hosts are also canonical 88964562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 89064562Sgshapiro`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 89164562Sgshapiro`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 89264562Sgshapiro`dnl') 89390792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 89490792Sgshapirodnl hosts for genericstable are also canonical 89590792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_', 89690792Sgshapiro`R$* < @ $* $=G > $* $: $1 < @ $2 $3 . > $4', 89790792Sgshapiro`R$* < @ $=G > $* $: $1 < @ $2 . > $3')', 89890792Sgshapiro`dnl') 89964562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added 90064562Sgshapirodnl by one of the rules before 90138032SpeterR$* < @ $* . . > $* $1 < @ $2 . > $3 90238032Speter 90338032Speter 90438032Speter################################################## 90538032Speter### Ruleset 4 -- Final Output Post-rewriting ### 90638032Speter################################################## 90764562SgshapiroSfinal=4 90838032Speter 90971345SgshapiroR$+ :; <@> $@ $1 : handle <list:;> 91038032SpeterR$* <@> $@ handle <> and list:; 91138032Speter 91238032Speter# strip trailing dot off possibly canonical name 91338032SpeterR$* < @ $+ . > $* $1 < @ $2 > $3 91438032Speter 91564562Sgshapiro# eliminate internal code 91638032SpeterR$* < @ *LOCAL* > $* $1 < @ $j > $2 91738032Speter 91838032Speter# externalize local domain info 91938032SpeterR$* < $+ > $* $1 $2 $3 defocus 92038032SpeterR@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 92138032SpeterR@ $* $@ @ $1 ... and exit 92238032Speter 92338032Speterifdef(`_NO_UUCP_', `dnl', 92438032Speter`# UUCP must always be presented in old form 92538032SpeterR$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 92638032Speter 92738032Speterifdef(`_USE_DECNET_SYNTAX_', 92838032Speter`# put DECnet back in :: form 92938032SpeterR$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 93038032Speter `dnl') 93138032Speter# delete duplicate local names 93238032SpeterR$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 93338032Speter 93438032Speter 93538032Speter 93638032Speter############################################################## 93738032Speter### Ruleset 97 -- recanonicalize and call ruleset zero ### 93838032Speter### (used for recursive calls) ### 93938032Speter############################################################## 94038032Speter 94164562SgshapiroSRecurse=97 94264562SgshapiroR$* $: $>canonify $1 94364562SgshapiroR$* $@ $>parse $1 94438032Speter 94538032Speter 94638032Speter###################################### 94738032Speter### Ruleset 0 -- Parse Address ### 94838032Speter###################################### 94938032Speter 95064562SgshapiroSparse=0 95138032Speter 95238032SpeterR$* $: $>Parse0 $1 initial parsing 95338032SpeterR<@> $#_LOCAL_ $: <@> special case error msgs 95464562SgshapiroR$* $: $>ParseLocal $1 handle local hacks 95538032SpeterR$* $: $>Parse1 $1 final parsing 95638032Speter 95738032Speter# 95838032Speter# Parse0 -- do initial syntax checking and eliminate local addresses. 95938032Speter# This should either return with the (possibly modified) input 96038032Speter# or return with a #error mailer. It should not return with a 96138032Speter# #mailer other than the #error mailer. 96238032Speter# 96338032Speter 96438032SpeterSParse0 96538032SpeterR<@> $@ <@> special case error msgs 96690792SgshapiroR$* : $* ; <@> $#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses" 96764562SgshapiroR@ <@ $* > < @ $1 > catch "@@host" bogosity 96890792SgshapiroR<@ $+> $#error $@ 5.1.3 $: "_CODE553 User address required" 96990792SgshapiroR$+ <@> $#error $@ 5.1.3 $: "_CODE553 Hostname required" 97038032SpeterR$* $: <> $1 97190792Sgshapirodnl allow tricks like [host1]:[host2] 97290792SgshapiroR<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4 97390792SgshapiroR<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4 97490792Sgshapirodnl but no a@[b]c 97590792SgshapiroR<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid address" 97690792SgshapiroR<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 97790792SgshapiroR<> $* <$* : $* > $* $#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part" 97838032SpeterR<> $* $1 97990792SgshapiroR$* < @ . $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 98090792SgshapiroR$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 98190792Sgshapirodnl no a@b@ 98290792SgshapiroR$* < @ $* @ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid route address" 98390792Sgshapirodnl no a@b@c 98490792SgshapiroR$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 98564562Sgshapirodnl comma only allowed before @; this check is not complete 98690792SgshapiroR$* , $~O $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 98738032Speter 98890792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks 98990792SgshapiroR$* . < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot" 99090792SgshapiroR. $* < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot" 99190792Sgshapirodnl', `dnl') 99290792Sgshapiro 99338032Speter# now delete the local info -- note $=O to find characters that cause forwarding 99464562SgshapiroR$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 99564562SgshapiroR< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 99638032SpeterR$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 99790792SgshapiroR< @ $+ > $#error $@ 5.1.3 $: "_CODE553 User address required" 99864562SgshapiroR$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 99938032SpeterR$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 100090792SgshapiroR< @ *LOCAL* > $#error $@ 5.1.3 $: "_CODE553 User address required" 100138032SpeterR$* $=O $* < @ *LOCAL* > 100264562Sgshapiro $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 100338032SpeterR$* < @ *LOCAL* > $: $1 100438032Speter 100538032Speter# 100638032Speter# Parse1 -- the bottom half of ruleset 0. 100738032Speter# 100838032Speter 100938032SpeterSParse1 101064562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 101164562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute} 101290792SgshapiroR$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <> 101390792SgshapiroR$+ < @ $={LDAPRouteEquiv} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>', 101464562Sgshapiro`dnl') 101564562Sgshapiro 101638032Speterifdef(`_MAILER_smtp_', 101738032Speter`# handle numeric address spec 101864562Sgshapirodnl there is no check whether this is really an IP number 101964562SgshapiroR$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 102064562SgshapiroR$* < @ [ $+ ] > $* $1 < @ [ $2 ] : $S > $3 Add smart host to path 102190792SgshapiroR$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 102264562SgshapiroR$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 102364562SgshapiroR$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 102438032Speter `dnl') 102538032Speter 102664562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 102738032Speter# handle virtual users 102890792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 102990792Sgshapirodnl this is not a documented option 103090792Sgshapirodnl it stops looping in virtusertable mapping if input and output 103190792Sgshapirodnl are identical, i.e., if address A is mapped to A. 103290792Sgshapirodnl it does not deal with multi-level recursion 103390792Sgshapiro# handle full domains in RHS of virtusertable 103490792SgshapiroR$+ < @ $+ > $: $(macro {RecipientAddress} $) $1 < @ $2 > 103590792SgshapiroR$+ < @ $+ > $: <?> $1 < @ $2 > $| $>final $1 < @ $2 > 103690792SgshapiroR<?> $+ $| $+ $: $1 $(macro {RecipientAddress} $@ $2 $) 103790792SgshapiroR<?> $+ $| $* $: $1', 103890792Sgshapiro`dnl') 103964562SgshapiroR$+ $: <!> $1 Mark for lookup 104090792Sgshapirodnl input: <!> local<@domain> 104164562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 104264562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 104364562Sgshapiro`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 104490792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain> 104564562SgshapiroR<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 104690792Sgshapirodnl if <@> local<@domain>: no match but try lookup 104790792Sgshapirodnl user+detail: try user++@domain if detail not empty 104890792SgshapiroR<@> $+ + $+ < @ $* . > 104990792Sgshapiro $: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105090792Sgshapirodnl user+detail: try user+*@domain 105138032SpeterR<@> $+ + $* < @ $* . > 105290792Sgshapiro $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105390792Sgshapirodnl user+detail: try user@domain 105438032SpeterR<@> $+ + $* < @ $* . > 105590792Sgshapiro $: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105664562Sgshapirodnl try default entry: @domain 105790792Sgshapirodnl ++@domain 105890792SgshapiroR<@> $+ + $+ < @ $+ . > $: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105964562Sgshapirodnl +*@domain 106090792SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 106164562Sgshapirodnl @domain if +detail exists 106298121Sgshapirodnl if no match, change marker to prevent a second @domain lookup 106398121SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . > 106498121Sgshapirodnl without +detail 106538032SpeterR<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 106690792Sgshapirodnl no match 106738032SpeterR<@> $+ $: $1 106890792Sgshapirodnl remove mark 106964562SgshapiroR<!> $+ $: $1 107064562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 107138032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 107290792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 107390792Sgshapiro# check virtuser input address against output address, if same, skip recursion 107490792SgshapiroR< $+ > $+ < @ $+ > $: < $1 > $2 < @ $3 > $| $1 107590792Sgshapiro# it is the same: stop now 107690792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress} $: $>ParseLocal $>Parse0 $>canonify $1 107790792SgshapiroR< $+ > $+ < @ $+ > $| $* $: < $1 > $2 < @ $3 > 107890792Sgshapirodnl', `dnl') 107980785Sgshapirodnl this is not a documented option 108080785Sgshapirodnl it performs no looping at all for virtusertable 108177349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_', 108277349Sgshapiro`R< $+ > $+ < @ $+ > $: $>ParseLocal $>Parse0 $>canonify $1', 108377349Sgshapiro`R< $+ > $+ < @ $+ > $: $>Recurse $1') 108477349Sgshapirodnl', `dnl') 108538032Speter 108638032Speter# short circuit local delivery so forwarded email works 108738032Speterifdef(`_MAILER_usenet_', `dnl 108864562SgshapiroR$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 108966494Sgshapiro 109066494Sgshapiro 109138032Speterifdef(`_STICKY_LOCAL_DOMAIN_', 109238032Speter`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 109364562SgshapiroR< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 109464562Sgshapirodnl $H empty (but @$=w.) 109538032SpeterR< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 109638032SpeterR< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 109764562Sgshapiro`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 109838032SpeterR$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 109938032Speter 110064562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 110138032Speter# not local -- try mailer table lookup 110238032SpeterR$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 110338032SpeterR< $+ . > $* $: < $1 > $2 strip trailing dot 110438032SpeterR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 110564562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 110664562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 110764562SgshapiroR< $+ > $* $: $>Mailertable <$1> $2 try domain', 110838032Speter`dnl') 110964562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)' 111038032Speter 111138032Speterifdef(`_NO_UUCP_', `dnl', 111238032Speter`# resolve remotely connected UUCP links (if any) 111338032Speterifdef(`_CLASS_V_', 111464562Sgshapiro`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 111538032Speter `dnl') 111638032Speterifdef(`_CLASS_W_', 111764562Sgshapiro`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 111838032Speter `dnl') 111938032Speterifdef(`_CLASS_X_', 112064562Sgshapiro`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 112138032Speter `dnl')') 112238032Speter 112338032Speter# resolve fake top level domains by forwarding to other hosts 112438032Speterifdef(`BITNET_RELAY', 112564562Sgshapiro`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 112638032Speter `dnl') 112738032Speterifdef(`DECNET_RELAY', 112864562Sgshapiro`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 112938032Speter `dnl') 113038032Speterifdef(`_MAILER_pop_', 113138032Speter`R$+ < @ POP. > $#pop $: $1 user@POP', 113238032Speter `dnl') 113338032Speterifdef(`_MAILER_fax_', 113438032Speter`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 113538032Speter`ifdef(`FAX_RELAY', 113664562Sgshapiro`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 113738032Speter `dnl')') 113838032Speter 113938032Speterifdef(`UUCP_RELAY', 114038032Speter`# forward non-local UUCP traffic to our UUCP relay 114164562SgshapiroR$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 114238032Speter`ifdef(`_MAILER_uucp_', 114338032Speter`# forward other UUCP traffic straight to UUCP 114438032SpeterR$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 114538032Speter `dnl')') 114638032Speterifdef(`_MAILER_usenet_', ` 114738032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup 114864562SgshapiroR$+ . USENET $#usenet $@ usenet $: $1', 114938032Speter `dnl') 115038032Speter 115138032Speterifdef(`_LOCAL_RULES_', 115238032Speter`# figure out what should stay in our local mail system 115338032Speterundivert(1)', `dnl') 115438032Speter 115538032Speter# pass names that still have a host to a smarthost (if defined) 115664562SgshapiroR$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 115738032Speter 115838032Speter# deal with other remote names 115938032Speterifdef(`_MAILER_smtp_', 116064562Sgshapiro`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 116190792Sgshapiro`R$* < @$* > $* $#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2') 116238032Speter 116338032Speter# handle locally delivered names 116464562SgshapiroR$=L $#_LOCAL_ $: @ $1 special local names 116538032SpeterR$+ $#_LOCAL_ $: $1 regular local names 116638032Speter 116738032Speter########################################################################### 116838032Speter### Ruleset 5 -- special rewriting after aliases have been expanded ### 116938032Speter########################################################################### 117038032Speter 117164562SgshapiroSLocal_localaddr 117264562SgshapiroSlocaladdr=5 117364562SgshapiroR$+ $: $1 $| $>"Local_localaddr" $1 117490792SgshapiroR$+ $| $#ok $@ $1 no change 117564562SgshapiroR$+ $| $#$* $#$2 117664562SgshapiroR$+ $| $* $: $1 117738032Speter 117890792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 117990792Sgshapiro# Preserve rcpt_host in {Host} 118090792SgshapiroR$+ $: $1 $| $&h $| $&{Host} check h and {Host} 118190792SgshapiroR$+ $| $| $: $(macro {Host} $@ $) $1 no h or {Host} 118290792SgshapiroR$+ $| $| $+ $: $1 h not set, {Host} set 118390792SgshapiroR$+ $| +$* $| $* $: $1 h is +detail, {Host} set 118495154SgshapiroR$+ $| $* @ $+ $| $* $: $(macro {Host} $@ @$3 $) $1 set {Host} to host in h 118590792SgshapiroR$+ $| $+ $| $* $: $(macro {Host} $@ @$2 $) $1 set {Host} to h 118690792Sgshapiro')dnl 118790792Sgshapiro 118890792Sgshapiroifdef(`_FFR_5_', `dnl 118966494Sgshapiro# Preserve host in a macro 119066494SgshapiroR$+ $: $(macro {LocalAddrHost} $) $1 119166494SgshapiroR$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 119266494Sgshapiro 119390792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl 119438032Speter# deal with plussed users so aliases work nicely 119566494SgshapiroR$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 119666494SgshapiroR$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 119766494Sgshapiro') 119838032Speter# prepend an empty "forward host" on the front 119938032SpeterR$+ $: <> $1 120038032Speter 120138032Speterifdef(`LUSER_RELAY', `dnl 120238032Speter# send unrecognized local users to a relay host 120390792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 120466494SgshapiroR< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 120566494SgshapiroR< > $+ $: < ? $L > < > $(user $1 $) look up user 120666494SgshapiroR< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 120766494SgshapiroR< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 120864562SgshapiroR< > $+ $: < $L > $(user $1 $) look up user 120990792SgshapiroR< $* > $+ <> $: < > $2 found; strip $L') 121090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 121190792SgshapiroR< $+ > $+ $: < $1 > $2 $&{Host}') 121290792Sgshapirodnl') 121338032Speter 121490792Sgshapiroifdef(`MAIL_HUB', `dnl 121590792SgshapiroR< > $+ $: < $H > $1 try hub', `dnl') 121690792Sgshapiroifdef(`LOCAL_RELAY', `dnl 121790792SgshapiroR< > $+ $: < $R > $1 try relay', `dnl') 121890792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 121990792SgshapiroR< > $+ $@ $1', `dnl 122064562SgshapiroR< > $+ $: < > < $1 <> $&h > nope, restore +detail 122190792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 122290792SgshapiroR< > < $+ @ $+ <> + $* > $: < > < $1 + $3 @ $2 > check whether +detail') 122364562SgshapiroR< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 122464562SgshapiroR< > < $+ <> $* > $: < > < $1 > else discard 122538032SpeterR< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 122666494SgshapiroR< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 122738032SpeterR< > < $+ > $@ $1 no +detail 122843730SpeterR$+ $: $1 <> $&h add +detail back in 122990792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 123090792SgshapiroR$+ @ $+ <> + $* $: $1 + $3 @ $2 check whether +detail') 123143730SpeterR$+ <> + $* $: $1 + $2 check whether +detail 123266494SgshapiroR$+ <> $* $: $1 else discard') 123364562SgshapiroR< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 123464562SgshapiroR< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 123590792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 123690792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 123790792SgshapiroR< $~[ : $+ > $+ @ $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $4 >') 123890792SgshapiroR< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 123990792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 124090792SgshapiroR< $+ > $+ @ $+ $@ $>MailerToTriple < $1 > $2 < @ $3 >') 124164562SgshapiroR< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 124238032Speter 124364562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 124490792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 124538032Speter################################################################### 124690792Sgshapiro### Ruleset LDAPMailertable -- mailertable lookup for LDAP ### 124790792Sgshapirodnl input: <Domain> FullAddress 124890792Sgshapiro################################################################### 124990792Sgshapiro 125090792SgshapiroSLDAPMailertable 125190792SgshapiroR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 125290792SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check resolved? 125390792SgshapiroR< $+ > $* $: < $1 > $>Mailertable <$1> $2 try domain 125490792SgshapiroR< $+ > $#$* $#$2 found 125590792SgshapiroR< $+ > $* $#_RELAY_ $@ $1 $: $2 not found, direct relay', 125690792Sgshapiro`dnl') 125790792Sgshapiro 125890792Sgshapiro################################################################### 125938032Speter### Ruleset 90 -- try domain part of mailertable entry ### 126064562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 126138032Speter################################################################### 126238032Speter 126364562SgshapiroSMailertable=90 126464562Sgshapirodnl shift and check 126564562Sgshapirodnl %2 is not documented in cf/README 126638032SpeterR$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 126764562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 126864562SgshapiroR$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 126964562SgshapiroR$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 127064562Sgshapirodnl is $2 always empty? 127138032SpeterR$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 127264562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 127364562Sgshapirodnl return full address 127438032SpeterR< $* > $* $@ $2 no mailertable match', 127538032Speter`dnl') 127638032Speter 127738032Speter################################################################### 127838032Speter### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 127964562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest 128064562Sgshapirodnl <> address -> address 128164562Sgshapirodnl <error:d.s.n:text> -> error 128264562Sgshapirodnl <error:text> -> error 128364562Sgshapirodnl <mailer:user@host> lp<@domain>rest -> mailer host user 128464562Sgshapirodnl <mailer:host> address -> mailer host address 128564562Sgshapirodnl <localdomain> address -> address 128664562Sgshapirodnl <host> address -> relay host address 128738032Speter################################################################### 128838032Speter 128964562SgshapiroSMailerToTriple=95 129038032SpeterR< > $* $@ $1 strip off null relay 129164562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 129238032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 129338032SpeterR< local : $* > $* $>CanonLocal < $1 > $2 129490792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 129590792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 129690792SgshapiroR< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 129738032SpeterR< $=w > $* $@ $2 delete local host 129838032SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 129938032Speter 130038032Speter################################################################### 130138032Speter### Ruleset CanonLocal -- canonify local: syntax ### 130264562Sgshapirodnl input: <user> address 130364562Sgshapirodnl <x> <@host> : rest -> Recurse rest 130464562Sgshapirodnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 130564562Sgshapirodnl <> user <@host> rest -> local user@host user 130664562Sgshapirodnl <> user -> local user user 130764562Sgshapirodnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 130864562Sgshapirodnl <user> lp <@host> rest -> local lp@host user 130964562Sgshapirodnl <user> lp -> local lp user 131038032Speter################################################################### 131138032Speter 131238032SpeterSCanonLocal 131343730Speter# strip local host from routed addresses 131464562SgshapiroR< $* > < @ $+ > : $+ $@ $>Recurse $3 131564562SgshapiroR< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 131643730Speter 131738032Speter# strip trailing dot from any host name that may appear 131838032SpeterR< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 131938032Speter 132038032Speter# handle local: syntax -- use old user, either with or without host 132138032SpeterR< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 132238032SpeterR< > $+ $#_LOCAL_ $@ $1 $: $1 132338032Speter 132438032Speter# handle local:user@host syntax -- ignore host part 132538032SpeterR< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 132638032Speter 132738032Speter# handle local:user syntax 132838032SpeterR< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 132938032SpeterR< $+ > $* $#_LOCAL_ $@ $2 $: $1 133038032Speter 133138032Speter################################################################### 133238032Speter### Ruleset 93 -- convert header names to masqueraded form ### 133338032Speter################################################################### 133438032Speter 133564562SgshapiroSMasqHdr=93 133638032Speter 133764562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 133838032Speter# handle generics database 133938032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_', 134064562Sgshapirodnl if generics should be applied add a @ as mark 134138032Speter`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 134238032Speter`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 134338032SpeterR$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 134464562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @ 134564562Sgshapirodnl ignore the first case for now 134664562Sgshapirodnl if it has the mark lookup full address 134790792Sgshapirodnl broken: %1 is full address not just detail 134864562SgshapiroR< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 134964562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain> 135064562Sgshapirodnl no match, try user+detail@domain 135164562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 135264562Sgshapiro $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 135364562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 135464562Sgshapiro $: < $(generics $1@$3 $: $) > $4 < @ $5 > 135564562Sgshapirodnl no match, remove mark 135664562SgshapiroR<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 135764562Sgshapirodnl no match, try @domain for exceptions 135864562SgshapiroR< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 135964562Sgshapirodnl workspace: ... or <match> user <@domain> 136064562Sgshapirodnl no match, try local part 136138032SpeterR< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 136264562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 136364562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 136464562SgshapiroR< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 136564562SgshapiroR< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 136638032SpeterR< > $* $: $1 not found', 136738032Speter`dnl') 136838032Speter 136964562Sgshapiro# do not masquerade anything in class N 137064562SgshapiroR$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 137164562Sgshapiro 137290792Sgshapiroifdef(`MASQUERADE_NAME', `dnl 137338032Speter# special case the users that should be exposed 137438032SpeterR$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 137538032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 137638032Speter`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 137738032Speter`R$=E < @ $=M . > $@ $1 < @ $2 . >') 137838032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 137938032Speter`R$=E < @ $=w . > $@ $1 < @ $2 . >') 138038032Speter 138138032Speter# handle domain-specific masquerading 138238032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 138338032Speter`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 138438032Speter`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 138538032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 138638032Speter`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 138738032SpeterR$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 138838032SpeterR$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 138938032SpeterR$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 139090792Sgshapirodnl', `dnl no masquerading 139190792Sgshapirodnl just fix *LOCAL* leftovers 139290792SgshapiroR$* < @ *LOCAL* > $@ $1 < @ $j . >') 139338032Speter 139438032Speter################################################################### 139538032Speter### Ruleset 94 -- convert envelope names to masqueraded form ### 139638032Speter################################################################### 139738032Speter 139864562SgshapiroSMasqEnv=94 139938032Speterifdef(`_MASQUERADE_ENVELOPE_', 140064562Sgshapiro`R$+ $@ $>MasqHdr $1', 140138032Speter`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 140238032Speter 140338032Speter################################################################### 140438032Speter### Ruleset 98 -- local part of ruleset zero (can be null) ### 140538032Speter################################################################### 140638032Speter 140764562SgshapiroSParseLocal=98 140864562Sgshapiroundivert(3)dnl LOCAL_RULE_0 140938032Speter 141064562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 141190792Sgshapiro###################################################################### 141290792Sgshapiro### LDAPExpand: Expand address using LDAP routing 141390792Sgshapiro### 141490792Sgshapiro### Parameters: 141590792Sgshapiro### <$1> -- parsed address (user < @ domain . >) (pass through) 141690792Sgshapiro### <$2> -- RFC822 address (user @ domain) (used for lookup) 141790792Sgshapiro### <$3> -- +detail information 141890792Sgshapiro### 141990792Sgshapiro### Returns: 142090792Sgshapiro### Mailer triplet ($#mailer $@ host $: address) 142190792Sgshapiro### Parsed address (user < @ domain . >) 142290792Sgshapiro###################################################################### 142390792Sgshapiro 142464562SgshapiroSLDAPExpand 142564562Sgshapiro# do the LDAP lookups 142690792SgshapiroR<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3> 142764562Sgshapiro 142894334Sgshapiro# look for temporary failures (return original address, MTA will queue up) 1429102528SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*> $@ $3 1430102528SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*> $@ $3 143194334Sgshapiro 143264562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost, 143364562Sgshapiro# return the new mailRoutingAddress 143490792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 143590792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2 143690792SgshapiroR<$+@$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $5 @ $2') 143790792SgshapiroR<$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 143890792SgshapiroR<$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 143964562Sgshapiro 144098121Sgshapiro 144164562Sgshapiro# if mailRoutingAddress and non-local mailHost, 144264562Sgshapiro# relay to mailHost with new mailRoutingAddress 144390792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 144490792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 144590792Sgshapiro# check mailertable for host, relay from there 144690792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$3> $>canonify $1 $6 @ $2', 144790792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')') 144890792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 144990792Sgshapiro# check mailertable for host, relay from there 145090792SgshapiroR<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1', 145190792Sgshapiro`R<$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $2 $: $>canonify $1') 145264562Sgshapiro 145364562Sgshapiro# if no mailRoutingAddress and local mailHost, 145464562Sgshapiro# return original address 145590792SgshapiroR<> <$=w> <$+> <$+> <$*> $@ $2 145664562Sgshapiro 145798121Sgshapiro 145864562Sgshapiro# if no mailRoutingAddress and non-local mailHost, 145964562Sgshapiro# relay to mailHost with original address 146090792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 146190792Sgshapiro# check mailertable for host, relay from there 146290792SgshapiroR<> <$+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2', 146390792Sgshapiro`R<> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $1 $: $2') 146464562Sgshapiro 146590792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_', 146690792Sgshapiro`# if no mailRoutingAddress and no mailHost, 146790792Sgshapiro# try without +detail 146890792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl 146990792Sgshapiro 147090792Sgshapiro# if still no mailRoutingAddress and no mailHost, 147164562Sgshapiro# try @domain 147290792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 147390792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <@ $4> <+$3>') 147490792SgshapiroR<> <> <$+> <$+ @ $+> <$*> $@ $>LDAPExpand <$1> <@ $3> <$4> 147564562Sgshapiro 147664562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt, 147764562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 147864562Sgshapiro# user does not exist 147990792SgshapiroR<> <> <$+> <@ $+> <$*> $: <?> < $&{addr_type} > < $1 > 148090792Sgshapiro# only give error for envelope recipient 148190792SgshapiroR<?> <e r> <$+> $#error $@ nouser $: "550 User unknown" 148290792SgshapiroR<?> <$*> <$+> $@ $2', 148364562Sgshapiro`dnl 148464562Sgshapiro# return the original address 148590792SgshapiroR<> <> <$+> <@ $+> <$*> $@ $1')', 148664562Sgshapiro`dnl') 148764562Sgshapiro 148864562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 148964562Sgshapiro')') 149090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 149138032Speter###################################################################### 149290792Sgshapiro### D: LookUpDomain -- search for domain in access database 149338032Speter### 149438032Speter### Parameters: 149538032Speter### <$1> -- key (domain name) 149638032Speter### <$2> -- default (what to return if not found in db) 149764562Sgshapirodnl must not be empty 149890792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 149964562Sgshapiro### ! does lookup only with tag 150064562Sgshapiro### + does lookup with and without tag 150190792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 150264562Sgshapirodnl returns: <default> <passthru> 150364562Sgshapirodnl <result> <passthru> 150438032Speter###################################################################### 150538032Speter 150690792SgshapiroSD 150764562Sgshapirodnl workspace <key> <default> <passthru> <mark> 150864562Sgshapirodnl lookup with tag (in front, no delimiter here) 150990792Sgshapirodnl 2 3 4 5 151090792SgshapiroR<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 151164562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 151264562Sgshapirodnl lookup without tag? 151390792Sgshapirodnl 1 2 3 4 151490792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 151590792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest 151690792Sgshapirodnl XXX apply this also to IP addresses? 151790792Sgshapirodnl currently it works the wrong way round for [1.2.3.4] 151890792Sgshapirodnl 1 2 3 4 5 6 151990792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6> 152090792Sgshapirodnl 1 2 3 4 5 152190792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl') 152290792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 152390792Sgshapirodnl found SKIP: return <default> and <passthru> 152490792Sgshapirodnl 1 2 3 4 5 152590792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 152690792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!) 152790792Sgshapirodnl 1 2 3 4 5 6 152890792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*> $@ $>D <[$1]> <$3> <$4 $5> <$6> 152990792Sgshapiroifdef(`NO_NETINET6', `dnl', 153090792Sgshapiro`dnl not found: IPv6 net 153190792Sgshapirodnl (could be merged with previous rule if we have a class containing .:) 153290792Sgshapirodnl 1 2 3 4 5 6 153390792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6> 153490792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>') 153564562Sgshapirodnl not found, but subdomain: try again 153690792Sgshapirodnl 1 2 3 4 5 6 153790792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6> 153890792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag: 153990792Sgshapirodnl 1 2 3 4 154090792SgshapiroR<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl') 154190792Sgshapirodnl not found, no subdomain: return <default> and <passthru> 154290792Sgshapirodnl 1 2 3 4 5 154390792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 154490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 154590792Sgshapirodnl 2 3 4 5 6 154690792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 154790792Sgshapirodnl return <result of lookup> and <passthru> 154890792Sgshapirodnl 2 3 4 5 6 154990792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 155038032Speter 155138032Speter###################################################################### 155290792Sgshapiro### A: LookUpAddress -- search for host address in access database 155338032Speter### 155438032Speter### Parameters: 155538032Speter### <$1> -- key (dot quadded host address) 155638032Speter### <$2> -- default (what to return if not found in db) 155764562Sgshapirodnl must not be empty 155890792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 155964562Sgshapiro### ! does lookup only with tag 156064562Sgshapiro### + does lookup with and without tag 156190792Sgshapiro### <$4> -- passthru (additional data passed through) 156264562Sgshapirodnl returns: <default> <passthru> 156364562Sgshapirodnl <result> <passthru> 156438032Speter###################################################################### 156538032Speter 156690792SgshapiroSA 156764562Sgshapirodnl lookup with tag 156890792Sgshapirodnl 2 3 4 5 156990792SgshapiroR<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 157064562Sgshapirodnl lookup without tag 157190792Sgshapirodnl 1 2 3 4 157290792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 157390792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru> 157490792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 157590792Sgshapirodnl found SKIP: return <default> and <passthru> 157690792Sgshapirodnl 1 2 3 4 5 157790792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 157890792Sgshapiroifdef(`NO_NETINET6', `dnl', 157990792Sgshapiro`dnl no match; IPv6: remove last part 158090792Sgshapirodnl 1 2 3 4 5 6 158190792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 158290792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>') 158364562Sgshapirodnl no match; IPv4: remove last part 158490792Sgshapirodnl 1 2 3 4 5 6 158590792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 158664562Sgshapirodnl no match: return default 158790792Sgshapirodnl 1 2 3 4 5 158890792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 158990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 159090792Sgshapirodnl 2 3 4 5 6 159190792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 159264562Sgshapirodnl match: return result 159390792Sgshapirodnl 2 3 4 5 6 159490792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 159590792Sgshapirodnl endif _ACCESS_TABLE_ 159690792Sgshapirodivert(0) 159738032Speter###################################################################### 159842575Speter### CanonAddr -- Convert an address into a standard form for 159942575Speter### relay checking. Route address syntax is 160042575Speter### crudely converted into a %-hack address. 160142575Speter### 160242575Speter### Parameters: 160342575Speter### $1 -- full recipient address 160442575Speter### 160542575Speter### Returns: 160642575Speter### parsed address, not in source route form 160764562Sgshapirodnl user%host%host<@domain> 160864562Sgshapirodnl host!user<@domain> 160942575Speter###################################################################### 161042575Speter 161142575SpeterSCanonAddr 161264562SgshapiroR$* $: $>Parse0 $>canonify $1 make domain canonical 161364562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 161442575SpeterR< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 161542575SpeterR$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 161642575SpeterR$* < @ $+ > : $* $3 $1 < @ $2 > 161764562Sgshapirodnl') 161842575Speter 161942575Speter###################################################################### 162038032Speter### ParseRecipient -- Strip off hosts in $=R as well as possibly 162138032Speter### $* $=m or the access database. 162238032Speter### Check user portion for host separators. 162338032Speter### 162438032Speter### Parameters: 162538032Speter### $1 -- full recipient address 162638032Speter### 162738032Speter### Returns: 162838032Speter### parsed, non-local-relaying address 162938032Speter###################################################################### 163038032Speter 163138032SpeterSParseRecipient 163264562Sgshapirodnl mark and canonify address 163342575SpeterR$* $: <?> $>CanonAddr $1 163464562Sgshapirodnl workspace: <?> localpart<@domain[.]> 163542575SpeterR<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 163664562Sgshapirodnl workspace: <?> localpart<@domain> 163742575SpeterR<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 163838032Speter 163938032Speter# if no $=O character, no host in the user portion, we are done 164042575SpeterR<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 164164562Sgshapirodnl no $=O in localpart: return 164242575SpeterR<?> $* $@ $1 164338032Speter 164490792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O 164564562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY> 164638032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 164738032Speter# if we relay, check username portion for user%host so host can be checked also 164842575SpeterR<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 164964562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 165064562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 165190792Sgshapiro 165290792Sgshapirodnl what if access map returns something else than RELAY? 165390792Sgshapirodnl we are only interested in RELAY entries... 165490792Sgshapirodnl other To: entries: blacklist recipient; generic entries? 165590792Sgshapirodnl if it is an error we probably do not want to relay anyway 165638032Speterifdef(`_RELAY_HOSTS_ONLY_', 165742575Speter`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 165864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 165964562SgshapiroR<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 166042575SpeterR<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 166142575Speter`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 166264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 166390792SgshapiroR<NO> $* < @ $+ > $: $>D <$2> <NO> <+ To> <$1 < @ $2 >> 166442575SpeterR<$+> <$+> $: <$1> $2',`dnl')') 166538032Speter 166664562Sgshapiro 166790792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl 166890792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain? 166990792SgshapiroR<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 167090792SgshapiroR<MX> < : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 167190792Sgshapirodnl yes: mark it as <RELAY> 167290792SgshapiroR<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 167390792Sgshapirodnl no: put old <NO> mark back 167490792SgshapiroR<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 167590792Sgshapiro 167690792Sgshapirodnl do we relay to this recipient domain? 167742575SpeterR<RELAY> $* < @ $* > $@ $>ParseRecipient $1 167890792Sgshapirodnl something else 167990792SgshapiroR<$+> $* $@ $2 168042575Speter 168164562Sgshapiro 168238032Speter###################################################################### 168338032Speter### check_relay -- check hostname/address on SMTP startup 168438032Speter###################################################################### 168538032Speter 168638032SpeterSLocal_check_relay 168764562SgshapiroScheck`'_U_`'relay 168838032SpeterR$* $: $1 $| $>"Local_check_relay" $1 168938032SpeterR$* $| $* $| $#$* $#$3 169038032SpeterR$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 169138032Speter 169238032SpeterSBasic_check_relay 169338032Speter# check for deferred delivery mode 169498121SgshapiroR$* $: < $&{deliveryMode} > $1 169538032SpeterR< d > $* $@ deferred 169638032SpeterR< $* > $* $: $2 169738032Speter 169864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 169966494Sgshapirodnl workspace: {client_name} $| {client_addr} 170090792SgshapiroR$+ $| $+ $: $>D < $1 > <?> <+ Connect> < $2 > 170166494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 1702110560Sgshapirodnl OR $| $+ if client_name is empty 1703110560SgshapiroR $| $+ $: $>A < $1 > <?> <+ Connect> <> empty client_name 1704110560Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 170590792SgshapiroR<?> <$+> $: $>A < $1 > <?> <+ Connect> <> no: another lookup 170690792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) 170790792SgshapiroR<?> <$*> $: OK found nothing 170890792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK 170990792SgshapiroR<$={Accept}> <$*> $@ $1 return value of lookup 171090792SgshapiroR<REJECT> <$*> $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 171190792SgshapiroR<DISCARD> <$*> $#discard $: discard 171290792Sgshapiroifdef(`_FFR_QUARANTINE', 171390792Sgshapiro`R<QUARANTINE:$+> <$*> $#error $@ quarantine $: $1', `dnl') 171464562Sgshapirodnl error tag 171566494SgshapiroR<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 171666494SgshapiroR<ERROR:$+> <$*> $#error $: $1 171790792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 171864562Sgshapirodnl generic error from access map 171966494SgshapiroR<$+> <$*> $#error $: $1', `dnl') 172038032Speter 172164562Sgshapiroifdef(`_RBL_',`dnl 172264562Sgshapiro# DNS based IP address spam list 172390792Sgshapirodnl workspace: ignored... 172438032SpeterR$* $: $&{client_addr} 172564562SgshapiroR$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 172664562SgshapiroR<?>OK $: OKSOFAR 172798121SgshapiroR<?>$+ $#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"', 172838032Speter`dnl') 172964562Sgshapiroundivert(8) 173038032Speter 173138032Speter###################################################################### 173238032Speter### check_mail -- check SMTP ``MAIL FROM:'' command argument 173338032Speter###################################################################### 173438032Speter 173538032SpeterSLocal_check_mail 173664562SgshapiroScheck`'_U_`'mail 173738032SpeterR$* $: $1 $| $>"Local_check_mail" $1 173838032SpeterR$* $| $#$* $#$2 173938032SpeterR$* $| $* $@ $>"Basic_check_mail" $1 174038032Speter 174138032SpeterSBasic_check_mail 174238032Speter# check for deferred delivery mode 174398121SgshapiroR$* $: < $&{deliveryMode} > $1 174438032SpeterR< d > $* $@ deferred 174538032SpeterR< $* > $* $: $2 174638032Speter 174764562Sgshapiro# authenticated? 174864562Sgshapirodnl done first: we can require authentication for every mail transaction 174964562Sgshapirodnl workspace: address as given by MAIL FROM: (sender) 175064562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 175164562SgshapiroR$* $| $#$+ $#$2 175264562Sgshapirodnl undo damage: remove result of tls_client call 175364562SgshapiroR$* $| $* $: $1 175438032Speter 175564562Sgshapirodnl workspace: address as given by MAIL FROM: 175664562SgshapiroR<> $@ <OK> we MUST accept <> (RFC 1123) 175738032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 175864562Sgshapirodnl do some additional checks 175964562Sgshapirodnl no user@host 176064562Sgshapirodnl no user@localhost (if nonlocal sender) 176164562Sgshapirodnl this is a pretty simple canonification, it will not catch every case 176264562Sgshapirodnl just make sure the address has <> around it (which is required by 176364562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...) 176464562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will 176564562Sgshapirodnl not be modified by host lookups. 176664562SgshapiroR$+ $: <?> $1 176764562SgshapiroR<?><$+> $: <@> <$1> 176864562SgshapiroR<?>$+ $: <@> <$1> 176964562Sgshapirodnl workspace: <@> <address> 177064562Sgshapirodnl prepend daemon_flags 177164562SgshapiroR$* $: $&{daemon_flags} $| $1 177264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 177364562Sgshapirodnl do not allow these at all or only from local systems? 177464562SgshapiroR$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 177564562Sgshapirodnl accept unqualified sender: change mark to avoid test 177664562SgshapiroR$* u $* $| <@> < $* > $: <?> < $3 > 177764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 177864562Sgshapirodnl or: <? ${client_name} > <address> 177964562Sgshapirodnl or: <?> <address> 178064562Sgshapirodnl remove daemon_flags 178164562SgshapiroR$* $| $* $: $2 178238032Speter# handle case of @localhost on address 178364562SgshapiroR<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 178464562SgshapiroR<@> < $* @ [127.0.0.1] > 178564562Sgshapiro $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 178664562SgshapiroR<@> < $* @ localhost.$m > 178764562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.$m > 178838032Speterifdef(`_NO_UUCP_', `dnl', 178964562Sgshapiro`R<@> < $* @ localhost.UUCP > 179064562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 179164562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 179264562Sgshapirodnl or: <@> <address> 179364562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 179464562SgshapiroR<@> $* $: $1 no localhost as domain 179564562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 179664562Sgshapirodnl or: <address> 179764562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 179864562SgshapiroR<? $=w> $* $: $2 local client: ok 179990792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address" 180064562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 180164562SgshapiroR<?> $* $: $1') 180264562Sgshapirodnl workspace: address (or <address>) 180364562SgshapiroR$* $: <?> $>CanonAddr $1 canonify sender address and mark it 180464562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 180564562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed 180664562SgshapiroR<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 180764562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 1808102528SgshapiroR<?> $* < @ $* $=P > $: <_RES_OK_> $1 < @ $2 $3 > 180964562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ? or OK 181098121Sgshapirodnl A sender address with my local host name ($j) is safe 1811102528SgshapiroR<?> $* < @ $j > $: <_RES_OK_> $1 < @ $j > 181264562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 181390792Sgshapiro`R<?> $* < @ $+ > $: <_RES_OK_> $1 < @ $2 > ... unresolvable OK', 181464562Sgshapiro`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 181564562SgshapiroR<? $* <$->> $* < @ $+ > 181664562Sgshapiro $: <$2> $3 < @ $4 >') 181790792Sgshapirodnl workspace <mark> CanonicalAddress where mark is ?, _RES_OK_, PERM, TEMP 181864562Sgshapirodnl mark is ? iff the address is user (wo @domain) 181938032Speter 182064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 182164562Sgshapiro# check sender address: user@address, user@, address 182264562Sgshapirodnl should we remove +ext from user? 182390792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP 182490792SgshapiroR<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3> 182564562SgshapiroR<$+> $+ $: @<$1> <$2> $| <U:$2@> 182664562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 182764562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 182864562Sgshapirodnl will only return user<@domain when "reversing" the args 182990792SgshapiroR@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <> 183064562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result> 183164562SgshapiroR<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 183264562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress> 183338032Speter# retransform for further use 183464562Sgshapirodnl required form: 183564562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress 183664562SgshapiroR<?> <$+> <$*> $: <$1> $2 no match 183764562SgshapiroR<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 183864562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress 183964562Sgshapirodnl mark is ? iff the address is user (wo @domain) 184038032Speter 184138032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 184238032Speter# handle case of no @domain on address 184364562Sgshapirodnl prepend daemon_flags 184464562SgshapiroR<?> $* $: $&{daemon_flags} $| <?> $1 184564562Sgshapirodnl accept unqualified sender: change mark to avoid test 184690792SgshapiroR$* u $* $| <?> $* $: <_RES_OK_> $3 184764562Sgshapirodnl remove daemon_flags 184864562SgshapiroR$* $| $* $: $2 1849110560SgshapiroR<?> $* $: < ? $&{client_addr} > $1 1850102528SgshapiroR<?> $* $@ <_RES_OK_> ...local unqualed ok 185190792SgshapiroR<? $+> $* $#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f 185238032Speter ...remote is not') 185338032Speter# check results 185464562SgshapiroR<?> $* $: @ $1 mark address: nothing known about it 185590792SgshapiroR<$={ResOk}> $* $@ <_RES_OK_> domain ok: stop 185664562SgshapiroR<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 185790792SgshapiroR<PERM> $* $#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist" 185864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 185990792SgshapiroR<$={Accept}> $* $# $1 accept from access map 186038032SpeterR<DISCARD> $* $#discard $: discard 186190792Sgshapiroifdef(`_FFR_QUARANTINE', 186290792Sgshapiro`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 186364562SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 186464562Sgshapirodnl error tag 186564562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 186664562SgshapiroR<ERROR:$+> $* $#error $: $1 186790792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 186864562Sgshapirodnl generic error from access map 186964562SgshapiroR<$+> $* $#error $: $1 error from access db', 187038032Speter`dnl') 187138032Speter 187238032Speter###################################################################### 187338032Speter### check_rcpt -- check SMTP ``RCPT TO:'' command argument 187438032Speter###################################################################### 187538032Speter 187638032SpeterSLocal_check_rcpt 187764562SgshapiroScheck`'_U_`'rcpt 187838032SpeterR$* $: $1 $| $>"Local_check_rcpt" $1 187938032SpeterR$* $| $#$* $#$2 188038032SpeterR$* $| $* $@ $>"Basic_check_rcpt" $1 188138032Speter 188238032SpeterSBasic_check_rcpt 188390792Sgshapiro# empty address? 188490792SgshapiroR<> $#error $@ nouser $: "553 User address required" 188590792SgshapiroR$@ $#error $@ nouser $: "553 User address required" 188638032Speter# check for deferred delivery mode 188798121SgshapiroR$* $: < $&{deliveryMode} > $1 188838032SpeterR< d > $* $@ deferred 188938032SpeterR< $* > $* $: $2 189038032Speter 189164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 189290792Sgshapirodnl this code checks for user@host where host is not a FQHN. 189390792Sgshapirodnl it is not activated. 189490792Sgshapirodnl notice: code to check for a recipient without a domain name is 189590792Sgshapirodnl available down below; look for the same macro. 189690792Sgshapirodnl this check is done here because the name might be qualified by the 189790792Sgshapirodnl canonicalization. 189890792Sgshapiro# require fully qualified domain part? 189990792Sgshapirodnl very simple canonification: make sure the address is in < > 190064562SgshapiroR$+ $: <?> $1 190190792SgshapiroR<?> <$+> $: <@> <$1> 190290792SgshapiroR<?> $+ $: <@> <$1> 190390792SgshapiroR<@> < postmaster > $: postmaster 1904110560SgshapiroR<@> < $* @ $+ . $+ > $: < $1 @ $2 . $3 > 190564562Sgshapirodnl prepend daemon_flags 190690792SgshapiroR<@> $* $: $&{daemon_flags} $| <@> $1 190764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 190864562Sgshapirodnl do not allow these at all or only from local systems? 190990792SgshapiroR$* r $* $| <@> < $* @ $* > $: < ? $&{client_name} > < $3 @ $4 > 191064562SgshapiroR<?> < $* > $: <$1> 191164562SgshapiroR<? $=w> < $* > $: <$1> 191290792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "553 Fully qualified domain name required" 191364562Sgshapirodnl remove daemon_flags for other cases 191464562SgshapiroR$* $| <@> $* $: $2', `dnl') 191564562Sgshapiro 191690792Sgshapirodnl ################################################################## 191790792Sgshapirodnl call subroutines for recipient and relay 191890792Sgshapirodnl possible returns from subroutines: 191990792Sgshapirodnl $#TEMP temporary failure 192090792Sgshapirodnl $#error permanent failure (or temporary if from access map) 192190792Sgshapirodnl $#other stop processing 192290792Sgshapirodnl RELAY RELAYing allowed 192390792Sgshapirodnl other otherwise 192490792Sgshapiro###################################################################### 192590792SgshapiroR$* $: $1 $| @ $>"Rcpt_ok" $1 192690792Sgshapirodnl temporary failure? remove mark @ and remember 192790792SgshapiroR$* $| @ $#TEMP $+ $: $1 $| T $2 192890792Sgshapirodnl error or ok (stop) 192990792SgshapiroR$* $| @ $#$* $#$2 193090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 193190792SgshapiroR$* $| @ RELAY $@ RELAY 193290792Sgshapirodnl something else: call check sender (relay) 193390792SgshapiroR$* $| @ $* $: O $| $>"Relay_ok" $1 193490792Sgshapirodnl temporary failure: call check sender (relay) 193590792SgshapiroR$* $| T $+ $: T $2 $| $>"Relay_ok" $1 193690792Sgshapirodnl temporary failure? return that 193790792SgshapiroR$* $| $#TEMP $+ $#error $2 193890792Sgshapirodnl error or ok (stop) 193990792SgshapiroR$* $| $#$* $#$2 194090792SgshapiroR$* $| RELAY $@ RELAY 194190792Sgshapirodnl something else: return previous temp failure 194290792SgshapiroR T $+ $| $* $#error $1 194390792Sgshapiro# anything else is bogus 194490792SgshapiroR$* $#error $@ 5.7.1 $: confRELAY_MSG 194590792Sgshapirodivert(0) 194690792Sgshapiro 194790792Sgshapiro###################################################################### 194890792Sgshapiro### Rcpt_ok: is the recipient ok? 194990792Sgshapirodnl input: recipient address (RCPT TO) 195090792Sgshapirodnl output: see explanation at call 195190792Sgshapiro###################################################################### 195290792SgshapiroSRcpt_ok 195338032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl 195442575SpeterR$* $: $>CanonAddr $1 195538032SpeterR$* < @ $* . > $1 < @ $2 > strip trailing dots', 195638032Speter`R$* $: $>ParseRecipient $1 strip relayable hosts') 195738032Speter 195842575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl 195942575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl 196042575Speter# unlimited bestmx 196142575SpeterR$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 196242575Speter`dnl 196342575Speter# limit bestmx to $=B 196443730SpeterR$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 196590792SgshapiroR$* $=O $* < @ $* @@ $=w . > $* $@ $>"Rcpt_ok" $1 $2 $3 196642575SpeterR$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 196742575SpeterR$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 196842575Speter 196938032Speterifdef(`_BLACKLIST_RCPT_',`dnl 197064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 197138032Speter# blacklist local users or any host from receiving mail 197238032SpeterR$* $: <?> $1 197364562Sgshapirodnl user is now tagged with @ to be consistent with check_mail 197464562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user) 197590792SgshapiroR<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2> 197690792SgshapiroR<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2> 197764562SgshapiroR<?> $+ $: <> <$1> $| <U:$1@> 197864562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 197964562Sgshapirodnl will only return user<@domain when "reversing" the args 198090792SgshapiroR<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+ To> $| <$2> <> 198164562SgshapiroR<@> <$*> $| <$*> $: <$2> <$1> reverse result 198264562SgshapiroR<?> <$*> $: @ $1 mark address as no match 198390792Sgshapirodnl we may have to filter here because otherwise some RHSs 198490792Sgshapirodnl would be interpreted as generic error messages... 198590792Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 198690792Sgshapirodnl that would make a lot of things easier. 198764562SgshapiroR<$={Accept}> <$*> $: @ $2 mark address as no match 198890792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 198990792SgshapiroR<SKIP> <$*> $: @ $1 mark address as no match', `dnl') 199090792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl 199190792Sgshapirodnl compatility with 8.11/8.10: 199264562Sgshapirodnl we have to filter these because otherwise they would be interpreted 199364562Sgshapirodnl as generic error message... 199464562Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 199564562Sgshapirodnl that would make a lot of things easier. 199664562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)? 199764562SgshapiroR<$={SpamTag}> <$*> $: @ $2 mark address as no match') 199890792SgshapiroR<REJECT> $* $#error $@ 5.2.1 $: confRCPTREJ_MSG 199964562SgshapiroR<DISCARD> $* $#discard $: discard 200090792Sgshapiroifdef(`_FFR_QUARANTINE', 200190792Sgshapiro`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 200264562Sgshapirodnl error tag 200364562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 200464562SgshapiroR<ERROR:$+> $* $#error $: $1 200590792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 200664562Sgshapirodnl generic error from access map 200764562SgshapiroR<$+> $* $#error $: $1 error from access db 200864562SgshapiroR@ $* $1 remove mark', `dnl')', `dnl') 200938032Speter 201090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 201190792Sgshapiro# authenticated via TLS? 201290792SgshapiroR$* $: $1 $| $>RelayTLS client authenticated? 201390792SgshapiroR$* $| $# $+ $# $2 error/ok? 201490792SgshapiroR$* $| $* $: $1 no 201564562Sgshapiro 201690792SgshapiroR$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type} 201790792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth 201890792SgshapiroR$* $| $# $* $# $2 201990792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech} 202090792SgshapiroR$* $| NO $: $1 202190792SgshapiroR$* $| $* $: $1 $| $&{auth_type} 202290792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ] 202364562Sgshapirodnl empty ${auth_type}? 202464562SgshapiroR$* $| $: $1 202564562Sgshapirodnl mechanism ${auth_type} accepted? 202664562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below 202790792SgshapiroR$* $| $={TrustAuthMech} $# RELAY 202890792Sgshapirodnl remove ${auth_type} 202964562SgshapiroR$* $| $* $: $1 203071345Sgshapirodnl workspace: localpart<@domain> | localpart 203164562Sgshapiroifelse(defn(`_NO_UUCP_'), `r', 203271345Sgshapiro`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 203371345SgshapiroR$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 203438032Speter# anything terminating locally is ok 203538032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 203690792SgshapiroR$+ < @ $* $=m > $@ RELAY', `dnl') 203790792SgshapiroR$+ < @ $=w > $@ RELAY 203838032Speterifdef(`_RELAY_HOSTS_ONLY_', 203990792Sgshapiro`R$+ < @ $=R > $@ RELAY 204064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 204164562SgshapiroR$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 204264562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 204364562SgshapiroR<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 204490792Sgshapiro`R$+ < @ $* $=R > $@ RELAY 204564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 204690792SgshapiroR$+ < @ $+ > $: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')') 204764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 204864562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 204990792SgshapiroR<RELAY> $* $@ RELAY 205090792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 205138032SpeterR<$*> <$*> $: $2',`dnl') 205238032Speter 205364562Sgshapiro 205438032Speterifdef(`_RELAY_MX_SERVED_', `dnl 205538032Speter# allow relaying for hosts which we MX serve 205664562SgshapiroR$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 205764562Sgshapirodnl this must not necessarily happen if the client is checked first... 205890792SgshapiroR< : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 205990792SgshapiroR<$* : $=w . : $*> $* $@ RELAY 206042575SpeterR< : $* : > $* $: $2', 206138032Speter`dnl') 206238032Speter 206338032Speter# check for local user (i.e. unqualified address) 206438032SpeterR$* $: <?> $1 206542575SpeterR<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 206638032Speter# local user is ok 206764562Sgshapirodnl is it really? the standard requires user@domain, not just user 206864562Sgshapirodnl but we should accept it anyway (maybe making it an option: 206964562Sgshapirodnl RequireFQDN ?) 207064562Sgshapirodnl postmaster must be accepted without domain (DRUMS) 207164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 207290792SgshapiroR<?> postmaster $@ OK 207364562Sgshapiro# require qualified recipient? 207464562Sgshapirodnl prepend daemon_flags 207564562SgshapiroR<?> $+ $: $&{daemon_flags} $| <?> $1 207664562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart 207764562Sgshapirodnl do not allow these at all or only from local systems? 207864562Sgshapirodnl r flag? add client_name 207964562SgshapiroR$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 208064562Sgshapirodnl no r flag: relay to local user (only local part) 208164562Sgshapiro# no qualified recipient required 208290792SgshapiroR$* $| <?> $+ $@ RELAY 208364562Sgshapirodnl client_name is empty 208490792SgshapiroR<?> <?> $+ $@ RELAY 208564562Sgshapirodnl client_name is local 208690792SgshapiroR<? $=w> <?> $+ $@ RELAY 208764562Sgshapirodnl client_name is not local 208864562SgshapiroR<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 208964562Sgshapirodnl no qualified recipient required 209090792SgshapiroR<?> $+ $@ RELAY') 209164562Sgshapirodnl it is a remote user: remove mark and then check client 209238032SpeterR<$+> $* $: $2 209364562Sgshapirodnl currently the recipient address is not used below 209438032Speter 209590792Sgshapiro###################################################################### 209690792Sgshapiro### Relay_ok: is the relay/sender ok? 209790792Sgshapirodnl input: ignored 209890792Sgshapirodnl output: see explanation at call 209990792Sgshapiro###################################################################### 210090792SgshapiroSRelay_ok 210138032Speter# anything originating locally is ok 210264562Sgshapiro# check IP address 210364562SgshapiroR$* $: $&{client_addr} 210490792SgshapiroR$@ $@ RELAY originated locally 210590792SgshapiroR0 $@ RELAY originated locally 2106110560SgshapiroR127.0.0.1 $@ RELAY originated locally 2107110560SgshapiroRIPv6:::1 $@ RELAY originated locally 210890792SgshapiroR$=R $* $@ RELAY relayable IP address 210964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 211090792SgshapiroR$* $: $>A <$1> <?> <+ Connect> <$1> 211190792SgshapiroR<RELAY> $* $@ RELAY relayable IP address 2112102528Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl 2113102528Sgshapirodnl this will cause rejections in cases like: 2114102528Sgshapirodnl Connect:My.Host.Domain RELAY 2115102528Sgshapirodnl Connect:My.Net REJECT 2116102528Sgshapirodnl since in check_relay client_name is checked before client_addr 2117102528SgshapiroR<REJECT> $* $@ REJECT rejected IP address') 211890792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 211964562SgshapiroR<$*> <$*> $: $2', `dnl') 212064562SgshapiroR$* $: [ $1 ] put brackets around it... 212190792SgshapiroR$=w $@ RELAY ... and see if it is local 212264562Sgshapiro 212364562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 212464562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 212564562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl 212664562Sgshapirodnl input: {client_addr} or something "broken" 212764562Sgshapirodnl just throw the input away; we do not need it. 212864562Sgshapiro# check whether FROM is allowed to use system as relay 212964562SgshapiroR$* $: <?> $>CanonAddr $&f 213090792SgshapiroR<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 213164562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl 213264562Sgshapiro# check whether local FROM is ok 213390792SgshapiroR<?> $+ < @ $=w > $@ RELAY FROM local', `dnl') 213464562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl 213594334SgshapiroR<?> $+ < @ $+ > $: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <> 213690792SgshapiroR<@> <RELAY> $@ RELAY RELAY FROM sender ok 213790792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 213890792Sgshapiro', `dnl 213990792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', 214090792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 214164562Sgshapiro')', 214264562Sgshapiro`dnl') 214364562Sgshapirodnl')', `dnl') 214490792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind. 214590792Sgshapirodnl it does not matter in this case because the following rule ignores 214690792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace. 214764562Sgshapiro 214864562Sgshapiro# check client name: first: did it resolve? 214964562Sgshapirodnl input: ignored 215064562SgshapiroR$* $: < $&{client_resolve} > 215190792SgshapiroR<TEMP> $#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 215264562SgshapiroR<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 215364562SgshapiroR<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 215464562Sgshapirodnl ${client_resolve} should be OK, so go ahead 215590792SgshapiroR$* $: <@> $&{client_name} 215690792Sgshapirodnl should not be necessary since it has been done for client_addr already 2157110560Sgshapirodnl this rule actually may cause a problem if {client_name} resolves to "" 2158110560Sgshapirodnl however, this should not happen since the forward lookup should fail 2159110560Sgshapirodnl and {client_resolve} should be TEMP or FAIL. 2160110560Sgshapirodnl nevertheless, removing the rule doesn't hurt. 2161110560Sgshapirodnl R<@> $@ RELAY 216290792Sgshapirodnl workspace: <@> ${client_name} (not empty) 216338032Speter# pass to name server to make hostname canonical 216490792SgshapiroR<@> $* $=P $:<?> $1 $2 216590792SgshapiroR<@> $+ $:<?> $[ $1 $] 216690792Sgshapirodnl workspace: <?> ${client_name} (canonified) 216764562SgshapiroR$* . $1 strip trailing dots 216838032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 216990792SgshapiroR<?> $* $=m $@ RELAY', `dnl') 217090792SgshapiroR<?> $=w $@ RELAY 217138032Speterifdef(`_RELAY_HOSTS_ONLY_', 217290792Sgshapiro`R<?> $=R $@ RELAY 217364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 217464562SgshapiroR<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 217564562SgshapiroR<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 217690792Sgshapiro`R<?> $* $=R $@ RELAY 217764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 217890792SgshapiroR<?> $* $: $>D <$1> <?> <+ Connect> <$1>',`dnl')') 217964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 218090792SgshapiroR<RELAY> $* $@ RELAY 218190792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 218238032SpeterR<$*> <$*> $: $2',`dnl') 218390792Sgshapirodnl end of _PROMISCUOUS_RELAY_ 218464562Sgshapirodivert(0) 218564562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 218664562Sgshapiro# turn a canonical address in the form user<@domain> 218764562Sgshapiro# qualify unqual. addresses with $j 218864562Sgshapirodnl it might have been only user (without <@domain>) 218964562SgshapiroSFullAddr 219064562SgshapiroR$* <@ $+ . > $1 <@ $2 > 219164562SgshapiroR$* <@ $* > $@ $1 <@ $2 > 219264562SgshapiroR$+ $@ $1 <@ $j > 219338032Speter 2194110560SgshapiroSDelay_TLS_Client 2195110560Sgshapiro# authenticated? 2196110560Sgshapirodnl code repeated here from Basic_check_mail 2197110560Sgshapirodnl only called from check_rcpt in delay mode if checkrcpt returns $# 2198110560SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 2199110560SgshapiroR$* $| $#$+ $#$2 2200110560Sgshapirodnl return result from checkrcpt 2201110560SgshapiroR$* $# $1 2202110560Sgshapiro 2203110560SgshapiroSDelay_TLS_Client2 2204110560Sgshapiro# authenticated? 2205110560Sgshapirodnl code repeated here from Basic_check_mail 2206110560Sgshapirodnl only called from check_rcpt in delay mode if stopping due to Friend/Hater 2207110560SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 2208110560SgshapiroR$* $| $#$+ $#$2 2209110560Sgshapirodnl return result from friend/hater check 2210110560SgshapiroR$* $@ $1 2211110560Sgshapiro 221264562Sgshapiro# call all necessary rulesets 221364562SgshapiroScheck_rcpt 221464562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset 221564562Sgshapirodnl which is the correct DSN code? 221664562Sgshapiro# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 2217110560Sgshapiro 221864562SgshapiroR$+ $: $1 $| $>checkrcpt $1 221964562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 2220110560Sgshapirodnl on error (or discard) stop now 2221110560SgshapiroR$+ $| $#error $* $#error $2 2222110560SgshapiroR$+ $| $#discard $* $#discard $2 2223110560Sgshapirodnl otherwise call tls_client; see above 2224110560SgshapiroR$+ $| $#$* $@ $>"Delay_TLS_Client" $2 222564562SgshapiroR$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 222664562Sgshapiroifdef(`_SPAM_FH_', 222764562Sgshapiro`dnl lookup user@ and user@address 222864562Sgshapiroifdef(`_ACCESS_TABLE_', `', 222964562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 223064562Sgshapiro')')dnl 223164562Sgshapirodnl one of the next two rules is supposed to match 223264562Sgshapirodnl this code has been copied from BLACKLIST... etc 223364562Sgshapirodnl and simplified by omitting some < >. 223490792SgshapiroR<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@> 223590792SgshapiroR<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > 223664562Sgshapirodnl R<?> $@ something_is_very_wrong_here 223790792Sgshapiro# lookup the addresses only with Spam tag 223890792SgshapiroR<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <> 223964562SgshapiroR<@> $* $| $* $: $2 $1 reverse result 224064562Sgshapirodnl', `dnl') 224164562Sgshapiroifdef(`_SPAM_FRIEND_', 224264562Sgshapiro`# is the recipient a spam friend? 224364562Sgshapiroifdef(`_SPAM_HATER_', 2244110560Sgshapiro `errprint(`*** ERROR: define either Hater or Friend -- not both. 224564562Sgshapiro')', `dnl') 2246110560SgshapiroR<FRIEND> $+ $@ $>"Delay_TLS_Client2" SPAMFRIEND 224764562SgshapiroR<$*> $+ $: $2', 224864562Sgshapiro`dnl') 224964562Sgshapiroifdef(`_SPAM_HATER_', 225064562Sgshapiro`# is the recipient no spam hater? 225190792SgshapiroR<HATER> $+ $: $1 spam hater: continue checks 2252110560SgshapiroR<$*> $+ $@ $>"Delay_TLS_Client2" NOSPAMHATER everyone else: stop 225364562Sgshapirodnl',`dnl') 225464562Sgshapirodnl run further checks: check_mail 225564562Sgshapirodnl should we "clean up" $&f? 225690792Sgshapiroifdef(`_FFR_MAIL_MACRO', 225790792Sgshapiro`R$* $: $1 $| $>checkmail $&{mail_from}', 225890792Sgshapiro`R$* $: $1 $| $>checkmail <$&f>') 225994334Sgshapirodnl recipient (canonical format) $| result of checkmail 226064562SgshapiroR$* $| $#$* $#$2 226164562Sgshapirodnl run further checks: check_relay 226294334SgshapiroR$* $| $* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 226364562SgshapiroR$* $| $#$* $#$2 226438032SpeterR$* $| $* $: $1 226538032Speter', `dnl') 226690792Sgshapiro 226790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 226864562Sgshapiro###################################################################### 226990792Sgshapiro### F: LookUpFull -- search for an entry in access database 227090792Sgshapiro### 227190792Sgshapiro### lookup of full key (which should be an address) and 227290792Sgshapiro### variations if +detail exists: +* and without +detail 227390792Sgshapiro### 227490792Sgshapiro### Parameters: 227590792Sgshapiro### <$1> -- key 227690792Sgshapiro### <$2> -- default (what to return if not found in db) 227790792Sgshapirodnl must not be empty 227890792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 227990792Sgshapiro### ! does lookup only with tag 228090792Sgshapiro### + does lookup with and without tag 228190792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 228290792Sgshapirodnl returns: <default> <passthru> 228390792Sgshapirodnl <result> <passthru> 228490792Sgshapiro###################################################################### 228590792Sgshapiro 228690792SgshapiroSF 228790792Sgshapirodnl workspace: <key> <def> <o tag> <thru> 228890792Sgshapirodnl full lookup 228990792Sgshapirodnl 2 3 4 5 229090792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 229190792Sgshapirodnl no match, try without tag 229290792Sgshapirodnl 1 2 3 4 229390792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 229490792Sgshapirodnl no match, +detail: try +* 229590792Sgshapirodnl 1 2 3 4 5 6 7 229690792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 229790792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 229890792Sgshapirodnl no match, +detail: try +* without tag 229990792Sgshapirodnl 1 2 3 4 5 6 230090792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 230190792Sgshapiro $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 230290792Sgshapirodnl no match, +detail: try without +detail 230390792Sgshapirodnl 1 2 3 4 5 6 7 230490792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 230590792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 230690792Sgshapirodnl no match, +detail: try without +detail and without tag 230790792Sgshapirodnl 1 2 3 4 5 6 230890792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 230990792Sgshapiro $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 231090792Sgshapirodnl no match, return <default> <passthru> 231190792Sgshapirodnl 1 2 3 4 5 231290792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 231390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 231490792Sgshapirodnl 2 3 4 5 231590792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 231690792Sgshapirodnl match, return <match> <passthru> 231790792Sgshapirodnl 2 3 4 5 231890792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 231990792Sgshapiro 232090792Sgshapiro###################################################################### 232190792Sgshapiro### E: LookUpExact -- search for an entry in access database 232290792Sgshapiro### 232390792Sgshapiro### Parameters: 232490792Sgshapiro### <$1> -- key 232590792Sgshapiro### <$2> -- default (what to return if not found in db) 232690792Sgshapirodnl must not be empty 232790792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 232890792Sgshapiro### ! does lookup only with tag 232990792Sgshapiro### + does lookup with and without tag 233090792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 233190792Sgshapirodnl returns: <default> <passthru> 233290792Sgshapirodnl <result> <passthru> 233390792Sgshapiro###################################################################### 233490792Sgshapiro 233590792SgshapiroSE 233690792Sgshapirodnl 2 3 4 5 233790792SgshapiroR<$*> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 233890792Sgshapirodnl no match, try without tag 233990792Sgshapirodnl 1 2 3 4 234090792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 234190792Sgshapirodnl no match, return default passthru 234290792Sgshapirodnl 1 2 3 4 5 234390792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 234490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 234590792Sgshapirodnl 2 3 4 5 234690792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 234790792Sgshapirodnl match, return <match> <passthru> 234890792Sgshapirodnl 2 3 4 5 234990792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 235090792Sgshapiro 235190792Sgshapiro###################################################################### 235290792Sgshapiro### U: LookUpUser -- search for an entry in access database 235390792Sgshapiro### 235490792Sgshapiro### lookup of key (which should be a local part) and 235590792Sgshapiro### variations if +detail exists: +* and without +detail 235690792Sgshapiro### 235790792Sgshapiro### Parameters: 235890792Sgshapiro### <$1> -- key (user@) 235990792Sgshapiro### <$2> -- default (what to return if not found in db) 236090792Sgshapirodnl must not be empty 236190792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 236290792Sgshapiro### ! does lookup only with tag 236390792Sgshapiro### + does lookup with and without tag 236490792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 236590792Sgshapirodnl returns: <default> <passthru> 236690792Sgshapirodnl <result> <passthru> 236790792Sgshapiro###################################################################### 236890792Sgshapiro 236990792SgshapiroSU 237090792Sgshapirodnl user lookups are always with trailing @ 237190792Sgshapirodnl 2 3 4 5 237290792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 237390792Sgshapirodnl no match, try without tag 237490792Sgshapirodnl 1 2 3 4 237590792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 237690792Sgshapirodnl do not remove the @ from the lookup: 237790792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup 237890792Sgshapirodnl no match, +detail: try +* 237990792Sgshapirodnl 1 2 3 4 5 6 238090792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 238190792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 238290792Sgshapirodnl no match, +detail: try +* without tag 238390792Sgshapirodnl 1 2 3 4 5 238490792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 238590792Sgshapiro $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 238690792Sgshapirodnl no match, +detail: try without +detail 238790792Sgshapirodnl 1 2 3 4 5 6 238890792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 238990792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 239090792Sgshapirodnl no match, +detail: try without +detail and without tag 239190792Sgshapirodnl 1 2 3 4 5 239290792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 239390792Sgshapiro $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 239490792Sgshapirodnl no match, return <default> <passthru> 239590792Sgshapirodnl 1 2 3 4 5 239690792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 239790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 239890792Sgshapirodnl 2 3 4 5 239990792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 240090792Sgshapirodnl match, return <match> <passthru> 240190792Sgshapirodnl 2 3 4 5 240290792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 240390792Sgshapiro 240490792Sgshapiro###################################################################### 240564562Sgshapiro### SearchList: search a list of items in the access map 240664562Sgshapiro### Parameters: 240764562Sgshapiro### <exact tag> $| <mark:address> <mark:address> ... <> 240864562Sgshapirodnl maybe we should have a @ (again) in front of the mark to 240964562Sgshapirodnl avoid errorneous matches (with error messages?) 241064562Sgshapirodnl if we can make sure that tag is always a single token 241164562Sgshapirodnl then we can omit the delimiter $|, otherwise we need it 241290792Sgshapirodnl to avoid errorneous matchs (first rule: D: if there 241364562Sgshapirodnl is that mark somewhere in the list, it will be taken). 241464562Sgshapirodnl moreover, we can do some tricks to enforce lookup with 241564562Sgshapirodnl the tag only, e.g.: 241664562Sgshapiro### where "exact" is either "+" or "!": 241764562Sgshapiro### <+ TAG> lookup with and w/o tag 241864562Sgshapiro### <! TAG> lookup with tag 241964562Sgshapirodnl Warning: + and ! should be in OperatorChars (otherwise there must be 242064562Sgshapirodnl a blank between them and the tag. 242164562Sgshapiro### possible values for "mark" are: 242290792Sgshapiro### D: recursive host lookup (LookUpDomain) 242364562Sgshapirodnl A: recursive address lookup (LookUpAddress) [not yet required] 242464562Sgshapiro### E: exact lookup, no modifications 242564562Sgshapiro### F: full lookup, try user+ext@domain and user@domain 242664562Sgshapiro### U: user lookup, try user+ext and user (input must have trailing @) 242764562Sgshapiro### return: <RHS of lookup> or <?> (not found) 242864562Sgshapiro###################################################################### 242938032Speter 243064562Sgshapiro# class with valid marks for SearchList 243164562Sgshapirodnl if A is activated: add it 243290792SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A') 243364562SgshapiroSSearchList 243490792Sgshapiro# just call the ruleset with the name of the tag... nice trick... 243590792Sgshapirodnl 2 3 4 243690792SgshapiroR<$+> $| <$={src}:$*> <$*> $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <> 243790792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <> 243890792Sgshapirodnl no match and nothing left: return 243990792SgshapiroR<$+> $| <> $| <?> <> $@ <?> 244090792Sgshapirodnl no match but something left: continue 244190792SgshapiroR<$+> $| <$+> $| <?> <> $@ $>SearchList <$1> $| <$2> 244290792Sgshapirodnl match: return 244390792SgshapiroR<$+> $| <$*> $| <$+> <> $@ <$3> 244464562Sgshapirodnl return result from recursive invocation 244590792SgshapiroR<$+> $| <$+> $@ <$2> 244690792Sgshapirodnl endif _ACCESS_TABLE_ 244790792Sgshapirodivert(0) 244838032Speter 244990792Sgshapiro###################################################################### 245090792Sgshapiro### trust_auth: is user trusted to authenticate as someone else? 245190792Sgshapiro### 245290792Sgshapiro### Parameters: 245390792Sgshapiro### $1: AUTH= parameter from MAIL command 245490792Sgshapiro###################################################################### 245590792Sgshapiro 245690792Sgshapirodnl empty ruleset definition so it can be called 245790792SgshapiroSLocal_trust_auth 245864562SgshapiroStrust_auth 245964562SgshapiroR$* $: $&{auth_type} $| $1 246064562Sgshapiro# required by RFC 2554 section 4. 246164562SgshapiroR$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 246264562Sgshapirodnl seems to be useful... 246364562SgshapiroR$* $| $&{auth_authen} $@ identical 246464562SgshapiroR$* $| <$&{auth_authen}> $@ identical 246564562Sgshapirodnl call user supplied code 246664562SgshapiroR$* $| $* $: $1 $| $>"Local_trust_auth" $1 246764562SgshapiroR$* $| $#$* $#$2 246864562Sgshapirodnl default: error 246964562SgshapiroR$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 247064562Sgshapiro 247190792Sgshapiro###################################################################### 247290792Sgshapiro### Relay_Auth: allow relaying based on authentication? 247390792Sgshapiro### 247490792Sgshapiro### Parameters: 247590792Sgshapiro### $1: ${auth_type} 247690792Sgshapiro###################################################################### 247790792SgshapiroSLocal_Relay_Auth 247864562Sgshapiro 247990792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 248090792Sgshapiro###################################################################### 248190792Sgshapiro### srv_features: which features to offer to a client? 248290792Sgshapiro### (done in server) 248390792Sgshapiro###################################################################### 248490792SgshapiroSsrv_features 248590792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl 248690792SgshapiroR$* $: $1 $| $>"Local_srv_features" $1 248790792SgshapiroR$* $| $#$* $#$2 248890792SgshapiroR$* $| $* $: $1', `dnl') 248990792SgshapiroR$* $: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <> 249090792SgshapiroR<?>$* $: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <> 249190792SgshapiroR<?>$* $: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)> 249264562SgshapiroR<?>$* $@ OK 249390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 249490792SgshapiroR<$* _ATMPF_>$* $#temp', `dnl') 249590792SgshapiroR<$+>$* $# $1 249664562Sgshapiro 249790792Sgshapiro###################################################################### 249890792Sgshapiro### try_tls: try to use STARTTLS? 249990792Sgshapiro### (done in client) 250090792Sgshapiro###################################################################### 250164562SgshapiroStry_tls 250290792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl 250390792SgshapiroR$* $: $1 $| $>"Local_try_tls" $1 250490792SgshapiroR$* $| $#$* $#$2 250590792SgshapiroR$* $| $* $: $1', `dnl') 250690792SgshapiroR$* $: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <> 250790792SgshapiroR<?>$* $: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <> 250890792SgshapiroR<?>$* $: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)> 250964562SgshapiroR<?>$* $@ OK 251090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 251190792SgshapiroR<$* _ATMPF_>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 251271345SgshapiroR<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 2513102528Sgshapiro 251490792Sgshapiro###################################################################### 251590792Sgshapiro### tls_rcpt: is connection with server "good" enough? 251690792Sgshapiro### (done in client, per recipient) 251790792Sgshapirodnl called from deliver() before RCPT command 251890792Sgshapiro### 251990792Sgshapiro### Parameters: 252090792Sgshapiro### $1: recipient 252190792Sgshapiro###################################################################### 252290792SgshapiroStls_rcpt 252390792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl 252490792SgshapiroR$* $: $1 $| $>"Local_tls_rcpt" $1 252590792SgshapiroR$* $| $#$* $#$2 252690792SgshapiroR$* $| $* $: $1', `dnl') 252790792Sgshapirodnl store name of other side 252890792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 252990792Sgshapirodnl canonify recipient address 253090792SgshapiroR$+ $: <?> $>CanonAddr $1 253190792Sgshapirodnl strip trailing dots 253290792SgshapiroR<?> $+ < @ $+ . > <?> $1 <@ $2 > 253390792Sgshapirodnl full address? 253490792SgshapiroR<?> $+ < @ $+ > $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:> 253590792Sgshapirodnl only localpart? 253690792SgshapiroR<?> $+ $: $1 $| <U:$1@> <E:> 253790792Sgshapirodnl look it up 253890792Sgshapirodnl also look up a default value via E: 253990792SgshapiroR$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <> 254090792Sgshapirodnl found nothing: stop here 254190792SgshapiroR$* $| <?> $@ OK 254290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 254390792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 254490792Sgshapirodnl use the generic routine (for now) 254590792SgshapiroR$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>') 254664562Sgshapiro 254790792Sgshapiro###################################################################### 254890792Sgshapiro### tls_client: is connection with client "good" enough? 254990792Sgshapiro### (done in server) 255090792Sgshapiro### 255190792Sgshapiro### Parameters: 255290792Sgshapiro### ${verify} $| (MAIL|STARTTLS) 255390792Sgshapiro###################################################################### 255464562Sgshapirodnl MAIL: called from check_mail 255564562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted 255664562SgshapiroStls_client 255790792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl 255890792SgshapiroR$* $: $1 $| $>"Local_tls_client" $1 255990792SgshapiroR$* $| $#$* $#$2 256090792SgshapiroR$* $| $* $: $1', `dnl') 256164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 256290792Sgshapirodnl store name of other side 256390792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 256464562Sgshapirodnl ignore second arg for now 256564562Sgshapirodnl maybe use it to distinguish permanent/temporary error? 256664562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered) 256764562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed) 256890792SgshapiroR$* $| $* $: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <> 256990792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <> 257064562Sgshapirodnl do a default lookup: just TLS_CLT_TAG 257164562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 257290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 257390792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 257490792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 257590792SgshapiroR$* $| $* $@ $>"TLS_connection" $1') 257664562Sgshapiro 257790792Sgshapiro###################################################################### 257890792Sgshapiro### tls_server: is connection with server "good" enough? 257990792Sgshapiro### (done in client) 258090792Sgshapiro### 258190792Sgshapiro### Parameter: 258290792Sgshapiro### ${verify} 258390792Sgshapiro###################################################################### 258464562Sgshapirodnl i.e. has the server been authenticated and is encryption active? 258564562Sgshapirodnl called from deliver() after STARTTLS command 258664562SgshapiroStls_server 258790792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl 258890792SgshapiroR$* $: $1 $| $>"Local_tls_server" $1 258990792SgshapiroR$* $| $#$* $#$2 259090792SgshapiroR$* $| $* $: $1', `dnl') 259164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 259290792Sgshapirodnl store name of other side 259390792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 259490792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <> 259590792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <> 259664562Sgshapirodnl do a default lookup: just TLS_SRV_TAG 259764562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 259890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 259990792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 260090792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 260190792SgshapiroR$* $@ $>"TLS_connection" $1') 260264562Sgshapiro 260390792Sgshapiro###################################################################### 260490792Sgshapiro### TLS_connection: is TLS connection "good" enough? 260590792Sgshapiro### 260690792Sgshapiro### Parameters: 260764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 260890792Sgshapiro### ${verify} $| <Requirement> [<>]', `dnl 260990792Sgshapiro### ${verify}') 261090792Sgshapiro### Requirement: RHS from access map, may be ? for none. 261190792Sgshapirodnl syntax for Requirement: 261290792Sgshapirodnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions] 261390792Sgshapirodnl extensions: could be a list of further requirements 261490792Sgshapirodnl for now: CN:string {cn_subject} == string 261590792Sgshapiro###################################################################### 261690792SgshapiroSTLS_connection 261790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error 261890792Sgshapirodnl deal with TLS handshake failures: abort 261990792SgshapiroRSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake." 262090792Sgshapirodivert(-1)') 262164562Sgshapirodnl common ruleset for tls_{client|server} 262290792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>] 262364562Sgshapirodnl remove optional <> 262464562SgshapiroR$* $| <$*>$* $: $1 $| <$2> 262590792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup> 262690792Sgshapiro# create the appropriate error codes 262764562Sgshapirodnl permanent or temporary error? 262864562SgshapiroR$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 262964562SgshapiroR$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 263064562Sgshapirodnl default case depends on TLS_PERM_ERR 263164562SgshapiroR$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 263290792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup> 263390792Sgshapiro# deal with TLS handshake failures: abort 263464562SgshapiroRSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 263564562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 263664562Sgshapirodnl use default error 263764562SgshapiroRSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 263890792SgshapiroR$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1 263990792Sgshapirodnl separate optional requirements 264090792SgshapiroR$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1 264190792SgshapiroR$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> <> $1 264290792Sgshapirodnl separate optional requirements 264390792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$* $: <$2> <$3:$4> <$5> $1 264464562Sgshapirodnl some other value in access map: accept 264564562Sgshapirodnl this also allows to override the default case (if used) 264664562SgshapiroR$* $| $* $@ OK 264764562Sgshapiro# authentication required: give appropriate error 264864562Sgshapiro# other side did authenticate (via STARTTLS) 264990792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify} 265064562Sgshapirodnl only verification required and it succeeded 265190792SgshapiroR<$*><VERIFY> <> OK $@ OK 265290792Sgshapirodnl verification required and it succeeded but extensions are given 265390792Sgshapirodnl change it to <SMTP:ESC> <REQ:0> <extensions> 265490792SgshapiroR<$*><VERIFY> <$+> OK $: <$1> <REQ:0> <$2> 265564562Sgshapirodnl verification required + some level of encryption 265690792SgshapiroR<$*><VERIFY:$-> <$*> OK $: <$1> <REQ:$2> <$3> 265764562Sgshapirodnl just some level of encryption required 265890792SgshapiroR<$*><ENCR:$-> <$*> $* $: <$1> <REQ:$2> <$3> 265990792Sgshapirodnl workspace: 266090792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]> <[extensions]> {verify} (!= OK) 266190792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits> <[extensions]> 266290792Sgshapirodnl verification required but ${verify} is not set (case 1.) 266390792SgshapiroR<$-:$+><VERIFY $*> <$*> $#error $@ $2 $: $1 " authentication required" 266490792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL $#error $@ $2 $: $1 " authentication failed" 266590792SgshapiroR<$-:$+><VERIFY $*> <$*> NO $#error $@ $2 $: $1 " not authenticated" 266690792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT $#error $@ $2 $: $1 " no authentication requested" 266790792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 266864562Sgshapirodnl some other value for ${verify} 266990792SgshapiroR<$-:$+><VERIFY $*> <$*> $+ $#error $@ $2 $: $1 " authentication failure " $4 267090792Sgshapirodnl some level of encryption required: get the maximum level (case 2.) 267190792SgshapiroR<$*><REQ:$-> <$*> $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf} 267264562Sgshapirodnl compare required bits with actual bits 267390792SgshapiroR<$*><REQ:$-> <$*> $- $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $) 267490792SgshapiroR<$-:$+><$-:$-> <$*> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 267590792Sgshapirodnl strength requirements fulfilled 267690792Sgshapirodnl TLS Additional Requirements Separator 267790792Sgshapirodnl this should be something which does not appear in the extensions itself 267890792Sgshapirodnl @ could be part of a CN, DN, etc... 267990792Sgshapirodnl use < > ? those are encoded in CN, DN, ... 268090792Sgshapirodefine(`_TLS_ARS_', `++')dnl 268190792Sgshapirodnl workspace: 268290792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare 268390792SgshapiroR<$-:$+><$-:$-> <$*> $* $: <$1:$2 _TLS_ARS_ $5> 268490792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions> 268590792Sgshapirodnl continue: check extensions 268690792SgshapiroR<$-:$+ _TLS_ARS_ > $@ OK 268790792Sgshapirodnl split extensions into own list 268890792SgshapiroR<$-:$+ _TLS_ARS_ $+ > $: <$1:$2> <$3> 268990792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ > <$1:$2> <$3> <$4> 269090792SgshapiroR<$-:$+> $+ $@ $>"TLS_req" $3 $| <$1:$2> 269164562Sgshapiro 269290792Sgshapiro###################################################################### 269390792Sgshapiro### TLS_req: check additional TLS requirements 269490792Sgshapiro### 269590792Sgshapiro### Parameters: [<list> <of> <req>] $| <$-:$+> 269690792Sgshapiro### $-: SMTP reply code 269790792Sgshapiro### $+: Enhanced Status Code 269890792Sgshapirodnl further requirements for this ruleset: 269990792Sgshapirodnl name of "other side" is stored is {TLS_name} (client/server_name) 270090792Sgshapirodnl 270190792Sgshapirodnl currently only CN[:common_name] is implemented 270290792Sgshapirodnl right now this is only a logical AND 270390792Sgshapirodnl i.e. all requirements must be true 270490792Sgshapirodnl how about an OR? CN must be X or CN must be Y or .. 270590792Sgshapirodnl use a macro to compute this as a trivial sequential 270690792Sgshapirodnl operations (no precedences etc)? 270790792Sgshapiro###################################################################### 270890792SgshapiroSTLS_req 270990792Sgshapirodnl no additional requirements: ok 271090792SgshapiroR $| $+ $@ OK 271190792Sgshapirodnl require CN: but no CN specified: use name of other side 271290792SgshapiroR<CN> $* $| <$+> $: <CN:$&{TLS_Name}> $1 $| <$2> 271390792Sgshapirodnl match, check rest 271490792SgshapiroR<CN:$&{cn_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 271590792Sgshapirodnl CN does not match 271690792Sgshapirodnl 1 2 3 4 271790792SgshapiroR<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1 271890792Sgshapirodnl cert subject 271990792SgshapiroR<CS:$&{cert_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 272090792Sgshapirodnl CS does not match 272190792Sgshapirodnl 1 2 3 4 2722110560SgshapiroR<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1 272390792Sgshapirodnl match, check rest 272490792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 272590792Sgshapirodnl CI does not match 272690792Sgshapirodnl 1 2 3 4 2727110560SgshapiroR<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1 272890792Sgshapirodnl return from recursive call 272990792SgshapiroROK $@ OK 273090792Sgshapiro 273190792Sgshapiro###################################################################### 273290792Sgshapiro### max: return the maximum of two values separated by : 273390792Sgshapiro### 273490792Sgshapiro### Parameters: [$-]:[$-] 273590792Sgshapiro###################################################################### 273664562SgshapiroSmax 273764562SgshapiroR: $: 0 273864562SgshapiroR:$- $: $1 273964562SgshapiroR$-: $: $1 274064562SgshapiroR$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 274164562SgshapiroRTRUE:$-:$- $: $2 274290792SgshapiroR$-:$-:$- $: $2 274390792Sgshapirodnl endif _ACCESS_TABLE_ 274490792Sgshapirodivert(0) 274564562Sgshapiro 274690792Sgshapiro###################################################################### 274790792Sgshapiro### RelayTLS: allow relaying based on TLS authentication 274890792Sgshapiro### 274990792Sgshapiro### Parameters: 275090792Sgshapiro### none 275190792Sgshapiro###################################################################### 275290792SgshapiroSRelayTLS 275364562Sgshapiro# authenticated? 275464562Sgshapirodnl we do not allow relaying for anyone who can present a cert 275564562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns 2756110560Sgshapirodnl CA in CertPath so we can authenticate users, we do not allow 275764562Sgshapirodnl them to abuse our server (they might be easier to get hold of, 275864562Sgshapirodnl but anyway). 275964562Sgshapirodnl so here is the trick: if the verification succeeded 276064562Sgshapirodnl we look up the cert issuer in the access map 276164562Sgshapirodnl (maybe after extracting a part with a regular expression) 276264562Sgshapirodnl if this returns RELAY we relay without further questions 276364562Sgshapirodnl if it returns SUBJECT we perform a similar check on the 276464562Sgshapirodnl cert subject. 276564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 276690792SgshapiroR$* $: <?> $&{verify} 276790792SgshapiroR<?> OK $: OK authenticated: continue 276890792SgshapiroR<?> $* $@ NO not authenticated 276964562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 277090792SgshapiroR$* $: $(CERTIssuer $&{cert_issuer} $)', 277190792Sgshapiro`R$* $: $&{cert_issuer}') 277290792SgshapiroR$+ $: $(access CERTISSUER`'_TAG_DELIM_`'$1 $) 277364562Sgshapirodnl use $# to stop further checks (delay_check) 277490792SgshapiroRRELAY $# RELAY 277564562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 277690792SgshapiroRSUBJECT $: <@> $(CERTSubject $&{cert_subject} $)', 277790792Sgshapiro`RSUBJECT $: <@> $&{cert_subject}') 277890792SgshapiroR<@> $+ $: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $) 277990792SgshapiroR<@> RELAY $# RELAY 278090792SgshapiroR$* $: NO', `dnl') 278164562Sgshapiro 278290792Sgshapiro###################################################################### 278390792Sgshapiro### authinfo: lookup authinfo in the access map 278490792Sgshapiro### 278590792Sgshapiro### Parameters: 278690792Sgshapiro### $1: {server_name} 278790792Sgshapiro### $2: {server_addr} 278890792Sgshapirodnl both are currently ignored 278990792Sgshapirodnl if it should be done via another map, we either need to restrict 279090792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another 279190792Sgshapirodnl parameter which I want to avoid, it's quite complex already) 279290792Sgshapiro###################################################################### 279390792Sgshapirodnl omit this ruleset if neither is defined? 279490792Sgshapirodnl it causes DefaultAuthInfo to be ignored 279590792Sgshapirodnl (which may be considered a good thing). 279690792SgshapiroSauthinfo 279790792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl 279890792SgshapiroR$* $: <$(authinfo AuthInfo:$&{server_name} $: ? $)> 279990792SgshapiroR<?> $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)> 280090792SgshapiroR<?> $: <$(authinfo AuthInfo: $: ? $)> 280190792SgshapiroR<?> $@ no no authinfo available 280290792SgshapiroR<$*> $# $1 280390792Sgshapirodnl', `dnl 280490792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 280590792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <> 280690792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <> 280790792SgshapiroR$* $| <?>$* $: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <> 280890792SgshapiroR$* $| <?>$* $@ no no authinfo available 280990792SgshapiroR$* $| <$*> <> $# $2 281090792Sgshapirodnl', `dnl')') 281190792Sgshapiro 281264562Sgshapiroundivert(9)dnl LOCAL_RULESETS 281338032Speter# 281438032Speter###################################################################### 281538032Speter###################################################################### 281638032Speter##### 281764562Sgshapiro`##### MAIL FILTER DEFINITIONS' 281864562Sgshapiro##### 281964562Sgshapiro###################################################################### 282064562Sgshapiro###################################################################### 282190792Sgshapiro_MAIL_FILTERS_ 282264562Sgshapiro# 282364562Sgshapiro###################################################################### 282464562Sgshapiro###################################################################### 282564562Sgshapiro##### 282638032Speter`##### MAILER DEFINITIONS' 282738032Speter##### 282838032Speter###################################################################### 282938032Speter###################################################################### 283064562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS 283166494Sgshapiro 2832