proto.m4 revision 120256
138032Speterdivert(-1) 238032Speter# 3120256Sgshapiro# Copyright (c) 1998-2003 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 16120256SgshapiroVERSIONID(`$Id: proto.m4,v 8.649.2.24 2003/08/04 21:14:26 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') 427112810Sgshapiroifdef(`confTO_QUEUERETURN_DSN', `dnl 428112810SgshapiroO Timeout.queuereturn.dsn=confTO_QUEUERETURN_DSN') 42964562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h') 43064562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h') 43164562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h') 43264562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h') 433112810Sgshapiroifdef(`confTO_QUEUEWARN_DSN', `dnl 434112810SgshapiroO Timeout.queuewarn.dsn=confTO_QUEUEWARN_DSN') 43564562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m') 43664562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s') 43764562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s') 43864562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s') 43964562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4') 44064562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4') 44164562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4') 44290792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m') 44390792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m') 44490792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h') 44538032Speter 44690792Sgshapiro# time for DeliverBy; extension disabled if less than 0 44790792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0') 44890792Sgshapiro 44938032Speter# should we not prune routes in route-addr syntax addresses? 45064562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False') 45138032Speter 45238032Speter# queue up everything before forking? 45364562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True') 45438032Speter 45538032Speter# status file 45664562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics') 45738032Speter 45838032Speter# time zone handling: 45938032Speter# if undefined, use system default 46038032Speter# if defined but null, use TZ envariable passed in 46138032Speter# if defined and non-null, use that info 46238032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=', 46338032Speter confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=', 46438032Speter `O TimeZoneSpec=confTIME_ZONE') 46538032Speter 46638032Speter# default UID (can be username or userid:groupid) 46764562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull') 46838032Speter 46938032Speter# list of locations of user database file (null means no lookup) 47064562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb') 47138032Speter 47238032Speter# fallback MX host 47364562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net') 47438032Speter 47538032Speter# if we are the best MX host for a site, try it directly instead of config err 47664562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False') 47738032Speter 47838032Speter# load average at which we just queue messages 47964562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8') 48038032Speter 48138032Speter# load average at which we refuse connections 48264562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12') 48338032Speter 48490792Sgshapiro# load average at which we delay connections; 0 means no limit 48590792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0') 48690792Sgshapiro 48738032Speter# maximum number of children we allow at one time 48898841Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0') 48938032Speter 49038032Speter# maximum number of new connections per second 49171345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0') 49238032Speter 49338032Speter# work recipient factor 49464562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') 49538032Speter 49638032Speter# deliver each queued job in a separate process? 49764562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False') 49838032Speter 49938032Speter# work class factor 50064562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800') 50138032Speter 50238032Speter# work time factor 50364562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000') 50438032Speter 50538032Speter# default character set 50664562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1') 50738032Speter 50890792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others) 50964562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch') 51038032Speter 51138032Speter# hosts file (normally /etc/hosts) 51264562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts') 51338032Speter 51438032Speter# dialup line delay on connection failure 51564562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s') 51638032Speter 51738032Speter# action to take if there are no recipients in the message 51864562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed') 51938032Speter 52038032Speter# chrooted environment for writing to files 52164562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch') 52238032Speter 52338032Speter# are colons OK in addresses? 52464562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True') 52538032Speter 52638032Speter# shall I avoid expanding CNAMEs (violates protocols)? 52764562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False') 52838032Speter 52938032Speter# SMTP initial login message (old $e macro) 53064562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b') 53138032Speter 53238032Speter# UNIX initial From header format (old $l macro) 53364562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d') 53438032Speter 53538032Speter# From: lines that have embedded newlines are unwrapped onto one line 53664562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False') 53738032Speter 53838032Speter# Allow HELO SMTP command that does not `include' a host name 53964562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False') 54038032Speter 54138032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic) 54264562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.') 54338032Speter 54438032Speter# delimiter (operator) characters (old $o macro) 54564562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]') 54638032Speter 54738032Speter# shall I avoid calling initgroups(3) because of high NIS costs? 54864562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False') 54938032Speter 55038032Speter# are group-writable `:include:' and .forward files (un)trustworthy? 55190792Sgshapiro# True (the default) means they are not trustworthy. 55264562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True') 55390792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES', 55490792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL. 55590792Sgshapiro')') 55638032Speter 55738032Speter# where do errors that occur when sending errors get sent? 55864562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster') 55938032Speter 56064562Sgshapiro# where to save bounces if all else fails 56164562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter') 56264562Sgshapiro 56338032Speter# what user id do we assume for the majority of the processing? 56464562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail') 56538032Speter 56638032Speter# maximum number of recipients per SMTP envelope 56764562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100') 56838032Speter 56990792Sgshapiro# limit the rate recipients per SMTP envelope are accepted 57090792Sgshapiro# once the threshold number of recipients have been rejected 57190792Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20') 57290792Sgshapiro 57338032Speter# shall we get local names from our installed interfaces? 57464562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 57538032Speter 57664562Sgshapiro# Return-Receipt-To: header implies DSN request 57764562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 57864562Sgshapiro 57964562Sgshapiro# override connection address (for testing) 58064562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 58164562Sgshapiro 58264562Sgshapiro# Trusted user for file ownership and starting the daemon 58364562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root') 58464562Sgshapiro 58564562Sgshapiro# Control socket for daemon management 58664562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 58764562Sgshapiro 58864562Sgshapiro# Maximum MIME header length to protect MUAs 589112810Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `2048/1024') 59064562Sgshapiro 59164562Sgshapiro# Maximum length of the sum of all headers 59264562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768') 59364562Sgshapiro 59464562Sgshapiro# Maximum depth of alias recursion 59564562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10') 59664562Sgshapiro 59764562Sgshapiro# location of pid file 59864562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid') 59964562Sgshapiro 60064562Sgshapiro# Prefix string for the process title shown on 'ps' listings 60164562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix') 60264562Sgshapiro 60364562Sgshapiro# Data file (df) memory-buffer file maximum size 60464562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096') 60564562Sgshapiro 60664562Sgshapiro# Transcript file (xf) memory-buffer file maximum size 60764562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096') 60864562Sgshapiro 60990792Sgshapiro# lookup type to find information about local mailboxes 61090792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw') 61190792Sgshapiro 61264562Sgshapiro# list of authentication mechanisms 61390792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5') 61464562Sgshapiro 61564562Sgshapiro# default authentication information for outgoing connections 61664562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info') 61764562Sgshapiro 61864562Sgshapiro# SMTP AUTH flags 61964562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `') 62064562Sgshapiro 62190792Sgshapiro# SMTP AUTH maximum encryption strength 62290792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `') 62390792Sgshapiro 62490792Sgshapiro# SMTP STARTTLS server options 62590792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `') 62690792Sgshapiro 62764562Sgshapiro# Input mail filters 62864562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 62964562Sgshapiro 63098841Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl 63164562Sgshapiro# Milter options 63290792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `') 63364562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 63464562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') 63564562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') 63664562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')') 63764562Sgshapiro 63864562Sgshapiro# CA directory 639110560Sgshapiro_OPTION(CACertPath, `confCACERT_PATH', `') 64064562Sgshapiro# CA file 641110560Sgshapiro_OPTION(CACertFile, `confCACERT', `') 64264562Sgshapiro# Server Cert 64364562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `') 64464562Sgshapiro# Server private key 64564562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `') 64664562Sgshapiro# Client Cert 64764562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `') 64864562Sgshapiro# Client private key 64964562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 65064562Sgshapiro# DHParameters (only required if DSA/DH is used) 65164562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `') 65264562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL) 65364562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `') 65464562Sgshapiro 65590792Sgshapiro############################ 65690792Sgshapiro`# QUEUE GROUP DEFINITIONS #' 65790792Sgshapiro############################ 65890792Sgshapiro_QUEUE_GROUP_ 65942575Speter 66038032Speter########################### 66138032Speter# Message precedences # 66238032Speter########################### 66338032Speter 66438032SpeterPfirst-class=0 66538032SpeterPspecial-delivery=100 66638032SpeterPlist=-30 66738032SpeterPbulk=-60 66838032SpeterPjunk=-100 66938032Speter 67038032Speter##################### 67138032Speter# Trusted users # 67238032Speter##################### 67338032Speter 67438032Speter# this is equivalent to setting class "t" 67564562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 67638032SpeterTroot 67738032SpeterTdaemon 67838032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp') 67938032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 68038032Speter 68138032Speter######################### 68238032Speter# Format of headers # 68338032Speter######################### 68438032Speter 68538032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl 68638032SpeterH?P?Return-Path: <$g> 68738032SpeterHReceived: confRECEIVED_HEADER 68838032SpeterH?D?Resent-Date: $a 68938032SpeterH?D?Date: $a 69038032SpeterH?F?Resent-From: confFROM_HEADER 69138032SpeterH?F?From: confFROM_HEADER 69238032SpeterH?x?Full-Name: $x 69338032Speter# HPosted-Date: $a 69438032Speter# H?l?Received-Date: $b 69538032SpeterH?M?Resent-Message-Id: <$t.$i@$j> 69638032SpeterH?M?Message-Id: <$t.$i@$j> 69764562Sgshapiro 69838032Speter# 69938032Speter###################################################################### 70038032Speter###################################################################### 70138032Speter##### 70238032Speter##### REWRITING RULES 70338032Speter##### 70438032Speter###################################################################### 70538032Speter###################################################################### 70638032Speter 70738032Speter############################################ 70838032Speter### Ruleset 3 -- Name Canonicalization ### 70938032Speter############################################ 71064562SgshapiroScanonify=3 71138032Speter 71238032Speter# handle null input (translate to <@> special case) 71338032SpeterR$@ $@ <@> 71438032Speter 71538032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon 71638032SpeterR$* $: $1 <@> mark addresses 71738032SpeterR$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> 71838032SpeterR@ $* <@> $: @ $1 unmark @host:... 71990792SgshapiroR$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr 72038032SpeterR$* :: $* <@> $: $1 :: $2 unmark node::addr 72138032SpeterR:`include': $* <@> $: :`include': $1 unmark :`include':... 72238032SpeterR$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon 72338032SpeterR$* : $* <@> $: $2 strip colon if marked 72438032SpeterR$* <@> $: $1 unmark 72538032SpeterR$* ; $1 strip trailing semi 72671345SgshapiroR$* < $+ :; > $* $@ $2 :; <@> catch <list:;> 72738032SpeterR$* < $* ; > $1 < $2 > bogus bracketed semi 72838032Speter 72938032Speter# null input now results from list:; syntax 73038032SpeterR$@ $@ :; <@> 73138032Speter 73238032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item 73338032SpeterR$* $: < $1 > housekeeping <> 73438032SpeterR$+ < $* > < $2 > strip excess on left 73538032SpeterR< $* > $+ < $1 > strip excess on right 73638032SpeterR<> $@ < @ > MAIL FROM:<> case 73738032SpeterR< $+ > $: $1 remove housekeeping <> 73838032Speter 73964562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 74038032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 74138032SpeterR@ $+ , $+ @ $1 : $2 change all "," to ":" 74238032Speter 74338032Speter# localize and dispose of route-based addresses 74490792Sgshapirodnl XXX: IPv6 colon conflict 74590792Sgshapiroifdef(`NO_NETINET6', `dnl', 74690792Sgshapiro`R@ [$+] : $+ $@ $>Canonify2 < @ [$1] > : $2 handle <route-addr>') 74764562SgshapiroR@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 74864562Sgshapirodnl',`dnl 74964562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d> 75064562SgshapiroR@ $+ , $+ $2 75190792Sgshapiroifdef(`NO_NETINET6', `dnl', 75290792Sgshapiro`R@ [ $* ] : $+ $2') 75364562SgshapiroR@ $+ : $+ $2 75464562Sgshapirodnl') 75538032Speter 75638032Speter# find focus for list syntax 75764562SgshapiroR $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 75838032SpeterR $+ : $* ; $@ $1 : $2; list syntax 75938032Speter 76038032Speter# find focus for @ syntax addresses 76138032SpeterR$+ @ $+ $: $1 < @ $2 > focus on domain 76238032SpeterR$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 76364562SgshapiroR$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 76438032Speter 76590792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here. 76690792Sgshapirodnl # do some sanity checking 76790792Sgshapirodnl R$* < @ $~[ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 76838032Speter 76938032Speterifdef(`_NO_UUCP_', `dnl', 77038032Speter`# convert old-style addresses to a domain-based address 77164562SgshapiroR$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 77264562SgshapiroR$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 77364562SgshapiroR$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 77438032Speter') 77538032Speterifdef(`_USE_DECNET_SYNTAX_', 77638032Speter`# convert node::user addresses into a domain-based address 77764562SgshapiroR$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 77864562SgshapiroR$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 77938032Speter', 78038032Speter `dnl') 78138032Speter# if we have % signs, take the rightmost one 78238032SpeterR$* % $* $1 @ $2 First make them all @s. 78338032SpeterR$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 78464562SgshapiroR$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 78538032Speter 78638032Speter# else we must be a local name 78764562SgshapiroR$* $@ $>Canonify2 $1 78838032Speter 78938032Speter 79038032Speter################################################ 79138032Speter### Ruleset 96 -- bottom half of ruleset 3 ### 79238032Speter################################################ 79338032Speter 79464562SgshapiroSCanonify2=96 79538032Speter 79638032Speter# handle special cases for local names 79738032SpeterR$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 79838032SpeterR$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 79938032Speterifdef(`_NO_UUCP_', `dnl', 80038032Speter`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 80164562Sgshapiro 80290792Sgshapiro# check for IPv4/IPv6 domain literal 80390792SgshapiroR$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr] 80438032SpeterR$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 80538032SpeterR$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 80638032Speter 80764562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl 80838032Speter# look up domains in the domain table 80938032SpeterR$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 81038032Speter 81164562Sgshapiroundivert(2)dnl LOCAL_RULE_3 81238032Speter 81364562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl 81438032Speter# handle BITNET mapping 81538032SpeterR$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 81638032Speter 81764562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl 81838032Speter# handle UUCP mapping 81938032SpeterR$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 82038032Speter 82138032Speterifdef(`_NO_UUCP_', `dnl', 82238032Speter`ifdef(`UUCP_RELAY', 82338032Speter`# pass UUCP addresses straight through 82438032SpeterR$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 82538032Speter`# if really UUCP, handle it immediately 82638032Speterifdef(`_CLASS_U_', 82738032Speter`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82838032Speterifdef(`_CLASS_V_', 82938032Speter`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 83038032Speterifdef(`_CLASS_W_', 83138032Speter`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 83238032Speterifdef(`_CLASS_X_', 83338032Speter`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 83438032Speterifdef(`_CLASS_Y_', 83538032Speter`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 83638032Speter 83738032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl 83838032Speter# try UUCP traffic as a local address 83938032SpeterR$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 84038032SpeterR$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 84138032Speter')') 84264562Sgshapiro# hostnames ending in class P are always canonical 84364562SgshapiroR$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 84464562Sgshapirodnl apply the next rule only for hostnames not in class P 84564562Sgshapirodnl this even works for phrases in class P since . is in class P 84664562Sgshapirodnl which daemon flags are set? 84764562SgshapiroR$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 84864562Sgshapirodnl the other rules in this section only apply if the hostname 84964562Sgshapirodnl does not end in class P hence no further checks are done here 85064562Sgshapirodnl if this ever changes make sure the lookups are "protected" again! 85164562Sgshapiroifdef(`_NO_CANONIFY_', `dnl 85264562Sgshapirodnl do not canonify unless: 85364562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection 85464562Sgshapirodnl with class P is non-empty) 85564562Sgshapirodnl or {daemon_flags} has c set 85664562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify} 85764562SgshapiroR$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 85864562Sgshapiro# pass to name server to make hostname canonical if requested 85964562SgshapiroR$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 86064562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 86164562SgshapiroR$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 86264562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work 86364562SgshapiroR$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 86464562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl 86564562Sgshapirodnl this should only apply to unqualified hostnames 86664562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar 86764562Sgshapirodnl then $- does not work. 86864562Sgshapiro# lookup unqualified hostnames 86990792SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 87064562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless: 87164562Sgshapirodnl {daemon_flags} contains CC (do not canonify) 87271345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work 87371345Sgshapirodnl should we do this for every hostname: even unqualified? 87471345SgshapiroR$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 87564562SgshapiroR$* CC $* $| $* $: $3 87690792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl 87790792Sgshapiro# do not canonify header addresses 87890792SgshapiroR$* $| $* < @ $* $~P > $* $: $&{addr_type} $| $2 < @ $3 $4 > $5 87990792SgshapiroR$* h $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 88090792SgshapiroR$* h $* $| $* $: $3', `dnl') 88138032Speter# pass to name server to make hostname canonical 88264562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 88364562Sgshapirodnl remove {daemon_flags} for other cases 88464562SgshapiroR$* $| $* $: $2 88538032Speter 88638032Speter# local host aliases and pseudo-domains are always canonical 88738032SpeterR$* < @ $=w > $* $: $1 < @ $2 . > $3 88838032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 88938032Speter`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 89038032Speter`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 89164562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 89264562Sgshapirodnl virtual hosts are also canonical 89364562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 89464562Sgshapiro`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 89564562Sgshapiro`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 89664562Sgshapiro`dnl') 89790792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 89890792Sgshapirodnl hosts for genericstable are also canonical 89990792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_', 90090792Sgshapiro`R$* < @ $* $=G > $* $: $1 < @ $2 $3 . > $4', 90190792Sgshapiro`R$* < @ $=G > $* $: $1 < @ $2 . > $3')', 90290792Sgshapiro`dnl') 90364562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added 90464562Sgshapirodnl by one of the rules before 90538032SpeterR$* < @ $* . . > $* $1 < @ $2 . > $3 90638032Speter 90738032Speter 90838032Speter################################################## 90938032Speter### Ruleset 4 -- Final Output Post-rewriting ### 91038032Speter################################################## 91164562SgshapiroSfinal=4 91238032Speter 91371345SgshapiroR$+ :; <@> $@ $1 : handle <list:;> 91438032SpeterR$* <@> $@ handle <> and list:; 91538032Speter 91638032Speter# strip trailing dot off possibly canonical name 91738032SpeterR$* < @ $+ . > $* $1 < @ $2 > $3 91838032Speter 91964562Sgshapiro# eliminate internal code 92038032SpeterR$* < @ *LOCAL* > $* $1 < @ $j > $2 92138032Speter 92238032Speter# externalize local domain info 92338032SpeterR$* < $+ > $* $1 $2 $3 defocus 92438032SpeterR@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 92538032SpeterR@ $* $@ @ $1 ... and exit 92638032Speter 92738032Speterifdef(`_NO_UUCP_', `dnl', 92838032Speter`# UUCP must always be presented in old form 92938032SpeterR$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 93038032Speter 93138032Speterifdef(`_USE_DECNET_SYNTAX_', 93238032Speter`# put DECnet back in :: form 93338032SpeterR$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 93438032Speter `dnl') 93538032Speter# delete duplicate local names 93638032SpeterR$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 93738032Speter 93838032Speter 93938032Speter 94038032Speter############################################################## 94138032Speter### Ruleset 97 -- recanonicalize and call ruleset zero ### 94238032Speter### (used for recursive calls) ### 94338032Speter############################################################## 94438032Speter 94564562SgshapiroSRecurse=97 94664562SgshapiroR$* $: $>canonify $1 94764562SgshapiroR$* $@ $>parse $1 94838032Speter 94938032Speter 95038032Speter###################################### 95138032Speter### Ruleset 0 -- Parse Address ### 95238032Speter###################################### 95338032Speter 95464562SgshapiroSparse=0 95538032Speter 95638032SpeterR$* $: $>Parse0 $1 initial parsing 95738032SpeterR<@> $#_LOCAL_ $: <@> special case error msgs 95864562SgshapiroR$* $: $>ParseLocal $1 handle local hacks 95938032SpeterR$* $: $>Parse1 $1 final parsing 96038032Speter 96138032Speter# 96238032Speter# Parse0 -- do initial syntax checking and eliminate local addresses. 96338032Speter# This should either return with the (possibly modified) input 96438032Speter# or return with a #error mailer. It should not return with a 96538032Speter# #mailer other than the #error mailer. 96638032Speter# 96738032Speter 96838032SpeterSParse0 96938032SpeterR<@> $@ <@> special case error msgs 97090792SgshapiroR$* : $* ; <@> $#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses" 97164562SgshapiroR@ <@ $* > < @ $1 > catch "@@host" bogosity 97290792SgshapiroR<@ $+> $#error $@ 5.1.3 $: "_CODE553 User address required" 97390792SgshapiroR$+ <@> $#error $@ 5.1.3 $: "_CODE553 Hostname required" 97438032SpeterR$* $: <> $1 97590792Sgshapirodnl allow tricks like [host1]:[host2] 97690792SgshapiroR<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4 97790792SgshapiroR<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4 97890792Sgshapirodnl but no a@[b]c 97990792SgshapiroR<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid address" 98090792SgshapiroR<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 98190792SgshapiroR<> $* <$* : $* > $* $#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part" 98238032SpeterR<> $* $1 98390792SgshapiroR$* < @ . $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 98490792SgshapiroR$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 98590792Sgshapirodnl no a@b@ 98690792SgshapiroR$* < @ $* @ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid route address" 98790792Sgshapirodnl no a@b@c 98890792SgshapiroR$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 98964562Sgshapirodnl comma only allowed before @; this check is not complete 99090792SgshapiroR$* , $~O $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 99138032Speter 99290792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks 99390792SgshapiroR$* . < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot" 99490792SgshapiroR. $* < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot" 99590792Sgshapirodnl', `dnl') 99690792Sgshapiro 99738032Speter# now delete the local info -- note $=O to find characters that cause forwarding 99864562SgshapiroR$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 99964562SgshapiroR< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 100038032SpeterR$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 100190792SgshapiroR< @ $+ > $#error $@ 5.1.3 $: "_CODE553 User address required" 100264562SgshapiroR$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 100338032SpeterR$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 100490792SgshapiroR< @ *LOCAL* > $#error $@ 5.1.3 $: "_CODE553 User address required" 100538032SpeterR$* $=O $* < @ *LOCAL* > 100664562Sgshapiro $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 100738032SpeterR$* < @ *LOCAL* > $: $1 100838032Speter 100938032Speter# 101038032Speter# Parse1 -- the bottom half of ruleset 0. 101138032Speter# 101238032Speter 101338032SpeterSParse1 101464562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 101564562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute} 101690792SgshapiroR$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <> 101790792SgshapiroR$+ < @ $={LDAPRouteEquiv} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>', 101864562Sgshapiro`dnl') 101964562Sgshapiro 102038032Speterifdef(`_MAILER_smtp_', 102138032Speter`# handle numeric address spec 102264562Sgshapirodnl there is no check whether this is really an IP number 102364562SgshapiroR$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 1024112810SgshapiroR$* < @ [ $+ ] > $* $: $1 < @ [ $2 ] : $S > $3 Add smart host to path 102590792SgshapiroR$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 102664562SgshapiroR$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 102764562SgshapiroR$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 102838032Speter `dnl') 102938032Speter 103064562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 103138032Speter# handle virtual users 103290792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 103390792Sgshapirodnl this is not a documented option 103490792Sgshapirodnl it stops looping in virtusertable mapping if input and output 103590792Sgshapirodnl are identical, i.e., if address A is mapped to A. 103690792Sgshapirodnl it does not deal with multi-level recursion 103790792Sgshapiro# handle full domains in RHS of virtusertable 103890792SgshapiroR$+ < @ $+ > $: $(macro {RecipientAddress} $) $1 < @ $2 > 103990792SgshapiroR$+ < @ $+ > $: <?> $1 < @ $2 > $| $>final $1 < @ $2 > 104090792SgshapiroR<?> $+ $| $+ $: $1 $(macro {RecipientAddress} $@ $2 $) 104190792SgshapiroR<?> $+ $| $* $: $1', 104290792Sgshapiro`dnl') 104364562SgshapiroR$+ $: <!> $1 Mark for lookup 104490792Sgshapirodnl input: <!> local<@domain> 104564562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 104664562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 104764562Sgshapiro`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 104890792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain> 104964562SgshapiroR<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 105090792Sgshapirodnl if <@> local<@domain>: no match but try lookup 105190792Sgshapirodnl user+detail: try user++@domain if detail not empty 105290792SgshapiroR<@> $+ + $+ < @ $* . > 105390792Sgshapiro $: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105490792Sgshapirodnl user+detail: try user+*@domain 105538032SpeterR<@> $+ + $* < @ $* . > 105690792Sgshapiro $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105790792Sgshapirodnl user+detail: try user@domain 105838032SpeterR<@> $+ + $* < @ $* . > 105990792Sgshapiro $: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 106064562Sgshapirodnl try default entry: @domain 106190792Sgshapirodnl ++@domain 106290792SgshapiroR<@> $+ + $+ < @ $+ . > $: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 106364562Sgshapirodnl +*@domain 106490792SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 106564562Sgshapirodnl @domain if +detail exists 106698121Sgshapirodnl if no match, change marker to prevent a second @domain lookup 106798121SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . > 106898121Sgshapirodnl without +detail 106938032SpeterR<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 107090792Sgshapirodnl no match 107138032SpeterR<@> $+ $: $1 107290792Sgshapirodnl remove mark 107364562SgshapiroR<!> $+ $: $1 107464562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 107538032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 107690792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 107790792Sgshapiro# check virtuser input address against output address, if same, skip recursion 107890792SgshapiroR< $+ > $+ < @ $+ > $: < $1 > $2 < @ $3 > $| $1 107990792Sgshapiro# it is the same: stop now 108090792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress} $: $>ParseLocal $>Parse0 $>canonify $1 108190792SgshapiroR< $+ > $+ < @ $+ > $| $* $: < $1 > $2 < @ $3 > 108290792Sgshapirodnl', `dnl') 108380785Sgshapirodnl this is not a documented option 108480785Sgshapirodnl it performs no looping at all for virtusertable 108577349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_', 108677349Sgshapiro`R< $+ > $+ < @ $+ > $: $>ParseLocal $>Parse0 $>canonify $1', 108777349Sgshapiro`R< $+ > $+ < @ $+ > $: $>Recurse $1') 108877349Sgshapirodnl', `dnl') 108938032Speter 109038032Speter# short circuit local delivery so forwarded email works 109138032Speterifdef(`_MAILER_usenet_', `dnl 109264562SgshapiroR$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 109366494Sgshapiro 109466494Sgshapiro 109538032Speterifdef(`_STICKY_LOCAL_DOMAIN_', 109638032Speter`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 109764562SgshapiroR< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 109864562Sgshapirodnl $H empty (but @$=w.) 109938032SpeterR< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 110038032SpeterR< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 110164562Sgshapiro`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 110238032SpeterR$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 110338032Speter 110464562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 110538032Speter# not local -- try mailer table lookup 110638032SpeterR$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 110738032SpeterR< $+ . > $* $: < $1 > $2 strip trailing dot 110838032SpeterR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 110964562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 111064562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 111164562SgshapiroR< $+ > $* $: $>Mailertable <$1> $2 try domain', 111238032Speter`dnl') 111364562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)' 111438032Speter 111538032Speterifdef(`_NO_UUCP_', `dnl', 111638032Speter`# resolve remotely connected UUCP links (if any) 111738032Speterifdef(`_CLASS_V_', 111864562Sgshapiro`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 111938032Speter `dnl') 112038032Speterifdef(`_CLASS_W_', 112164562Sgshapiro`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 112238032Speter `dnl') 112338032Speterifdef(`_CLASS_X_', 112464562Sgshapiro`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 112538032Speter `dnl')') 112638032Speter 112738032Speter# resolve fake top level domains by forwarding to other hosts 112838032Speterifdef(`BITNET_RELAY', 112964562Sgshapiro`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 113038032Speter `dnl') 113138032Speterifdef(`DECNET_RELAY', 113264562Sgshapiro`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 113338032Speter `dnl') 113438032Speterifdef(`_MAILER_pop_', 113538032Speter`R$+ < @ POP. > $#pop $: $1 user@POP', 113638032Speter `dnl') 113738032Speterifdef(`_MAILER_fax_', 113838032Speter`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 113938032Speter`ifdef(`FAX_RELAY', 114064562Sgshapiro`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 114138032Speter `dnl')') 114238032Speter 114338032Speterifdef(`UUCP_RELAY', 114438032Speter`# forward non-local UUCP traffic to our UUCP relay 114564562SgshapiroR$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 114638032Speter`ifdef(`_MAILER_uucp_', 114738032Speter`# forward other UUCP traffic straight to UUCP 114838032SpeterR$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 114938032Speter `dnl')') 115038032Speterifdef(`_MAILER_usenet_', ` 115138032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup 115264562SgshapiroR$+ . USENET $#usenet $@ usenet $: $1', 115338032Speter `dnl') 115438032Speter 115538032Speterifdef(`_LOCAL_RULES_', 115638032Speter`# figure out what should stay in our local mail system 115738032Speterundivert(1)', `dnl') 115838032Speter 115938032Speter# pass names that still have a host to a smarthost (if defined) 116064562SgshapiroR$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 116138032Speter 116238032Speter# deal with other remote names 116338032Speterifdef(`_MAILER_smtp_', 116464562Sgshapiro`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 116590792Sgshapiro`R$* < @$* > $* $#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2') 116638032Speter 116738032Speter# handle locally delivered names 116864562SgshapiroR$=L $#_LOCAL_ $: @ $1 special local names 116938032SpeterR$+ $#_LOCAL_ $: $1 regular local names 117038032Speter 117138032Speter########################################################################### 117238032Speter### Ruleset 5 -- special rewriting after aliases have been expanded ### 117338032Speter########################################################################### 117438032Speter 117564562SgshapiroSLocal_localaddr 117664562SgshapiroSlocaladdr=5 117764562SgshapiroR$+ $: $1 $| $>"Local_localaddr" $1 117890792SgshapiroR$+ $| $#ok $@ $1 no change 117964562SgshapiroR$+ $| $#$* $#$2 118064562SgshapiroR$+ $| $* $: $1 118138032Speter 118290792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 118390792Sgshapiro# Preserve rcpt_host in {Host} 118490792SgshapiroR$+ $: $1 $| $&h $| $&{Host} check h and {Host} 118590792SgshapiroR$+ $| $| $: $(macro {Host} $@ $) $1 no h or {Host} 118690792SgshapiroR$+ $| $| $+ $: $1 h not set, {Host} set 118790792SgshapiroR$+ $| +$* $| $* $: $1 h is +detail, {Host} set 118895154SgshapiroR$+ $| $* @ $+ $| $* $: $(macro {Host} $@ @$3 $) $1 set {Host} to host in h 118990792SgshapiroR$+ $| $+ $| $* $: $(macro {Host} $@ @$2 $) $1 set {Host} to h 119090792Sgshapiro')dnl 119190792Sgshapiro 119290792Sgshapiroifdef(`_FFR_5_', `dnl 119366494Sgshapiro# Preserve host in a macro 119466494SgshapiroR$+ $: $(macro {LocalAddrHost} $) $1 119566494SgshapiroR$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 119666494Sgshapiro 119790792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl 119838032Speter# deal with plussed users so aliases work nicely 119966494SgshapiroR$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 120066494SgshapiroR$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 120166494Sgshapiro') 120238032Speter# prepend an empty "forward host" on the front 120338032SpeterR$+ $: <> $1 120438032Speter 120538032Speterifdef(`LUSER_RELAY', `dnl 120638032Speter# send unrecognized local users to a relay host 120790792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 120866494SgshapiroR< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 120966494SgshapiroR< > $+ $: < ? $L > < > $(user $1 $) look up user 121066494SgshapiroR< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 121166494SgshapiroR< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 121264562SgshapiroR< > $+ $: < $L > $(user $1 $) look up user 121390792SgshapiroR< $* > $+ <> $: < > $2 found; strip $L') 121490792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 121590792SgshapiroR< $+ > $+ $: < $1 > $2 $&{Host}') 121690792Sgshapirodnl') 121738032Speter 121890792Sgshapiroifdef(`MAIL_HUB', `dnl 121990792SgshapiroR< > $+ $: < $H > $1 try hub', `dnl') 122090792Sgshapiroifdef(`LOCAL_RELAY', `dnl 122190792SgshapiroR< > $+ $: < $R > $1 try relay', `dnl') 122290792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 122390792SgshapiroR< > $+ $@ $1', `dnl 122464562SgshapiroR< > $+ $: < > < $1 <> $&h > nope, restore +detail 122590792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 122690792SgshapiroR< > < $+ @ $+ <> + $* > $: < > < $1 + $3 @ $2 > check whether +detail') 122764562SgshapiroR< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 122864562SgshapiroR< > < $+ <> $* > $: < > < $1 > else discard 122938032SpeterR< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 123066494SgshapiroR< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 123138032SpeterR< > < $+ > $@ $1 no +detail 123243730SpeterR$+ $: $1 <> $&h add +detail back in 123390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 123490792SgshapiroR$+ @ $+ <> + $* $: $1 + $3 @ $2 check whether +detail') 123543730SpeterR$+ <> + $* $: $1 + $2 check whether +detail 123666494SgshapiroR$+ <> $* $: $1 else discard') 123764562SgshapiroR< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 123864562SgshapiroR< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 123990792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 124090792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 124190792SgshapiroR< $~[ : $+ > $+ @ $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $4 >') 124290792SgshapiroR< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 124390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 124490792SgshapiroR< $+ > $+ @ $+ $@ $>MailerToTriple < $1 > $2 < @ $3 >') 124564562SgshapiroR< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 124638032Speter 124764562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 124890792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 124938032Speter################################################################### 125090792Sgshapiro### Ruleset LDAPMailertable -- mailertable lookup for LDAP ### 125190792Sgshapirodnl input: <Domain> FullAddress 125290792Sgshapiro################################################################### 125390792Sgshapiro 125490792SgshapiroSLDAPMailertable 125590792SgshapiroR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 125690792SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check resolved? 125790792SgshapiroR< $+ > $* $: < $1 > $>Mailertable <$1> $2 try domain 125890792SgshapiroR< $+ > $#$* $#$2 found 125990792SgshapiroR< $+ > $* $#_RELAY_ $@ $1 $: $2 not found, direct relay', 126090792Sgshapiro`dnl') 126190792Sgshapiro 126290792Sgshapiro################################################################### 126338032Speter### Ruleset 90 -- try domain part of mailertable entry ### 126464562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 126538032Speter################################################################### 126638032Speter 126764562SgshapiroSMailertable=90 126864562Sgshapirodnl shift and check 126964562Sgshapirodnl %2 is not documented in cf/README 127038032SpeterR$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 127164562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 127264562SgshapiroR$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 127364562SgshapiroR$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 127464562Sgshapirodnl is $2 always empty? 127538032SpeterR$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 127664562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 127764562Sgshapirodnl return full address 127838032SpeterR< $* > $* $@ $2 no mailertable match', 127938032Speter`dnl') 128038032Speter 128138032Speter################################################################### 128238032Speter### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 128364562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest 128464562Sgshapirodnl <> address -> address 128564562Sgshapirodnl <error:d.s.n:text> -> error 1286120256Sgshapirodnl <error:keyword:text> -> error 128764562Sgshapirodnl <error:text> -> error 128864562Sgshapirodnl <mailer:user@host> lp<@domain>rest -> mailer host user 128964562Sgshapirodnl <mailer:host> address -> mailer host address 129064562Sgshapirodnl <localdomain> address -> address 129164562Sgshapirodnl <host> address -> relay host address 129238032Speter################################################################### 129338032Speter 129464562SgshapiroSMailerToTriple=95 129538032SpeterR< > $* $@ $1 strip off null relay 129664562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 1297120256SgshapiroR< error : $- : $+ > $* $#error $@ $(dequote $1 $) $: $2 1298120256SgshapiroR< error : $+ > $* $#error $: $1 129938032SpeterR< local : $* > $* $>CanonLocal < $1 > $2 130090792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 130190792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 130290792SgshapiroR< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 130338032SpeterR< $=w > $* $@ $2 delete local host 130438032SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 130538032Speter 130638032Speter################################################################### 130738032Speter### Ruleset CanonLocal -- canonify local: syntax ### 130864562Sgshapirodnl input: <user> address 130964562Sgshapirodnl <x> <@host> : rest -> Recurse rest 131064562Sgshapirodnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 131164562Sgshapirodnl <> user <@host> rest -> local user@host user 131264562Sgshapirodnl <> user -> local user user 131364562Sgshapirodnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 131464562Sgshapirodnl <user> lp <@host> rest -> local lp@host user 131564562Sgshapirodnl <user> lp -> local lp user 131638032Speter################################################################### 131738032Speter 131838032SpeterSCanonLocal 131943730Speter# strip local host from routed addresses 132064562SgshapiroR< $* > < @ $+ > : $+ $@ $>Recurse $3 132164562SgshapiroR< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 132243730Speter 132338032Speter# strip trailing dot from any host name that may appear 132438032SpeterR< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 132538032Speter 132638032Speter# handle local: syntax -- use old user, either with or without host 132738032SpeterR< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 132838032SpeterR< > $+ $#_LOCAL_ $@ $1 $: $1 132938032Speter 133038032Speter# handle local:user@host syntax -- ignore host part 133138032SpeterR< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 133238032Speter 133338032Speter# handle local:user syntax 133438032SpeterR< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 133538032SpeterR< $+ > $* $#_LOCAL_ $@ $2 $: $1 133638032Speter 133738032Speter################################################################### 133838032Speter### Ruleset 93 -- convert header names to masqueraded form ### 133938032Speter################################################################### 134038032Speter 134164562SgshapiroSMasqHdr=93 134238032Speter 134364562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 134438032Speter# handle generics database 134538032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_', 134664562Sgshapirodnl if generics should be applied add a @ as mark 134738032Speter`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 134838032Speter`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 134938032SpeterR$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 135064562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @ 135164562Sgshapirodnl ignore the first case for now 135264562Sgshapirodnl if it has the mark lookup full address 135390792Sgshapirodnl broken: %1 is full address not just detail 135464562SgshapiroR< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 135564562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain> 135664562Sgshapirodnl no match, try user+detail@domain 135764562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 135864562Sgshapiro $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 135964562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 136064562Sgshapiro $: < $(generics $1@$3 $: $) > $4 < @ $5 > 136164562Sgshapirodnl no match, remove mark 136264562SgshapiroR<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 136364562Sgshapirodnl no match, try @domain for exceptions 136464562SgshapiroR< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 136564562Sgshapirodnl workspace: ... or <match> user <@domain> 136664562Sgshapirodnl no match, try local part 136738032SpeterR< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 136864562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 136964562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 137064562SgshapiroR< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 137164562SgshapiroR< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 137238032SpeterR< > $* $: $1 not found', 137338032Speter`dnl') 137438032Speter 137564562Sgshapiro# do not masquerade anything in class N 137664562SgshapiroR$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 137764562Sgshapiro 137890792Sgshapiroifdef(`MASQUERADE_NAME', `dnl 137938032Speter# special case the users that should be exposed 138038032SpeterR$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 138138032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 138238032Speter`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 138338032Speter`R$=E < @ $=M . > $@ $1 < @ $2 . >') 138438032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 138538032Speter`R$=E < @ $=w . > $@ $1 < @ $2 . >') 138638032Speter 138738032Speter# handle domain-specific masquerading 138838032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 138938032Speter`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 139038032Speter`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 139138032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 139238032Speter`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 139338032SpeterR$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 139438032SpeterR$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 139538032SpeterR$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 139690792Sgshapirodnl', `dnl no masquerading 139790792Sgshapirodnl just fix *LOCAL* leftovers 139890792SgshapiroR$* < @ *LOCAL* > $@ $1 < @ $j . >') 139938032Speter 140038032Speter################################################################### 140138032Speter### Ruleset 94 -- convert envelope names to masqueraded form ### 140238032Speter################################################################### 140338032Speter 140464562SgshapiroSMasqEnv=94 140538032Speterifdef(`_MASQUERADE_ENVELOPE_', 140664562Sgshapiro`R$+ $@ $>MasqHdr $1', 140738032Speter`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 140838032Speter 140938032Speter################################################################### 141038032Speter### Ruleset 98 -- local part of ruleset zero (can be null) ### 141138032Speter################################################################### 141238032Speter 141364562SgshapiroSParseLocal=98 141464562Sgshapiroundivert(3)dnl LOCAL_RULE_0 141538032Speter 141664562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 141790792Sgshapiro###################################################################### 141890792Sgshapiro### LDAPExpand: Expand address using LDAP routing 141990792Sgshapiro### 142090792Sgshapiro### Parameters: 142190792Sgshapiro### <$1> -- parsed address (user < @ domain . >) (pass through) 142290792Sgshapiro### <$2> -- RFC822 address (user @ domain) (used for lookup) 142390792Sgshapiro### <$3> -- +detail information 142490792Sgshapiro### 142590792Sgshapiro### Returns: 142690792Sgshapiro### Mailer triplet ($#mailer $@ host $: address) 142790792Sgshapiro### Parsed address (user < @ domain . >) 142890792Sgshapiro###################################################################### 142990792Sgshapiro 143064562SgshapiroSLDAPExpand 143164562Sgshapiro# do the LDAP lookups 143290792SgshapiroR<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3> 143364562Sgshapiro 143494334Sgshapiro# look for temporary failures (return original address, MTA will queue up) 1435102528SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*> $@ $3 1436102528SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*> $@ $3 143794334Sgshapiro 143864562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost, 143964562Sgshapiro# return the new mailRoutingAddress 144090792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 144190792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2 144290792SgshapiroR<$+@$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $5 @ $2') 144390792SgshapiroR<$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 144490792SgshapiroR<$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 144564562Sgshapiro 144698121Sgshapiro 144764562Sgshapiro# if mailRoutingAddress and non-local mailHost, 144864562Sgshapiro# relay to mailHost with new mailRoutingAddress 144990792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 145090792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 145190792Sgshapiro# check mailertable for host, relay from there 145290792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$3> $>canonify $1 $6 @ $2', 145390792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')') 145490792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 145590792Sgshapiro# check mailertable for host, relay from there 145690792SgshapiroR<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1', 145790792Sgshapiro`R<$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $2 $: $>canonify $1') 145864562Sgshapiro 145964562Sgshapiro# if no mailRoutingAddress and local mailHost, 146064562Sgshapiro# return original address 146190792SgshapiroR<> <$=w> <$+> <$+> <$*> $@ $2 146264562Sgshapiro 146398121Sgshapiro 146464562Sgshapiro# if no mailRoutingAddress and non-local mailHost, 146564562Sgshapiro# relay to mailHost with original address 146690792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 146790792Sgshapiro# check mailertable for host, relay from there 146890792SgshapiroR<> <$+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2', 146990792Sgshapiro`R<> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $1 $: $2') 147064562Sgshapiro 147190792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_', 147290792Sgshapiro`# if no mailRoutingAddress and no mailHost, 147390792Sgshapiro# try without +detail 147490792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl 147590792Sgshapiro 147690792Sgshapiro# if still no mailRoutingAddress and no mailHost, 147764562Sgshapiro# try @domain 147890792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 147990792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <@ $4> <+$3>') 148090792SgshapiroR<> <> <$+> <$+ @ $+> <$*> $@ $>LDAPExpand <$1> <@ $3> <$4> 148164562Sgshapiro 148264562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt, 148364562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 148464562Sgshapiro# user does not exist 148590792SgshapiroR<> <> <$+> <@ $+> <$*> $: <?> < $&{addr_type} > < $1 > 148690792Sgshapiro# only give error for envelope recipient 148790792SgshapiroR<?> <e r> <$+> $#error $@ nouser $: "550 User unknown" 148890792SgshapiroR<?> <$*> <$+> $@ $2', 148964562Sgshapiro`dnl 149064562Sgshapiro# return the original address 149190792SgshapiroR<> <> <$+> <@ $+> <$*> $@ $1')', 149264562Sgshapiro`dnl') 149364562Sgshapiro 149464562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 149564562Sgshapiro')') 149690792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 149738032Speter###################################################################### 149890792Sgshapiro### D: LookUpDomain -- search for domain in access database 149938032Speter### 150038032Speter### Parameters: 150138032Speter### <$1> -- key (domain name) 150238032Speter### <$2> -- default (what to return if not found in db) 150364562Sgshapirodnl must not be empty 150490792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 150564562Sgshapiro### ! does lookup only with tag 150664562Sgshapiro### + does lookup with and without tag 150790792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 150864562Sgshapirodnl returns: <default> <passthru> 150964562Sgshapirodnl <result> <passthru> 151038032Speter###################################################################### 151138032Speter 151290792SgshapiroSD 151364562Sgshapirodnl workspace <key> <default> <passthru> <mark> 151464562Sgshapirodnl lookup with tag (in front, no delimiter here) 151590792Sgshapirodnl 2 3 4 5 151690792SgshapiroR<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 151764562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 151864562Sgshapirodnl lookup without tag? 151990792Sgshapirodnl 1 2 3 4 152090792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 152190792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest 152290792Sgshapirodnl XXX apply this also to IP addresses? 152390792Sgshapirodnl currently it works the wrong way round for [1.2.3.4] 152490792Sgshapirodnl 1 2 3 4 5 6 152590792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6> 152690792Sgshapirodnl 1 2 3 4 5 152790792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl') 152890792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 152990792Sgshapirodnl found SKIP: return <default> and <passthru> 153090792Sgshapirodnl 1 2 3 4 5 153190792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 153290792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!) 153390792Sgshapirodnl 1 2 3 4 5 6 153490792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*> $@ $>D <[$1]> <$3> <$4 $5> <$6> 153590792Sgshapiroifdef(`NO_NETINET6', `dnl', 153690792Sgshapiro`dnl not found: IPv6 net 153790792Sgshapirodnl (could be merged with previous rule if we have a class containing .:) 153890792Sgshapirodnl 1 2 3 4 5 6 153990792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6> 154090792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>') 154164562Sgshapirodnl not found, but subdomain: try again 154290792Sgshapirodnl 1 2 3 4 5 6 154390792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6> 154490792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag: 154590792Sgshapirodnl 1 2 3 4 154690792SgshapiroR<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl') 154790792Sgshapirodnl not found, no subdomain: return <default> and <passthru> 154890792Sgshapirodnl 1 2 3 4 5 154990792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 155090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 155190792Sgshapirodnl 2 3 4 5 6 155290792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 155390792Sgshapirodnl return <result of lookup> and <passthru> 155490792Sgshapirodnl 2 3 4 5 6 155590792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 155638032Speter 155738032Speter###################################################################### 155890792Sgshapiro### A: LookUpAddress -- search for host address in access database 155938032Speter### 156038032Speter### Parameters: 156138032Speter### <$1> -- key (dot quadded host address) 156238032Speter### <$2> -- default (what to return if not found in db) 156364562Sgshapirodnl must not be empty 156490792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 156564562Sgshapiro### ! does lookup only with tag 156664562Sgshapiro### + does lookup with and without tag 156790792Sgshapiro### <$4> -- passthru (additional data passed through) 156864562Sgshapirodnl returns: <default> <passthru> 156964562Sgshapirodnl <result> <passthru> 157038032Speter###################################################################### 157138032Speter 157290792SgshapiroSA 157364562Sgshapirodnl lookup with tag 157490792Sgshapirodnl 2 3 4 5 157590792SgshapiroR<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 157664562Sgshapirodnl lookup without tag 157790792Sgshapirodnl 1 2 3 4 157890792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 157990792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru> 158090792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 158190792Sgshapirodnl found SKIP: return <default> and <passthru> 158290792Sgshapirodnl 1 2 3 4 5 158390792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 158490792Sgshapiroifdef(`NO_NETINET6', `dnl', 158590792Sgshapiro`dnl no match; IPv6: remove last part 158690792Sgshapirodnl 1 2 3 4 5 6 158790792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 158890792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>') 158964562Sgshapirodnl no match; IPv4: remove last part 159090792Sgshapirodnl 1 2 3 4 5 6 159190792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 159264562Sgshapirodnl no match: return default 159390792Sgshapirodnl 1 2 3 4 5 159490792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 159590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 159690792Sgshapirodnl 2 3 4 5 6 159790792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 159864562Sgshapirodnl match: return result 159990792Sgshapirodnl 2 3 4 5 6 160090792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 160190792Sgshapirodnl endif _ACCESS_TABLE_ 160290792Sgshapirodivert(0) 160338032Speter###################################################################### 160442575Speter### CanonAddr -- Convert an address into a standard form for 160542575Speter### relay checking. Route address syntax is 160642575Speter### crudely converted into a %-hack address. 160742575Speter### 160842575Speter### Parameters: 160942575Speter### $1 -- full recipient address 161042575Speter### 161142575Speter### Returns: 161242575Speter### parsed address, not in source route form 161364562Sgshapirodnl user%host%host<@domain> 161464562Sgshapirodnl host!user<@domain> 161542575Speter###################################################################### 161642575Speter 161742575SpeterSCanonAddr 161864562SgshapiroR$* $: $>Parse0 $>canonify $1 make domain canonical 161964562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 162042575SpeterR< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 162142575SpeterR$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 162242575SpeterR$* < @ $+ > : $* $3 $1 < @ $2 > 162364562Sgshapirodnl') 162442575Speter 162542575Speter###################################################################### 162638032Speter### ParseRecipient -- Strip off hosts in $=R as well as possibly 162738032Speter### $* $=m or the access database. 162838032Speter### Check user portion for host separators. 162938032Speter### 163038032Speter### Parameters: 163138032Speter### $1 -- full recipient address 163238032Speter### 163338032Speter### Returns: 163438032Speter### parsed, non-local-relaying address 163538032Speter###################################################################### 163638032Speter 163738032SpeterSParseRecipient 163864562Sgshapirodnl mark and canonify address 163942575SpeterR$* $: <?> $>CanonAddr $1 164064562Sgshapirodnl workspace: <?> localpart<@domain[.]> 164142575SpeterR<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 164264562Sgshapirodnl workspace: <?> localpart<@domain> 164342575SpeterR<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 164438032Speter 164538032Speter# if no $=O character, no host in the user portion, we are done 164642575SpeterR<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 164764562Sgshapirodnl no $=O in localpart: return 164842575SpeterR<?> $* $@ $1 164938032Speter 165090792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O 165164562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY> 165238032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 165338032Speter# if we relay, check username portion for user%host so host can be checked also 165442575SpeterR<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 165564562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 165664562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 165790792Sgshapiro 165890792Sgshapirodnl what if access map returns something else than RELAY? 165990792Sgshapirodnl we are only interested in RELAY entries... 166090792Sgshapirodnl other To: entries: blacklist recipient; generic entries? 166190792Sgshapirodnl if it is an error we probably do not want to relay anyway 166238032Speterifdef(`_RELAY_HOSTS_ONLY_', 166342575Speter`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 166464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 166564562SgshapiroR<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 166642575SpeterR<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 166742575Speter`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 166864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 166990792SgshapiroR<NO> $* < @ $+ > $: $>D <$2> <NO> <+ To> <$1 < @ $2 >> 167042575SpeterR<$+> <$+> $: <$1> $2',`dnl')') 167138032Speter 167264562Sgshapiro 167390792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl 167490792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain? 167590792SgshapiroR<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 167690792SgshapiroR<MX> < : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 167790792Sgshapirodnl yes: mark it as <RELAY> 167890792SgshapiroR<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 167990792Sgshapirodnl no: put old <NO> mark back 168090792SgshapiroR<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 168190792Sgshapiro 168290792Sgshapirodnl do we relay to this recipient domain? 168342575SpeterR<RELAY> $* < @ $* > $@ $>ParseRecipient $1 168490792Sgshapirodnl something else 168590792SgshapiroR<$+> $* $@ $2 168642575Speter 168764562Sgshapiro 168838032Speter###################################################################### 168938032Speter### check_relay -- check hostname/address on SMTP startup 169038032Speter###################################################################### 169138032Speter 169238032SpeterSLocal_check_relay 169364562SgshapiroScheck`'_U_`'relay 169438032SpeterR$* $: $1 $| $>"Local_check_relay" $1 169538032SpeterR$* $| $* $| $#$* $#$3 169638032SpeterR$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 169738032Speter 169838032SpeterSBasic_check_relay 169938032Speter# check for deferred delivery mode 170098121SgshapiroR$* $: < $&{deliveryMode} > $1 170138032SpeterR< d > $* $@ deferred 170238032SpeterR< $* > $* $: $2 170338032Speter 170464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 170566494Sgshapirodnl workspace: {client_name} $| {client_addr} 170690792SgshapiroR$+ $| $+ $: $>D < $1 > <?> <+ Connect> < $2 > 170766494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 1708110560Sgshapirodnl OR $| $+ if client_name is empty 1709110560SgshapiroR $| $+ $: $>A < $1 > <?> <+ Connect> <> empty client_name 1710110560Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 171190792SgshapiroR<?> <$+> $: $>A < $1 > <?> <+ Connect> <> no: another lookup 171290792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) 171390792SgshapiroR<?> <$*> $: OK found nothing 171490792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK 171590792SgshapiroR<$={Accept}> <$*> $@ $1 return value of lookup 171690792SgshapiroR<REJECT> <$*> $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 171790792SgshapiroR<DISCARD> <$*> $#discard $: discard 171890792Sgshapiroifdef(`_FFR_QUARANTINE', 171990792Sgshapiro`R<QUARANTINE:$+> <$*> $#error $@ quarantine $: $1', `dnl') 172064562Sgshapirodnl error tag 172166494SgshapiroR<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 172266494SgshapiroR<ERROR:$+> <$*> $#error $: $1 172390792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 172464562Sgshapirodnl generic error from access map 172566494SgshapiroR<$+> <$*> $#error $: $1', `dnl') 172638032Speter 172764562Sgshapiroifdef(`_RBL_',`dnl 172864562Sgshapiro# DNS based IP address spam list 172990792Sgshapirodnl workspace: ignored... 173038032SpeterR$* $: $&{client_addr} 173164562SgshapiroR$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 173264562SgshapiroR<?>OK $: OKSOFAR 173398121SgshapiroR<?>$+ $#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"', 173438032Speter`dnl') 173564562Sgshapiroundivert(8) 173638032Speter 173738032Speter###################################################################### 173838032Speter### check_mail -- check SMTP ``MAIL FROM:'' command argument 173938032Speter###################################################################### 174038032Speter 174138032SpeterSLocal_check_mail 174264562SgshapiroScheck`'_U_`'mail 174338032SpeterR$* $: $1 $| $>"Local_check_mail" $1 174438032SpeterR$* $| $#$* $#$2 174538032SpeterR$* $| $* $@ $>"Basic_check_mail" $1 174638032Speter 174738032SpeterSBasic_check_mail 174838032Speter# check for deferred delivery mode 174998121SgshapiroR$* $: < $&{deliveryMode} > $1 175038032SpeterR< d > $* $@ deferred 175138032SpeterR< $* > $* $: $2 175238032Speter 175364562Sgshapiro# authenticated? 175464562Sgshapirodnl done first: we can require authentication for every mail transaction 175564562Sgshapirodnl workspace: address as given by MAIL FROM: (sender) 175664562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 175764562SgshapiroR$* $| $#$+ $#$2 175864562Sgshapirodnl undo damage: remove result of tls_client call 175964562SgshapiroR$* $| $* $: $1 176038032Speter 176164562Sgshapirodnl workspace: address as given by MAIL FROM: 176264562SgshapiroR<> $@ <OK> we MUST accept <> (RFC 1123) 176338032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 176464562Sgshapirodnl do some additional checks 176564562Sgshapirodnl no user@host 176664562Sgshapirodnl no user@localhost (if nonlocal sender) 176764562Sgshapirodnl this is a pretty simple canonification, it will not catch every case 176864562Sgshapirodnl just make sure the address has <> around it (which is required by 176964562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...) 177064562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will 177164562Sgshapirodnl not be modified by host lookups. 177264562SgshapiroR$+ $: <?> $1 177364562SgshapiroR<?><$+> $: <@> <$1> 177464562SgshapiroR<?>$+ $: <@> <$1> 177564562Sgshapirodnl workspace: <@> <address> 177664562Sgshapirodnl prepend daemon_flags 177764562SgshapiroR$* $: $&{daemon_flags} $| $1 177864562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 177964562Sgshapirodnl do not allow these at all or only from local systems? 178064562SgshapiroR$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 178164562Sgshapirodnl accept unqualified sender: change mark to avoid test 178264562SgshapiroR$* u $* $| <@> < $* > $: <?> < $3 > 178364562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 178464562Sgshapirodnl or: <? ${client_name} > <address> 178564562Sgshapirodnl or: <?> <address> 178664562Sgshapirodnl remove daemon_flags 178764562SgshapiroR$* $| $* $: $2 178838032Speter# handle case of @localhost on address 178964562SgshapiroR<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 179064562SgshapiroR<@> < $* @ [127.0.0.1] > 179164562Sgshapiro $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 179264562SgshapiroR<@> < $* @ localhost.$m > 179364562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.$m > 179438032Speterifdef(`_NO_UUCP_', `dnl', 179564562Sgshapiro`R<@> < $* @ localhost.UUCP > 179664562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 179764562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 179864562Sgshapirodnl or: <@> <address> 179964562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 180064562SgshapiroR<@> $* $: $1 no localhost as domain 180164562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 180264562Sgshapirodnl or: <address> 180364562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 180464562SgshapiroR<? $=w> $* $: $2 local client: ok 180590792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address" 180664562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 180764562SgshapiroR<?> $* $: $1') 180864562Sgshapirodnl workspace: address (or <address>) 180964562SgshapiroR$* $: <?> $>CanonAddr $1 canonify sender address and mark it 181064562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 181164562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed 181264562SgshapiroR<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 181364562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 1814102528SgshapiroR<?> $* < @ $* $=P > $: <_RES_OK_> $1 < @ $2 $3 > 181564562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ? or OK 181698121Sgshapirodnl A sender address with my local host name ($j) is safe 1817102528SgshapiroR<?> $* < @ $j > $: <_RES_OK_> $1 < @ $j > 181864562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 181990792Sgshapiro`R<?> $* < @ $+ > $: <_RES_OK_> $1 < @ $2 > ... unresolvable OK', 182064562Sgshapiro`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 182164562SgshapiroR<? $* <$->> $* < @ $+ > 182264562Sgshapiro $: <$2> $3 < @ $4 >') 182390792Sgshapirodnl workspace <mark> CanonicalAddress where mark is ?, _RES_OK_, PERM, TEMP 182464562Sgshapirodnl mark is ? iff the address is user (wo @domain) 182538032Speter 182664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 182764562Sgshapiro# check sender address: user@address, user@, address 182864562Sgshapirodnl should we remove +ext from user? 182990792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP 183090792SgshapiroR<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3> 183164562SgshapiroR<$+> $+ $: @<$1> <$2> $| <U:$2@> 183264562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 183364562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 183464562Sgshapirodnl will only return user<@domain when "reversing" the args 183590792SgshapiroR@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <> 183664562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result> 183764562SgshapiroR<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 183864562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress> 183938032Speter# retransform for further use 184064562Sgshapirodnl required form: 184164562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress 184264562SgshapiroR<?> <$+> <$*> $: <$1> $2 no match 184364562SgshapiroR<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 184464562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress 184564562Sgshapirodnl mark is ? iff the address is user (wo @domain) 184638032Speter 184738032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 184838032Speter# handle case of no @domain on address 184964562Sgshapirodnl prepend daemon_flags 185064562SgshapiroR<?> $* $: $&{daemon_flags} $| <?> $1 185164562Sgshapirodnl accept unqualified sender: change mark to avoid test 185290792SgshapiroR$* u $* $| <?> $* $: <_RES_OK_> $3 185364562Sgshapirodnl remove daemon_flags 185464562SgshapiroR$* $| $* $: $2 1855110560SgshapiroR<?> $* $: < ? $&{client_addr} > $1 1856102528SgshapiroR<?> $* $@ <_RES_OK_> ...local unqualed ok 185790792SgshapiroR<? $+> $* $#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f 185838032Speter ...remote is not') 185938032Speter# check results 186064562SgshapiroR<?> $* $: @ $1 mark address: nothing known about it 186190792SgshapiroR<$={ResOk}> $* $@ <_RES_OK_> domain ok: stop 186264562SgshapiroR<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 186390792SgshapiroR<PERM> $* $#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist" 186464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 186590792SgshapiroR<$={Accept}> $* $# $1 accept from access map 186638032SpeterR<DISCARD> $* $#discard $: discard 186790792Sgshapiroifdef(`_FFR_QUARANTINE', 186890792Sgshapiro`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 186964562SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 187064562Sgshapirodnl error tag 187164562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 187264562SgshapiroR<ERROR:$+> $* $#error $: $1 187390792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 187464562Sgshapirodnl generic error from access map 187564562SgshapiroR<$+> $* $#error $: $1 error from access db', 187638032Speter`dnl') 187738032Speter 187838032Speter###################################################################### 187938032Speter### check_rcpt -- check SMTP ``RCPT TO:'' command argument 188038032Speter###################################################################### 188138032Speter 188238032SpeterSLocal_check_rcpt 188364562SgshapiroScheck`'_U_`'rcpt 188438032SpeterR$* $: $1 $| $>"Local_check_rcpt" $1 188538032SpeterR$* $| $#$* $#$2 188638032SpeterR$* $| $* $@ $>"Basic_check_rcpt" $1 188738032Speter 188838032SpeterSBasic_check_rcpt 188990792Sgshapiro# empty address? 189090792SgshapiroR<> $#error $@ nouser $: "553 User address required" 189190792SgshapiroR$@ $#error $@ nouser $: "553 User address required" 189238032Speter# check for deferred delivery mode 189398121SgshapiroR$* $: < $&{deliveryMode} > $1 189438032SpeterR< d > $* $@ deferred 189538032SpeterR< $* > $* $: $2 189638032Speter 189764562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 189890792Sgshapirodnl this code checks for user@host where host is not a FQHN. 189990792Sgshapirodnl it is not activated. 190090792Sgshapirodnl notice: code to check for a recipient without a domain name is 190190792Sgshapirodnl available down below; look for the same macro. 190290792Sgshapirodnl this check is done here because the name might be qualified by the 190390792Sgshapirodnl canonicalization. 190490792Sgshapiro# require fully qualified domain part? 190590792Sgshapirodnl very simple canonification: make sure the address is in < > 190664562SgshapiroR$+ $: <?> $1 190790792SgshapiroR<?> <$+> $: <@> <$1> 190890792SgshapiroR<?> $+ $: <@> <$1> 190990792SgshapiroR<@> < postmaster > $: postmaster 1910110560SgshapiroR<@> < $* @ $+ . $+ > $: < $1 @ $2 . $3 > 191164562Sgshapirodnl prepend daemon_flags 191290792SgshapiroR<@> $* $: $&{daemon_flags} $| <@> $1 191364562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 1914120256Sgshapirodnl 'r'equire qual.rcpt: ok 1915120256SgshapiroR$* r $* $| <@> < $+ @ $+ > $: < $3 @ $4 > 191664562Sgshapirodnl do not allow these at all or only from local systems? 1917120256SgshapiroR$* r $* $| <@> < $* > $: < ? $&{client_name} > < $3 > 191864562SgshapiroR<?> < $* > $: <$1> 191964562SgshapiroR<? $=w> < $* > $: <$1> 192090792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "553 Fully qualified domain name required" 192164562Sgshapirodnl remove daemon_flags for other cases 192264562SgshapiroR$* $| <@> $* $: $2', `dnl') 192364562Sgshapiro 192490792Sgshapirodnl ################################################################## 192590792Sgshapirodnl call subroutines for recipient and relay 192690792Sgshapirodnl possible returns from subroutines: 192790792Sgshapirodnl $#TEMP temporary failure 192890792Sgshapirodnl $#error permanent failure (or temporary if from access map) 192990792Sgshapirodnl $#other stop processing 193090792Sgshapirodnl RELAY RELAYing allowed 193190792Sgshapirodnl other otherwise 193290792Sgshapiro###################################################################### 193390792SgshapiroR$* $: $1 $| @ $>"Rcpt_ok" $1 193490792Sgshapirodnl temporary failure? remove mark @ and remember 193590792SgshapiroR$* $| @ $#TEMP $+ $: $1 $| T $2 193690792Sgshapirodnl error or ok (stop) 193790792SgshapiroR$* $| @ $#$* $#$2 193890792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 193990792SgshapiroR$* $| @ RELAY $@ RELAY 194090792Sgshapirodnl something else: call check sender (relay) 194190792SgshapiroR$* $| @ $* $: O $| $>"Relay_ok" $1 194290792Sgshapirodnl temporary failure: call check sender (relay) 194390792SgshapiroR$* $| T $+ $: T $2 $| $>"Relay_ok" $1 194490792Sgshapirodnl temporary failure? return that 194590792SgshapiroR$* $| $#TEMP $+ $#error $2 194690792Sgshapirodnl error or ok (stop) 194790792SgshapiroR$* $| $#$* $#$2 194890792SgshapiroR$* $| RELAY $@ RELAY 194990792Sgshapirodnl something else: return previous temp failure 195090792SgshapiroR T $+ $| $* $#error $1 195190792Sgshapiro# anything else is bogus 195290792SgshapiroR$* $#error $@ 5.7.1 $: confRELAY_MSG 195390792Sgshapirodivert(0) 195490792Sgshapiro 195590792Sgshapiro###################################################################### 195690792Sgshapiro### Rcpt_ok: is the recipient ok? 195790792Sgshapirodnl input: recipient address (RCPT TO) 195890792Sgshapirodnl output: see explanation at call 195990792Sgshapiro###################################################################### 196090792SgshapiroSRcpt_ok 196138032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl 196242575SpeterR$* $: $>CanonAddr $1 196338032SpeterR$* < @ $* . > $1 < @ $2 > strip trailing dots', 196438032Speter`R$* $: $>ParseRecipient $1 strip relayable hosts') 196538032Speter 196642575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl 196742575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl 196842575Speter# unlimited bestmx 196942575SpeterR$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 197042575Speter`dnl 197142575Speter# limit bestmx to $=B 197243730SpeterR$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 197390792SgshapiroR$* $=O $* < @ $* @@ $=w . > $* $@ $>"Rcpt_ok" $1 $2 $3 197442575SpeterR$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 197542575SpeterR$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 197642575Speter 197738032Speterifdef(`_BLACKLIST_RCPT_',`dnl 197864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 197938032Speter# blacklist local users or any host from receiving mail 198038032SpeterR$* $: <?> $1 198164562Sgshapirodnl user is now tagged with @ to be consistent with check_mail 198264562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user) 198390792SgshapiroR<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2> 198490792SgshapiroR<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2> 198564562SgshapiroR<?> $+ $: <> <$1> $| <U:$1@> 198664562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 198764562Sgshapirodnl will only return user<@domain when "reversing" the args 198890792SgshapiroR<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+ To> $| <$2> <> 198964562SgshapiroR<@> <$*> $| <$*> $: <$2> <$1> reverse result 199064562SgshapiroR<?> <$*> $: @ $1 mark address as no match 199190792Sgshapirodnl we may have to filter here because otherwise some RHSs 199290792Sgshapirodnl would be interpreted as generic error messages... 199390792Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 199490792Sgshapirodnl that would make a lot of things easier. 199564562SgshapiroR<$={Accept}> <$*> $: @ $2 mark address as no match 199690792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 199790792SgshapiroR<SKIP> <$*> $: @ $1 mark address as no match', `dnl') 199890792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl 199990792Sgshapirodnl compatility with 8.11/8.10: 200064562Sgshapirodnl we have to filter these because otherwise they would be interpreted 200164562Sgshapirodnl as generic error message... 200264562Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 200364562Sgshapirodnl that would make a lot of things easier. 200464562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)? 200564562SgshapiroR<$={SpamTag}> <$*> $: @ $2 mark address as no match') 200690792SgshapiroR<REJECT> $* $#error $@ 5.2.1 $: confRCPTREJ_MSG 200764562SgshapiroR<DISCARD> $* $#discard $: discard 200890792Sgshapiroifdef(`_FFR_QUARANTINE', 200990792Sgshapiro`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 201064562Sgshapirodnl error tag 201164562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 201264562SgshapiroR<ERROR:$+> $* $#error $: $1 201390792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 201464562Sgshapirodnl generic error from access map 201564562SgshapiroR<$+> $* $#error $: $1 error from access db 201664562SgshapiroR@ $* $1 remove mark', `dnl')', `dnl') 201738032Speter 201890792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 201990792Sgshapiro# authenticated via TLS? 202090792SgshapiroR$* $: $1 $| $>RelayTLS client authenticated? 202190792SgshapiroR$* $| $# $+ $# $2 error/ok? 202290792SgshapiroR$* $| $* $: $1 no 202364562Sgshapiro 202490792SgshapiroR$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type} 202590792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth 202690792SgshapiroR$* $| $# $* $# $2 202790792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech} 202890792SgshapiroR$* $| NO $: $1 202990792SgshapiroR$* $| $* $: $1 $| $&{auth_type} 203090792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ] 203164562Sgshapirodnl empty ${auth_type}? 203264562SgshapiroR$* $| $: $1 203364562Sgshapirodnl mechanism ${auth_type} accepted? 203464562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below 203590792SgshapiroR$* $| $={TrustAuthMech} $# RELAY 203690792Sgshapirodnl remove ${auth_type} 203764562SgshapiroR$* $| $* $: $1 203871345Sgshapirodnl workspace: localpart<@domain> | localpart 203964562Sgshapiroifelse(defn(`_NO_UUCP_'), `r', 204071345Sgshapiro`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 204171345SgshapiroR$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 204238032Speter# anything terminating locally is ok 204338032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 204490792SgshapiroR$+ < @ $* $=m > $@ RELAY', `dnl') 204590792SgshapiroR$+ < @ $=w > $@ RELAY 204638032Speterifdef(`_RELAY_HOSTS_ONLY_', 204790792Sgshapiro`R$+ < @ $=R > $@ RELAY 204864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 204964562SgshapiroR$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 205064562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 205164562SgshapiroR<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 205290792Sgshapiro`R$+ < @ $* $=R > $@ RELAY 205364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 205490792SgshapiroR$+ < @ $+ > $: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')') 205564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 205664562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 205790792SgshapiroR<RELAY> $* $@ RELAY 205890792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 205938032SpeterR<$*> <$*> $: $2',`dnl') 206038032Speter 206164562Sgshapiro 206238032Speterifdef(`_RELAY_MX_SERVED_', `dnl 206338032Speter# allow relaying for hosts which we MX serve 206464562SgshapiroR$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 206564562Sgshapirodnl this must not necessarily happen if the client is checked first... 206690792SgshapiroR< : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 206790792SgshapiroR<$* : $=w . : $*> $* $@ RELAY 206842575SpeterR< : $* : > $* $: $2', 206938032Speter`dnl') 207038032Speter 207138032Speter# check for local user (i.e. unqualified address) 207238032SpeterR$* $: <?> $1 207342575SpeterR<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 207438032Speter# local user is ok 207564562Sgshapirodnl is it really? the standard requires user@domain, not just user 207664562Sgshapirodnl but we should accept it anyway (maybe making it an option: 207764562Sgshapirodnl RequireFQDN ?) 207864562Sgshapirodnl postmaster must be accepted without domain (DRUMS) 207964562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 208090792SgshapiroR<?> postmaster $@ OK 208164562Sgshapiro# require qualified recipient? 208264562Sgshapirodnl prepend daemon_flags 208364562SgshapiroR<?> $+ $: $&{daemon_flags} $| <?> $1 208464562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart 208564562Sgshapirodnl do not allow these at all or only from local systems? 208664562Sgshapirodnl r flag? add client_name 208764562SgshapiroR$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 208864562Sgshapirodnl no r flag: relay to local user (only local part) 208964562Sgshapiro# no qualified recipient required 209090792SgshapiroR$* $| <?> $+ $@ RELAY 209164562Sgshapirodnl client_name is empty 209290792SgshapiroR<?> <?> $+ $@ RELAY 209364562Sgshapirodnl client_name is local 209490792SgshapiroR<? $=w> <?> $+ $@ RELAY 209564562Sgshapirodnl client_name is not local 209664562SgshapiroR<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 209764562Sgshapirodnl no qualified recipient required 209890792SgshapiroR<?> $+ $@ RELAY') 209964562Sgshapirodnl it is a remote user: remove mark and then check client 210038032SpeterR<$+> $* $: $2 210164562Sgshapirodnl currently the recipient address is not used below 210238032Speter 210390792Sgshapiro###################################################################### 210490792Sgshapiro### Relay_ok: is the relay/sender ok? 210590792Sgshapirodnl input: ignored 210690792Sgshapirodnl output: see explanation at call 210790792Sgshapiro###################################################################### 210890792SgshapiroSRelay_ok 210938032Speter# anything originating locally is ok 211064562Sgshapiro# check IP address 211164562SgshapiroR$* $: $&{client_addr} 211290792SgshapiroR$@ $@ RELAY originated locally 211390792SgshapiroR0 $@ RELAY originated locally 2114110560SgshapiroR127.0.0.1 $@ RELAY originated locally 2115110560SgshapiroRIPv6:::1 $@ RELAY originated locally 211690792SgshapiroR$=R $* $@ RELAY relayable IP address 211764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 211890792SgshapiroR$* $: $>A <$1> <?> <+ Connect> <$1> 211990792SgshapiroR<RELAY> $* $@ RELAY relayable IP address 2120102528Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl 2121102528Sgshapirodnl this will cause rejections in cases like: 2122102528Sgshapirodnl Connect:My.Host.Domain RELAY 2123102528Sgshapirodnl Connect:My.Net REJECT 2124102528Sgshapirodnl since in check_relay client_name is checked before client_addr 2125102528SgshapiroR<REJECT> $* $@ REJECT rejected IP address') 212690792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 212764562SgshapiroR<$*> <$*> $: $2', `dnl') 212864562SgshapiroR$* $: [ $1 ] put brackets around it... 212990792SgshapiroR$=w $@ RELAY ... and see if it is local 213064562Sgshapiro 213164562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 213264562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 213364562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl 213464562Sgshapirodnl input: {client_addr} or something "broken" 213564562Sgshapirodnl just throw the input away; we do not need it. 213664562Sgshapiro# check whether FROM is allowed to use system as relay 213764562SgshapiroR$* $: <?> $>CanonAddr $&f 213890792SgshapiroR<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 213964562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl 214064562Sgshapiro# check whether local FROM is ok 214190792SgshapiroR<?> $+ < @ $=w > $@ RELAY FROM local', `dnl') 214264562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl 214394334SgshapiroR<?> $+ < @ $+ > $: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <> 214490792SgshapiroR<@> <RELAY> $@ RELAY RELAY FROM sender ok 214590792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 214690792Sgshapiro', `dnl 214790792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', 214890792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 214964562Sgshapiro')', 215064562Sgshapiro`dnl') 215164562Sgshapirodnl')', `dnl') 215290792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind. 215390792Sgshapirodnl it does not matter in this case because the following rule ignores 215490792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace. 215564562Sgshapiro 215664562Sgshapiro# check client name: first: did it resolve? 215764562Sgshapirodnl input: ignored 215864562SgshapiroR$* $: < $&{client_resolve} > 215990792SgshapiroR<TEMP> $#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 216064562SgshapiroR<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 216164562SgshapiroR<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 216264562Sgshapirodnl ${client_resolve} should be OK, so go ahead 216390792SgshapiroR$* $: <@> $&{client_name} 216490792Sgshapirodnl should not be necessary since it has been done for client_addr already 2165110560Sgshapirodnl this rule actually may cause a problem if {client_name} resolves to "" 2166110560Sgshapirodnl however, this should not happen since the forward lookup should fail 2167110560Sgshapirodnl and {client_resolve} should be TEMP or FAIL. 2168110560Sgshapirodnl nevertheless, removing the rule doesn't hurt. 2169110560Sgshapirodnl R<@> $@ RELAY 217090792Sgshapirodnl workspace: <@> ${client_name} (not empty) 217138032Speter# pass to name server to make hostname canonical 217290792SgshapiroR<@> $* $=P $:<?> $1 $2 217390792SgshapiroR<@> $+ $:<?> $[ $1 $] 217490792Sgshapirodnl workspace: <?> ${client_name} (canonified) 217564562SgshapiroR$* . $1 strip trailing dots 217638032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 217790792SgshapiroR<?> $* $=m $@ RELAY', `dnl') 217890792SgshapiroR<?> $=w $@ RELAY 217938032Speterifdef(`_RELAY_HOSTS_ONLY_', 218090792Sgshapiro`R<?> $=R $@ RELAY 218164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 218264562SgshapiroR<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 218364562SgshapiroR<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 218490792Sgshapiro`R<?> $* $=R $@ RELAY 218564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 218690792SgshapiroR<?> $* $: $>D <$1> <?> <+ Connect> <$1>',`dnl')') 218764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 218890792SgshapiroR<RELAY> $* $@ RELAY 218990792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 219038032SpeterR<$*> <$*> $: $2',`dnl') 219190792Sgshapirodnl end of _PROMISCUOUS_RELAY_ 219264562Sgshapirodivert(0) 219364562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 219464562Sgshapiro# turn a canonical address in the form user<@domain> 219564562Sgshapiro# qualify unqual. addresses with $j 219664562Sgshapirodnl it might have been only user (without <@domain>) 219764562SgshapiroSFullAddr 219864562SgshapiroR$* <@ $+ . > $1 <@ $2 > 219964562SgshapiroR$* <@ $* > $@ $1 <@ $2 > 220064562SgshapiroR$+ $@ $1 <@ $j > 220138032Speter 2202120256SgshapiroSDelay_TLS_Clt 2203110560Sgshapiro# authenticated? 2204110560Sgshapirodnl code repeated here from Basic_check_mail 2205110560Sgshapirodnl only called from check_rcpt in delay mode if checkrcpt returns $# 2206110560SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 2207110560SgshapiroR$* $| $#$+ $#$2 2208110560Sgshapirodnl return result from checkrcpt 2209120256SgshapiroR$* $| $* $# $1 2210110560SgshapiroR$* $# $1 2211110560Sgshapiro 2212120256SgshapiroSDelay_TLS_Clt2 2213110560Sgshapiro# authenticated? 2214110560Sgshapirodnl code repeated here from Basic_check_mail 2215110560Sgshapirodnl only called from check_rcpt in delay mode if stopping due to Friend/Hater 2216110560SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 2217110560SgshapiroR$* $| $#$+ $#$2 2218110560Sgshapirodnl return result from friend/hater check 2219120256SgshapiroR$* $| $* $@ $1 2220110560SgshapiroR$* $@ $1 2221110560Sgshapiro 222264562Sgshapiro# call all necessary rulesets 222364562SgshapiroScheck_rcpt 222464562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset 222564562Sgshapirodnl which is the correct DSN code? 222664562Sgshapiro# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 2227110560Sgshapiro 222864562SgshapiroR$+ $: $1 $| $>checkrcpt $1 222964562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 2230110560Sgshapirodnl on error (or discard) stop now 2231110560SgshapiroR$+ $| $#error $* $#error $2 2232110560SgshapiroR$+ $| $#discard $* $#discard $2 2233110560Sgshapirodnl otherwise call tls_client; see above 2234120256SgshapiroR$+ $| $#$* $@ $>"Delay_TLS_Clt" $2 223564562SgshapiroR$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 223664562Sgshapiroifdef(`_SPAM_FH_', 223764562Sgshapiro`dnl lookup user@ and user@address 223864562Sgshapiroifdef(`_ACCESS_TABLE_', `', 223964562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 224064562Sgshapiro')')dnl 224164562Sgshapirodnl one of the next two rules is supposed to match 224264562Sgshapirodnl this code has been copied from BLACKLIST... etc 224364562Sgshapirodnl and simplified by omitting some < >. 224490792SgshapiroR<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@> 224590792SgshapiroR<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > 224664562Sgshapirodnl R<?> $@ something_is_very_wrong_here 224790792Sgshapiro# lookup the addresses only with Spam tag 224890792SgshapiroR<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <> 224964562SgshapiroR<@> $* $| $* $: $2 $1 reverse result 225064562Sgshapirodnl', `dnl') 225164562Sgshapiroifdef(`_SPAM_FRIEND_', 225264562Sgshapiro`# is the recipient a spam friend? 225364562Sgshapiroifdef(`_SPAM_HATER_', 2254110560Sgshapiro `errprint(`*** ERROR: define either Hater or Friend -- not both. 225564562Sgshapiro')', `dnl') 2256120256SgshapiroR<FRIEND> $+ $@ $>"Delay_TLS_Clt2" SPAMFRIEND 225764562SgshapiroR<$*> $+ $: $2', 225864562Sgshapiro`dnl') 225964562Sgshapiroifdef(`_SPAM_HATER_', 226064562Sgshapiro`# is the recipient no spam hater? 226190792SgshapiroR<HATER> $+ $: $1 spam hater: continue checks 2262120256SgshapiroR<$*> $+ $@ $>"Delay_TLS_Clt2" NOSPAMHATER everyone else: stop 226364562Sgshapirodnl',`dnl') 226464562Sgshapirodnl run further checks: check_mail 226564562Sgshapirodnl should we "clean up" $&f? 226690792Sgshapiroifdef(`_FFR_MAIL_MACRO', 226790792Sgshapiro`R$* $: $1 $| $>checkmail $&{mail_from}', 226890792Sgshapiro`R$* $: $1 $| $>checkmail <$&f>') 226994334Sgshapirodnl recipient (canonical format) $| result of checkmail 227064562SgshapiroR$* $| $#$* $#$2 227164562Sgshapirodnl run further checks: check_relay 227294334SgshapiroR$* $| $* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 227364562SgshapiroR$* $| $#$* $#$2 227438032SpeterR$* $| $* $: $1 227538032Speter', `dnl') 227690792Sgshapiro 227790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 227864562Sgshapiro###################################################################### 227990792Sgshapiro### F: LookUpFull -- search for an entry in access database 228090792Sgshapiro### 228190792Sgshapiro### lookup of full key (which should be an address) and 228290792Sgshapiro### variations if +detail exists: +* and without +detail 228390792Sgshapiro### 228490792Sgshapiro### Parameters: 228590792Sgshapiro### <$1> -- key 228690792Sgshapiro### <$2> -- default (what to return if not found in db) 228790792Sgshapirodnl must not be empty 228890792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 228990792Sgshapiro### ! does lookup only with tag 229090792Sgshapiro### + does lookup with and without tag 229190792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 229290792Sgshapirodnl returns: <default> <passthru> 229390792Sgshapirodnl <result> <passthru> 229490792Sgshapiro###################################################################### 229590792Sgshapiro 229690792SgshapiroSF 229790792Sgshapirodnl workspace: <key> <def> <o tag> <thru> 229890792Sgshapirodnl full lookup 229990792Sgshapirodnl 2 3 4 5 230090792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 230190792Sgshapirodnl no match, try without tag 230290792Sgshapirodnl 1 2 3 4 230390792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 230490792Sgshapirodnl no match, +detail: try +* 230590792Sgshapirodnl 1 2 3 4 5 6 7 230690792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 230790792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 230890792Sgshapirodnl no match, +detail: try +* without tag 230990792Sgshapirodnl 1 2 3 4 5 6 231090792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 231190792Sgshapiro $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 231290792Sgshapirodnl no match, +detail: try without +detail 231390792Sgshapirodnl 1 2 3 4 5 6 7 231490792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 231590792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 231690792Sgshapirodnl no match, +detail: try without +detail and without tag 231790792Sgshapirodnl 1 2 3 4 5 6 231890792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 231990792Sgshapiro $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 232090792Sgshapirodnl no match, return <default> <passthru> 232190792Sgshapirodnl 1 2 3 4 5 232290792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 232390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 232490792Sgshapirodnl 2 3 4 5 232590792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 232690792Sgshapirodnl match, return <match> <passthru> 232790792Sgshapirodnl 2 3 4 5 232890792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 232990792Sgshapiro 233090792Sgshapiro###################################################################### 233190792Sgshapiro### E: LookUpExact -- search for an entry in access database 233290792Sgshapiro### 233390792Sgshapiro### Parameters: 233490792Sgshapiro### <$1> -- key 233590792Sgshapiro### <$2> -- default (what to return if not found in db) 233690792Sgshapirodnl must not be empty 233790792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 233890792Sgshapiro### ! does lookup only with tag 233990792Sgshapiro### + does lookup with and without tag 234090792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 234190792Sgshapirodnl returns: <default> <passthru> 234290792Sgshapirodnl <result> <passthru> 234390792Sgshapiro###################################################################### 234490792Sgshapiro 234590792SgshapiroSE 234690792Sgshapirodnl 2 3 4 5 234790792SgshapiroR<$*> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 234890792Sgshapirodnl no match, try without tag 234990792Sgshapirodnl 1 2 3 4 235090792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 235190792Sgshapirodnl no match, return default passthru 235290792Sgshapirodnl 1 2 3 4 5 235390792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 235490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 235590792Sgshapirodnl 2 3 4 5 235690792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 235790792Sgshapirodnl match, return <match> <passthru> 235890792Sgshapirodnl 2 3 4 5 235990792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 236090792Sgshapiro 236190792Sgshapiro###################################################################### 236290792Sgshapiro### U: LookUpUser -- search for an entry in access database 236390792Sgshapiro### 236490792Sgshapiro### lookup of key (which should be a local part) and 236590792Sgshapiro### variations if +detail exists: +* and without +detail 236690792Sgshapiro### 236790792Sgshapiro### Parameters: 236890792Sgshapiro### <$1> -- key (user@) 236990792Sgshapiro### <$2> -- default (what to return if not found in db) 237090792Sgshapirodnl must not be empty 237190792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 237290792Sgshapiro### ! does lookup only with tag 237390792Sgshapiro### + does lookup with and without tag 237490792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 237590792Sgshapirodnl returns: <default> <passthru> 237690792Sgshapirodnl <result> <passthru> 237790792Sgshapiro###################################################################### 237890792Sgshapiro 237990792SgshapiroSU 238090792Sgshapirodnl user lookups are always with trailing @ 238190792Sgshapirodnl 2 3 4 5 238290792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 238390792Sgshapirodnl no match, try without tag 238490792Sgshapirodnl 1 2 3 4 238590792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 238690792Sgshapirodnl do not remove the @ from the lookup: 238790792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup 238890792Sgshapirodnl no match, +detail: try +* 238990792Sgshapirodnl 1 2 3 4 5 6 239090792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 239190792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 239290792Sgshapirodnl no match, +detail: try +* without tag 239390792Sgshapirodnl 1 2 3 4 5 239490792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 239590792Sgshapiro $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 239690792Sgshapirodnl no match, +detail: try without +detail 239790792Sgshapirodnl 1 2 3 4 5 6 239890792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 239990792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 240090792Sgshapirodnl no match, +detail: try without +detail and without tag 240190792Sgshapirodnl 1 2 3 4 5 240290792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 240390792Sgshapiro $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 240490792Sgshapirodnl no match, return <default> <passthru> 240590792Sgshapirodnl 1 2 3 4 5 240690792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 240790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 240890792Sgshapirodnl 2 3 4 5 240990792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 241090792Sgshapirodnl match, return <match> <passthru> 241190792Sgshapirodnl 2 3 4 5 241290792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 241390792Sgshapiro 241490792Sgshapiro###################################################################### 241564562Sgshapiro### SearchList: search a list of items in the access map 241664562Sgshapiro### Parameters: 241764562Sgshapiro### <exact tag> $| <mark:address> <mark:address> ... <> 241864562Sgshapirodnl maybe we should have a @ (again) in front of the mark to 241964562Sgshapirodnl avoid errorneous matches (with error messages?) 242064562Sgshapirodnl if we can make sure that tag is always a single token 242164562Sgshapirodnl then we can omit the delimiter $|, otherwise we need it 242290792Sgshapirodnl to avoid errorneous matchs (first rule: D: if there 242364562Sgshapirodnl is that mark somewhere in the list, it will be taken). 242464562Sgshapirodnl moreover, we can do some tricks to enforce lookup with 242564562Sgshapirodnl the tag only, e.g.: 242664562Sgshapiro### where "exact" is either "+" or "!": 242764562Sgshapiro### <+ TAG> lookup with and w/o tag 242864562Sgshapiro### <! TAG> lookup with tag 242964562Sgshapirodnl Warning: + and ! should be in OperatorChars (otherwise there must be 243064562Sgshapirodnl a blank between them and the tag. 243164562Sgshapiro### possible values for "mark" are: 243290792Sgshapiro### D: recursive host lookup (LookUpDomain) 243364562Sgshapirodnl A: recursive address lookup (LookUpAddress) [not yet required] 243464562Sgshapiro### E: exact lookup, no modifications 243564562Sgshapiro### F: full lookup, try user+ext@domain and user@domain 243664562Sgshapiro### U: user lookup, try user+ext and user (input must have trailing @) 243764562Sgshapiro### return: <RHS of lookup> or <?> (not found) 243864562Sgshapiro###################################################################### 243938032Speter 244064562Sgshapiro# class with valid marks for SearchList 244164562Sgshapirodnl if A is activated: add it 244290792SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A') 244364562SgshapiroSSearchList 244490792Sgshapiro# just call the ruleset with the name of the tag... nice trick... 244590792Sgshapirodnl 2 3 4 244690792SgshapiroR<$+> $| <$={src}:$*> <$*> $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <> 244790792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <> 244890792Sgshapirodnl no match and nothing left: return 244990792SgshapiroR<$+> $| <> $| <?> <> $@ <?> 245090792Sgshapirodnl no match but something left: continue 245190792SgshapiroR<$+> $| <$+> $| <?> <> $@ $>SearchList <$1> $| <$2> 245290792Sgshapirodnl match: return 245390792SgshapiroR<$+> $| <$*> $| <$+> <> $@ <$3> 245464562Sgshapirodnl return result from recursive invocation 245590792SgshapiroR<$+> $| <$+> $@ <$2> 245690792Sgshapirodnl endif _ACCESS_TABLE_ 245790792Sgshapirodivert(0) 245838032Speter 245990792Sgshapiro###################################################################### 246090792Sgshapiro### trust_auth: is user trusted to authenticate as someone else? 246190792Sgshapiro### 246290792Sgshapiro### Parameters: 246390792Sgshapiro### $1: AUTH= parameter from MAIL command 246490792Sgshapiro###################################################################### 246590792Sgshapiro 246690792Sgshapirodnl empty ruleset definition so it can be called 246790792SgshapiroSLocal_trust_auth 246864562SgshapiroStrust_auth 246964562SgshapiroR$* $: $&{auth_type} $| $1 247064562Sgshapiro# required by RFC 2554 section 4. 247164562SgshapiroR$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 247264562Sgshapirodnl seems to be useful... 247364562SgshapiroR$* $| $&{auth_authen} $@ identical 247464562SgshapiroR$* $| <$&{auth_authen}> $@ identical 247564562Sgshapirodnl call user supplied code 2476120256SgshapiroR$* $| $* $: $1 $| $>"Local_trust_auth" $2 247764562SgshapiroR$* $| $#$* $#$2 247864562Sgshapirodnl default: error 247964562SgshapiroR$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 248064562Sgshapiro 248190792Sgshapiro###################################################################### 248290792Sgshapiro### Relay_Auth: allow relaying based on authentication? 248390792Sgshapiro### 248490792Sgshapiro### Parameters: 248590792Sgshapiro### $1: ${auth_type} 248690792Sgshapiro###################################################################### 248790792SgshapiroSLocal_Relay_Auth 248864562Sgshapiro 248990792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 249090792Sgshapiro###################################################################### 249190792Sgshapiro### srv_features: which features to offer to a client? 249290792Sgshapiro### (done in server) 249390792Sgshapiro###################################################################### 249490792SgshapiroSsrv_features 249590792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl 249690792SgshapiroR$* $: $1 $| $>"Local_srv_features" $1 249790792SgshapiroR$* $| $#$* $#$2 249890792SgshapiroR$* $| $* $: $1', `dnl') 249990792SgshapiroR$* $: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <> 250090792SgshapiroR<?>$* $: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <> 250190792SgshapiroR<?>$* $: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)> 250264562SgshapiroR<?>$* $@ OK 250390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 250490792SgshapiroR<$* _ATMPF_>$* $#temp', `dnl') 250590792SgshapiroR<$+>$* $# $1 250664562Sgshapiro 250790792Sgshapiro###################################################################### 250890792Sgshapiro### try_tls: try to use STARTTLS? 250990792Sgshapiro### (done in client) 251090792Sgshapiro###################################################################### 251164562SgshapiroStry_tls 251290792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl 251390792SgshapiroR$* $: $1 $| $>"Local_try_tls" $1 251490792SgshapiroR$* $| $#$* $#$2 251590792SgshapiroR$* $| $* $: $1', `dnl') 251690792SgshapiroR$* $: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <> 251790792SgshapiroR<?>$* $: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <> 251890792SgshapiroR<?>$* $: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)> 251964562SgshapiroR<?>$* $@ OK 252090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 252190792SgshapiroR<$* _ATMPF_>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 252271345SgshapiroR<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 2523102528Sgshapiro 252490792Sgshapiro###################################################################### 252590792Sgshapiro### tls_rcpt: is connection with server "good" enough? 252690792Sgshapiro### (done in client, per recipient) 252790792Sgshapirodnl called from deliver() before RCPT command 252890792Sgshapiro### 252990792Sgshapiro### Parameters: 253090792Sgshapiro### $1: recipient 253190792Sgshapiro###################################################################### 253290792SgshapiroStls_rcpt 253390792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl 253490792SgshapiroR$* $: $1 $| $>"Local_tls_rcpt" $1 253590792SgshapiroR$* $| $#$* $#$2 253690792SgshapiroR$* $| $* $: $1', `dnl') 253790792Sgshapirodnl store name of other side 253890792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 253990792Sgshapirodnl canonify recipient address 254090792SgshapiroR$+ $: <?> $>CanonAddr $1 254190792Sgshapirodnl strip trailing dots 254290792SgshapiroR<?> $+ < @ $+ . > <?> $1 <@ $2 > 254390792Sgshapirodnl full address? 254490792SgshapiroR<?> $+ < @ $+ > $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:> 254590792Sgshapirodnl only localpart? 254690792SgshapiroR<?> $+ $: $1 $| <U:$1@> <E:> 254790792Sgshapirodnl look it up 254890792Sgshapirodnl also look up a default value via E: 254990792SgshapiroR$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <> 255090792Sgshapirodnl found nothing: stop here 255190792SgshapiroR$* $| <?> $@ OK 255290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 255390792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 255490792Sgshapirodnl use the generic routine (for now) 255590792SgshapiroR$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>') 255664562Sgshapiro 255790792Sgshapiro###################################################################### 255890792Sgshapiro### tls_client: is connection with client "good" enough? 255990792Sgshapiro### (done in server) 256090792Sgshapiro### 256190792Sgshapiro### Parameters: 256290792Sgshapiro### ${verify} $| (MAIL|STARTTLS) 256390792Sgshapiro###################################################################### 256464562Sgshapirodnl MAIL: called from check_mail 256564562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted 256664562SgshapiroStls_client 256790792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl 256890792SgshapiroR$* $: $1 $| $>"Local_tls_client" $1 256990792SgshapiroR$* $| $#$* $#$2 257090792SgshapiroR$* $| $* $: $1', `dnl') 257164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 257290792Sgshapirodnl store name of other side 257390792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 257464562Sgshapirodnl ignore second arg for now 257564562Sgshapirodnl maybe use it to distinguish permanent/temporary error? 257664562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered) 257764562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed) 257890792SgshapiroR$* $| $* $: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <> 257990792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <> 258064562Sgshapirodnl do a default lookup: just TLS_CLT_TAG 258164562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 258290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 258390792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 258490792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 258590792SgshapiroR$* $| $* $@ $>"TLS_connection" $1') 258664562Sgshapiro 258790792Sgshapiro###################################################################### 258890792Sgshapiro### tls_server: is connection with server "good" enough? 258990792Sgshapiro### (done in client) 259090792Sgshapiro### 259190792Sgshapiro### Parameter: 259290792Sgshapiro### ${verify} 259390792Sgshapiro###################################################################### 259464562Sgshapirodnl i.e. has the server been authenticated and is encryption active? 259564562Sgshapirodnl called from deliver() after STARTTLS command 259664562SgshapiroStls_server 259790792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl 259890792SgshapiroR$* $: $1 $| $>"Local_tls_server" $1 259990792SgshapiroR$* $| $#$* $#$2 260090792SgshapiroR$* $| $* $: $1', `dnl') 260164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 260290792Sgshapirodnl store name of other side 260390792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 260490792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <> 260590792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <> 260664562Sgshapirodnl do a default lookup: just TLS_SRV_TAG 260764562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 260890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 260990792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 261090792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 261190792SgshapiroR$* $@ $>"TLS_connection" $1') 261264562Sgshapiro 261390792Sgshapiro###################################################################### 261490792Sgshapiro### TLS_connection: is TLS connection "good" enough? 261590792Sgshapiro### 261690792Sgshapiro### Parameters: 261764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 261890792Sgshapiro### ${verify} $| <Requirement> [<>]', `dnl 261990792Sgshapiro### ${verify}') 262090792Sgshapiro### Requirement: RHS from access map, may be ? for none. 262190792Sgshapirodnl syntax for Requirement: 262290792Sgshapirodnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions] 262390792Sgshapirodnl extensions: could be a list of further requirements 262490792Sgshapirodnl for now: CN:string {cn_subject} == string 262590792Sgshapiro###################################################################### 262690792SgshapiroSTLS_connection 262790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error 262890792Sgshapirodnl deal with TLS handshake failures: abort 262990792SgshapiroRSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake." 263090792Sgshapirodivert(-1)') 263164562Sgshapirodnl common ruleset for tls_{client|server} 263290792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>] 263364562Sgshapirodnl remove optional <> 263464562SgshapiroR$* $| <$*>$* $: $1 $| <$2> 263590792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup> 263690792Sgshapiro# create the appropriate error codes 263764562Sgshapirodnl permanent or temporary error? 263864562SgshapiroR$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 263964562SgshapiroR$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 264064562Sgshapirodnl default case depends on TLS_PERM_ERR 264164562SgshapiroR$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 264290792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup> 264390792Sgshapiro# deal with TLS handshake failures: abort 264464562SgshapiroRSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 264564562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 264664562Sgshapirodnl use default error 264764562SgshapiroRSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 264890792SgshapiroR$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1 264990792Sgshapirodnl separate optional requirements 265090792SgshapiroR$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1 265190792SgshapiroR$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> <> $1 265290792Sgshapirodnl separate optional requirements 265390792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$* $: <$2> <$3:$4> <$5> $1 265464562Sgshapirodnl some other value in access map: accept 265564562Sgshapirodnl this also allows to override the default case (if used) 265664562SgshapiroR$* $| $* $@ OK 265764562Sgshapiro# authentication required: give appropriate error 265864562Sgshapiro# other side did authenticate (via STARTTLS) 265990792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify} 266064562Sgshapirodnl only verification required and it succeeded 266190792SgshapiroR<$*><VERIFY> <> OK $@ OK 266290792Sgshapirodnl verification required and it succeeded but extensions are given 266390792Sgshapirodnl change it to <SMTP:ESC> <REQ:0> <extensions> 266490792SgshapiroR<$*><VERIFY> <$+> OK $: <$1> <REQ:0> <$2> 266564562Sgshapirodnl verification required + some level of encryption 266690792SgshapiroR<$*><VERIFY:$-> <$*> OK $: <$1> <REQ:$2> <$3> 266764562Sgshapirodnl just some level of encryption required 266890792SgshapiroR<$*><ENCR:$-> <$*> $* $: <$1> <REQ:$2> <$3> 266990792Sgshapirodnl workspace: 267090792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]> <[extensions]> {verify} (!= OK) 267190792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits> <[extensions]> 267290792Sgshapirodnl verification required but ${verify} is not set (case 1.) 267390792SgshapiroR<$-:$+><VERIFY $*> <$*> $#error $@ $2 $: $1 " authentication required" 267490792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL $#error $@ $2 $: $1 " authentication failed" 267590792SgshapiroR<$-:$+><VERIFY $*> <$*> NO $#error $@ $2 $: $1 " not authenticated" 267690792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT $#error $@ $2 $: $1 " no authentication requested" 267790792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 267864562Sgshapirodnl some other value for ${verify} 267990792SgshapiroR<$-:$+><VERIFY $*> <$*> $+ $#error $@ $2 $: $1 " authentication failure " $4 268090792Sgshapirodnl some level of encryption required: get the maximum level (case 2.) 268190792SgshapiroR<$*><REQ:$-> <$*> $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf} 268264562Sgshapirodnl compare required bits with actual bits 268390792SgshapiroR<$*><REQ:$-> <$*> $- $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $) 268490792SgshapiroR<$-:$+><$-:$-> <$*> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 268590792Sgshapirodnl strength requirements fulfilled 268690792Sgshapirodnl TLS Additional Requirements Separator 268790792Sgshapirodnl this should be something which does not appear in the extensions itself 268890792Sgshapirodnl @ could be part of a CN, DN, etc... 268990792Sgshapirodnl use < > ? those are encoded in CN, DN, ... 269090792Sgshapirodefine(`_TLS_ARS_', `++')dnl 269190792Sgshapirodnl workspace: 269290792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare 269390792SgshapiroR<$-:$+><$-:$-> <$*> $* $: <$1:$2 _TLS_ARS_ $5> 269490792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions> 269590792Sgshapirodnl continue: check extensions 269690792SgshapiroR<$-:$+ _TLS_ARS_ > $@ OK 269790792Sgshapirodnl split extensions into own list 269890792SgshapiroR<$-:$+ _TLS_ARS_ $+ > $: <$1:$2> <$3> 269990792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ > <$1:$2> <$3> <$4> 270090792SgshapiroR<$-:$+> $+ $@ $>"TLS_req" $3 $| <$1:$2> 270164562Sgshapiro 270290792Sgshapiro###################################################################### 270390792Sgshapiro### TLS_req: check additional TLS requirements 270490792Sgshapiro### 270590792Sgshapiro### Parameters: [<list> <of> <req>] $| <$-:$+> 270690792Sgshapiro### $-: SMTP reply code 270790792Sgshapiro### $+: Enhanced Status Code 270890792Sgshapirodnl further requirements for this ruleset: 270990792Sgshapirodnl name of "other side" is stored is {TLS_name} (client/server_name) 271090792Sgshapirodnl 271190792Sgshapirodnl currently only CN[:common_name] is implemented 271290792Sgshapirodnl right now this is only a logical AND 271390792Sgshapirodnl i.e. all requirements must be true 271490792Sgshapirodnl how about an OR? CN must be X or CN must be Y or .. 271590792Sgshapirodnl use a macro to compute this as a trivial sequential 271690792Sgshapirodnl operations (no precedences etc)? 271790792Sgshapiro###################################################################### 271890792SgshapiroSTLS_req 271990792Sgshapirodnl no additional requirements: ok 272090792SgshapiroR $| $+ $@ OK 272190792Sgshapirodnl require CN: but no CN specified: use name of other side 272290792SgshapiroR<CN> $* $| <$+> $: <CN:$&{TLS_Name}> $1 $| <$2> 272390792Sgshapirodnl match, check rest 272490792SgshapiroR<CN:$&{cn_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 272590792Sgshapirodnl CN does not match 272690792Sgshapirodnl 1 2 3 4 272790792SgshapiroR<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1 272890792Sgshapirodnl cert subject 272990792SgshapiroR<CS:$&{cert_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 273090792Sgshapirodnl CS does not match 273190792Sgshapirodnl 1 2 3 4 2732110560SgshapiroR<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1 273390792Sgshapirodnl match, check rest 273490792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 273590792Sgshapirodnl CI does not match 273690792Sgshapirodnl 1 2 3 4 2737110560SgshapiroR<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1 273890792Sgshapirodnl return from recursive call 273990792SgshapiroROK $@ OK 274090792Sgshapiro 274190792Sgshapiro###################################################################### 274290792Sgshapiro### max: return the maximum of two values separated by : 274390792Sgshapiro### 274490792Sgshapiro### Parameters: [$-]:[$-] 274590792Sgshapiro###################################################################### 274664562SgshapiroSmax 274764562SgshapiroR: $: 0 274864562SgshapiroR:$- $: $1 274964562SgshapiroR$-: $: $1 275064562SgshapiroR$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 275164562SgshapiroRTRUE:$-:$- $: $2 275290792SgshapiroR$-:$-:$- $: $2 275390792Sgshapirodnl endif _ACCESS_TABLE_ 275490792Sgshapirodivert(0) 275564562Sgshapiro 275690792Sgshapiro###################################################################### 275790792Sgshapiro### RelayTLS: allow relaying based on TLS authentication 275890792Sgshapiro### 275990792Sgshapiro### Parameters: 276090792Sgshapiro### none 276190792Sgshapiro###################################################################### 276290792SgshapiroSRelayTLS 276364562Sgshapiro# authenticated? 276464562Sgshapirodnl we do not allow relaying for anyone who can present a cert 276564562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns 2766110560Sgshapirodnl CA in CertPath so we can authenticate users, we do not allow 276764562Sgshapirodnl them to abuse our server (they might be easier to get hold of, 276864562Sgshapirodnl but anyway). 276964562Sgshapirodnl so here is the trick: if the verification succeeded 277064562Sgshapirodnl we look up the cert issuer in the access map 277164562Sgshapirodnl (maybe after extracting a part with a regular expression) 277264562Sgshapirodnl if this returns RELAY we relay without further questions 277364562Sgshapirodnl if it returns SUBJECT we perform a similar check on the 277464562Sgshapirodnl cert subject. 277564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 277690792SgshapiroR$* $: <?> $&{verify} 277790792SgshapiroR<?> OK $: OK authenticated: continue 277890792SgshapiroR<?> $* $@ NO not authenticated 277964562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 278090792SgshapiroR$* $: $(CERTIssuer $&{cert_issuer} $)', 278190792Sgshapiro`R$* $: $&{cert_issuer}') 278290792SgshapiroR$+ $: $(access CERTISSUER`'_TAG_DELIM_`'$1 $) 278364562Sgshapirodnl use $# to stop further checks (delay_check) 278490792SgshapiroRRELAY $# RELAY 278564562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 278690792SgshapiroRSUBJECT $: <@> $(CERTSubject $&{cert_subject} $)', 278790792Sgshapiro`RSUBJECT $: <@> $&{cert_subject}') 278890792SgshapiroR<@> $+ $: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $) 278990792SgshapiroR<@> RELAY $# RELAY 279090792SgshapiroR$* $: NO', `dnl') 279164562Sgshapiro 279290792Sgshapiro###################################################################### 279390792Sgshapiro### authinfo: lookup authinfo in the access map 279490792Sgshapiro### 279590792Sgshapiro### Parameters: 279690792Sgshapiro### $1: {server_name} 279790792Sgshapiro### $2: {server_addr} 279890792Sgshapirodnl both are currently ignored 279990792Sgshapirodnl if it should be done via another map, we either need to restrict 280090792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another 280190792Sgshapirodnl parameter which I want to avoid, it's quite complex already) 280290792Sgshapiro###################################################################### 280390792Sgshapirodnl omit this ruleset if neither is defined? 280490792Sgshapirodnl it causes DefaultAuthInfo to be ignored 280590792Sgshapirodnl (which may be considered a good thing). 280690792SgshapiroSauthinfo 280790792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl 280890792SgshapiroR$* $: <$(authinfo AuthInfo:$&{server_name} $: ? $)> 280990792SgshapiroR<?> $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)> 281090792SgshapiroR<?> $: <$(authinfo AuthInfo: $: ? $)> 281190792SgshapiroR<?> $@ no no authinfo available 281290792SgshapiroR<$*> $# $1 281390792Sgshapirodnl', `dnl 281490792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 281590792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <> 281690792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <> 281790792SgshapiroR$* $| <?>$* $: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <> 281890792SgshapiroR$* $| <?>$* $@ no no authinfo available 281990792SgshapiroR$* $| <$*> <> $# $2 282090792Sgshapirodnl', `dnl')') 282190792Sgshapiro 282264562Sgshapiroundivert(9)dnl LOCAL_RULESETS 282338032Speter# 282438032Speter###################################################################### 282538032Speter###################################################################### 282638032Speter##### 282764562Sgshapiro`##### MAIL FILTER DEFINITIONS' 282864562Sgshapiro##### 282964562Sgshapiro###################################################################### 283064562Sgshapiro###################################################################### 283190792Sgshapiro_MAIL_FILTERS_ 283264562Sgshapiro# 283364562Sgshapiro###################################################################### 283464562Sgshapiro###################################################################### 283564562Sgshapiro##### 283638032Speter`##### MAILER DEFINITIONS' 283738032Speter##### 283838032Speter###################################################################### 283938032Speter###################################################################### 284064562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS 284166494Sgshapiro 2842