proto.m4 revision 98121
138032Speterdivert(-1) 238032Speter# 3125820Sgshapiro# Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. 464562Sgshapiro# All rights reserved. 538032Speter# Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. 638032Speter# Copyright (c) 1988, 1993 738032Speter# The Regents of the University of California. All rights reserved. 838032Speter# 938032Speter# By using this file, you agree to the terms and conditions set 1038032Speter# forth in the LICENSE file which can be found at the top level of 1138032Speter# the sendmail distribution. 1238032Speter# 1338032Speter# 1438032Speterdivert(0) 1538032Speter 16141858SgshapiroVERSIONID(`$Id: proto.m4,v 8.646 2002/05/19 21:22:40 gshapiro 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 114125820SgshapiroCP. 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) 14238032SpeterDS`'ifdef(`SMART_HOST', `SMART_HOST') 14390792Sgshapiro 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 15938032Speterifdef(`_ACCESS_TABLE_', `dnl 16064562Sgshapiro# access_db acceptance class 16164562SgshapiroC{Accept}OK RELAY 16264562Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl 16390792Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl 16464562Sgshapiro# possible access_db RHS for spam friends/haters 16564562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')', 16664562Sgshapiro`dnl') 16738032Speter 16838032Speterdnl mark for "domain is ok" (resolved or accepted anyway) 16990792Sgshapirodefine(`_RES_OK_', `OKR')dnl 17090792Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl 17138032Speter# Resolve map (to check if a host exists in check_mail) 17238032SpeterKresolve host -a<_RES_OK_> -T<TEMP>') 17390792SgshapiroC{ResOk}_RES_OK_ 17490792Sgshapiro 17538032Speterifdef(`_NEED_MACRO_MAP_', `dnl 17680785Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map 17780785Sgshapirodefine(`_MACRO_MAP_', `1')dnl 17880785SgshapiroKmacro macro')', `dnl') 17980785Sgshapiro 18066494Sgshapiroifdef(`confCR_FILE', `dnl 18138032Speter# Hosts for which relaying is permitted ($=R) 18266494SgshapiroFR`'confCR_FILE', 18338032Speter`dnl') 18438032Speter 18538032Speterdefine(`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 19090792Sgshapirodnl this may be useful in other contexts too 19164562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map 19264562Sgshapirodefine(`_ARITH_MAP_', `1')dnl 19364562SgshapiroKarith arith') 19464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 19564562Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map 19690792Sgshapirodefine(`_MACRO_MAP_', `1')dnl 19790792SgshapiroKmacro macro') 19890792Sgshapiro# possible values for TLS_connection in access map 19990792SgshapiroC{tls}VERIFY ENCR', `dnl') 200132943Sgshapiroifdef(`_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 20764562Sgshapiroifdef(`LOCAL_RELAY', `dnl 20890792Sgshapiro# who I send unqualified names to (null means deliver locally) 209110647SgshapiroDR`'LOCAL_RELAY') 210110560Sgshapiro 21190792Sgshapiroifdef(`MAIL_HUB', `dnl 21238032Speter# who gets all local email traffic ($R has precedence for unqualified names) 21390792SgshapiroDH`'MAIL_HUB') 214110560Sgshapiro 215110647Sgshapiro# dequoting map 21690792SgshapiroKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `') 21738032Speter 21838032Speterdivert(0)dnl # end of nullclient diversion 21990792Sgshapiro# 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 22238032Speter# class N: domains that should not be converted to $M 22364562Sgshapiro#CL root 22438032Speterundivert(5)dnl 22564562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl') 22638032Speter 22738032Speterifdef(`MASQUERADE_NAME', `dnl 22864562Sgshapiro# who I masquerade as (null for no masquerading) (see also $=M) 22938032SpeterDM`'MASQUERADE_NAME') 23090792Sgshapiro 23138032Speter# my name for error messages 23290792Sgshapiroifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON') 23338032Speter 23438032Speterundivert(6)dnl LOCAL_CONFIG 23538032Speterinclude(_CF_DIR_`m4/version.m4') 23638032Speter 23764562Sgshapiro############### 23838032Speter# Options # 23938032Speter############### 24038032Speterifdef(`confAUTO_REBUILD', 24138032Speter`errprint(WARNING: `confAUTO_REBUILD' is no longer valid. 24238032Speter 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? 24690792Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False') 24738032Speter 24838032Speter# 8-bit data handling 24964562Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8') 25038032Speter 25138032Speter# wait for alias file rebuild (default units: minutes) 25277349Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m') 25338032Speter 25438032Speter# location of alias file 25564562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases') 25638032Speter 25738032Speter# minimum number of free blocks on filesystem 25864562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100') 25964562Sgshapiro 26038032Speter# maximum message size 26164562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000') 26238032Speter 26338032Speter# substitution for space (blank) characters 264132943Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_') 26538032Speter 26638032Speter# avoid connecting to "expensive" mailers on initial submission? 26764562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False') 26838032Speter 26938032Speter# checkpoint queue runs after every N successful deliveries 27064562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10') 27138032Speter 27238032Speter# default delivery mode 27364562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background') 27438032Speter 27538032Speter# error message header/file 27664562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header') 27738032Speter 27838032Speter# error mode 27964562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print') 28038032Speter 28138032Speter# save Unix-style "From_" lines at top of header? 28264562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False') 28338032Speter 28438032Speter# queue file mode (qf files) 28564562Sgshapiro_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600') 28638032Speter 28790792Sgshapiro# temporary file mode 28890792Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600') 28990792Sgshapiro 29038032Speter# match recipients against GECOS field? 29164562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False') 29238032Speter 29338032Speter# maximum hop count 29464562Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `25') 29538032Speter 29638032Speter# location of help file 29790792SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile') 29838032Speter 29938032Speter# ignore dots as terminators in incoming messages? 30064562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False') 30138032Speter 30238032Speter# name resolver options 30364562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY') 30438032Speter 30538032Speter# deliver MIME-encapsulated error messages? 30664562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True') 30738032Speter 30838032Speter# Forward file search path 30964562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward') 31038032Speter 31138032Speter# open connection cache size 31264562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2') 31338032Speter 31438032Speter# open connection cache timeout 31564562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m') 31638032Speter 31738032Speter# persistent host status directory 31864562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat') 31938032Speter 32038032Speter# single thread deliveries (requires HostStatusDirectory)? 32164562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False') 32238032Speter 32338032Speter# use Errors-To: header? 32464562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False') 32538032Speter 32638032Speter# log level 32764562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10') 32838032Speter 32938032Speter# send to me too, even in an alias expansion? 33064562Sgshapiro_OPTION(MeToo, `confME_TOO', `True') 33138032Speter 33238032Speter# verify RHS in newaliases? 33364562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False') 33438032Speter 33538032Speter# default messages to old style headers if no special punctuation? 33664562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False') 33738032Speter 33838032Speter# SMTP daemon options 33964562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl', 34038032Speter`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. 34138032Speter Use `DAEMON_OPTIONS()'; see cf/README. 34264562Sgshapiro)'dnl 34394334Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')') 34494334Sgshapiroifelse(defn(`_DPO_'), `', 34564562Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet 34664562SgshapiroO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_') 34766494Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E') 34890792Sgshapiro 34990792Sgshapiro# SMTP client options 35064562Sgshapiroifelse(defn(`confCLIENT_OPTIONS'), `', `dnl', 35138032Speter`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid. See cf/README for more information. 35264562Sgshapiro)'dnl 35390792Sgshapiro`CLIENT_OPTIONS(`confCLIENT_OPTIONS')') 35490792Sgshapiroifelse(defn(`_CPO_'), `', 35590792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_') 35690792Sgshapiro 35790792Sgshapiro# Modifiers to `define' {daemon_flags} for direct submissions 35890792Sgshapiro_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `') 35964562Sgshapiro 36090792Sgshapiro# Use as mail submission program? See sendmail/SECURITY 36190792Sgshapiro_OPTION(UseMSP, `confUSE_MSP', `') 36290792Sgshapiro 36390792Sgshapiro# privacy flags 36490792Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings') 36590792Sgshapiro 36638032Speter# who (if anyone) should get extra copies of error messages 36764562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster') 36838032Speter 36938032Speter# slope of queue-only function 37064562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000') 37138032Speter 37238032Speter# limit on number of concurrent queue runners 37364562Sgshapiro_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `') 37438032Speter 37590792Sgshapiro# maximum number of queue-runners per queue-grouping with multiple queues 37690792Sgshapiro_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1') 37790792Sgshapiro 37890792Sgshapiro# priority of queue runners (nice(3)) 37990792Sgshapiro_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `') 38090792Sgshapiro 38190792Sgshapiro# shall we sort the queue by hostname first? 38290792Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority') 38390792Sgshapiro 38490792Sgshapiro# minimum time in queue before retry 38590792Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m') 38690792Sgshapiro 38790792Sgshapiro# how many jobs can you process in the queue? 38890792Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000') 38990792Sgshapiro 39090792Sgshapiro# perform initial split of envelope without checking MX records 39190792Sgshapiro_OPTION(FastSplit, `confFAST_SPLIT', `1') 39290792Sgshapiro 39390792Sgshapiro# queue directory 39490792SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue') 39590792Sgshapiro 39638032Speter# key for shared memory; 0 to turn off 39764562Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0') 39838032Speter 39990792Sgshapiroifdef(`confSHARED_MEMORY_KEY_FILE', `dnl 40090792Sgshapiro# file to store key for shared memory (if SharedMemoryKey = -1) 40190792SgshapiroO SharedMemoryKeyFile=confSHARED_MEMORY_KEY_FILE') 40294334Sgshapiro 40394334Sgshapiro# timeouts (many of these) 40494334Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m') 40594334Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m') 40638032Speter_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s') 40764562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m') 40864562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m') 40990792Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m') 41064562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h') 41164562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m') 41264562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h') 41364562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h') 41464562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m') 41564562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m') 41664562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m') 41764562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h') 41864562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s') 41964562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s') 42064562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m') 42164562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d') 42264562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d') 42364562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d') 42464562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d') 42564562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h') 42664562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h') 42764562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h') 428132943Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h') 42964562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m') 43064562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s') 43164562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s') 43264562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s') 433132943Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4') 43464562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4') 43564562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4') 43664562Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m') 43764562Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m') 43864562Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h') 43964562Sgshapiro 44064562Sgshapiro# time for DeliverBy; extension disabled if less than 0 44190792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0') 44290792Sgshapiro 44390792Sgshapiro# should we not prune routes in route-addr syntax addresses? 44438032Speter_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False') 44590792Sgshapiro 44690792Sgshapiro# queue up everything before forking? 44790792Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True') 44838032Speter 44964562Sgshapiro# status file 45038032SpeterO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics') 45138032Speter 45264562Sgshapiro# time zone handling: 45338032Speter# if undefined, use system default 45438032Speter# if defined but null, use TZ envariable passed in 45564562Sgshapiro# if defined and non-null, use that info 45638032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=', 45738032Speter confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=', 45838032Speter `O TimeZoneSpec=confTIME_ZONE') 45938032Speter 46038032Speter# default UID (can be username or userid:groupid) 46138032Speter_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull') 46238032Speter 46338032Speter# list of locations of user database file (null means no lookup) 46438032Speter_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb') 46538032Speter 46664562Sgshapiro# fallback MX host 46738032Speter_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net') 46838032Speter 46964562Sgshapiro# if we are the best MX host for a site, try it directly instead of config err 47038032Speter_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False') 47138032Speter 47264562Sgshapiro# load average at which we just queue messages 47338032Speter_OPTION(QueueLA, `confQUEUE_LA', `8') 474132943Sgshapiro 475132943Sgshapiro# load average at which we refuse connections 476132943Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12') 47738032Speter 47864562Sgshapiro# load average at which we delay connections; 0 means no limit 47938032Speter_OPTION(DelayLA, `confDELAY_LA', `0') 48038032Speter 48164562Sgshapiro# maximum number of children we allow at one time 48238032Speter_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12') 48338032Speter 48464562Sgshapiro# maximum number of new connections per second 48538032Speter_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0') 486132943Sgshapiro 487132943Sgshapiro# work recipient factor 488132943Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') 48990792Sgshapiro 49090792Sgshapiro# deliver each queued job in a separate process? 49190792Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False') 49238032Speter 49398841Sgshapiro# work class factor 49438032Speter_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800') 49538032Speter 49671345Sgshapiro# work time factor 49738032Speter_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000') 498132943Sgshapiro 499132943Sgshapiro# default character set 500132943Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1') 50138032Speter 50264562Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others) 50338032Speter_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch') 50438032Speter 50564562Sgshapiro# hosts file (normally /etc/hosts) 50638032Speter_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts') 50738032Speter 50864562Sgshapiro# dialup line delay on connection failure 50938032Speter_OPTION(DialDelay, `confDIAL_DELAY', `10s') 51038032Speter 51164562Sgshapiro# action to take if there are no recipients in the message 51238032Speter_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed') 51338032Speter 514141858Sgshapiro# chrooted environment for writing to files 51538032Speter_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch') 51690792Sgshapiro 51764562Sgshapiro# are colons OK in addresses? 51838032Speter_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True') 51938032Speter 52064562Sgshapiro# shall I avoid expanding CNAMEs (violates protocols)? 52138032Speter_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False') 52238032Speter 52364562Sgshapiro# SMTP initial login message (old $e macro) 52438032Speter_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b') 52538032Speter 52664562Sgshapiro# UNIX initial From header format (old $l macro) 52738032Speter_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d') 52838032Speter 52964562Sgshapiro# From: lines that have embedded newlines are unwrapped onto one line 53038032Speter_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False') 53138032Speter 53264562Sgshapiro# Allow HELO SMTP command that does not `include' a host name 53338032Speter_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False') 53438032Speter 53564562Sgshapiro# Characters to be quoted in a full name phrase (@,;:\()[] are automatic) 53638032Speter_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.') 53738032Speter 53864562Sgshapiro# delimiter (operator) characters (old $o macro) 53938032Speter_OPTION(OperatorChars, `confOPERATORS', `.:@[]') 54038032Speter 54164562Sgshapiro# shall I avoid calling initgroups(3) because of high NIS costs? 54238032Speter_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False') 54338032Speter 54464562Sgshapiro# are group-writable `:include:' and .forward files (un)trustworthy? 54538032Speter# True (the default) means they are not trustworthy. 54638032Speter_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True') 54764562Sgshapiroifdef(`confUNSAFE_GROUP_WRITES', 54838032Speter`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL. 54938032Speter')') 55064562Sgshapiro 55138032Speter# where do errors that occur when sending errors get sent? 55238032Speter_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster') 55364562Sgshapiro 55438032Speter# where to save bounces if all else fails 55538032Speter_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter') 55664562Sgshapiro 55738032Speter# what user id do we assume for the majority of the processing? 55838032Speter_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail') 55990792Sgshapiro 56064562Sgshapiro# maximum number of recipients per SMTP envelope 56190792Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100') 56290792Sgshapiro 56390792Sgshapiro# limit the rate recipients per SMTP envelope are accepted 56438032Speter# once the threshold number of recipients have been rejected 56538032Speter_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20') 56664562Sgshapiro 56738032Speter# shall we get local names from our installed interfaces? 56864562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 56964562Sgshapiro 57064562Sgshapiro# Return-Receipt-To: header implies DSN request 57138032Speter_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 57264562Sgshapiro 57338032Speter# override connection address (for testing) 57438032Speter_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 575132943Sgshapiro 57638032Speter# Trusted user for file ownership and starting the daemon 57790792Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root') 57890792Sgshapiro 579132943Sgshapiro# Control socket for daemon management 58090792Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 58138032Speter 58264562Sgshapiro# Maximum MIME header length to protect MUAs 58338032Speter_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0') 58464562Sgshapiro 58564562Sgshapiro# Maximum length of the sum of all headers 58664562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768') 58764562Sgshapiro 58864562Sgshapiro# Maximum depth of alias recursion 58964562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10') 59064562Sgshapiro 59164562Sgshapiro# location of pid file 59264562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid') 59364562Sgshapiro 59464562Sgshapiro# Prefix string for the process title shown on 'ps' listings 59564562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix') 59664562Sgshapiro 597132943Sgshapiro# Data file (df) memory-buffer file maximum size 59864562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096') 59964562Sgshapiro 60064562Sgshapiro# Transcript file (xf) memory-buffer file maximum size 60164562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096') 60264562Sgshapiro 60364562Sgshapiro# lookup type to find information about local mailboxes 60464562Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw') 60564562Sgshapiro 60664562Sgshapiro# list of authentication mechanisms 60764562Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5') 60864562Sgshapiro 60964562Sgshapiro# default authentication information for outgoing connections 61064562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info') 61164562Sgshapiro 61264562Sgshapiro# SMTP AUTH flags 61364562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `') 61464562Sgshapiro 61564562Sgshapiro# SMTP AUTH maximum encryption strength 61664562Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `') 61790792Sgshapiro 61890792Sgshapiro# SMTP STARTTLS server options 61990792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `') 620132943Sgshapiro 621132943Sgshapiro# Input mail filters 622132943Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 62364562Sgshapiro 62490792Sgshapiroifdef(`confINPUT_MAIL_FILTERS', `dnl 62564562Sgshapiro# Milter options 626132943Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `') 627132943Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 628132943Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') 62964562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') 63064562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')') 63164562Sgshapiro 63264562Sgshapiro# CA directory 63364562Sgshapiro_OPTION(CACERTPath, `confCACERT_PATH', `') 63464562Sgshapiro# CA file 63590792Sgshapiro_OPTION(CACERTFile, `confCACERT', `') 63690792Sgshapiro# Server Cert 63790792Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `') 63890792Sgshapiro# Server private key 63990792Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `') 64090792Sgshapiro# Client Cert 64164562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `') 64264562Sgshapiro# Client private key 64364562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 64498841Sgshapiro# DHParameters (only required if DSA/DH is used) 64564562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `') 64690792Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL) 64764562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `') 64864562Sgshapiro 64964562Sgshapiro############################ 650125820Sgshapiro`# QUEUE GROUP DEFINITIONS #' 651132943Sgshapiro############################ 65264562Sgshapiro_QUEUE_GROUP_ 65364562Sgshapiro 654110560Sgshapiro########################### 65564562Sgshapiro# Message precedences # 656110560Sgshapiro########################### 65764562Sgshapiro 65864562SgshapiroPfirst-class=0 65964562SgshapiroPspecial-delivery=100 66064562SgshapiroPlist=-30 66164562SgshapiroPbulk=-60 66264562SgshapiroPjunk=-100 66364562Sgshapiro 66464562Sgshapiro##################### 665132943Sgshapiro# Trusted users # 666132943Sgshapiro##################### 66764562Sgshapiro 66864562Sgshapiro# this is equivalent to setting class "t" 66964562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 67064562SgshapiroTroot 67164562SgshapiroTdaemon 67290792Sgshapiroifdef(`_NO_UUCP_', `dnl', `Tuucp') 67390792Sgshapiroifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 67490792Sgshapiro 67590792Sgshapiro######################### 67642575Speter# Format of headers # 67738032Speter######################### 67838032Speter 67938032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl 68038032SpeterH?P?Return-Path: <$g> 68138032SpeterHReceived: confRECEIVED_HEADER 68238032SpeterH?D?Resent-Date: $a 68338032SpeterH?D?Date: $a 68438032SpeterH?F?Resent-From: confFROM_HEADER 68538032SpeterH?F?From: confFROM_HEADER 68638032SpeterH?x?Full-Name: $x 68738032Speter# HPosted-Date: $a 68838032Speter# H?l?Received-Date: $b 68938032SpeterH?M?Resent-Message-Id: <$t.$i@$j> 69038032SpeterH?M?Message-Id: <$t.$i@$j> 69138032Speter 69264562Sgshapiro# 69338032Speter###################################################################### 69438032Speter###################################################################### 69538032Speter##### 69638032Speter##### REWRITING RULES 69738032Speter##### 69838032Speter###################################################################### 69938032Speter###################################################################### 70038032Speter 70138032Speter############################################ 70238032Speter### Ruleset 3 -- Name Canonicalization ### 703132943Sgshapiro############################################ 70438032SpeterScanonify=3 70538032Speter 70638032Speter# handle null input (translate to <@> special case) 70738032SpeterR$@ $@ <@> 70838032Speter 70938032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon 71038032SpeterR$* $: $1 <@> mark addresses 71138032SpeterR$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> 71238032SpeterR@ $* <@> $: @ $1 unmark @host:... 713132943SgshapiroR$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr 714132943SgshapiroR$* :: $* <@> $: $1 :: $2 unmark node::addr 71564562SgshapiroR:`include': $* <@> $: :`include': $1 unmark :`include':... 71638032SpeterR$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon 71738032SpeterR$* : $* <@> $: $2 strip colon if marked 71838032SpeterR$* <@> $: $1 unmark 71938032SpeterR$* ; $1 strip trailing semi 72038032SpeterR$* < $+ :; > $* $@ $2 :; <@> catch <list:;> 72138032SpeterR$* < $* ; > $1 < $2 > bogus bracketed semi 72238032Speter 72338032Speter# null input now results from list:; syntax 72438032SpeterR$@ $@ :; <@> 72538032Speter 72638032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item 72738032SpeterR$* $: < $1 > housekeeping <> 72864562SgshapiroR$+ < $* > < $2 > strip excess on left 72938032SpeterR< $* > $+ < $1 > strip excess on right 73038032SpeterR<> $@ < @ > MAIL FROM:<> case 73138032SpeterR< $+ > $: $1 remove housekeeping <> 73238032Speter 73338032Speterifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 73438032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 73538032SpeterR@ $+ , $+ @ $1 : $2 change all "," to ":" 73638032Speter 73790792Sgshapiro# localize and dispose of route-based addresses 73838032Speterdnl XXX: IPv6 colon conflict 73938032Speterifdef(`NO_NETINET6', `dnl', 74038032Speter`R@ [$+] : $+ $@ $>Canonify2 < @ [$1] > : $2 handle <route-addr>') 74138032SpeterR@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 74238032Speterdnl',`dnl 74338032Speter# strip route address <@a,@b,@c:user@d> -> <user@d> 74471345SgshapiroR@ $+ , $+ $2 74538032Speterifdef(`NO_NETINET6', `dnl', 74638032Speter`R@ [ $* ] : $+ $2') 74738032SpeterR@ $+ : $+ $2 74838032Speterdnl') 74938032Speter 75038032Speter# find focus for list syntax 75138032SpeterR $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 75238032SpeterR $+ : $* ; $@ $1 : $2; list syntax 75338032Speter 75438032Speter# find focus for @ syntax addresses 75538032SpeterR$+ @ $+ $: $1 < @ $2 > focus on domain 75638032SpeterR$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 75764562SgshapiroR$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 75838032Speter 75938032Speterdnl This is flagged as an error in S0; no need to silently fix it here. 76038032Speterdnl # do some sanity checking 76138032Speterdnl R$* < @ $~[ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 76290792Sgshapiro 76390792Sgshapiroifdef(`_NO_UUCP_', `dnl', 76490792Sgshapiro`# convert old-style addresses to a domain-based address 76564562SgshapiroR$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 76664562SgshapiroR$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 76764562SgshapiroR$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 76864562Sgshapiro') 76990792Sgshapiroifdef(`_USE_DECNET_SYNTAX_', 77090792Sgshapiro`# convert node::user addresses into a domain-based address 77164562SgshapiroR$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 77264562SgshapiroR$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 77338032Speter', 77438032Speter `dnl') 77564562Sgshapiro# if we have % signs, take the rightmost one 77638032SpeterR$* % $* $1 @ $2 First make them all @s. 77738032SpeterR$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 77838032SpeterR$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 77938032Speter 78038032Speter# else we must be a local name 78164562SgshapiroR$* $@ $>Canonify2 $1 78238032Speter 78390792Sgshapiro 78490792Sgshapiro################################################ 78590792Sgshapiro### Ruleset 96 -- bottom half of ruleset 3 ### 78638032Speter################################################ 78738032Speter 78838032SpeterSCanonify2=96 78964562Sgshapiro 79064562Sgshapiro# handle special cases for local names 79164562SgshapiroR$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 79238032SpeterR$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 79338032Speterifdef(`_NO_UUCP_', `dnl', 79438032Speter`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 79564562Sgshapiro 79664562Sgshapiro# check for IPv4/IPv6 domain literal 79738032SpeterR$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr] 79838032SpeterR$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 79938032SpeterR$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 80038032Speter 80138032Speterifdef(`_DOMAIN_TABLE_', `dnl 80264562Sgshapiro# look up domains in the domain table 80338032SpeterR$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 80438032Speter 80564562Sgshapiroundivert(2)dnl LOCAL_RULE_3 80638032Speter 80738032Speterifdef(`_BITDOMAIN_TABLE_', `dnl 80838032Speter# handle BITNET mapping 80938032SpeterR$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 81038032Speter 81138032Speterifdef(`_UUDOMAIN_TABLE_', `dnl 81264562Sgshapiro# handle UUCP mapping 81338032SpeterR$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 81438032Speter 81538032Speterifdef(`_NO_UUCP_', `dnl', 81638032Speter`ifdef(`UUCP_RELAY', 81738032Speter`# pass UUCP addresses straight through 81838032SpeterR$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 81964562Sgshapiro`# if really UUCP, handle it immediately 82090792Sgshapiroifdef(`_CLASS_U_', 82190792Sgshapiro`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82238032Speterifdef(`_CLASS_V_', 82338032Speter`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82438032Speterifdef(`_CLASS_W_', 82564562Sgshapiro`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82638032Speterifdef(`_CLASS_X_', 82738032Speter`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82838032Speterifdef(`_CLASS_Y_', 82964562Sgshapiro`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 83038032Speter 83164562Sgshapiroifdef(`_NO_CANONIFY_', `dnl', `dnl 83238032Speter# try UUCP traffic as a local address 83338032SpeterR$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 83438032SpeterR$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 83564562Sgshapiro')') 83638032Speter# hostnames ending in class P are always canonical 83738032SpeterR$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 83838032Speterdnl apply the next rule only for hostnames not in class P 83938032Speterdnl this even works for phrases in class P since . is in class P 84038032Speterdnl which daemon flags are set? 84138032SpeterR$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 84238032Speterdnl the other rules in this section only apply if the hostname 84338032Speterdnl does not end in class P hence no further checks are done here 84438032Speterdnl if this ever changes make sure the lookups are "protected" again! 84538032Speterifdef(`_NO_CANONIFY_', `dnl 84638032Speterdnl do not canonify unless: 84738032Speterdnl domain ends in class {Canonify} (this does not work if the intersection 84838032Speterdnl with class P is non-empty) 84938032Speterdnl or {daemon_flags} has c set 85038032Speter# pass to name server to make hostname canonical if in class {Canonify} 85138032SpeterR$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 85238032Speter# pass to name server to make hostname canonical if requested 85338032SpeterR$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 85438032Speterdnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 85538032SpeterR$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 85638032Speter# add a trailing dot to qualified hostnames so other rules will work 85738032SpeterR$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 85838032Speterifdef(`_CANONIFY_HOSTS_', `dnl 85938032Speterdnl this should only apply to unqualified hostnames 86064562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar 86164562Sgshapirodnl then $- does not work. 86264562Sgshapiro# lookup unqualified hostnames 86364562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 86464562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless: 86564562Sgshapirodnl {daemon_flags} contains CC (do not canonify) 86664562Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work 86764562Sgshapirodnl should we do this for every hostname: even unqualified? 86864562SgshapiroR$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 86964562SgshapiroR$* CC $* $| $* $: $3 87064562Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl 87164562Sgshapiro# do not canonify header addresses 87264562SgshapiroR$* $| $* < @ $* $~P > $* $: $&{addr_type} $| $2 < @ $3 $4 > $5 87364562SgshapiroR$* h $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 87464562SgshapiroR$* h $* $| $* $: $3', `dnl') 87564562Sgshapiro# pass to name server to make hostname canonical 87664562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 87764562Sgshapirodnl remove {daemon_flags} for other cases 87864562SgshapiroR$* $| $* $: $2 87964562Sgshapiro 88064562Sgshapiro# local host aliases and pseudo-domains are always canonical 88164562SgshapiroR$* < @ $=w > $* $: $1 < @ $2 . > $3 88264562Sgshapiroifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 88364562Sgshapiro`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 88464562Sgshapiro`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 88564562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 88664562Sgshapirodnl virtual hosts are also canonical 88790792Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 88864562Sgshapiro`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 88964562Sgshapiro`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 89071345Sgshapiro`dnl') 89171345Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 89271345Sgshapirodnl hosts for genericstable are also canonical 89364562Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_', 89490792Sgshapiro`R$* < @ $* $=G > $* $: $1 < @ $2 $3 . > $4', 89590792Sgshapiro`R$* < @ $=G > $* $: $1 < @ $2 . > $3')', 89690792Sgshapiro`dnl') 89790792Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added 89890792Sgshapirodnl by one of the rules before 89938032SpeterR$* < @ $* . . > $* $1 < @ $2 . > $3 90064562Sgshapiro 90164562Sgshapiro 90264562Sgshapiro################################################## 90338032Speter### Ruleset 4 -- Final Output Post-rewriting ### 90438032Speter################################################## 90538032SpeterSfinal=4 90638032Speter 90738032SpeterR$+ :; <@> $@ $1 : handle <list:;> 90838032SpeterR$* <@> $@ handle <> and list:; 90964562Sgshapiro 91064562Sgshapiro# strip trailing dot off possibly canonical name 91164562SgshapiroR$* < @ $+ . > $* $1 < @ $2 > $3 91264562Sgshapiro 91364562Sgshapiro# eliminate internal code 91464562SgshapiroR$* < @ *LOCAL* > $* $1 < @ $j > $2 91590792Sgshapiro 91690792Sgshapiro# externalize local domain info 91790792SgshapiroR$* < $+ > $* $1 $2 $3 defocus 91890792SgshapiroR@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 91990792SgshapiroR@ $* $@ @ $1 ... and exit 92090792Sgshapiro 92164562Sgshapiroifdef(`_NO_UUCP_', `dnl', 92264562Sgshapiro`# UUCP must always be presented in old form 92338032SpeterR$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 92438032Speter 92538032Speterifdef(`_USE_DECNET_SYNTAX_', 92638032Speter`# put DECnet back in :: form 92738032SpeterR$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 92838032Speter `dnl') 92964562Sgshapiro# delete duplicate local names 93038032SpeterR$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 93171345Sgshapiro 93238032Speter 93338032Speter 93438032Speter############################################################## 93538032Speter### Ruleset 97 -- recanonicalize and call ruleset zero ### 93638032Speter### (used for recursive calls) ### 93764562Sgshapiro############################################################## 93838032Speter 93938032SpeterSRecurse=97 94038032SpeterR$* $: $>canonify $1 94138032SpeterR$* $@ $>parse $1 94238032Speter 94338032Speter 94438032Speter###################################### 94538032Speter### Ruleset 0 -- Parse Address ### 94638032Speter###################################### 94738032Speter 94838032SpeterSparse=0 94938032Speter 95038032SpeterR$* $: $>Parse0 $1 initial parsing 95138032SpeterR<@> $#_LOCAL_ $: <@> special case error msgs 95238032SpeterR$* $: $>ParseLocal $1 handle local hacks 95338032SpeterR$* $: $>Parse1 $1 final parsing 95438032Speter 95538032Speter# 95638032Speter# Parse0 -- do initial syntax checking and eliminate local addresses. 95738032Speter# This should either return with the (possibly modified) input 95838032Speter# or return with a #error mailer. It should not return with a 95938032Speter# #mailer other than the #error mailer. 96038032Speter# 96138032Speter 96238032SpeterSParse0 96364562SgshapiroR<@> $@ <@> special case error msgs 96464562SgshapiroR$* : $* ; <@> $#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses" 96564562SgshapiroR@ <@ $* > < @ $1 > catch "@@host" bogosity 96638032SpeterR<@ $+> $#error $@ 5.1.3 $: "_CODE553 User address required" 96738032SpeterR$+ <@> $#error $@ 5.1.3 $: "_CODE553 Hostname required" 96838032SpeterR$* $: <> $1 96938032Speterdnl allow tricks like [host1]:[host2] 97038032SpeterR<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4 97138032SpeterR<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4 97264562Sgshapirodnl but no a@[b]c 97338032SpeterR<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid address" 97438032SpeterR<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 97538032SpeterR<> $* <$* : $* > $* $#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part" 97664562SgshapiroR<> $* $1 97738032SpeterR$* < @ . $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 97838032SpeterR$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 97938032Speterdnl no a@b@ 98038032SpeterR$* < @ $* @ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid route address" 98138032Speterdnl no a@b@c 98238032SpeterR$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 98338032Speterdnl comma only allowed before @; this check is not complete 98438032SpeterR$* , $~O $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 98538032Speter 98638032Speterifdef(`_STRICT_RFC821_', `# more RFC 821 checks 98738032SpeterR$* . < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot" 98890792SgshapiroR. $* < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot" 98964562Sgshapirodnl', `dnl') 99090792Sgshapiro 99190792Sgshapiro# now delete the local info -- note $=O to find characters that cause forwarding 99238032SpeterR$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 99390792SgshapiroR< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 99490792SgshapiroR$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 99590792SgshapiroR< @ $+ > $#error $@ 5.1.3 $: "_CODE553 User address required" 99690792SgshapiroR$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 99790792SgshapiroR$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 99890792SgshapiroR< @ *LOCAL* > $#error $@ 5.1.3 $: "_CODE553 User address required" 99990792SgshapiroR$* $=O $* < @ *LOCAL* > 100038032Speter $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 100190792SgshapiroR$* < @ *LOCAL* > $: $1 100290792Sgshapiro 100390792Sgshapiro# 100490792Sgshapiro# Parse1 -- the bottom half of ruleset 0. 100590792Sgshapiro# 100690792Sgshapiro 100764562SgshapiroSParse1 100890792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 100938032Speter# handle LDAP routing for hosts in $={LDAPRoute} 101090792SgshapiroR$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <> 101190792SgshapiroR$+ < @ $={LDAPRouteEquiv} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>', 101290792Sgshapiro`dnl') 101390792Sgshapiro 101490792Sgshapiroifdef(`_MAILER_smtp_', 101538032Speter`# handle numeric address spec 101664562Sgshapirodnl there is no check whether this is really an IP number 101764562SgshapiroR$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 101838032SpeterR$* < @ [ $+ ] > $* $1 < @ [ $2 ] : $S > $3 Add smart host to path 101990792SgshapiroR$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 102064562SgshapiroR$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 102138032SpeterR$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 102290792Sgshapiro `dnl') 102338032Speter 102464562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 102538032Speter# handle virtual users 102638032Speterifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 102738032Speterdnl this is not a documented option 102838032Speterdnl it stops looping in virtusertable mapping if input and output 102938032Speterdnl are identical, i.e., if address A is mapped to A. 103038032Speterdnl it does not deal with multi-level recursion 103138032Speter# handle full domains in RHS of virtusertable 103264562SgshapiroR$+ < @ $+ > $: $(macro {RecipientAddress} $) $1 < @ $2 > 103364562SgshapiroR$+ < @ $+ > $: <?> $1 < @ $2 > $| $>final $1 < @ $2 > 103490792SgshapiroR<?> $+ $| $+ $: $1 $(macro {RecipientAddress} $@ $2 $) 103590792SgshapiroR<?> $+ $| $* $: $1', 103664562Sgshapiro`dnl') 103764562SgshapiroR$+ $: <!> $1 Mark for lookup 103838032Speterdnl input: <!> local<@domain> 103938032Speterifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 104064562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 104164562Sgshapiro`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 1042112810Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain> 104390792SgshapiroR<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 104464562Sgshapirodnl if <@> local<@domain>: no match but try lookup 104564562Sgshapirodnl user+detail: try user++@domain if detail not empty 104638032SpeterR<@> $+ + $+ < @ $* . > 104738032Speter $: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 104864562Sgshapirodnl user+detail: try user+*@domain 104938032SpeterR<@> $+ + $* < @ $* . > 105090792Sgshapiro $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105190792Sgshapirodnl user+detail: try user@domain 105290792SgshapiroR<@> $+ + $* < @ $* . > 105390792Sgshapiro $: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105490792Sgshapirodnl try default entry: @domain 105590792Sgshapirodnl ++@domain 105690792SgshapiroR<@> $+ + $+ < @ $+ . > $: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105790792Sgshapirodnl +*@domain 105890792SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105990792Sgshapirodnl @domain if +detail exists 106090792Sgshapirodnl if no match, change marker to prevent a second @domain lookup 106164562SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . > 106290792Sgshapirodnl without +detail 106364562SgshapiroR<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 106464562Sgshapirodnl no match 106564562SgshapiroR<@> $+ $: $1 106690792Sgshapirodnl remove mark 106764562SgshapiroR<!> $+ $: $1 106890792SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 106990792SgshapiroR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 107090792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 107190792Sgshapiro# check virtuser input address against output address, if same, skip recursion 107290792SgshapiroR< $+ > $+ < @ $+ > $: < $1 > $2 < @ $3 > $| $1 107338032Speter# it is the same: stop now 107490792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress} $: $>ParseLocal $>Parse0 $>canonify $1 107590792SgshapiroR< $+ > $+ < @ $+ > $| $* $: < $1 > $2 < @ $3 > 107638032Speterdnl', `dnl') 107790792Sgshapirodnl this is not a documented option 107864562Sgshapirodnl it performs no looping at all for virtusertable 107990792Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_', 108090792Sgshapiro`R< $+ > $+ < @ $+ > $: $>ParseLocal $>Parse0 $>canonify $1', 108164562Sgshapiro`R< $+ > $+ < @ $+ > $: $>Recurse $1') 108290792Sgshapirodnl', `dnl') 108364562Sgshapiro 108498121Sgshapiro# short circuit local delivery so forwarded email works 108598121Sgshapiroifdef(`_MAILER_usenet_', `dnl 108698121SgshapiroR$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 108738032Speter 108890792Sgshapiro 108938032Speterifdef(`_STICKY_LOCAL_DOMAIN_', 109090792Sgshapiro`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 109164562SgshapiroR< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 109264562Sgshapirodnl $H empty (but @$=w.) 109338032SpeterR< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 109490792SgshapiroR< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 109590792Sgshapiro`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 109690792SgshapiroR$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 109790792Sgshapiro 109890792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 109990792Sgshapiro# not local -- try mailer table lookup 110090792SgshapiroR$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 110180785SgshapiroR< $+ . > $* $: < $1 > $2 strip trailing dot 110280785SgshapiroR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 110377349Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 110477349SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 110577349SgshapiroR< $+ > $* $: $>Mailertable <$1> $2 try domain', 110677349Sgshapiro`dnl') 110738032Speterundivert(4)dnl UUCP rules from `MAILER(uucp)' 110838032Speter 110938032Speterifdef(`_NO_UUCP_', `dnl', 111064562Sgshapiro`# resolve remotely connected UUCP links (if any) 111166494Sgshapiroifdef(`_CLASS_V_', 111266494Sgshapiro`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 111338032Speter `dnl') 111438032Speterifdef(`_CLASS_W_', 111564562Sgshapiro`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 111664562Sgshapiro `dnl') 111738032Speterifdef(`_CLASS_X_', 111838032Speter`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 111964562Sgshapiro `dnl')') 112038032Speter 112138032Speter# resolve fake top level domains by forwarding to other hosts 112264562Sgshapiroifdef(`BITNET_RELAY', 112338032Speter`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 112438032Speter `dnl') 112538032Speterifdef(`DECNET_RELAY', 112638032Speter`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 112764562Sgshapiro `dnl') 112864562Sgshapiroifdef(`_MAILER_pop_', 112964562Sgshapiro`R$+ < @ POP. > $#pop $: $1 user@POP', 113038032Speter `dnl') 113164562Sgshapiroifdef(`_MAILER_fax_', 113238032Speter`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 113338032Speter`ifdef(`FAX_RELAY', 113438032Speter`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 113538032Speter `dnl')') 113664562Sgshapiro 113738032Speterifdef(`UUCP_RELAY', 113838032Speter`# forward non-local UUCP traffic to our UUCP relay 113964562SgshapiroR$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 114038032Speter`ifdef(`_MAILER_uucp_', 114138032Speter`# forward other UUCP traffic straight to UUCP 114264562SgshapiroR$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 114338032Speter `dnl')') 114438032Speterifdef(`_MAILER_usenet_', ` 114538032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup 114638032SpeterR$+ . USENET $#usenet $@ usenet $: $1', 114764562Sgshapiro `dnl') 114838032Speter 114938032Speterifdef(`_LOCAL_RULES_', 115064562Sgshapiro`# figure out what should stay in our local mail system 115138032Speterundivert(1)', `dnl') 115238032Speter 115338032Speter# pass names that still have a host to a smarthost (if defined) 115438032SpeterR$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 115538032Speter 115638032Speter# deal with other remote names 115738032Speterifdef(`_MAILER_smtp_', 115864562Sgshapiro`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 115938032Speter`R$* < @$* > $* $#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2') 116038032Speter 116138032Speter# handle locally delivered names 116238032SpeterR$=L $#_LOCAL_ $: @ $1 special local names 116364562SgshapiroR$+ $#_LOCAL_ $: $1 regular local names 116438032Speter 116538032Speter########################################################################### 116638032Speter### Ruleset 5 -- special rewriting after aliases have been expanded ### 116738032Speter########################################################################### 116838032Speter 116938032SpeterSLocal_localaddr 117064562SgshapiroSlocaladdr=5 117138032SpeterR$+ $: $1 $| $>"Local_localaddr" $1 117238032SpeterR$+ $| $#ok $@ $1 no change 117338032SpeterR$+ $| $#$* $#$2 117438032SpeterR$+ $| $* $: $1 117538032Speter 117638032Speterifdef(`_PRESERVE_LUSER_HOST_', `dnl 117738032Speter# Preserve rcpt_host in {Host} 117864562SgshapiroR$+ $: $1 $| $&h $| $&{Host} check h and {Host} 117938032SpeterR$+ $| $| $: $(macro {Host} $@ $) $1 no h or {Host} 118038032SpeterR$+ $| $| $+ $: $1 h not set, {Host} set 118138032SpeterR$+ $| +$* $| $* $: $1 h is +detail, {Host} set 118264562SgshapiroR$+ $| $* @ $+ $| $* $: $(macro {Host} $@ @$3 $) $1 set {Host} to host in h 118390792SgshapiroR$+ $| $+ $| $* $: $(macro {Host} $@ @$2 $) $1 set {Host} to h 118438032Speter')dnl 118538032Speter 118664562Sgshapiroifdef(`_FFR_5_', `dnl 118738032Speter# Preserve host in a macro 118838032SpeterR$+ $: $(macro {LocalAddrHost} $) $1 118938032SpeterR$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 119038032Speter 119138032Speterifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl 119238032Speter# deal with plussed users so aliases work nicely 119364562SgshapiroR$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 119464562SgshapiroR$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 119564562Sgshapiro') 119690792Sgshapiro# prepend an empty "forward host" on the front 119764562SgshapiroR$+ $: <> $1 119864562Sgshapiro 119938032Speterifdef(`LUSER_RELAY', `dnl 120090792Sgshapiro# send unrecognized local users to a relay host 120190792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 120290792SgshapiroR< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 120390792SgshapiroR< > $+ $: < ? $L > < > $(user $1 $) look up user 120490792SgshapiroR< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 120590792SgshapiroR< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 120695154SgshapiroR< > $+ $: < $L > $(user $1 $) look up user 120790792SgshapiroR< $* > $+ <> $: < > $2 found; strip $L') 120890792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 120990792SgshapiroR< $+ > $+ $: < $1 > $2 $&{Host}') 121090792Sgshapirodnl') 121166494Sgshapiro 121266494Sgshapiroifdef(`MAIL_HUB', `dnl 121366494SgshapiroR< > $+ $: < $H > $1 try hub', `dnl') 121466494Sgshapiroifdef(`LOCAL_RELAY', `dnl 121590792SgshapiroR< > $+ $: < $R > $1 try relay', `dnl') 121638032Speterifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 121766494SgshapiroR< > $+ $@ $1', `dnl 121866494SgshapiroR< > $+ $: < > < $1 <> $&h > nope, restore +detail 121966494Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 122038032SpeterR< > < $+ @ $+ <> + $* > $: < > < $1 + $3 @ $2 > check whether +detail') 122138032SpeterR< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 122238032SpeterR< > < $+ <> $* > $: < > < $1 > else discard 122338032SpeterR< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 122438032SpeterR< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 122590792SgshapiroR< > < $+ > $@ $1 no +detail 122666494SgshapiroR$+ $: $1 <> $&h add +detail back in 122766494Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 122866494SgshapiroR$+ @ $+ <> + $* $: $1 + $3 @ $2 check whether +detail') 122966494SgshapiroR$+ <> + $* $: $1 + $2 check whether +detail 123064562SgshapiroR$+ <> $* $: $1 else discard') 123190792SgshapiroR< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 123290792SgshapiroR< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 123390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 123490792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 123538032SpeterR< $~[ : $+ > $+ @ $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $4 >') 123690792SgshapiroR< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 123790792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 123890792SgshapiroR< $+ > $+ @ $+ $@ $>MailerToTriple < $1 > $2 < @ $3 >') 123990792SgshapiroR< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 124090792Sgshapiro 124190792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 124264562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 124390792Sgshapiro################################################################### 124490792Sgshapiro### Ruleset LDAPMailertable -- mailertable lookup for LDAP ### 124564562Sgshapirodnl input: <Domain> FullAddress 124664562Sgshapiro################################################################### 124738032Speter 124866494SgshapiroSLDAPMailertable 124938032SpeterR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 125043730SpeterR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check resolved? 125190792SgshapiroR< $+ > $* $: < $1 > $>Mailertable <$1> $2 try domain 125290792SgshapiroR< $+ > $#$* $#$2 found 125343730SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 not found, direct relay', 125466494Sgshapiro`dnl') 125564562Sgshapiro 125664562Sgshapiro################################################################### 125790792Sgshapiro### Ruleset 90 -- try domain part of mailertable entry ### 125890792Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 125990792Sgshapiro################################################################### 126090792Sgshapiro 126190792SgshapiroSMailertable=90 126290792Sgshapirodnl shift and check 126364562Sgshapirodnl %2 is not documented in cf/README 126438032SpeterR$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 126564562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 126690792SgshapiroR$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 126738032SpeterR$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 126890792Sgshapirodnl is $2 always empty? 126990792SgshapiroR$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 127090792SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 127190792Sgshapirodnl return full address 127290792SgshapiroR< $* > $* $@ $2 no mailertable match', 127390792Sgshapiro`dnl') 127490792Sgshapiro 127590792Sgshapiro################################################################### 127690792Sgshapiro### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 127790792Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest 127890792Sgshapirodnl <> address -> address 127990792Sgshapirodnl <error:d.s.n:text> -> error 128090792Sgshapirodnl <error:text> -> error 128138032Speterdnl <mailer:user@host> lp<@domain>rest -> mailer host user 128264562Sgshapirodnl <mailer:host> address -> mailer host address 128338032Speterdnl <localdomain> address -> address 128438032Speterdnl <host> address -> relay host address 128564562Sgshapiro################################################################### 128664562Sgshapiro 128764562SgshapiroSMailerToTriple=95 128838032SpeterR< > $* $@ $1 strip off null relay 128964562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 129064562SgshapiroR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 129164562SgshapiroR< local : $* > $* $>CanonLocal < $1 > $2 129264562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 129338032SpeterR< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 129464562SgshapiroR< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 129564562SgshapiroR< $=w > $* $@ $2 delete local host 129638032SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 129738032Speter 129838032Speter################################################################### 129938032Speter### Ruleset CanonLocal -- canonify local: syntax ### 130038032Speterdnl input: <user> address 130164562Sgshapirodnl <x> <@host> : rest -> Recurse rest 130264562Sgshapirodnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 130364562Sgshapirodnl <> user <@host> rest -> local user@host user 1304120256Sgshapirodnl <> user -> local user user 130564562Sgshapirodnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 130664562Sgshapirodnl <user> lp <@host> rest -> local lp@host user 130764562Sgshapirodnl <user> lp -> local lp user 130864562Sgshapiro################################################################### 130964562Sgshapiro 131038032SpeterSCanonLocal 131138032Speter# strip local host from routed addresses 131264562SgshapiroR< $* > < @ $+ > : $+ $@ $>Recurse $3 131338032SpeterR< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 131464562Sgshapiro 1315120256Sgshapiro# strip trailing dot from any host name that may appear 1316120256SgshapiroR< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 131738032Speter 131890792Sgshapiro# handle local: syntax -- use old user, either with or without host 131990792SgshapiroR< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 132090792SgshapiroR< > $+ $#_LOCAL_ $@ $1 $: $1 132138032Speter 132238032Speter# handle local:user@host syntax -- ignore host part 132338032SpeterR< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 132438032Speter 132538032Speter# handle local:user syntax 132664562SgshapiroR< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 132764562SgshapiroR< $+ > $* $#_LOCAL_ $@ $2 $: $1 132864562Sgshapiro 132964562Sgshapiro################################################################### 133064562Sgshapiro### Ruleset 93 -- convert header names to masqueraded form ### 133164562Sgshapiro################################################################### 133264562Sgshapiro 133364562SgshapiroSMasqHdr=93 133438032Speter 133538032Speterifdef(`_GENERICS_TABLE_', `dnl 133638032Speter# handle generics database 133743730Speterifdef(`_GENERICS_ENTIRE_DOMAIN_', 133864562Sgshapirodnl if generics should be applied add a @ as mark 133964562Sgshapiro`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 134043730Speter`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 134138032SpeterR$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 134238032Speterdnl workspace: either user<@domain> or <user@domain> user <@domain> @ 134338032Speterdnl ignore the first case for now 134438032Speterdnl if it has the mark lookup full address 134538032Speterdnl broken: %1 is full address not just detail 134638032SpeterR< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 134738032Speterdnl workspace: ... or <match|@user@domain> user <@domain> 134838032Speterdnl no match, try user+detail@domain 134938032SpeterR<@$+ + $* @ $+> $+ < @ $+ > 135038032Speter $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 135138032SpeterR<@$+ + $* @ $+> $+ < @ $+ > 135238032Speter $: < $(generics $1@$3 $: $) > $4 < @ $5 > 135338032Speterdnl no match, remove mark 135438032SpeterR<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 135538032Speterdnl no match, try @domain for exceptions 135638032SpeterR< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 135738032Speterdnl workspace: ... or <match> user <@domain> 135838032Speterdnl no match, try local part 135964562SgshapiroR< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 136038032SpeterR< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 136164562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 136238032SpeterR< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 136338032SpeterR< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 136464562SgshapiroR< > $* $: $1 not found', 136538032Speter`dnl') 136638032Speter 136738032Speter# do not masquerade anything in class N 136864562SgshapiroR$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 136964562Sgshapiro 137064562Sgshapiroifdef(`MASQUERADE_NAME', `dnl 137190792Sgshapiro# special case the users that should be exposed 137264562SgshapiroR$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 137364562Sgshapiroifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 137464562Sgshapiro`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 137564562Sgshapiro`R$=E < @ $=M . > $@ $1 < @ $2 . >') 137664562Sgshapiroifdef(`_LIMITED_MASQUERADE_', `dnl', 137764562Sgshapiro`R$=E < @ $=w . > $@ $1 < @ $2 . >') 137864562Sgshapiro 137964562Sgshapiro# handle domain-specific masquerading 138064562Sgshapiroifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 138164562Sgshapiro`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 138264562Sgshapiro`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 138364562Sgshapiroifdef(`_LIMITED_MASQUERADE_', `dnl', 138464562Sgshapiro`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 138538032SpeterR$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 138664562SgshapiroR$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 138764562SgshapiroR$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 138864562Sgshapirodnl', `dnl no masquerading 138964562Sgshapirodnl just fix *LOCAL* leftovers 139038032SpeterR$* < @ *LOCAL* > $@ $1 < @ $j . >') 139138032Speter 139238032Speter################################################################### 139364562Sgshapiro### Ruleset 94 -- convert envelope names to masqueraded form ### 139464562Sgshapiro################################################################### 139564562Sgshapiro 139690792SgshapiroSMasqEnv=94 139738032Speterifdef(`_MASQUERADE_ENVELOPE_', 139838032Speter`R$+ $@ $>MasqHdr $1', 139938032Speter`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 140038032Speter 140138032Speter################################################################### 140238032Speter### Ruleset 98 -- local part of ruleset zero (can be null) ### 140338032Speter################################################################### 140438032Speter 140538032SpeterSParseLocal=98 140638032Speterundivert(3)dnl LOCAL_RULE_0 140738032Speter 140838032Speterifdef(`_LDAP_ROUTING_', `dnl 140938032Speter###################################################################### 141038032Speter### LDAPExpand: Expand address using LDAP routing 141138032Speter### 141238032Speter### Parameters: 141338032Speter### <$1> -- parsed address (user < @ domain . >) (pass through) 141490792Sgshapiro### <$2> -- RFC822 address (user @ domain) (used for lookup) 141590792Sgshapiro### <$3> -- +detail information 141690792Sgshapiro### 141738032Speter### Returns: 141838032Speter### Mailer triplet ($#mailer $@ host $: address) 141938032Speter### Parsed address (user < @ domain . >) 142038032Speter###################################################################### 142138032Speter 142264562SgshapiroSLDAPExpand 142338032Speter# do the LDAP lookups 142464562SgshapiroR<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3> 142538032Speter 142638032Speter# look for temporary failures (return original address, MTA will queue up) 142738032SpeterR<$* <TMPF>> <$*> <$+> <$+> <$*> $@ $2 142838032SpeterR<$*> <$* <TMPF>> <$+> <$+> <$*> $@ $2 142938032Speter 143038032Speter# if mailRoutingAddress and local or non-existant mailHost, 143164562Sgshapiro# return the new mailRoutingAddress 143264562Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 143338032SpeterR<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2 143464562SgshapiroR<$+@$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $5 @ $2') 143590792SgshapiroR<$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 143690792SgshapiroR<$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 143790792Sgshapiro 143890792Sgshapiro 143990792Sgshapiro# if mailRoutingAddress and non-local mailHost, 144090792Sgshapiro# relay to mailHost with new mailRoutingAddress 144190792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 144290792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 144390792Sgshapiro# check mailertable for host, relay from there 144490792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$3> $>canonify $1 $6 @ $2', 144590792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')') 144690792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 144790792Sgshapiro# check mailertable for host, relay from there 1448132943SgshapiroR<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1', 1449132943Sgshapiro`R<$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $2 $: $>canonify $1') 1450132943Sgshapiro 145164562Sgshapiro# if no mailRoutingAddress and local mailHost, 145264562Sgshapiro# return original address 145390792SgshapiroR<> <$=w> <$+> <$+> <$*> $@ $2 145464562Sgshapiro 1455132943Sgshapiro 1456132943Sgshapiro# if no mailRoutingAddress and non-local mailHost, 1457132943Sgshapiro# relay to mailHost with original address 1458132943Sgshapiroifdef(`_MAILER_TABLE_', `dnl 1459132943Sgshapiro# check mailertable for host, relay from there 1460132943SgshapiroR<> <$+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2', 1461132943Sgshapiro`R<> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $1 $: $2') 1462132943Sgshapiro 146394334Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_', 146464562Sgshapiro`# if no mailRoutingAddress and no mailHost, 146564562Sgshapiro# try without +detail 146690792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl 146790792Sgshapiro 146890792Sgshapiro# if still no mailRoutingAddress and no mailHost, 146990792Sgshapiro# try @domain 147090792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 147164562SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <@ $4> <+$3>') 147298121SgshapiroR<> <> <$+> <$+ @ $+> <$*> $@ $>LDAPExpand <$1> <@ $3> <$4> 147364562Sgshapiro 147464562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt, 147590792Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 147690792Sgshapiro# user does not exist 147790792SgshapiroR<> <> <$+> <@ $+> <$*> $: <?> < $&{addr_type} > < $1 > 147890792Sgshapiro# only give error for envelope recipient 147990792SgshapiroR<?> <e r> <$+> $#error $@ nouser $: "550 User unknown" 148090792SgshapiroR<?> <$*> <$+> $@ $2', 148190792Sgshapiro`dnl 148290792Sgshapiro# return the original address 148390792SgshapiroR<> <> <$+> <@ $+> <$*> $@ $1')', 148464562Sgshapiro`dnl') 148564562Sgshapiro 148664562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 148790792Sgshapiro')') 148864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 148998121Sgshapiro###################################################################### 149064562Sgshapiro### D: LookUpDomain -- search for domain in access database 149164562Sgshapiro### 149290792Sgshapiro### Parameters: 149390792Sgshapiro### <$1> -- key (domain name) 149490792Sgshapiro### <$2> -- default (what to return if not found in db) 149590792Sgshapirodnl must not be empty 149664562Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 149790792Sgshapiro### ! does lookup only with tag 149890792Sgshapiro### + does lookup with and without tag 149990792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 150090792Sgshapirodnl returns: <default> <passthru> 150190792Sgshapirodnl <result> <passthru> 1502132943Sgshapiro###################################################################### 150390792Sgshapiro 150464562SgshapiroSD 150590792Sgshapirodnl workspace <key> <default> <passthru> <mark> 150690792Sgshapirodnl lookup with tag (in front, no delimiter here) 1507132943Sgshapirodnl 2 3 4 5 150864562SgshapiroR<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 150964562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 151064562Sgshapirodnl lookup without tag? 151164562Sgshapirodnl 1 2 3 4 151290792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 151390792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest 151490792Sgshapirodnl XXX apply this also to IP addresses? 1515132943Sgshapirodnl currently it works the wrong way round for [1.2.3.4] 1516132943Sgshapirodnl 1 2 3 4 5 6 1517132943SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6> 151890792Sgshapirodnl 1 2 3 4 5 151964562SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl') 152064562Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 152190792Sgshapirodnl found SKIP: return <default> and <passthru> 152264562Sgshapirodnl 1 2 3 4 5 152364562SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 152464562Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!) 152564562Sgshapirodnl 1 2 3 4 5 6 152690792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*> $@ $>D <[$1]> <$3> <$4 $5> <$6> 152738032Speterifdef(`NO_NETINET6', `dnl', 152890792Sgshapiro`dnl not found: IPv6 net 152938032Speterdnl (could be merged with previous rule if we have a class containing .:) 153038032Speterdnl 1 2 3 4 5 6 153138032SpeterR<?> <[$+::$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6> 153238032SpeterR<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>') 153364562Sgshapirodnl not found, but subdomain: try again 153490792Sgshapirodnl 1 2 3 4 5 6 153564562SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6> 153664562Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag: 153790792Sgshapirodnl 1 2 3 4 153864562SgshapiroR<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl') 153964562Sgshapirodnl not found, no subdomain: return <default> and <passthru> 154038032Speterdnl 1 2 3 4 5 154138032SpeterR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 154290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 154364562Sgshapirodnl 2 3 4 5 6 154464562SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 154590792Sgshapirodnl return <result of lookup> and <passthru> 154690792Sgshapirodnl 2 3 4 5 6 154764562SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 154864562Sgshapiro 154990792Sgshapiro###################################################################### 155090792Sgshapiro### A: LookUpAddress -- search for host address in access database 155190792Sgshapiro### 155290792Sgshapiro### Parameters: 155390792Sgshapiro### <$1> -- key (dot quadded host address) 155490792Sgshapiro### <$2> -- default (what to return if not found in db) 155590792Sgshapirodnl must not be empty 155690792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 155790792Sgshapiro### ! does lookup only with tag 155890792Sgshapiro### + does lookup with and without tag 155990792Sgshapiro### <$4> -- passthru (additional data passed through) 156090792Sgshapirodnl returns: <default> <passthru> 156190792Sgshapirodnl <result> <passthru> 156290792Sgshapiro###################################################################### 156390792Sgshapiro 156490792SgshapiroSA 156590792Sgshapirodnl lookup with tag 156690792Sgshapirodnl 2 3 4 5 156790792SgshapiroR<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 156890792Sgshapirodnl lookup without tag 156990792Sgshapirodnl 1 2 3 4 157090792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 157164562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru> 157290792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 157390792Sgshapirodnl found SKIP: return <default> and <passthru> 157490792Sgshapirodnl 1 2 3 4 5 157590792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 157690792Sgshapiroifdef(`NO_NETINET6', `dnl', 157790792Sgshapiro`dnl no match; IPv6: remove last part 157890792Sgshapirodnl 1 2 3 4 5 6 157990792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 158090792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>') 158190792Sgshapirodnl no match; IPv4: remove last part 158290792Sgshapirodnl 1 2 3 4 5 6 158390792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 158490792Sgshapirodnl no match: return default 158590792Sgshapirodnl 1 2 3 4 5 158638032SpeterR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 158738032Speterifdef(`_ATMPF_', `dnl tempfail? 158890792Sgshapirodnl 2 3 4 5 6 158938032SpeterR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 159038032Speterdnl match: return result 159138032Speterdnl 2 3 4 5 6 159238032SpeterR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 159364562Sgshapirodnl endif _ACCESS_TABLE_ 159490792Sgshapirodivert(0) 159564562Sgshapiro###################################################################### 159664562Sgshapiro### CanonAddr -- Convert an address into a standard form for 159790792Sgshapiro### relay checking. Route address syntax is 159864562Sgshapiro### crudely converted into a %-hack address. 159964562Sgshapiro### 160038032Speter### Parameters: 160138032Speter### $1 -- full recipient address 160290792Sgshapiro### 160364562Sgshapiro### Returns: 160490792Sgshapiro### parsed address, not in source route form 160590792Sgshapirodnl user%host%host<@domain> 160664562Sgshapirodnl host!user<@domain> 160790792Sgshapiro###################################################################### 160890792Sgshapiro 160990792SgshapiroSCanonAddr 161090792SgshapiroR$* $: $>Parse0 $>canonify $1 make domain canonical 161190792Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 161290792SgshapiroR< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 161390792SgshapiroR$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 161490792SgshapiroR$* < @ $+ > : $* $3 $1 < @ $2 > 161590792Sgshapirodnl') 161690792Sgshapiro 161790792Sgshapiro###################################################################### 161890792Sgshapiro### ParseRecipient -- Strip off hosts in $=R as well as possibly 161964562Sgshapiro### $* $=m or the access database. 162090792Sgshapiro### Check user portion for host separators. 162190792Sgshapiro### 162264562Sgshapiro### Parameters: 162390792Sgshapiro### $1 -- full recipient address 162490792Sgshapiro### 162590792Sgshapiro### Returns: 162690792Sgshapiro### parsed, non-local-relaying address 162790792Sgshapiro###################################################################### 162864562Sgshapiro 162990792SgshapiroSParseRecipient 163090792Sgshapirodnl mark and canonify address 163190792SgshapiroR$* $: <?> $>CanonAddr $1 163290792Sgshapirodnl workspace: <?> localpart<@domain[.]> 163338032SpeterR<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 163442575Speterdnl workspace: <?> localpart<@domain> 163542575SpeterR<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 163642575Speter 163742575Speter# if no $=O character, no host in the user portion, we are done 163842575SpeterR<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 163942575Speterdnl no $=O in localpart: return 164042575SpeterR<?> $* $@ $1 164142575Speter 164242575Speterdnl workspace: <NO> localpart<@domain>, where localpart contains $=O 164364562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY> 164464562Sgshapiroifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 164542575Speter# if we relay, check username portion for user%host so host can be checked also 164642575SpeterR<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 164742575Speterdnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 164864562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 164964562Sgshapiro 165042575Speterdnl what if access map returns something else than RELAY? 165142575Speterdnl we are only interested in RELAY entries... 165242575Speterdnl other To: entries: blacklist recipient; generic entries? 165364562Sgshapirodnl if it is an error we probably do not want to relay anyway 165442575Speterifdef(`_RELAY_HOSTS_ONLY_', 165542575Speter`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 165638032Speterifdef(`_ACCESS_TABLE_', `dnl 165738032SpeterR<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 165838032SpeterR<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 165938032Speter`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 166038032Speterifdef(`_ACCESS_TABLE_', `dnl 166138032SpeterR<NO> $* < @ $+ > $: $>D <$2> <NO> <+ To> <$1 < @ $2 >> 166238032SpeterR<$+> <$+> $: <$1> $2',`dnl')') 166338032Speter 166438032Speter 166538032Speterifdef(`_RELAY_MX_SERVED_', `dnl 166638032Speterdnl do "we" ($=w) act as backup MX server for the destination domain? 166738032SpeterR<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 166864562SgshapiroR<MX> < : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 166942575Speterdnl yes: mark it as <RELAY> 167064562SgshapiroR<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 167142575Speterdnl no: put old <NO> mark back 167264562SgshapiroR<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 167342575Speter 167438032Speterdnl do we relay to this recipient domain? 167538032SpeterR<RELAY> $* < @ $* > $@ $>ParseRecipient $1 167642575Speterdnl something else 167764562SgshapiroR<$+> $* $@ $2 167842575Speter 167938032Speter 168090792Sgshapiro###################################################################### 168164562Sgshapiro### check_relay -- check hostname/address on SMTP startup 168238032Speter###################################################################### 168338032Speter 168442575SpeterSLocal_check_relay 168564562SgshapiroScheck`'_U_`'relay 168664562SgshapiroR$* $: $1 $| $>"Local_check_relay" $1 168790792SgshapiroR$* $| $* $| $#$* $#$3 168890792SgshapiroR$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 168990792Sgshapiro 169090792SgshapiroSBasic_check_relay 169190792Sgshapiro# check for deferred delivery mode 169238032SpeterR$* $: < $&{deliveryMode} > $1 169342575SpeterR< d > $* $@ deferred 169464562SgshapiroR< $* > $* $: $2 169564562Sgshapiro 169642575Speterifdef(`_ACCESS_TABLE_', `dnl 169742575Speterdnl workspace: {client_name} $| {client_addr} 169864562SgshapiroR$+ $| $+ $: $>D < $1 > <?> <+ Connect> < $2 > 169990792Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 170042575SpeterR<?> <$+> $: $>A < $1 > <?> <+ Connect> <> no: another lookup 170138032Speterdnl workspace: <result-of-lookup> (<>|<{client_addr}>) 170264562SgshapiroR<?> <$*> $: OK found nothing 170390792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK 170490792SgshapiroR<$={Accept}> <$*> $@ $1 return value of lookup 170590792SgshapiroR<REJECT> <$*> $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 1706132943SgshapiroR<DISCARD> <$*> $#discard $: discard 170790792Sgshapiroifdef(`_FFR_QUARANTINE', 170890792Sgshapiro`R<QUARANTINE:$+> <$*> $#error $@ quarantine $: $1', `dnl') 170990792Sgshapirodnl error tag 171090792SgshapiroR<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 171190792SgshapiroR<ERROR:$+> <$*> $#error $: $1 171290792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 171342575Speterdnl generic error from access map 171490792SgshapiroR<$+> <$*> $#error $: $1', `dnl') 171590792Sgshapiro 171642575Speterifdef(`_RBL_',`dnl 171764562Sgshapiro# DNS based IP address spam list 171838032Speterdnl workspace: ignored... 171938032SpeterR$* $: $&{client_addr} 172038032SpeterR$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 172138032SpeterR<?>OK $: OKSOFAR 1722132943SgshapiroR<?>$+ $#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"', 1723132943Sgshapiro`dnl') 1724132943Sgshapiroundivert(8) 1725132943Sgshapiro 1726132943Sgshapiro###################################################################### 1727132943Sgshapiro### check_mail -- check SMTP ``MAIL FROM:'' command argument 1728132943Sgshapiro###################################################################### 1729132943Sgshapiro 1730132943SgshapiroSLocal_check_mail 1731132943SgshapiroScheck`'_U_`'mail 173238032SpeterR$* $: $1 $| $>"Local_check_mail" $1 173364562SgshapiroR$* $| $#$* $#$2 1734132943SgshapiroR$* $| $* $@ $>"Basic_check_mail" $1 1735132943Sgshapiro 173638032SpeterSBasic_check_mail 173738032Speter# check for deferred delivery mode 173838032SpeterR$* $: < $&{deliveryMode} > $1 173938032SpeterR< d > $* $@ deferred 174038032SpeterR< $* > $* $: $2 174138032Speter 174298121Sgshapiro# authenticated? 174338032Speterdnl done first: we can require authentication for every mail transaction 174438032Speterdnl workspace: address as given by MAIL FROM: (sender) 174538032SpeterR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 174664562SgshapiroR$* $| $#$+ $#$2 174766494Sgshapirodnl undo damage: remove result of tls_client call 174890792SgshapiroR$* $| $* $: $1 174966494Sgshapiro 1750110560Sgshapirodnl workspace: address as given by MAIL FROM: 1751110560SgshapiroR<> $@ <OK> we MUST accept <> (RFC 1123) 1752110560Sgshapiroifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 175390792Sgshapirodnl do some additional checks 175490792Sgshapirodnl no user@host 175590792Sgshapirodnl no user@localhost (if nonlocal sender) 175690792Sgshapirodnl this is a pretty simple canonification, it will not catch every case 175790792Sgshapirodnl just make sure the address has <> around it (which is required by 1758132943Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...) 175990792Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will 1760132943Sgshapirodnl not be modified by host lookups. 176164562SgshapiroR$+ $: <?> $1 176266494SgshapiroR<?><$+> $: <@> <$1> 176366494SgshapiroR<?>$+ $: <@> <$1> 176490792Sgshapirodnl workspace: <@> <address> 176564562Sgshapirodnl prepend daemon_flags 176666494SgshapiroR$* $: $&{daemon_flags} $| $1 176738032Speterdnl workspace: ${daemon_flags} $| <@> <address> 176864562Sgshapirodnl do not allow these at all or only from local systems? 176964562SgshapiroR$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 177090792Sgshapirodnl accept unqualified sender: change mark to avoid test 177138032SpeterR$* u $* $| <@> < $* > $: <?> < $3 > 177264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 177364562Sgshapirodnl or: <? ${client_name} > <address> 177498121Sgshapirodnl or: <?> <address> 177538032Speterdnl remove daemon_flags 1776132943SgshapiroR$* $| $* $: $2 1777132943Sgshapiro# handle case of @localhost on address 1778132943SgshapiroR<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 1779132943SgshapiroR<@> < $* @ [127.0.0.1] > 1780132943Sgshapiro $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 1781132943SgshapiroR<@> < $* @ localhost.$m > 1782132943Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.$m > 1783132943Sgshapiroifdef(`_NO_UUCP_', `dnl', 178464562Sgshapiro`R<@> < $* @ localhost.UUCP > 178538032Speter $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 178638032Speterdnl workspace: < ? $&{client_name} > <user@localhost|host> 178738032Speterdnl or: <@> <address> 178838032Speterdnl or: <?> <address> (thanks to u in ${daemon_flags}) 178938032SpeterR<@> $* $: $1 no localhost as domain 179038032Speterdnl workspace: < ? $&{client_name} > <user@localhost|host> 179164562Sgshapirodnl or: <address> 179238032Speterdnl or: <?> <address> (thanks to u in ${daemon_flags}) 179338032SpeterR<? $=w> $* $: $2 local client: ok 179438032SpeterR<? $+> <$+> $#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address" 179538032Speterdnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 179638032SpeterR<?> $* $: $1') 179738032Speterdnl workspace: address (or <address>) 179898121SgshapiroR$* $: <?> $>CanonAddr $1 canonify sender address and mark it 179938032Speterdnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 180038032Speterdnl there is nothing behind the <@host> so no trailing $* needed 180138032SpeterR<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 180264562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 180364562SgshapiroR<?> $* < @ $* $=P > $: <OK> $1 < @ $2 $3 > 180464562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ? or OK 180564562Sgshapirodnl A sender address with my local host name ($j) is safe 180664562SgshapiroR<?> $* < @ $j > $: <OK> $1 < @ $j > 180764562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 180864562Sgshapiro`R<?> $* < @ $+ > $: <_RES_OK_> $1 < @ $2 > ... unresolvable OK', 180938032Speter`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 181064562SgshapiroR<? $* <$->> $* < @ $+ > 181164562Sgshapiro $: <$2> $3 < @ $4 >') 181238032Speterdnl workspace <mark> CanonicalAddress where mark is ?, _RES_OK_, PERM, TEMP 181364562Sgshapirodnl mark is ? iff the address is user (wo @domain) 181464562Sgshapiro 181564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 181664562Sgshapiro# check sender address: user@address, user@, address 181764562Sgshapirodnl should we remove +ext from user? 181864562Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP 181964562SgshapiroR<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3> 182064562SgshapiroR<$+> $+ $: @<$1> <$2> $| <U:$2@> 182164562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 182264562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 182364562Sgshapirodnl will only return user<@domain when "reversing" the args 182464562SgshapiroR@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <> 182564562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result> 182664562SgshapiroR<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 182764562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress> 182864562Sgshapiro# retransform for further use 182964562Sgshapirodnl required form: 183064562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress 183164562SgshapiroR<?> <$+> <$*> $: <$1> $2 no match 183264562SgshapiroR<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 183364562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress 183464562Sgshapirodnl mark is ? iff the address is user (wo @domain) 183564562Sgshapiro 183664562Sgshapiroifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 183738032Speter# handle case of no @domain on address 183864562Sgshapirodnl prepend daemon_flags 183964562SgshapiroR<?> $* $: $&{daemon_flags} $| <?> $1 184064562Sgshapirodnl accept unqualified sender: change mark to avoid test 184164562SgshapiroR$* u $* $| <?> $* $: <_RES_OK_> $3 184264562Sgshapirodnl remove daemon_flags 184338032SpeterR$* $| $* $: $2 184464562SgshapiroR<?> $* $: < ? $&{client_name} > $1 184564562SgshapiroR<?> $* $@ <OK> ...local unqualed ok 184664562SgshapiroR<? $+> $* $#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f 184764562Sgshapiro ...remote is not') 184864562Sgshapiro# check results 184964562SgshapiroR<?> $* $: @ $1 mark address: nothing known about it 185064562SgshapiroR<$={ResOk}> $* $@ <_RES_OK_> domain ok: stop 185164562SgshapiroR<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 185264562SgshapiroR<PERM> $* $#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist" 185364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 185490792SgshapiroR<$={Accept}> $* $# $1 accept from access map 185564562SgshapiroR<DISCARD> $* $#discard $: discard 185664562Sgshapiroifdef(`_FFR_QUARANTINE', 185764562Sgshapiro`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 185864562SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 185964562Sgshapirodnl error tag 186064562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 186164562SgshapiroR<ERROR:$+> $* $#error $: $1 186264562Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 1863102528Sgshapirodnl generic error from access map 186464562SgshapiroR<$+> $* $#error $: $1 error from access db', 186598121Sgshapiro`dnl') 1866102528Sgshapiro 186764562Sgshapiro###################################################################### 186890792Sgshapiro### check_rcpt -- check SMTP ``RCPT TO:'' command argument 186964562Sgshapiro###################################################################### 187064562Sgshapiro 187164562SgshapiroSLocal_check_rcpt 187290792SgshapiroScheck`'_U_`'rcpt 187364562SgshapiroR$* $: $1 $| $>"Local_check_rcpt" $1 187438032SpeterR$* $| $#$* $#$2 187564562SgshapiroR$* $| $* $@ $>"Basic_check_rcpt" $1 187664562Sgshapiro 187764562SgshapiroSBasic_check_rcpt 187890792Sgshapiro# empty address? 187990792SgshapiroR<> $#error $@ nouser $: "553 User address required" 188064562SgshapiroR$@ $#error $@ nouser $: "553 User address required" 188164562Sgshapiro# check for deferred delivery mode 188264562SgshapiroR$* $: < $&{deliveryMode} > $1 188364562SgshapiroR< d > $* $@ deferred 188490792SgshapiroR< $* > $* $: $2 188564562Sgshapiro 188664562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 188764562Sgshapirodnl this code checks for user@host where host is not a FQHN. 188838032Speterdnl it is not activated. 188964562Sgshapirodnl notice: code to check for a recipient without a domain name is 189064562Sgshapirodnl available down below; look for the same macro. 189164562Sgshapirodnl this check is done here because the name might be qualified by the 189264562Sgshapirodnl canonicalization. 189364562Sgshapiro# require fully qualified domain part? 189464562Sgshapirodnl very simple canonification: make sure the address is in < > 189538032SpeterR$+ $: <?> $1 189638032SpeterR<?> <$+> $: <@> <$1> 189738032SpeterR<?> $+ $: <@> <$1> 189864562SgshapiroR<@> < postmaster > $: postmaster 189964562SgshapiroR<@> < $* @ $+ . $+ > $: < $3 @ $4 . $5 > 190064562Sgshapirodnl prepend daemon_flags 190190792SgshapiroR<@> $* $: $&{daemon_flags} $| <@> $1 190264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 190364562Sgshapirodnl do not allow these at all or only from local systems? 1904110560SgshapiroR$* r $* $| <@> < $* @ $* > $: < ? $&{client_name} > < $3 @ $4 > 1905102528SgshapiroR<?> < $* > $: <$1> 190690792SgshapiroR<? $=w> < $* > $: <$1> 190738032SpeterR<? $+> <$+> $#error $@ 5.5.4 $: "553 Fully qualified domain name required" 190838032Speterdnl remove daemon_flags for other cases 190964562SgshapiroR$* $| <@> $* $: $2', `dnl') 191090792Sgshapiro 191164562Sgshapirodnl ################################################################## 191290792Sgshapirodnl call subroutines for recipient and relay 191364562Sgshapirodnl possible returns from subroutines: 191490792Sgshapirodnl $#TEMP temporary failure 191538032Speterdnl $#error permanent failure (or temporary if from access map) 1916132943Sgshapirodnl $#other stop processing 1917132943Sgshapirodnl RELAY RELAYing allowed 191864562Sgshapirodnl other otherwise 191964562Sgshapiro###################################################################### 192064562SgshapiroR$* $: $1 $| @ $>"Rcpt_ok" $1 192190792Sgshapirodnl temporary failure? remove mark @ and remember 192264562SgshapiroR$* $| @ $#TEMP $+ $: $1 $| T $2 192364562Sgshapirodnl error or ok (stop) 192438032SpeterR$* $| @ $#$* $#$2 192538032Speterifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 192638032SpeterR$* $| @ RELAY $@ RELAY 192738032Speterdnl something else: call check sender (relay) 192838032SpeterR$* $| @ $* $: O $| $>"Relay_ok" $1 192938032Speterdnl temporary failure: call check sender (relay) 193038032SpeterR$* $| T $+ $: T $2 $| $>"Relay_ok" $1 193164562Sgshapirodnl temporary failure? return that 193238032SpeterR$* $| $#TEMP $+ $#error $2 193338032Speterdnl error or ok (stop) 193438032SpeterR$* $| $#$* $#$2 193538032SpeterR$* $| RELAY $@ RELAY 193638032Speterdnl something else: return previous temp failure 193790792SgshapiroR T $+ $| $* $#error $1 193890792Sgshapiro# anything else is bogus 193990792SgshapiroR$* $#error $@ 5.7.1 $: confRELAY_MSG 194038032Speterdivert(0) 194198121Sgshapiro 194238032Speter###################################################################### 194338032Speter### Rcpt_ok: is the recipient ok? 194438032Speterdnl input: recipient address (RCPT TO) 194564562Sgshapirodnl output: see explanation at call 194690792Sgshapiro###################################################################### 194790792SgshapiroSRcpt_ok 194890792Sgshapiroifdef(`_LOOSE_RELAY_CHECK_',`dnl 194990792SgshapiroR$* $: $>CanonAddr $1 195090792SgshapiroR$* < @ $* . > $1 < @ $2 > strip trailing dots', 195190792Sgshapiro`R$* $: $>ParseRecipient $1 strip relayable hosts') 195290792Sgshapiro 195390792Sgshapiroifdef(`_BESTMX_IS_LOCAL_',`dnl 195464562Sgshapiroifelse(_BESTMX_IS_LOCAL_, `', `dnl 195590792Sgshapiro# unlimited bestmx 195690792SgshapiroR$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 195790792Sgshapiro`dnl 1958110560Sgshapiro# limit bestmx to $=B 195964562SgshapiroR$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 196090792SgshapiroR$* $=O $* < @ $* @@ $=w . > $* $@ $>"Rcpt_ok" $1 $2 $3 196164562SgshapiroR$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 1962120256SgshapiroR$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 1963120256Sgshapiro 196464562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl 1965120256Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 196664562Sgshapiro# blacklist local users or any host from receiving mail 196764562SgshapiroR$* $: <?> $1 196890792Sgshapirodnl user is now tagged with @ to be consistent with check_mail 196964562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user) 197064562SgshapiroR<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2> 197164562SgshapiroR<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2> 197290792SgshapiroR<?> $+ $: <> <$1> $| <U:$1@> 197390792Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 197490792Sgshapirodnl will only return user<@domain when "reversing" the args 197590792SgshapiroR<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+ To> $| <$2> <> 197690792SgshapiroR<@> <$*> $| <$*> $: <$2> <$1> reverse result 197790792SgshapiroR<?> <$*> $: @ $1 mark address as no match 197890792Sgshapirodnl we may have to filter here because otherwise some RHSs 197990792Sgshapirodnl would be interpreted as generic error messages... 198090792Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 198190792Sgshapirodnl that would make a lot of things easier. 198290792SgshapiroR<$={Accept}> <$*> $: @ $2 mark address as no match 198390792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 198490792SgshapiroR<SKIP> <$*> $: @ $1 mark address as no match', `dnl') 198590792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl 198690792Sgshapirodnl compatility with 8.11/8.10: 198790792Sgshapirodnl we have to filter these because otherwise they would be interpreted 198890792Sgshapirodnl as generic error message... 198990792Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 199090792Sgshapirodnl that would make a lot of things easier. 199190792Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)? 199290792SgshapiroR<$={SpamTag}> <$*> $: @ $2 mark address as no match') 199390792SgshapiroR<REJECT> $* $#error $@ 5.2.1 $: confRCPTREJ_MSG 199490792SgshapiroR<DISCARD> $* $#discard $: discard 199590792Sgshapiroifdef(`_FFR_QUARANTINE', 199690792Sgshapiro`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 199790792Sgshapirodnl error tag 199890792SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 199990792SgshapiroR<ERROR:$+> $* $#error $: $1 200090792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 200190792Sgshapirodnl generic error from access map 200290792SgshapiroR<$+> $* $#error $: $1 error from access db 200390792SgshapiroR@ $* $1 remove mark', `dnl')', `dnl') 200490792Sgshapiro 200590792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 200690792Sgshapiro# authenticated via TLS? 200790792SgshapiroR$* $: $1 $| $>RelayTLS client authenticated? 200890792SgshapiroR$* $| $# $+ $# $2 error/ok? 200938032SpeterR$* $| $* $: $1 no 201042575Speter 201138032SpeterR$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type} 201238032Speterdnl workspace: localpart<@domain> $| result of Local_Relay_Auth 201338032SpeterR$* $| $# $* $# $2 201442575Speterdnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech} 201542575SpeterR$* $| NO $: $1 201642575SpeterR$* $| $* $: $1 $| $&{auth_type} 201742575Speterdnl workspace: localpart<@domain> [ $| ${auth_type} ] 201842575Speterdnl empty ${auth_type}? 201942575SpeterR$* $| $: $1 202043730Speterdnl mechanism ${auth_type} accepted? 202190792Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below 202242575SpeterR$* $| $={TrustAuthMech} $# RELAY 202342575Speterdnl remove ${auth_type} 202442575SpeterR$* $| $* $: $1 202538032Speterdnl workspace: localpart<@domain> | localpart 202664562Sgshapiroifelse(defn(`_NO_UUCP_'), `r', 202738032Speter`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 202838032SpeterR$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 202964562Sgshapiro# anything terminating locally is ok 203064562Sgshapiroifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 203190792SgshapiroR$+ < @ $* $=m > $@ RELAY', `dnl') 203290792SgshapiroR$+ < @ $=w > $@ RELAY 203364562Sgshapiroifdef(`_RELAY_HOSTS_ONLY_', 203464562Sgshapiro`R$+ < @ $=R > $@ RELAY 203564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 203690792SgshapiroR$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 203764562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 203864562SgshapiroR<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 203990792Sgshapiro`R$+ < @ $* $=R > $@ RELAY 204090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 204190792SgshapiroR$+ < @ $+ > $: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')') 204290792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 204364562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 204490792SgshapiroR<RELAY> $* $@ RELAY 204590792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 204690792SgshapiroR<$*> <$*> $: $2',`dnl') 204790792Sgshapiro 204864562Sgshapiro 204964562Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl 205064562Sgshapiro# allow relaying for hosts which we MX serve 205164562SgshapiroR$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 205264562Sgshapirodnl this must not necessarily happen if the client is checked first... 205364562SgshapiroR< : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 205490792SgshapiroR<$* : $=w . : $*> $* $@ RELAY 205564562SgshapiroR< : $* : > $* $: $2', 2056132943Sgshapiro`dnl') 205764562Sgshapiro 205864562Sgshapiro# check for local user (i.e. unqualified address) 205964562SgshapiroR$* $: <?> $1 206090792SgshapiroR<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 206164562Sgshapiro# local user is ok 206264562Sgshapirodnl is it really? the standard requires user@domain, not just user 206364562Sgshapirodnl but we should accept it anyway (maybe making it an option: 206438032Speterdnl RequireFQDN ?) 206590792Sgshapirodnl postmaster must be accepted without domain (DRUMS) 206690792Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 206790792SgshapiroR<?> postmaster $@ OK 206890792Sgshapiro# require qualified recipient? 206990792Sgshapirodnl prepend daemon_flags 207064562SgshapiroR<?> $+ $: $&{daemon_flags} $| <?> $1 207190792Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart 207290792Sgshapirodnl do not allow these at all or only from local systems? 207390792Sgshapirodnl r flag? add client_name 207490792SgshapiroR$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 207590792Sgshapirodnl no r flag: relay to local user (only local part) 207690792Sgshapiro# no qualified recipient required 207790792SgshapiroR$* $| <?> $+ $@ RELAY 207864562Sgshapirodnl client_name is empty 207964562SgshapiroR<?> <?> $+ $@ RELAY 208064562Sgshapirodnl client_name is local 208164562SgshapiroR<? $=w> <?> $+ $@ RELAY 208290792Sgshapirodnl client_name is not local 208390792SgshapiroR<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 208464562Sgshapirodnl no qualified recipient required 208571345SgshapiroR<?> $+ $@ RELAY') 208664562Sgshapirodnl it is a remote user: remove mark and then check client 208771345SgshapiroR<$+> $* $: $2 208871345Sgshapirodnl currently the recipient address is not used below 208938032Speter 209038032Speter###################################################################### 209190792Sgshapiro### Relay_ok: is the relay/sender ok? 209290792Sgshapirodnl input: ignored 209338032Speterdnl output: see explanation at call 209490792Sgshapiro###################################################################### 209564562SgshapiroSRelay_ok 209664562Sgshapiro# anything originating locally is ok 209764562Sgshapiro# check IP address 209864562SgshapiroR$* $: $&{client_addr} 209990792SgshapiroR$@ $@ RELAY originated locally 210064562SgshapiroR0 $@ RELAY originated locally 2101132943SgshapiroR$=R $* $@ RELAY relayable IP address 2102132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 2103132943SgshapiroR$* $: $>A <$1> <?> <+ Connect> <$1> 2104132943SgshapiroR<RELAY> $* $@ RELAY relayable IP address 2105132943SgshapiroR<REJECT> $* $@ REJECT rejected IP address 210664562Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 210764562SgshapiroR<$*> <$*> $: $2', `dnl') 210890792SgshapiroR$* $: [ $1 ] put brackets around it... 210990792SgshapiroR$=w $@ RELAY ... and see if it is local 211038032Speter 211138032Speterifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 211264562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 211338032Speterifdef(`_RELAY_MAIL_FROM_', `dnl 211438032Speterdnl input: {client_addr} or something "broken" 211564562Sgshapirodnl just throw the input away; we do not need it. 211664562Sgshapiro# check whether FROM is allowed to use system as relay 2117132943SgshapiroR$* $: <?> $>CanonAddr $&f 211890792SgshapiroR<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 211942575Speterifdef(`_RELAY_LOCAL_FROM_', `dnl 212038032Speter# check whether local FROM is ok 212138032SpeterR<?> $+ < @ $=w > $@ RELAY FROM local', `dnl') 212238032Speterifdef(`_RELAY_DB_FROM_', `dnl 212338032SpeterR<?> $+ < @ $+ > $: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <> 212442575SpeterR<@> <RELAY> $@ RELAY RELAY FROM sender ok 212538032Speterifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 212664562Sgshapiro', `dnl 212764562Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', 212864562Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 212964562Sgshapiro')', 213064562Sgshapiro`dnl') 213190792Sgshapirodnl')', `dnl') 213264562Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind. 213364562Sgshapirodnl it does not matter in this case because the following rule ignores 213464562Sgshapirodnl the input. otherwise these rules must "clean up" the workspace. 213564562Sgshapiro 213664562Sgshapiro# check client name: first: did it resolve? 213764562Sgshapirodnl input: ignored 213864562SgshapiroR$* $: < $&{client_resolve} > 213964562SgshapiroR<TEMP> $#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 214064562SgshapiroR<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 214190792SgshapiroR<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 214264562Sgshapirodnl ${client_resolve} should be OK, so go ahead 214390792SgshapiroR$* $: <@> $&{client_name} 214464562Sgshapirodnl should not be necessary since it has been done for client_addr already 214590792SgshapiroR<@> $@ RELAY 214664562Sgshapirodnl workspace: <@> ${client_name} (not empty) 214764562Sgshapiro# pass to name server to make hostname canonical 214864562SgshapiroR<@> $* $=P $:<?> $1 $2 214990792SgshapiroR<@> $+ $:<?> $[ $1 $] 215064562Sgshapirodnl workspace: <?> ${client_name} (canonified) 215138032SpeterR$* . $1 strip trailing dots 215264562Sgshapiroifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 215338032SpeterR<?> $* $=m $@ RELAY', `dnl') 215490792SgshapiroR<?> $=w $@ RELAY 215590792Sgshapiroifdef(`_RELAY_HOSTS_ONLY_', 215690792Sgshapiro`R<?> $=R $@ RELAY 215790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 215890792SgshapiroR<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 215990792SgshapiroR<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 216038032Speter`R<?> $* $=R $@ RELAY 216164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 216264562SgshapiroR<?> $* $: $>D <$1> <?> <+ Connect> <$1>',`dnl')') 216390792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 216490792SgshapiroR<RELAY> $* $@ RELAY 2165110560Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2166110560SgshapiroR<$*> <$*> $: $2',`dnl') 216790792Sgshapirodnl end of _PROMISCUOUS_RELAY_ 216864562Sgshapirodivert(0) 216990792Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 217090792Sgshapiro# turn a canonical address in the form user<@domain> 2171102528Sgshapiro# qualify unqual. addresses with $j 2172102528Sgshapirodnl it might have been only user (without <@domain>) 2173102528SgshapiroSFullAddr 2174102528SgshapiroR$* <@ $+ . > $1 <@ $2 > 2175102528SgshapiroR$* <@ $* > $@ $1 <@ $2 > 2176102528SgshapiroR$+ $@ $1 <@ $j > 217790792Sgshapiro 217864562Sgshapiro# call all necessary rulesets 217964562SgshapiroScheck_rcpt 218090792Sgshapirodnl this test should be in the Basic_check_rcpt ruleset 218164562Sgshapirodnl which is the correct DSN code? 218264562Sgshapiro# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 218364562SgshapiroR$+ $: $1 $| $>checkrcpt $1 218464562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 218564562SgshapiroR$+ $| $#$* $#$2 218664562SgshapiroR$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 218764562Sgshapiroifdef(`_SPAM_FH_', 218864562Sgshapiro`dnl lookup user@ and user@address 218990792Sgshapiroifdef(`_ACCESS_TABLE_', `', 219064562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 219164562Sgshapiro')')dnl 219290792Sgshapirodnl one of the next two rules is supposed to match 219364562Sgshapirodnl this code has been copied from BLACKLIST... etc 219494334Sgshapirodnl and simplified by omitting some < >. 219590792SgshapiroR<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@> 219690792SgshapiroR<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > 219790792Sgshapirodnl R<?> $@ something_is_very_wrong_here 219890792Sgshapiro# lookup the addresses only with Spam tag 219990792SgshapiroR<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <> 220064562SgshapiroR<@> $* $| $* $: $2 $1 reverse result 220164562Sgshapirodnl', `dnl') 220264562Sgshapiroifdef(`_SPAM_FRIEND_', 220390792Sgshapiro`# is the recipient a spam friend? 220490792Sgshapiroifdef(`_SPAM_HATER_', 220590792Sgshapiro `errprint(`*** ERROR: define either SpamHater or SpamFriend 220664562Sgshapiro')', `dnl') 220764562SgshapiroR<FRIEND> $+ $@ SPAMFRIEND 220864562SgshapiroR<$*> $+ $: $2', 220964562Sgshapiro`dnl') 2210132943Sgshapiroifdef(`_SPAM_HATER_', 221164562Sgshapiro`# is the recipient no spam hater? 221264562SgshapiroR<HATER> $+ $: $1 spam hater: continue checks 221364562SgshapiroR<$*> $+ $@ NOSPAMHATER everyone else: stop 221490792Sgshapirodnl',`dnl') 221590792Sgshapirodnl run further checks: check_mail 2216110560Sgshapirodnl should we "clean up" $&f? 2217110560Sgshapiroifdef(`_FFR_MAIL_MACRO', 2218110560Sgshapiro`R$* $: $1 $| $>checkmail $&{mail_from}', 2219110560Sgshapiro`R$* $: $1 $| $>checkmail <$&f>') 2220110560Sgshapirodnl recipient (canonical format) $| result of checkmail 222190792SgshapiroR$* $| $#$* $#$2 222238032Speterdnl run further checks: check_relay 222390792SgshapiroR$* $| $* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 222490792SgshapiroR$* $| $#$* $#$2 222590792SgshapiroR$* $| $* $: $1 222664562Sgshapiro', `dnl') 222738032Speter 222890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 222990792Sgshapiro###################################################################### 223038032Speter### F: LookUpFull -- search for an entry in access database 223190792Sgshapiro### 223264562Sgshapiro### lookup of full key (which should be an address) and 223364562Sgshapiro### variations if +detail exists: +* and without +detail 223464562Sgshapiro### 223590792Sgshapiro### Parameters: 223664562Sgshapiro### <$1> -- key 223790792Sgshapiro### <$2> -- default (what to return if not found in db) 223864562Sgshapirodnl must not be empty 223990792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 224090792Sgshapiro### ! does lookup only with tag 224138032Speter### + does lookup with and without tag 224290792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 224364562Sgshapirodnl returns: <default> <passthru> 224464562Sgshapirodnl <result> <passthru> 224564562Sgshapiro###################################################################### 224664562Sgshapiro 224764562SgshapiroSF 224864562Sgshapirodnl workspace: <key> <def> <o tag> <thru> 224964562Sgshapirodnl full lookup 225064562Sgshapirodnl 2 3 4 5 225164562SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 225238032Speterdnl no match, try without tag 2253120256Sgshapirodnl 1 2 3 4 2254110560SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 2255110560Sgshapirodnl no match, +detail: try +* 2256110560Sgshapirodnl 1 2 3 4 5 6 7 2257110560SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 2258110560Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 2259110560Sgshapirodnl no match, +detail: try +* without tag 2260120256Sgshapirodnl 1 2 3 4 5 6 2261110560SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 2262110560Sgshapiro $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 2263120256Sgshapirodnl no match, +detail: try without +detail 2264110560Sgshapirodnl 1 2 3 4 5 6 7 2265110560SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 2266110560Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 2267110560Sgshapirodnl no match, +detail: try without +detail and without tag 2268110560Sgshapirodnl 1 2 3 4 5 6 2269110560SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 2270120256Sgshapiro $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 2271110560Sgshapirodnl no match, return <default> <passthru> 2272110560Sgshapirodnl 1 2 3 4 5 227364562SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 227464562Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 227564562Sgshapirodnl 2 3 4 5 227664562SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 227764562Sgshapirodnl match, return <match> <passthru> 2278110560Sgshapirodnl 2 3 4 5 227964562SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 228064562Sgshapiro 2281110560Sgshapiro###################################################################### 2282110560Sgshapiro### E: LookUpExact -- search for an entry in access database 2283110560Sgshapiro### 2284110560Sgshapiro### Parameters: 2285120256Sgshapiro### <$1> -- key 228664562Sgshapiro### <$2> -- default (what to return if not found in db) 228764562Sgshapirodnl must not be empty 228864562Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 228964562Sgshapiro### ! does lookup only with tag 229064562Sgshapiro### + does lookup with and without tag 229164562Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 229264562Sgshapirodnl returns: <default> <passthru> 229364562Sgshapirodnl <result> <passthru> 229464562Sgshapiro###################################################################### 229590792Sgshapiro 229690792SgshapiroSE 229764562Sgshapirodnl 2 3 4 5 229890792SgshapiroR<$*> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 229990792Sgshapirodnl no match, try without tag 230064562Sgshapirodnl 1 2 3 4 230164562SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 230264562Sgshapirodnl no match, return default passthru 230364562Sgshapirodnl 1 2 3 4 5 230464562SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 2305110560Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 230664562Sgshapirodnl 2 3 4 5 2307120256SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 230864562Sgshapirodnl match, return <match> <passthru> 230964562Sgshapirodnl 2 3 4 5 231064562SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 231164562Sgshapiro 231290792Sgshapiro###################################################################### 2313120256Sgshapiro### U: LookUpUser -- search for an entry in access database 231464562Sgshapiro### 231564562Sgshapiro### lookup of key (which should be a local part) and 231664562Sgshapiro### variations if +detail exists: +* and without +detail 231790792Sgshapiro### 231890792Sgshapiro### Parameters: 231990792Sgshapiro### <$1> -- key (user@) 232094334Sgshapiro### <$2> -- default (what to return if not found in db) 232164562Sgshapirodnl must not be empty 232264562Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 232394334Sgshapiro### ! does lookup only with tag 232464562Sgshapiro### + does lookup with and without tag 232538032Speter### <$4> -- passthru (additional data passed unchanged through) 232638032Speterdnl returns: <default> <passthru> 232790792Sgshapirodnl <result> <passthru> 232890792Sgshapiro###################################################################### 232964562Sgshapiro 233090792SgshapiroSU 233190792Sgshapirodnl user lookups are always with trailing @ 233290792Sgshapirodnl 2 3 4 5 233390792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 233490792Sgshapirodnl no match, try without tag 233590792Sgshapirodnl 1 2 3 4 233690792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 233790792Sgshapirodnl do not remove the @ from the lookup: 233890792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup 233990792Sgshapirodnl no match, +detail: try +* 234090792Sgshapirodnl 1 2 3 4 5 6 234190792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 234290792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 234390792Sgshapirodnl no match, +detail: try +* without tag 234490792Sgshapirodnl 1 2 3 4 5 234590792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 234690792Sgshapiro $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 234790792Sgshapirodnl no match, +detail: try without +detail 234890792Sgshapirodnl 1 2 3 4 5 6 234990792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 235090792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 235190792Sgshapirodnl no match, +detail: try without +detail and without tag 235290792Sgshapirodnl 1 2 3 4 5 235390792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 235490792Sgshapiro $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 235590792Sgshapirodnl no match, return <default> <passthru> 235690792Sgshapirodnl 1 2 3 4 5 235790792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 235890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 235990792Sgshapirodnl 2 3 4 5 236090792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 236190792Sgshapirodnl match, return <match> <passthru> 236290792Sgshapirodnl 2 3 4 5 236390792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 236490792Sgshapiro 236590792Sgshapiro###################################################################### 236690792Sgshapiro### SearchList: search a list of items in the access map 236790792Sgshapiro### Parameters: 236890792Sgshapiro### <exact tag> $| <mark:address> <mark:address> ... <> 236990792Sgshapirodnl maybe we should have a @ (again) in front of the mark to 237090792Sgshapirodnl avoid errorneous matches (with error messages?) 237190792Sgshapirodnl if we can make sure that tag is always a single token 237290792Sgshapirodnl then we can omit the delimiter $|, otherwise we need it 237390792Sgshapirodnl to avoid errorneous matchs (first rule: D: if there 237490792Sgshapirodnl is that mark somewhere in the list, it will be taken). 237590792Sgshapirodnl moreover, we can do some tricks to enforce lookup with 237690792Sgshapirodnl the tag only, e.g.: 237790792Sgshapiro### where "exact" is either "+" or "!": 237890792Sgshapiro### <+ TAG> lookup with and w/o tag 237990792Sgshapiro### <! TAG> lookup with tag 238090792Sgshapirodnl Warning: + and ! should be in OperatorChars (otherwise there must be 238190792Sgshapirodnl a blank between them and the tag. 238290792Sgshapiro### possible values for "mark" are: 238390792Sgshapiro### D: recursive host lookup (LookUpDomain) 238490792Sgshapirodnl A: recursive address lookup (LookUpAddress) [not yet required] 238590792Sgshapiro### E: exact lookup, no modifications 238690792Sgshapiro### F: full lookup, try user+ext@domain and user@domain 238790792Sgshapiro### U: user lookup, try user+ext and user (input must have trailing @) 238890792Sgshapiro### return: <RHS of lookup> or <?> (not found) 238990792Sgshapiro###################################################################### 239090792Sgshapiro 239190792Sgshapiro# class with valid marks for SearchList 239290792Sgshapirodnl if A is activated: add it 239390792SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A') 239490792SgshapiroSSearchList 239590792Sgshapiro# just call the ruleset with the name of the tag... nice trick... 239690792Sgshapirodnl 2 3 4 239790792SgshapiroR<$+> $| <$={src}:$*> <$*> $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <> 239890792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <> 239990792Sgshapirodnl no match and nothing left: return 240090792SgshapiroR<$+> $| <> $| <?> <> $@ <?> 240190792Sgshapirodnl no match but something left: continue 240290792SgshapiroR<$+> $| <$+> $| <?> <> $@ $>SearchList <$1> $| <$2> 240390792Sgshapirodnl match: return 240490792SgshapiroR<$+> $| <$*> $| <$+> <> $@ <$3> 240590792Sgshapirodnl return result from recursive invocation 240690792SgshapiroR<$+> $| <$+> $@ <$2> 240790792Sgshapirodnl endif _ACCESS_TABLE_ 240890792Sgshapirodivert(0) 240990792Sgshapiro 241090792Sgshapiro###################################################################### 241190792Sgshapiro### trust_auth: is user trusted to authenticate as someone else? 241290792Sgshapiro### 241390792Sgshapiro### Parameters: 241490792Sgshapiro### $1: AUTH= parameter from MAIL command 241590792Sgshapiro###################################################################### 241690792Sgshapiro 241790792Sgshapirodnl empty ruleset definition so it can be called 241890792SgshapiroSLocal_trust_auth 241990792SgshapiroStrust_auth 242090792SgshapiroR$* $: $&{auth_type} $| $1 242190792Sgshapiro# required by RFC 2554 section 4. 242290792SgshapiroR$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 242390792Sgshapirodnl seems to be useful... 242490792SgshapiroR$* $| $&{auth_authen} $@ identical 242590792SgshapiroR$* $| <$&{auth_authen}> $@ identical 242690792Sgshapirodnl call user supplied code 242790792SgshapiroR$* $| $* $: $1 $| $>"Local_trust_auth" $1 242890792SgshapiroR$* $| $#$* $#$2 242990792Sgshapirodnl default: error 243090792SgshapiroR$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 243190792Sgshapiro 243290792Sgshapiro###################################################################### 243390792Sgshapiro### Relay_Auth: allow relaying based on authentication? 243490792Sgshapiro### 243590792Sgshapiro### Parameters: 243690792Sgshapiro### $1: ${auth_type} 243790792Sgshapiro###################################################################### 243890792SgshapiroSLocal_Relay_Auth 243990792Sgshapiro 244090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 244190792Sgshapiro###################################################################### 244290792Sgshapiro### srv_features: which features to offer to a client? 244390792Sgshapiro### (done in server) 244490792Sgshapiro###################################################################### 244590792SgshapiroSsrv_features 244690792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl 244790792SgshapiroR$* $: $1 $| $>"Local_srv_features" $1 244890792SgshapiroR$* $| $#$* $#$2 244990792SgshapiroR$* $| $* $: $1', `dnl') 245090792SgshapiroR$* $: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <> 245190792SgshapiroR<?>$* $: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <> 245290792SgshapiroR<?>$* $: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)> 245390792SgshapiroR<?>$* $@ OK 245490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 245590792SgshapiroR<$* _ATMPF_>$* $#temp', `dnl') 245690792SgshapiroR<$+>$* $# $1 245790792Sgshapiro 245890792Sgshapiro###################################################################### 245990792Sgshapiro### try_tls: try to use STARTTLS? 246090792Sgshapiro### (done in client) 246190792Sgshapiro###################################################################### 246290792SgshapiroStry_tls 246390792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl 246490792SgshapiroR$* $: $1 $| $>"Local_try_tls" $1 246590792SgshapiroR$* $| $#$* $#$2 246664562SgshapiroR$* $| $* $: $1', `dnl') 246764562SgshapiroR$* $: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <> 246864562SgshapiroR<?>$* $: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <> 246964562SgshapiroR<?>$* $: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)> 247064562SgshapiroR<?>$* $@ OK 247164562Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 247264562SgshapiroR<$* _ATMPF_>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 247390792SgshapiroR<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 247464562Sgshapiro 247564562Sgshapiro###################################################################### 247664562Sgshapiro### tls_rcpt: is connection with server "good" enough? 247764562Sgshapiro### (done in client, per recipient) 247864562Sgshapirodnl called from deliver() before RCPT command 247964562Sgshapiro### 248064562Sgshapiro### Parameters: 248164562Sgshapiro### $1: recipient 248264562Sgshapiro###################################################################### 248390792SgshapiroStls_rcpt 248464562Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl 248564562SgshapiroR$* $: $1 $| $>"Local_tls_rcpt" $1 248664562SgshapiroR$* $| $#$* $#$2 248764562SgshapiroR$* $| $* $: $1', `dnl') 248864562Sgshapirodnl store name of other side 248964562SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 249038032Speterdnl canonify recipient address 249164562SgshapiroR$+ $: <?> $>CanonAddr $1 249264562Sgshapirodnl strip trailing dots 2493132943SgshapiroR<?> $+ < @ $+ . > <?> $1 <@ $2 > 249464562Sgshapirodnl full address? 249590792SgshapiroR<?> $+ < @ $+ > $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:> 249690792Sgshapirodnl only localpart? 2497132943SgshapiroR<?> $+ $: $1 $| <U:$1@> <E:> 249890792Sgshapirodnl look it up 249990792Sgshapirodnl also look up a default value via E: 250090792SgshapiroR$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <> 250190792Sgshapirodnl found nothing: stop here 250290792SgshapiroR$* $| <?> $@ OK 250390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 250490792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 250564562Sgshapirodnl use the generic routine (for now) 250690792SgshapiroR$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>') 250790792Sgshapiro 250890792Sgshapiro###################################################################### 250938032Speter### tls_client: is connection with client "good" enough? 251090792Sgshapiro### (done in server) 251190792Sgshapiro### 251290792Sgshapiro### Parameters: 251390792Sgshapiro### ${verify} $| (MAIL|STARTTLS) 251490792Sgshapiro###################################################################### 251590792Sgshapirodnl MAIL: called from check_mail 251690792Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted 251790792SgshapiroStls_client 251890792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl 251964562SgshapiroR$* $: $1 $| $>"Local_tls_client" $1 252064562SgshapiroR$* $| $#$* $#$2 252164562SgshapiroR$* $| $* $: $1', `dnl') 252264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 252364562Sgshapirodnl store name of other side 252464562SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 252564562Sgshapirodnl ignore second arg for now 252664562Sgshapirodnl maybe use it to distinguish permanent/temporary error? 2527120256Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered) 252864562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed) 252964562SgshapiroR$* $| $* $: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <> 253064562SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <> 253164562Sgshapirodnl do a default lookup: just TLS_CLT_TAG 253290792SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 253390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 253490792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 253590792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 253690792SgshapiroR$* $| $* $@ $>"TLS_connection" $1') 253790792Sgshapiro 253890792Sgshapiro###################################################################### 253964562Sgshapiro### tls_server: is connection with server "good" enough? 254090792Sgshapiro### (done in client) 254190792Sgshapiro### 254290792Sgshapiro### Parameter: 254390792Sgshapiro### ${verify} 254490792Sgshapiro###################################################################### 254590792Sgshapirodnl i.e. has the server been authenticated and is encryption active? 254690792Sgshapirodnl called from deliver() after STARTTLS command 254790792SgshapiroStls_server 254890792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl 2549132943SgshapiroR$* $: $1 $| $>"Local_tls_server" $1 255090792SgshapiroR$* $| $#$* $#$2 255190792SgshapiroR$* $| $* $: $1', `dnl') 255290792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 255364562Sgshapirodnl store name of other side 255490792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 255590792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <> 2556132943SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <> 255764562Sgshapirodnl do a default lookup: just TLS_SRV_TAG 255890792SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 255990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 256090792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 256190792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 256264562SgshapiroR$* $@ $>"TLS_connection" $1') 256390792Sgshapiro 256490792Sgshapiro###################################################################### 256590792Sgshapiro### TLS_connection: is TLS connection "good" enough? 256690792Sgshapiro### 2567132943Sgshapiro### Parameters: 256890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 256990792Sgshapiro### ${verify} $| <Requirement> [<>]', `dnl 257090792Sgshapiro### ${verify}') 257164562Sgshapiro### Requirement: RHS from access map, may be ? for none. 257290792Sgshapirodnl syntax for Requirement: 257390792Sgshapirodnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions] 2574132943Sgshapirodnl extensions: could be a list of further requirements 2575132943Sgshapirodnl for now: CN:string {cn_subject} == string 257690792Sgshapiro###################################################################### 257790792SgshapiroSTLS_connection 257890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error 257990792Sgshapirodnl deal with TLS handshake failures: abort 258090792SgshapiroRSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake." 258190792Sgshapirodivert(-1)') 258290792Sgshapirodnl common ruleset for tls_{client|server} 258390792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>] 258490792Sgshapirodnl remove optional <> 258590792SgshapiroR$* $| <$*>$* $: $1 $| <$2> 258690792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup> 258790792Sgshapiro# create the appropriate error codes 258890792Sgshapirodnl permanent or temporary error? 2589132943SgshapiroR$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 259090792SgshapiroR$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 259190792Sgshapirodnl default case depends on TLS_PERM_ERR 259290792SgshapiroR$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 259390792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup> 259490792Sgshapiro# deal with TLS handshake failures: abort 259590792SgshapiroRSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 259690792Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 259790792Sgshapirodnl use default error 259890792SgshapiroRSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 259990792SgshapiroR$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1 260090792Sgshapirodnl separate optional requirements 260190792SgshapiroR$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1 260290792SgshapiroR$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> <> $1 260390792Sgshapirodnl separate optional requirements 260490792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$* $: <$2> <$3:$4> <$5> $1 260590792Sgshapirodnl some other value in access map: accept 260690792Sgshapirodnl this also allows to override the default case (if used) 260790792SgshapiroR$* $| $* $@ OK 260890792Sgshapiro# authentication required: give appropriate error 260964562Sgshapiro# other side did authenticate (via STARTTLS) 261090792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify} 261190792Sgshapirodnl only verification required and it succeeded 261290792SgshapiroR<$*><VERIFY> <> OK $@ OK 261390792Sgshapirodnl verification required and it succeeded but extensions are given 261490792Sgshapirodnl change it to <SMTP:ESC> <REQ:0> <extensions> 261590792SgshapiroR<$*><VERIFY> <$+> OK $: <$1> <REQ:0> <$2> 261690792Sgshapirodnl verification required + some level of encryption 261764562SgshapiroR<$*><VERIFY:$-> <$*> OK $: <$1> <REQ:$2> <$3> 261864562Sgshapirodnl just some level of encryption required 261964562SgshapiroR<$*><ENCR:$-> <$*> $* $: <$1> <REQ:$2> <$3> 262090792Sgshapirodnl workspace: 262190792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]> <[extensions]> {verify} (!= OK) 262290792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits> <[extensions]> 262390792Sgshapirodnl verification required but ${verify} is not set (case 1.) 262464562SgshapiroR<$-:$+><VERIFY $*> <$*> $#error $@ $2 $: $1 " authentication required" 262590792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL $#error $@ $2 $: $1 " authentication failed" 262690792SgshapiroR<$-:$+><VERIFY $*> <$*> NO $#error $@ $2 $: $1 " not authenticated" 262764562SgshapiroR<$-:$+><VERIFY $*> <$*> NOT $#error $@ $2 $: $1 " no authentication requested" 262864562SgshapiroR<$-:$+><VERIFY $*> <$*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 262964562Sgshapirodnl some other value for ${verify} 263064562SgshapiroR<$-:$+><VERIFY $*> <$*> $+ $#error $@ $2 $: $1 " authentication failure " $4 263190792Sgshapirodnl some level of encryption required: get the maximum level (case 2.) 263290792SgshapiroR<$*><REQ:$-> <$*> $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf} 263364562Sgshapirodnl compare required bits with actual bits 263464562SgshapiroR<$*><REQ:$-> <$*> $- $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $) 263590792SgshapiroR<$-:$+><$-:$-> <$*> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 263690792Sgshapirodnl strength requirements fulfilled 263790792Sgshapirodnl TLS Additional Requirements Separator 263890792Sgshapirodnl this should be something which does not appear in the extensions itself 263964562Sgshapirodnl @ could be part of a CN, DN, etc... 264090792Sgshapirodnl use < > ? those are encoded in CN, DN, ... 264190792Sgshapirodefine(`_TLS_ARS_', `++')dnl 264290792Sgshapirodnl workspace: 264390792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare 264490792SgshapiroR<$-:$+><$-:$-> <$*> $* $: <$1:$2 _TLS_ARS_ $5> 264590792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions> 264690792Sgshapirodnl continue: check extensions 264764562SgshapiroR<$-:$+ _TLS_ARS_ > $@ OK 264864562Sgshapirodnl split extensions into own list 264964562SgshapiroR<$-:$+ _TLS_ARS_ $+ > $: <$1:$2> <$3> 265090792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ > <$1:$2> <$3> <$4> 265190792SgshapiroR<$-:$+> $+ $@ $>"TLS_req" $3 $| <$1:$2> 265290792Sgshapiro 265390792Sgshapiro###################################################################### 265464562Sgshapiro### TLS_req: check additional TLS requirements 265590792Sgshapiro### 265690792Sgshapiro### Parameters: [<list> <of> <req>] $| <$-:$+> 265790792Sgshapiro### $-: SMTP reply code 265890792Sgshapiro### $+: Enhanced Status Code 265964562Sgshapirodnl further requirements for this ruleset: 266064562Sgshapirodnl name of "other side" is stored is {TLS_name} (client/server_name) 266190792Sgshapirodnl 266290792Sgshapirodnl currently only CN[:common_name] is implemented 266390792Sgshapirodnl right now this is only a logical AND 266490792Sgshapirodnl i.e. all requirements must be true 266564562Sgshapirodnl how about an OR? CN must be X or CN must be Y or .. 266690792Sgshapirodnl use a macro to compute this as a trivial sequential 266790792Sgshapirodnl operations (no precedences etc)? 266890792Sgshapiro###################################################################### 266990792SgshapiroSTLS_req 267064562Sgshapirodnl no additional requirements: ok 267190792SgshapiroR $| $+ $@ OK 267290792Sgshapirodnl require CN: but no CN specified: use name of other side 267390792SgshapiroR<CN> $* $| <$+> $: <CN:$&{TLS_Name}> $1 $| <$2> 267490792Sgshapirodnl match, check rest 267590792SgshapiroR<CN:$&{cn_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 267690792Sgshapirodnl CN does not match 267790792Sgshapirodnl 1 2 3 4 267890792SgshapiroR<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1 267990792Sgshapirodnl cert subject 268090792SgshapiroR<CS:$&{cert_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 268190792Sgshapirodnl CS does not match 268290792Sgshapirodnl 1 2 3 4 268390792SgshapiroR<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CERT Subject " $&{cert_subject} " does not match " $1 268464562Sgshapirodnl match, check rest 268590792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 268664562Sgshapirodnl CI does not match 268764562Sgshapirodnl 1 2 3 4 268890792SgshapiroR<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CERT Issuer " $&{cert_issuer} " does not match " $1 268990792Sgshapirodnl return from recursive call 269064562SgshapiroROK $@ OK 2691132943Sgshapiro 2692132943Sgshapiro###################################################################### 269364562Sgshapiro### max: return the maximum of two values separated by : 2694132943Sgshapiro### 269590792Sgshapiro### Parameters: [$-]:[$-] 269690792Sgshapiro###################################################################### 269764562SgshapiroSmax 269864562SgshapiroR: $: 0 269964562SgshapiroR:$- $: $1 270064562SgshapiroR$-: $: $1 270190792SgshapiroR$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 270290792SgshapiroRTRUE:$-:$- $: $2 270390792SgshapiroR$-:$-:$- $: $2 2704132943Sgshapirodnl endif _ACCESS_TABLE_ 270590792Sgshapirodivert(0) 2706132943Sgshapiro 270764562Sgshapiro###################################################################### 270864562Sgshapiro### RelayTLS: allow relaying based on TLS authentication 270964562Sgshapiro### 271064562Sgshapiro### Parameters: 271164562Sgshapiro### none 271290792Sgshapiro###################################################################### 271364562SgshapiroSRelayTLS 271490792Sgshapiro# authenticated? 271590792Sgshapirodnl we do not allow relaying for anyone who can present a cert 271690792Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns 271790792Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow 271864562Sgshapirodnl them to abuse our server (they might be easier to get hold of, 271990792Sgshapirodnl but anyway). 272064562Sgshapirodnl so here is the trick: if the verification succeeded 272190792Sgshapirodnl we look up the cert issuer in the access map 272290792Sgshapirodnl (maybe after extracting a part with a regular expression) 272390792Sgshapirodnl if this returns RELAY we relay without further questions 272490792Sgshapirodnl if it returns SUBJECT we perform a similar check on the 272590792Sgshapirodnl cert subject. 272690792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 272790792SgshapiroR$* $: <?> $&{verify} 272890792SgshapiroR<?> OK $: OK authenticated: continue 272990792SgshapiroR<?> $* $@ NO not authenticated 273090792Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 273164562SgshapiroR$* $: $(CERTIssuer $&{cert_issuer} $)', 273290792Sgshapiro`R$* $: $&{cert_issuer}') 273390792SgshapiroR$+ $: $(access CERTISSUER`'_TAG_DELIM_`'$1 $) 273490792Sgshapirodnl use $# to stop further checks (delay_check) 273564562SgshapiroRRELAY $# RELAY 273690792Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 273790792SgshapiroRSUBJECT $: <@> $(CERTSubject $&{cert_subject} $)', 273890792Sgshapiro`RSUBJECT $: <@> $&{cert_subject}') 273990792SgshapiroR<@> $+ $: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $) 274090792SgshapiroR<@> RELAY $# RELAY 274190792SgshapiroR$* $: NO', `dnl') 274290792Sgshapiro 274390792Sgshapiro###################################################################### 274490792Sgshapiro### authinfo: lookup authinfo in the access map 274590792Sgshapiro### 274690792Sgshapiro### Parameters: 274790792Sgshapiro### $1: {server_name} 274890792Sgshapiro### $2: {server_addr} 274990792Sgshapirodnl both are currently ignored 275090792Sgshapirodnl if it should be done via another map, we either need to restrict 275190792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another 275290792Sgshapirodnl parameter which I want to avoid, it's quite complex already) 275390792Sgshapiro###################################################################### 275464562Sgshapirodnl omit this ruleset if neither is defined? 275590792Sgshapirodnl it causes DefaultAuthInfo to be ignored 275690792Sgshapirodnl (which may be considered a good thing). 275790792SgshapiroSauthinfo 275890792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl 275990792SgshapiroR$* $: <$(authinfo AuthInfo:$&{server_name} $: ? $)> 276090792SgshapiroR<?> $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)> 276190792SgshapiroR<?> $: <$(authinfo AuthInfo: $: ? $)> 276290792SgshapiroR<?> $@ no no authinfo available 276390792SgshapiroR<$*> $# $1 276490792Sgshapirodnl', `dnl 276590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 276690792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <> 276790792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <> 276890792SgshapiroR$* $| <?>$* $: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <> 276990792SgshapiroR$* $| <?>$* $@ no no authinfo available 277090792SgshapiroR$* $| <$*> <> $# $2 277190792Sgshapirodnl', `dnl')') 277290792Sgshapiro 277390792Sgshapiroundivert(9)dnl LOCAL_RULESETS 277490792Sgshapiro# 277590792Sgshapiro###################################################################### 277690792Sgshapiro###################################################################### 277790792Sgshapiro##### 277890792Sgshapiro`##### MAIL FILTER DEFINITIONS' 277990792Sgshapiro##### 278090792Sgshapiro###################################################################### 278190792Sgshapiro###################################################################### 278290792Sgshapiro_MAIL_FILTERS_ 278390792Sgshapiro# 278490792Sgshapiro###################################################################### 2785110560Sgshapiro###################################################################### 278690792Sgshapiro##### 278790792Sgshapiro`##### MAILER DEFINITIONS' 278890792Sgshapiro##### 278990792Sgshapiro###################################################################### 2790110560Sgshapiro###################################################################### 279190792Sgshapiroundivert(7)dnl MAILER_DEFINITIONS 279290792Sgshapiro 279390792Sgshapiro