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