proto.m4 revision 102528
138032Speterdivert(-1) 238032Speter# 394334Sgshapiro# Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. 464562Sgshapiro# All rights reserved. 538032Speter# Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. 638032Speter# Copyright (c) 1988, 1993 738032Speter# The Regents of the University of California. All rights reserved. 838032Speter# 938032Speter# By using this file, you agree to the terms and conditions set 1038032Speter# forth in the LICENSE file which can be found at the top level of 1138032Speter# the sendmail distribution. 1238032Speter# 1338032Speter# 1438032Speterdivert(0) 1538032Speter 16102528SgshapiroVERSIONID(`$Id: proto.m4,v 8.649.2.5 2002/08/15 02:39:01 ca Exp $') 1738032Speter 1864562Sgshapiro# level CF_LEVEL config file format 1964562SgshapiroV`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley') 2038032Speterdivert(-1) 2138032Speter 2290792Sgshapirodnl if MAILER(`local') not defined: do it ourself; be nice 2390792Sgshapirodnl maybe we should issue a warning? 2490792Sgshapiroifdef(`_MAILER_local_',`', `MAILER(local)') 2590792Sgshapiro 2638032Speter# do some sanity checking 2738032Speterifdef(`__OSTYPE__',, 2864562Sgshapiro `errprint(`*** ERROR: No system type defined (use OSTYPE macro) 2964562Sgshapiro')') 3038032Speter 3138032Speter# pick our default mailers 3238032Speterifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')') 3338032Speterifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')') 3438032Speterifdef(`confRELAY_MAILER',, 3538032Speter `define(`confRELAY_MAILER', 3638032Speter `ifdef(`_MAILER_smtp_', `relay', 3738032Speter `ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')') 3838032Speterifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')') 3938032Speterdefine(`_SMTP_', `confSMTP_MAILER')dnl for readability only 4038032Speterdefine(`_LOCAL_', `confLOCAL_MAILER')dnl for readability only 4138032Speterdefine(`_RELAY_', `confRELAY_MAILER')dnl for readability only 4238032Speterdefine(`_UUCP_', `confUUCP_MAILER')dnl for readability only 4338032Speter 4438032Speter# back compatibility with old config files 4538032Speterifdef(`confDEF_GROUP_ID', 4664562Sgshapiro`errprint(`*** confDEF_GROUP_ID is obsolete. 4764562Sgshapiro Use confDEF_USER_ID with a colon in the value instead. 4864562Sgshapiro')') 4938032Speterifdef(`confREAD_TIMEOUT', 5064562Sgshapiro`errprint(`*** confREAD_TIMEOUT is obsolete. 5164562Sgshapiro Use individual confTO_<timeout> parameters instead. 5264562Sgshapiro')') 5338032Speterifdef(`confMESSAGE_TIMEOUT', 5438032Speter `define(`_ARG_', index(confMESSAGE_TIMEOUT, /)) 5538032Speter ifelse(_ARG_, -1, 5638032Speter `define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)', 5738032Speter `define(`confTO_QUEUERETURN', 5838032Speter substr(confMESSAGE_TIMEOUT, 0, _ARG_)) 5938032Speter define(`confTO_QUEUEWARN', 6038032Speter substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')') 6138032Speterifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,, 6264562Sgshapiro`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete. 6364562Sgshapiro Use confMAX_MESSAGE_SIZE for the second part of the value. 6464562Sgshapiro')')') 6538032Speter 6664562Sgshapiro 6764562Sgshapiro# Sanity check on ldap_routing feature 6864562Sgshapiro# If the user doesn't specify a new map, they better have given as a 6964562Sgshapiro# default LDAP specification which has the LDAP base (and most likely the host) 7064562Sgshapiroifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(` 7164562SgshapiroWARNING: Using default FEATURE(ldap_routing) map definition(s) 7264562Sgshapirowithout setting confLDAP_DEFAULT_SPEC option. 7364562Sgshapiro')')')dnl 7464562Sgshapiro 7538032Speter# clean option definitions below.... 7664562Sgshapirodefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl 7738032Speter 7864562Sgshapirodnl required to "rename" the check_* rulesets... 7964562Sgshapirodefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_')) 8064562Sgshapirodnl default relaying denied message 8190792Sgshapiroifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG', 8290792Sgshapiroifdef(`_USE_AUTH_', `"550 Relaying denied. Proper authentication required."', `"550 Relaying denied"'))') 8390792Sgshapiroifdef(`confRCPTREJ_MSG', `', `define(`confRCPTREJ_MSG', `"550 Mailbox disabled for this recipient"')') 8490792Sgshapirodefine(`_CODE553', `553') 8538032Speterdivert(0)dnl 8638032Speter 8764562Sgshapiro# override file safeties - setting this option compromises system security, 8864562Sgshapiro# addressing the actual file configuration problem is preferred 8964562Sgshapiro# need to set this before any file actions are encountered in the cf file 9064562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe') 9138032Speter 9264562Sgshapiro# default LDAP map specification 9364562Sgshapiro# need to set this now before any LDAP maps are defined 9464562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost') 9564562Sgshapiro 9638032Speter################## 9738032Speter# local info # 9838032Speter################## 9938032Speter 10090792Sgshapiro# my LDAP cluster 10190792Sgshapiro# need to set this before any LDAP lookups are done (including classes) 10290792Sgshapiroifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m') 10390792Sgshapiro 10438032SpeterCwlocalhost 10538032Speterifdef(`USE_CW_FILE', 10638032Speter`# file containing names of hosts for which we receive email 10738032SpeterFw`'confCW_FILE', 10838032Speter `dnl') 10938032Speter 11038032Speter# my official domain name 11138032Speter# ... `define' this only if sendmail cannot automatically determine your domain 11238032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM') 11338032Speter 11438032SpeterCP. 11538032Speter 11638032Speterifdef(`UUCP_RELAY', 11738032Speter`# UUCP relay host 11838032SpeterDY`'UUCP_RELAY 11938032SpeterCPUUCP 12038032Speter 12138032Speter')dnl 12238032Speterifdef(`BITNET_RELAY', 12338032Speter`# BITNET relay host 12438032SpeterDB`'BITNET_RELAY 12538032SpeterCPBITNET 12638032Speter 12738032Speter')dnl 12838032Speterifdef(`DECNET_RELAY', 12938032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl 13038032Speter# DECnet relay host 13138032SpeterDC`'DECNET_RELAY 13238032SpeterCPDECNET 13338032Speter 13438032Speter')dnl 13538032Speterifdef(`FAX_RELAY', 13638032Speter`# FAX relay host 13738032SpeterDF`'FAX_RELAY 13838032SpeterCPFAX 13938032Speter 14038032Speter')dnl 14138032Speter# "Smart" relay host (may be null) 14290792SgshapiroDS`'ifdef(`SMART_HOST', `SMART_HOST') 14338032Speter 14438032Speterifdef(`LUSER_RELAY', `dnl 14538032Speter# place to which unknown users should be forwarded 14638032SpeterKuser user -m -a<> 14738032SpeterDL`'LUSER_RELAY', 14838032Speter`dnl') 14938032Speter 15038032Speter# operators that cannot be in local usernames (i.e., network indicators) 15138032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!') 15238032Speter 15338032Speter# a class with just dot (for identifying canonical names) 15438032SpeterC.. 15538032Speter 15638032Speter# a class with just a left bracket (for identifying domain literals) 15738032SpeterC[[ 15838032Speter 15964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 16064562Sgshapiro# access_db acceptance class 16164562SgshapiroC{Accept}OK RELAY 16290792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl 16364562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl 16464562Sgshapiro# possible access_db RHS for spam friends/haters 16564562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')', 16638032Speter`dnl') 16738032Speter 16890792Sgshapirodnl mark for "domain is ok" (resolved or accepted anyway) 16990792Sgshapirodefine(`_RES_OK_', `OKR')dnl 17038032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl 17138032Speter# Resolve map (to check if a host exists in check_mail) 17290792SgshapiroKresolve host -a<_RES_OK_> -T<TEMP>') 17390792SgshapiroC{ResOk}_RES_OK_ 17438032Speter 17580785Sgshapiroifdef(`_NEED_MACRO_MAP_', `dnl 17680785Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map 17780785Sgshapirodefine(`_MACRO_MAP_', `1')dnl 17880785SgshapiroKmacro macro')', `dnl') 17966494Sgshapiro 18038032Speterifdef(`confCR_FILE', `dnl 18166494Sgshapiro# Hosts for which relaying is permitted ($=R) 18238032SpeterFR`'confCR_FILE', 18338032Speter`dnl') 18438032Speter 18590792Sgshapirodefine(`TLS_SRV_TAG', `"TLS_Srv"')dnl 18690792Sgshapirodefine(`TLS_CLT_TAG', `"TLS_Clt"')dnl 18790792Sgshapirodefine(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl 18890792Sgshapirodefine(`TLS_TRY_TAG', `"Try_TLS"')dnl 18990792Sgshapirodefine(`SRV_FEAT_TAG', `"Srv_Features"')dnl 19064562Sgshapirodnl this may be useful in other contexts too 19164562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map 19264562Sgshapirodefine(`_ARITH_MAP_', `1')dnl 19364562SgshapiroKarith arith') 19464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 19590792Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map 19690792Sgshapirodefine(`_MACRO_MAP_', `1')dnl 19790792SgshapiroKmacro macro') 19890792Sgshapiro# possible values for TLS_connection in access map 19964562SgshapiroC{tls}VERIFY ENCR', `dnl') 20064562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 20164562Sgshapiro# extract relevant part from cert issuer 20264562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl') 20364562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 20464562Sgshapiro# extract relevant part from cert subject 20564562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl') 20664562Sgshapiro 20790792Sgshapiroifdef(`LOCAL_RELAY', `dnl 20838032Speter# who I send unqualified names to (null means deliver locally) 20990792SgshapiroDR`'LOCAL_RELAY') 21038032Speter 21190792Sgshapiroifdef(`MAIL_HUB', `dnl 21238032Speter# who gets all local email traffic ($R has precedence for unqualified names) 21390792SgshapiroDH`'MAIL_HUB') 21438032Speter 21538032Speter# dequoting map 21690792SgshapiroKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `') 21738032Speter 21838032Speterdivert(0)dnl # end of nullclient diversion 21938032Speter# class E: names that should be exposed as from this host, even if we masquerade 22064562Sgshapiro# class L: names that should be delivered locally, even if we have a relay 22138032Speter# class M: domains that should be converted to $M 22264562Sgshapiro# class N: domains that should not be converted to $M 22338032Speter#CL root 22438032Speterundivert(5)dnl 22564562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl') 22638032Speter 22790792Sgshapiroifdef(`MASQUERADE_NAME', `dnl 22838032Speter# who I masquerade as (null for no masquerading) (see also $=M) 22990792SgshapiroDM`'MASQUERADE_NAME') 23038032Speter 23138032Speter# my name for error messages 23238032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON') 23338032Speter 23464562Sgshapiroundivert(6)dnl LOCAL_CONFIG 23538032Speterinclude(_CF_DIR_`m4/version.m4') 23638032Speter 23738032Speter############### 23838032Speter# Options # 23938032Speter############### 24090792Sgshapiroifdef(`confAUTO_REBUILD', 24190792Sgshapiro`errprint(WARNING: `confAUTO_REBUILD' is no longer valid. 24290792Sgshapiro There was a potential for a denial of service attack if this is set. 24390792Sgshapiro)')dnl 24438032Speter 24538032Speter# strip message body to 7 bits on input? 24664562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False') 24738032Speter 24838032Speter# 8-bit data handling 24977349Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8') 25038032Speter 25138032Speter# wait for alias file rebuild (default units: minutes) 25264562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m') 25338032Speter 25438032Speter# location of alias file 25564562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases') 25664562Sgshapiro 25738032Speter# minimum number of free blocks on filesystem 25864562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100') 25938032Speter 26038032Speter# maximum message size 26164562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000') 26238032Speter 26338032Speter# substitution for space (blank) characters 26464562Sgshapiro_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 28490792Sgshapiro# queue file mode (qf files) 28590792Sgshapiro_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600') 28690792Sgshapiro 28738032Speter# temporary file mode 28864562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600') 28938032Speter 29038032Speter# match recipients against GECOS field? 29164562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False') 29238032Speter 29338032Speter# maximum hop count 29490792Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `25') 29538032Speter 29638032Speter# location of help file 29764562SgshapiroO 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', 34094334Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. 34194334Sgshapiro Use `DAEMON_OPTIONS()'; see cf/README. 34264562Sgshapiro)'dnl 34364562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')') 34466494Sgshapiroifelse(defn(`_DPO_'), `', 34590792Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet 34690792SgshapiroO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_') 34764562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E') 34838032Speter 34964562Sgshapiro# SMTP client options 35090792Sgshapiroifelse(defn(`confCLIENT_OPTIONS'), `', `dnl', 35190792Sgshapiro`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid. See cf/README for more information. 35290792Sgshapiro)'dnl 35390792Sgshapiro`CLIENT_OPTIONS(`confCLIENT_OPTIONS')') 35490792Sgshapiroifelse(defn(`_CPO_'), `', 35590792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_') 35664562Sgshapiro 35790792Sgshapiro# Modifiers to `define' {daemon_flags} for direct submissions 35890792Sgshapiro_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `') 35990792Sgshapiro 36090792Sgshapiro# Use as mail submission program? See sendmail/SECURITY 36190792Sgshapiro_OPTION(UseMSP, `confUSE_MSP', `') 36290792Sgshapiro 36338032Speter# privacy flags 36464562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings') 36538032Speter 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 37290792Sgshapiro# limit on number of concurrent queue runners 37390792Sgshapiro_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `') 37490792Sgshapiro 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 39338032Speter# queue directory 39464562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue') 39538032Speter 39690792Sgshapiro# key for shared memory; 0 to turn off 39790792Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0') 39890792Sgshapiro 39994334Sgshapiroifdef(`confSHARED_MEMORY_KEY_FILE', `dnl 40094334Sgshapiro# file to store key for shared memory (if SharedMemoryKey = -1) 40194334SgshapiroO SharedMemoryKeyFile=confSHARED_MEMORY_KEY_FILE') 40294334Sgshapiro 40338032Speter# timeouts (many of these) 40464562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m') 40564562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m') 40690792Sgshapiro_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s') 40764562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m') 40864562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m') 40964562Sgshapiro_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') 42864562Sgshapiro_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') 43364562Sgshapiro_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') 43690792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m') 43790792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m') 43890792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h') 43938032Speter 44090792Sgshapiro# time for DeliverBy; extension disabled if less than 0 44190792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0') 44290792Sgshapiro 44338032Speter# should we not prune routes in route-addr syntax addresses? 44464562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False') 44538032Speter 44638032Speter# queue up everything before forking? 44764562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True') 44838032Speter 44938032Speter# status file 45064562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics') 45138032Speter 45238032Speter# time zone handling: 45338032Speter# if undefined, use system default 45438032Speter# if defined but null, use TZ envariable passed in 45538032Speter# 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) 46164562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull') 46238032Speter 46338032Speter# list of locations of user database file (null means no lookup) 46464562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb') 46538032Speter 46638032Speter# fallback MX host 46764562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net') 46838032Speter 46938032Speter# if we are the best MX host for a site, try it directly instead of config err 47064562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False') 47138032Speter 47238032Speter# load average at which we just queue messages 47364562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8') 47438032Speter 47538032Speter# load average at which we refuse connections 47664562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12') 47738032Speter 47890792Sgshapiro# load average at which we delay connections; 0 means no limit 47990792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0') 48090792Sgshapiro 48138032Speter# maximum number of children we allow at one time 48298841Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0') 48338032Speter 48438032Speter# maximum number of new connections per second 48571345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0') 48638032Speter 48738032Speter# work recipient factor 48864562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') 48938032Speter 49038032Speter# deliver each queued job in a separate process? 49164562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False') 49238032Speter 49338032Speter# work class factor 49464562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800') 49538032Speter 49638032Speter# work time factor 49764562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000') 49838032Speter 49938032Speter# default character set 50064562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1') 50138032Speter 50290792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others) 50364562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch') 50438032Speter 50538032Speter# hosts file (normally /etc/hosts) 50664562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts') 50738032Speter 50838032Speter# dialup line delay on connection failure 50964562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s') 51038032Speter 51138032Speter# action to take if there are no recipients in the message 51264562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed') 51338032Speter 51438032Speter# chrooted environment for writing to files 51564562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch') 51638032Speter 51738032Speter# are colons OK in addresses? 51864562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True') 51938032Speter 52038032Speter# shall I avoid expanding CNAMEs (violates protocols)? 52164562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False') 52238032Speter 52338032Speter# SMTP initial login message (old $e macro) 52464562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b') 52538032Speter 52638032Speter# UNIX initial From header format (old $l macro) 52764562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d') 52838032Speter 52938032Speter# From: lines that have embedded newlines are unwrapped onto one line 53064562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False') 53138032Speter 53238032Speter# Allow HELO SMTP command that does not `include' a host name 53364562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False') 53438032Speter 53538032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic) 53664562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.') 53738032Speter 53838032Speter# delimiter (operator) characters (old $o macro) 53964562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]') 54038032Speter 54138032Speter# shall I avoid calling initgroups(3) because of high NIS costs? 54264562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False') 54338032Speter 54438032Speter# are group-writable `:include:' and .forward files (un)trustworthy? 54590792Sgshapiro# True (the default) means they are not trustworthy. 54664562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True') 54790792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES', 54890792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL. 54990792Sgshapiro')') 55038032Speter 55138032Speter# where do errors that occur when sending errors get sent? 55264562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster') 55338032Speter 55464562Sgshapiro# where to save bounces if all else fails 55564562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter') 55664562Sgshapiro 55738032Speter# what user id do we assume for the majority of the processing? 55864562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail') 55938032Speter 56038032Speter# maximum number of recipients per SMTP envelope 56164562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100') 56238032Speter 56390792Sgshapiro# limit the rate recipients per SMTP envelope are accepted 56490792Sgshapiro# once the threshold number of recipients have been rejected 56590792Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20') 56690792Sgshapiro 56738032Speter# shall we get local names from our installed interfaces? 56864562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 56938032Speter 57064562Sgshapiro# Return-Receipt-To: header implies DSN request 57164562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 57264562Sgshapiro 57364562Sgshapiro# override connection address (for testing) 57464562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 57564562Sgshapiro 57664562Sgshapiro# Trusted user for file ownership and starting the daemon 57764562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root') 57864562Sgshapiro 57964562Sgshapiro# Control socket for daemon management 58064562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 58164562Sgshapiro 58264562Sgshapiro# Maximum MIME header length to protect MUAs 58364562Sgshapiro_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 59764562Sgshapiro# 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 60390792Sgshapiro# lookup type to find information about local mailboxes 60490792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw') 60590792Sgshapiro 60664562Sgshapiro# list of authentication mechanisms 60790792Sgshapiro_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 61590792Sgshapiro# SMTP AUTH maximum encryption strength 61690792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `') 61790792Sgshapiro 61890792Sgshapiro# SMTP STARTTLS server options 61990792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `') 62090792Sgshapiro 62164562Sgshapiro# Input mail filters 62264562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 62364562Sgshapiro 62498841Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl 62564562Sgshapiro# Milter options 62690792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `') 62764562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 62864562Sgshapiro_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 63564562Sgshapiro_OPTION(CACERTFile, `confCACERT', `') 63664562Sgshapiro# Server Cert 63764562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `') 63864562Sgshapiro# Server private key 63964562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `') 64064562Sgshapiro# Client Cert 64164562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `') 64264562Sgshapiro# Client private key 64364562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 64464562Sgshapiro# DHParameters (only required if DSA/DH is used) 64564562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `') 64664562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL) 64764562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `') 64864562Sgshapiro 64990792Sgshapiro############################ 65090792Sgshapiro`# QUEUE GROUP DEFINITIONS #' 65190792Sgshapiro############################ 65290792Sgshapiro_QUEUE_GROUP_ 65342575Speter 65438032Speter########################### 65538032Speter# Message precedences # 65638032Speter########################### 65738032Speter 65838032SpeterPfirst-class=0 65938032SpeterPspecial-delivery=100 66038032SpeterPlist=-30 66138032SpeterPbulk=-60 66238032SpeterPjunk=-100 66338032Speter 66438032Speter##################### 66538032Speter# Trusted users # 66638032Speter##################### 66738032Speter 66838032Speter# this is equivalent to setting class "t" 66964562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 67038032SpeterTroot 67138032SpeterTdaemon 67238032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp') 67338032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 67438032Speter 67538032Speter######################### 67638032Speter# 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> 69164562Sgshapiro 69238032Speter# 69338032Speter###################################################################### 69438032Speter###################################################################### 69538032Speter##### 69638032Speter##### REWRITING RULES 69738032Speter##### 69838032Speter###################################################################### 69938032Speter###################################################################### 70038032Speter 70138032Speter############################################ 70238032Speter### Ruleset 3 -- Name Canonicalization ### 70338032Speter############################################ 70464562SgshapiroScanonify=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:... 71390792SgshapiroR$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr 71438032SpeterR$* :: $* <@> $: $1 :: $2 unmark node::addr 71538032SpeterR:`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 72071345SgshapiroR$* < $+ :; > $* $@ $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 <> 72838032SpeterR$+ < $* > < $2 > strip excess on left 72938032SpeterR< $* > $+ < $1 > strip excess on right 73038032SpeterR<> $@ < @ > MAIL FROM:<> case 73138032SpeterR< $+ > $: $1 remove housekeeping <> 73238032Speter 73364562Sgshapiroifdef(`_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 73738032Speter# localize and dispose of route-based addresses 73890792Sgshapirodnl XXX: IPv6 colon conflict 73990792Sgshapiroifdef(`NO_NETINET6', `dnl', 74090792Sgshapiro`R@ [$+] : $+ $@ $>Canonify2 < @ [$1] > : $2 handle <route-addr>') 74164562SgshapiroR@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 74264562Sgshapirodnl',`dnl 74364562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d> 74464562SgshapiroR@ $+ , $+ $2 74590792Sgshapiroifdef(`NO_NETINET6', `dnl', 74690792Sgshapiro`R@ [ $* ] : $+ $2') 74764562SgshapiroR@ $+ : $+ $2 74864562Sgshapirodnl') 74938032Speter 75038032Speter# find focus for list syntax 75164562SgshapiroR $+ : $* ; @ $+ $@ $>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 75990792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here. 76090792Sgshapirodnl # do some sanity checking 76190792Sgshapirodnl R$* < @ $~[ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 76238032Speter 76338032Speterifdef(`_NO_UUCP_', `dnl', 76438032Speter`# 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 76838032Speter') 76938032Speterifdef(`_USE_DECNET_SYNTAX_', 77038032Speter`# 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') 77538032Speter# 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. 77864562SgshapiroR$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 77938032Speter 78038032Speter# else we must be a local name 78164562SgshapiroR$* $@ $>Canonify2 $1 78238032Speter 78338032Speter 78438032Speter################################################ 78538032Speter### Ruleset 96 -- bottom half of ruleset 3 ### 78638032Speter################################################ 78738032Speter 78864562SgshapiroSCanonify2=96 78938032Speter 79038032Speter# handle special cases for local names 79138032SpeterR$* < @ 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 79690792Sgshapiro# check for IPv4/IPv6 domain literal 79790792SgshapiroR$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr] 79838032SpeterR$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 79938032SpeterR$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 80038032Speter 80164562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl 80238032Speter# look up domains in the domain table 80338032SpeterR$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 80438032Speter 80564562Sgshapiroundivert(2)dnl LOCAL_RULE_3 80638032Speter 80764562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl 80838032Speter# handle BITNET mapping 80938032SpeterR$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 81038032Speter 81164562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl 81238032Speter# 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', 81938032Speter`# if really UUCP, handle it immediately 82038032Speterifdef(`_CLASS_U_', 82138032Speter`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82238032Speterifdef(`_CLASS_V_', 82338032Speter`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82438032Speterifdef(`_CLASS_W_', 82538032Speter`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82638032Speterifdef(`_CLASS_X_', 82738032Speter`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82838032Speterifdef(`_CLASS_Y_', 82938032Speter`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 83038032Speter 83138032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl 83238032Speter# try UUCP traffic as a local address 83338032SpeterR$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 83438032SpeterR$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 83538032Speter')') 83664562Sgshapiro# hostnames ending in class P are always canonical 83764562SgshapiroR$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 83864562Sgshapirodnl apply the next rule only for hostnames not in class P 83964562Sgshapirodnl this even works for phrases in class P since . is in class P 84064562Sgshapirodnl which daemon flags are set? 84164562SgshapiroR$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 84264562Sgshapirodnl the other rules in this section only apply if the hostname 84364562Sgshapirodnl does not end in class P hence no further checks are done here 84464562Sgshapirodnl if this ever changes make sure the lookups are "protected" again! 84564562Sgshapiroifdef(`_NO_CANONIFY_', `dnl 84664562Sgshapirodnl do not canonify unless: 84764562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection 84864562Sgshapirodnl with class P is non-empty) 84964562Sgshapirodnl or {daemon_flags} has c set 85064562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify} 85164562SgshapiroR$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 85264562Sgshapiro# pass to name server to make hostname canonical if requested 85364562SgshapiroR$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 85464562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 85564562SgshapiroR$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 85664562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work 85764562SgshapiroR$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 85864562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl 85964562Sgshapirodnl 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 86390792SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 86464562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless: 86564562Sgshapirodnl {daemon_flags} contains CC (do not canonify) 86671345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work 86771345Sgshapirodnl should we do this for every hostname: even unqualified? 86871345SgshapiroR$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 86964562SgshapiroR$* CC $* $| $* $: $3 87090792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl 87190792Sgshapiro# do not canonify header addresses 87290792SgshapiroR$* $| $* < @ $* $~P > $* $: $&{addr_type} $| $2 < @ $3 $4 > $5 87390792SgshapiroR$* h $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 87490792SgshapiroR$* h $* $| $* $: $3', `dnl') 87538032Speter# pass to name server to make hostname canonical 87664562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 87764562Sgshapirodnl remove {daemon_flags} for other cases 87864562SgshapiroR$* $| $* $: $2 87938032Speter 88038032Speter# local host aliases and pseudo-domains are always canonical 88138032SpeterR$* < @ $=w > $* $: $1 < @ $2 . > $3 88238032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 88338032Speter`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 88438032Speter`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 88564562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 88664562Sgshapirodnl virtual hosts are also canonical 88764562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 88864562Sgshapiro`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 88964562Sgshapiro`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 89064562Sgshapiro`dnl') 89190792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 89290792Sgshapirodnl hosts for genericstable are also canonical 89390792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_', 89490792Sgshapiro`R$* < @ $* $=G > $* $: $1 < @ $2 $3 . > $4', 89590792Sgshapiro`R$* < @ $=G > $* $: $1 < @ $2 . > $3')', 89690792Sgshapiro`dnl') 89764562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added 89864562Sgshapirodnl by one of the rules before 89938032SpeterR$* < @ $* . . > $* $1 < @ $2 . > $3 90038032Speter 90138032Speter 90238032Speter################################################## 90338032Speter### Ruleset 4 -- Final Output Post-rewriting ### 90438032Speter################################################## 90564562SgshapiroSfinal=4 90638032Speter 90771345SgshapiroR$+ :; <@> $@ $1 : handle <list:;> 90838032SpeterR$* <@> $@ handle <> and list:; 90938032Speter 91038032Speter# strip trailing dot off possibly canonical name 91138032SpeterR$* < @ $+ . > $* $1 < @ $2 > $3 91238032Speter 91364562Sgshapiro# eliminate internal code 91438032SpeterR$* < @ *LOCAL* > $* $1 < @ $j > $2 91538032Speter 91638032Speter# externalize local domain info 91738032SpeterR$* < $+ > $* $1 $2 $3 defocus 91838032SpeterR@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 91938032SpeterR@ $* $@ @ $1 ... and exit 92038032Speter 92138032Speterifdef(`_NO_UUCP_', `dnl', 92238032Speter`# 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') 92938032Speter# delete duplicate local names 93038032SpeterR$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 93138032Speter 93238032Speter 93338032Speter 93438032Speter############################################################## 93538032Speter### Ruleset 97 -- recanonicalize and call ruleset zero ### 93638032Speter### (used for recursive calls) ### 93738032Speter############################################################## 93838032Speter 93964562SgshapiroSRecurse=97 94064562SgshapiroR$* $: $>canonify $1 94164562SgshapiroR$* $@ $>parse $1 94238032Speter 94338032Speter 94438032Speter###################################### 94538032Speter### Ruleset 0 -- Parse Address ### 94638032Speter###################################### 94738032Speter 94864562SgshapiroSparse=0 94938032Speter 95038032SpeterR$* $: $>Parse0 $1 initial parsing 95138032SpeterR<@> $#_LOCAL_ $: <@> special case error msgs 95264562SgshapiroR$* $: $>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 96338032SpeterR<@> $@ <@> special case error msgs 96490792SgshapiroR$* : $* ; <@> $#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses" 96564562SgshapiroR@ <@ $* > < @ $1 > catch "@@host" bogosity 96690792SgshapiroR<@ $+> $#error $@ 5.1.3 $: "_CODE553 User address required" 96790792SgshapiroR$+ <@> $#error $@ 5.1.3 $: "_CODE553 Hostname required" 96838032SpeterR$* $: <> $1 96990792Sgshapirodnl allow tricks like [host1]:[host2] 97090792SgshapiroR<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4 97190792SgshapiroR<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4 97290792Sgshapirodnl but no a@[b]c 97390792SgshapiroR<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid address" 97490792SgshapiroR<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 97590792SgshapiroR<> $* <$* : $* > $* $#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part" 97638032SpeterR<> $* $1 97790792SgshapiroR$* < @ . $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 97890792SgshapiroR$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 97990792Sgshapirodnl no a@b@ 98090792SgshapiroR$* < @ $* @ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid route address" 98190792Sgshapirodnl no a@b@c 98290792SgshapiroR$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 98364562Sgshapirodnl comma only allowed before @; this check is not complete 98490792SgshapiroR$* , $~O $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 98538032Speter 98690792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks 98790792SgshapiroR$* . < @ $* > $* $#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" 98990792Sgshapirodnl', `dnl') 99090792Sgshapiro 99138032Speter# now delete the local info -- note $=O to find characters that cause forwarding 99264562SgshapiroR$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 99364562SgshapiroR< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 99438032SpeterR$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 99590792SgshapiroR< @ $+ > $#error $@ 5.1.3 $: "_CODE553 User address required" 99664562SgshapiroR$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 99738032SpeterR$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 99890792SgshapiroR< @ *LOCAL* > $#error $@ 5.1.3 $: "_CODE553 User address required" 99938032SpeterR$* $=O $* < @ *LOCAL* > 100064562Sgshapiro $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 100138032SpeterR$* < @ *LOCAL* > $: $1 100238032Speter 100338032Speter# 100438032Speter# Parse1 -- the bottom half of ruleset 0. 100538032Speter# 100638032Speter 100738032SpeterSParse1 100864562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 100964562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute} 101090792SgshapiroR$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <> 101190792SgshapiroR$+ < @ $={LDAPRouteEquiv} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>', 101264562Sgshapiro`dnl') 101364562Sgshapiro 101438032Speterifdef(`_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 101864562SgshapiroR$* < @ [ $+ ] > $* $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 102164562SgshapiroR$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 102238032Speter `dnl') 102338032Speter 102464562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 102538032Speter# handle virtual users 102690792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 102790792Sgshapirodnl this is not a documented option 102890792Sgshapirodnl it stops looping in virtusertable mapping if input and output 102990792Sgshapirodnl are identical, i.e., if address A is mapped to A. 103090792Sgshapirodnl it does not deal with multi-level recursion 103190792Sgshapiro# handle full domains in RHS of virtusertable 103290792SgshapiroR$+ < @ $+ > $: $(macro {RecipientAddress} $) $1 < @ $2 > 103390792SgshapiroR$+ < @ $+ > $: <?> $1 < @ $2 > $| $>final $1 < @ $2 > 103490792SgshapiroR<?> $+ $| $+ $: $1 $(macro {RecipientAddress} $@ $2 $) 103590792SgshapiroR<?> $+ $| $* $: $1', 103690792Sgshapiro`dnl') 103764562SgshapiroR$+ $: <!> $1 Mark for lookup 103890792Sgshapirodnl input: <!> local<@domain> 103964562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 104064562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 104164562Sgshapiro`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 104290792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain> 104364562SgshapiroR<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 104490792Sgshapirodnl if <@> local<@domain>: no match but try lookup 104590792Sgshapirodnl user+detail: try user++@domain if detail not empty 104690792SgshapiroR<@> $+ + $+ < @ $* . > 104790792Sgshapiro $: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 104890792Sgshapirodnl user+detail: try user+*@domain 104938032SpeterR<@> $+ + $* < @ $* . > 105090792Sgshapiro $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105190792Sgshapirodnl user+detail: try user@domain 105238032SpeterR<@> $+ + $* < @ $* . > 105390792Sgshapiro $: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105464562Sgshapirodnl try default entry: @domain 105590792Sgshapirodnl ++@domain 105690792SgshapiroR<@> $+ + $+ < @ $+ . > $: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105764562Sgshapirodnl +*@domain 105890792SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105964562Sgshapirodnl @domain if +detail exists 106098121Sgshapirodnl if no match, change marker to prevent a second @domain lookup 106198121SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . > 106298121Sgshapirodnl without +detail 106338032SpeterR<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 106490792Sgshapirodnl no match 106538032SpeterR<@> $+ $: $1 106690792Sgshapirodnl remove mark 106764562SgshapiroR<!> $+ $: $1 106864562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 106938032SpeterR< 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 107390792Sgshapiro# it is the same: stop now 107490792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress} $: $>ParseLocal $>Parse0 $>canonify $1 107590792SgshapiroR< $+ > $+ < @ $+ > $| $* $: < $1 > $2 < @ $3 > 107690792Sgshapirodnl', `dnl') 107780785Sgshapirodnl this is not a documented option 107880785Sgshapirodnl it performs no looping at all for virtusertable 107977349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_', 108077349Sgshapiro`R< $+ > $+ < @ $+ > $: $>ParseLocal $>Parse0 $>canonify $1', 108177349Sgshapiro`R< $+ > $+ < @ $+ > $: $>Recurse $1') 108277349Sgshapirodnl', `dnl') 108338032Speter 108438032Speter# short circuit local delivery so forwarded email works 108538032Speterifdef(`_MAILER_usenet_', `dnl 108664562SgshapiroR$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 108766494Sgshapiro 108866494Sgshapiro 108938032Speterifdef(`_STICKY_LOCAL_DOMAIN_', 109038032Speter`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? 109438032SpeterR< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 109564562Sgshapiro`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 109638032SpeterR$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 109738032Speter 109864562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 109938032Speter# not local -- try mailer table lookup 110038032SpeterR$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 110138032SpeterR< $+ . > $* $: < $1 > $2 strip trailing dot 110238032SpeterR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 110364562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 110464562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 110564562SgshapiroR< $+ > $* $: $>Mailertable <$1> $2 try domain', 110638032Speter`dnl') 110764562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)' 110838032Speter 110938032Speterifdef(`_NO_UUCP_', `dnl', 111038032Speter`# resolve remotely connected UUCP links (if any) 111138032Speterifdef(`_CLASS_V_', 111264562Sgshapiro`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 111338032Speter `dnl') 111438032Speterifdef(`_CLASS_W_', 111564562Sgshapiro`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 111638032Speter `dnl') 111738032Speterifdef(`_CLASS_X_', 111864562Sgshapiro`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 111938032Speter `dnl')') 112038032Speter 112138032Speter# resolve fake top level domains by forwarding to other hosts 112238032Speterifdef(`BITNET_RELAY', 112364562Sgshapiro`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 112438032Speter `dnl') 112538032Speterifdef(`DECNET_RELAY', 112664562Sgshapiro`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 112738032Speter `dnl') 112838032Speterifdef(`_MAILER_pop_', 112938032Speter`R$+ < @ POP. > $#pop $: $1 user@POP', 113038032Speter `dnl') 113138032Speterifdef(`_MAILER_fax_', 113238032Speter`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 113338032Speter`ifdef(`FAX_RELAY', 113464562Sgshapiro`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 113538032Speter `dnl')') 113638032Speter 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 114238032SpeterR$* < @ $+ .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 114664562SgshapiroR$+ . USENET $#usenet $@ usenet $: $1', 114738032Speter `dnl') 114838032Speter 114938032Speterifdef(`_LOCAL_RULES_', 115038032Speter`# 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) 115464562SgshapiroR$* < @ $* > $* $: $>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', 115990792Sgshapiro`R$* < @$* > $* $#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2') 116038032Speter 116138032Speter# handle locally delivered names 116264562SgshapiroR$=L $#_LOCAL_ $: @ $1 special local names 116338032SpeterR$+ $#_LOCAL_ $: $1 regular local names 116438032Speter 116538032Speter########################################################################### 116638032Speter### Ruleset 5 -- special rewriting after aliases have been expanded ### 116738032Speter########################################################################### 116838032Speter 116964562SgshapiroSLocal_localaddr 117064562SgshapiroSlocaladdr=5 117164562SgshapiroR$+ $: $1 $| $>"Local_localaddr" $1 117290792SgshapiroR$+ $| $#ok $@ $1 no change 117364562SgshapiroR$+ $| $#$* $#$2 117464562SgshapiroR$+ $| $* $: $1 117538032Speter 117690792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 117790792Sgshapiro# Preserve rcpt_host in {Host} 117890792SgshapiroR$+ $: $1 $| $&h $| $&{Host} check h and {Host} 117990792SgshapiroR$+ $| $| $: $(macro {Host} $@ $) $1 no h or {Host} 118090792SgshapiroR$+ $| $| $+ $: $1 h not set, {Host} set 118190792SgshapiroR$+ $| +$* $| $* $: $1 h is +detail, {Host} set 118295154SgshapiroR$+ $| $* @ $+ $| $* $: $(macro {Host} $@ @$3 $) $1 set {Host} to host in h 118390792SgshapiroR$+ $| $+ $| $* $: $(macro {Host} $@ @$2 $) $1 set {Host} to h 118490792Sgshapiro')dnl 118590792Sgshapiro 118690792Sgshapiroifdef(`_FFR_5_', `dnl 118766494Sgshapiro# Preserve host in a macro 118866494SgshapiroR$+ $: $(macro {LocalAddrHost} $) $1 118966494SgshapiroR$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 119066494Sgshapiro 119190792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl 119238032Speter# deal with plussed users so aliases work nicely 119366494SgshapiroR$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 119466494SgshapiroR$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 119566494Sgshapiro') 119638032Speter# prepend an empty "forward host" on the front 119738032SpeterR$+ $: <> $1 119838032Speter 119938032Speterifdef(`LUSER_RELAY', `dnl 120038032Speter# send unrecognized local users to a relay host 120190792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 120266494SgshapiroR< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 120366494SgshapiroR< > $+ $: < ? $L > < > $(user $1 $) look up user 120466494SgshapiroR< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 120566494SgshapiroR< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 120664562SgshapiroR< > $+ $: < $L > $(user $1 $) look up user 120790792SgshapiroR< $* > $+ <> $: < > $2 found; strip $L') 120890792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 120990792SgshapiroR< $+ > $+ $: < $1 > $2 $&{Host}') 121090792Sgshapirodnl') 121138032Speter 121290792Sgshapiroifdef(`MAIL_HUB', `dnl 121390792SgshapiroR< > $+ $: < $H > $1 try hub', `dnl') 121490792Sgshapiroifdef(`LOCAL_RELAY', `dnl 121590792SgshapiroR< > $+ $: < $R > $1 try relay', `dnl') 121690792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 121790792SgshapiroR< > $+ $@ $1', `dnl 121864562SgshapiroR< > $+ $: < > < $1 <> $&h > nope, restore +detail 121990792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 122090792SgshapiroR< > < $+ @ $+ <> + $* > $: < > < $1 + $3 @ $2 > check whether +detail') 122164562SgshapiroR< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 122264562SgshapiroR< > < $+ <> $* > $: < > < $1 > else discard 122338032SpeterR< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 122466494SgshapiroR< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 122538032SpeterR< > < $+ > $@ $1 no +detail 122643730SpeterR$+ $: $1 <> $&h add +detail back in 122790792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 122890792SgshapiroR$+ @ $+ <> + $* $: $1 + $3 @ $2 check whether +detail') 122943730SpeterR$+ <> + $* $: $1 + $2 check whether +detail 123066494SgshapiroR$+ <> $* $: $1 else discard') 123164562SgshapiroR< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 123264562SgshapiroR< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 123390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 123490792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 123590792SgshapiroR< $~[ : $+ > $+ @ $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $4 >') 123690792SgshapiroR< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 123790792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 123890792SgshapiroR< $+ > $+ @ $+ $@ $>MailerToTriple < $1 > $2 < @ $3 >') 123964562SgshapiroR< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 124038032Speter 124164562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 124290792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 124338032Speter################################################################### 124490792Sgshapiro### Ruleset LDAPMailertable -- mailertable lookup for LDAP ### 124590792Sgshapirodnl input: <Domain> FullAddress 124690792Sgshapiro################################################################### 124790792Sgshapiro 124890792SgshapiroSLDAPMailertable 124990792SgshapiroR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 125090792SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check resolved? 125190792SgshapiroR< $+ > $* $: < $1 > $>Mailertable <$1> $2 try domain 125290792SgshapiroR< $+ > $#$* $#$2 found 125390792SgshapiroR< $+ > $* $#_RELAY_ $@ $1 $: $2 not found, direct relay', 125490792Sgshapiro`dnl') 125590792Sgshapiro 125690792Sgshapiro################################################################### 125738032Speter### Ruleset 90 -- try domain part of mailertable entry ### 125864562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 125938032Speter################################################################### 126038032Speter 126164562SgshapiroSMailertable=90 126264562Sgshapirodnl 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 126664562SgshapiroR$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 126764562SgshapiroR$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 126864562Sgshapirodnl is $2 always empty? 126938032SpeterR$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 127064562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 127164562Sgshapirodnl return full address 127238032SpeterR< $* > $* $@ $2 no mailertable match', 127338032Speter`dnl') 127438032Speter 127538032Speter################################################################### 127638032Speter### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 127764562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest 127864562Sgshapirodnl <> address -> address 127964562Sgshapirodnl <error:d.s.n:text> -> error 128064562Sgshapirodnl <error:text> -> error 128164562Sgshapirodnl <mailer:user@host> lp<@domain>rest -> mailer host user 128264562Sgshapirodnl <mailer:host> address -> mailer host address 128364562Sgshapirodnl <localdomain> address -> address 128464562Sgshapirodnl <host> address -> relay host address 128538032Speter################################################################### 128638032Speter 128764562SgshapiroSMailerToTriple=95 128838032SpeterR< > $* $@ $1 strip off null relay 128964562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 129038032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 129138032SpeterR< local : $* > $* $>CanonLocal < $1 > $2 129290792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 129390792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 129490792SgshapiroR< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 129538032SpeterR< $=w > $* $@ $2 delete local host 129638032SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 129738032Speter 129838032Speter################################################################### 129938032Speter### Ruleset CanonLocal -- canonify local: syntax ### 130064562Sgshapirodnl 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 130464562Sgshapirodnl <> 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 130838032Speter################################################################### 130938032Speter 131038032SpeterSCanonLocal 131143730Speter# strip local host from routed addresses 131264562SgshapiroR< $* > < @ $+ > : $+ $@ $>Recurse $3 131364562SgshapiroR< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 131443730Speter 131538032Speter# strip trailing dot from any host name that may appear 131638032SpeterR< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 131738032Speter 131838032Speter# handle local: syntax -- use old user, either with or without host 131938032SpeterR< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 132038032SpeterR< > $+ $#_LOCAL_ $@ $1 $: $1 132138032Speter 132238032Speter# handle local:user@host syntax -- ignore host part 132338032SpeterR< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 132438032Speter 132538032Speter# handle local:user syntax 132638032SpeterR< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 132738032SpeterR< $+ > $* $#_LOCAL_ $@ $2 $: $1 132838032Speter 132938032Speter################################################################### 133038032Speter### Ruleset 93 -- convert header names to masqueraded form ### 133138032Speter################################################################### 133238032Speter 133364562SgshapiroSMasqHdr=93 133438032Speter 133564562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 133638032Speter# handle generics database 133738032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_', 133864562Sgshapirodnl if generics should be applied add a @ as mark 133938032Speter`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 134038032Speter`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 134138032SpeterR$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 134264562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @ 134364562Sgshapirodnl ignore the first case for now 134464562Sgshapirodnl if it has the mark lookup full address 134590792Sgshapirodnl broken: %1 is full address not just detail 134664562SgshapiroR< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 134764562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain> 134864562Sgshapirodnl no match, try user+detail@domain 134964562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 135064562Sgshapiro $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 135164562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 135264562Sgshapiro $: < $(generics $1@$3 $: $) > $4 < @ $5 > 135364562Sgshapirodnl no match, remove mark 135464562SgshapiroR<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 135564562Sgshapirodnl no match, try @domain for exceptions 135664562SgshapiroR< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 135764562Sgshapirodnl workspace: ... or <match> user <@domain> 135864562Sgshapirodnl no match, try local part 135938032SpeterR< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 136064562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 136164562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 136264562SgshapiroR< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 136364562SgshapiroR< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 136438032SpeterR< > $* $: $1 not found', 136538032Speter`dnl') 136638032Speter 136764562Sgshapiro# do not masquerade anything in class N 136864562SgshapiroR$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 136964562Sgshapiro 137090792Sgshapiroifdef(`MASQUERADE_NAME', `dnl 137138032Speter# special case the users that should be exposed 137238032SpeterR$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 137338032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 137438032Speter`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 137538032Speter`R$=E < @ $=M . > $@ $1 < @ $2 . >') 137638032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 137738032Speter`R$=E < @ $=w . > $@ $1 < @ $2 . >') 137838032Speter 137938032Speter# handle domain-specific masquerading 138038032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 138138032Speter`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 138238032Speter`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 138338032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 138438032Speter`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 138538032SpeterR$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 138638032SpeterR$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 138738032SpeterR$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 138890792Sgshapirodnl', `dnl no masquerading 138990792Sgshapirodnl just fix *LOCAL* leftovers 139090792SgshapiroR$* < @ *LOCAL* > $@ $1 < @ $j . >') 139138032Speter 139238032Speter################################################################### 139338032Speter### Ruleset 94 -- convert envelope names to masqueraded form ### 139438032Speter################################################################### 139538032Speter 139664562SgshapiroSMasqEnv=94 139738032Speterifdef(`_MASQUERADE_ENVELOPE_', 139864562Sgshapiro`R$+ $@ $>MasqHdr $1', 139938032Speter`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 140038032Speter 140138032Speter################################################################### 140238032Speter### Ruleset 98 -- local part of ruleset zero (can be null) ### 140338032Speter################################################################### 140438032Speter 140564562SgshapiroSParseLocal=98 140664562Sgshapiroundivert(3)dnl LOCAL_RULE_0 140738032Speter 140864562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 140990792Sgshapiro###################################################################### 141090792Sgshapiro### LDAPExpand: Expand address using LDAP routing 141190792Sgshapiro### 141290792Sgshapiro### Parameters: 141390792Sgshapiro### <$1> -- parsed address (user < @ domain . >) (pass through) 141490792Sgshapiro### <$2> -- RFC822 address (user @ domain) (used for lookup) 141590792Sgshapiro### <$3> -- +detail information 141690792Sgshapiro### 141790792Sgshapiro### Returns: 141890792Sgshapiro### Mailer triplet ($#mailer $@ host $: address) 141990792Sgshapiro### Parsed address (user < @ domain . >) 142090792Sgshapiro###################################################################### 142190792Sgshapiro 142264562SgshapiroSLDAPExpand 142364562Sgshapiro# do the LDAP lookups 142490792SgshapiroR<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3> 142564562Sgshapiro 142694334Sgshapiro# look for temporary failures (return original address, MTA will queue up) 1427102528SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*> $@ $3 1428102528SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*> $@ $3 142994334Sgshapiro 143064562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost, 143164562Sgshapiro# return the new mailRoutingAddress 143290792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 143390792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2 143490792SgshapiroR<$+@$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $5 @ $2') 143590792SgshapiroR<$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 143690792SgshapiroR<$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 143764562Sgshapiro 143898121Sgshapiro 143964562Sgshapiro# if mailRoutingAddress and non-local mailHost, 144064562Sgshapiro# 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 144890792SgshapiroR<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1', 144990792Sgshapiro`R<$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $2 $: $>canonify $1') 145064562Sgshapiro 145164562Sgshapiro# if no mailRoutingAddress and local mailHost, 145264562Sgshapiro# return original address 145390792SgshapiroR<> <$=w> <$+> <$+> <$*> $@ $2 145464562Sgshapiro 145598121Sgshapiro 145664562Sgshapiro# if no mailRoutingAddress and non-local mailHost, 145764562Sgshapiro# relay to mailHost with original address 145890792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 145990792Sgshapiro# check mailertable for host, relay from there 146090792SgshapiroR<> <$+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2', 146190792Sgshapiro`R<> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $1 $: $2') 146264562Sgshapiro 146390792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_', 146490792Sgshapiro`# if no mailRoutingAddress and no mailHost, 146590792Sgshapiro# try without +detail 146690792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl 146790792Sgshapiro 146890792Sgshapiro# if still no mailRoutingAddress and no mailHost, 146964562Sgshapiro# try @domain 147090792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 147190792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <@ $4> <+$3>') 147290792SgshapiroR<> <> <$+> <$+ @ $+> <$*> $@ $>LDAPExpand <$1> <@ $3> <$4> 147364562Sgshapiro 147464562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt, 147564562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 147664562Sgshapiro# 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', 148164562Sgshapiro`dnl 148264562Sgshapiro# 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. 148764562Sgshapiro')') 148890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 148938032Speter###################################################################### 149090792Sgshapiro### D: LookUpDomain -- search for domain in access database 149138032Speter### 149238032Speter### Parameters: 149338032Speter### <$1> -- key (domain name) 149438032Speter### <$2> -- default (what to return if not found in db) 149564562Sgshapirodnl must not be empty 149690792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 149764562Sgshapiro### ! does lookup only with tag 149864562Sgshapiro### + does lookup with and without tag 149990792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 150064562Sgshapirodnl returns: <default> <passthru> 150164562Sgshapirodnl <result> <passthru> 150238032Speter###################################################################### 150338032Speter 150490792SgshapiroSD 150564562Sgshapirodnl workspace <key> <default> <passthru> <mark> 150664562Sgshapirodnl lookup with tag (in front, no delimiter here) 150790792Sgshapirodnl 2 3 4 5 150890792SgshapiroR<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 150964562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 151064562Sgshapirodnl lookup without tag? 151190792Sgshapirodnl 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? 151590792Sgshapirodnl currently it works the wrong way round for [1.2.3.4] 151690792Sgshapirodnl 1 2 3 4 5 6 151790792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6> 151890792Sgshapirodnl 1 2 3 4 5 151990792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl') 152090792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 152190792Sgshapirodnl found SKIP: return <default> and <passthru> 152290792Sgshapirodnl 1 2 3 4 5 152390792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 152490792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!) 152590792Sgshapirodnl 1 2 3 4 5 6 152690792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*> $@ $>D <[$1]> <$3> <$4 $5> <$6> 152790792Sgshapiroifdef(`NO_NETINET6', `dnl', 152890792Sgshapiro`dnl not found: IPv6 net 152990792Sgshapirodnl (could be merged with previous rule if we have a class containing .:) 153090792Sgshapirodnl 1 2 3 4 5 6 153190792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6> 153290792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>') 153364562Sgshapirodnl not found, but subdomain: try again 153490792Sgshapirodnl 1 2 3 4 5 6 153590792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6> 153690792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag: 153790792Sgshapirodnl 1 2 3 4 153890792SgshapiroR<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl') 153990792Sgshapirodnl not found, no subdomain: return <default> and <passthru> 154090792Sgshapirodnl 1 2 3 4 5 154190792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 154290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 154390792Sgshapirodnl 2 3 4 5 6 154490792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 154590792Sgshapirodnl return <result of lookup> and <passthru> 154690792Sgshapirodnl 2 3 4 5 6 154790792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 154838032Speter 154938032Speter###################################################################### 155090792Sgshapiro### A: LookUpAddress -- search for host address in access database 155138032Speter### 155238032Speter### Parameters: 155338032Speter### <$1> -- key (dot quadded host address) 155438032Speter### <$2> -- default (what to return if not found in db) 155564562Sgshapirodnl must not be empty 155690792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 155764562Sgshapiro### ! does lookup only with tag 155864562Sgshapiro### + does lookup with and without tag 155990792Sgshapiro### <$4> -- passthru (additional data passed through) 156064562Sgshapirodnl returns: <default> <passthru> 156164562Sgshapirodnl <result> <passthru> 156238032Speter###################################################################### 156338032Speter 156490792SgshapiroSA 156564562Sgshapirodnl lookup with tag 156690792Sgshapirodnl 2 3 4 5 156790792SgshapiroR<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 156864562Sgshapirodnl lookup without tag 156990792Sgshapirodnl 1 2 3 4 157090792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 157190792Sgshapirodnl 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>') 158164562Sgshapirodnl no match; IPv4: remove last part 158290792Sgshapirodnl 1 2 3 4 5 6 158390792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 158464562Sgshapirodnl no match: return default 158590792Sgshapirodnl 1 2 3 4 5 158690792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 158790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 158890792Sgshapirodnl 2 3 4 5 6 158990792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 159064562Sgshapirodnl match: return result 159190792Sgshapirodnl 2 3 4 5 6 159290792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 159390792Sgshapirodnl endif _ACCESS_TABLE_ 159490792Sgshapirodivert(0) 159538032Speter###################################################################### 159642575Speter### CanonAddr -- Convert an address into a standard form for 159742575Speter### relay checking. Route address syntax is 159842575Speter### crudely converted into a %-hack address. 159942575Speter### 160042575Speter### Parameters: 160142575Speter### $1 -- full recipient address 160242575Speter### 160342575Speter### Returns: 160442575Speter### parsed address, not in source route form 160564562Sgshapirodnl user%host%host<@domain> 160664562Sgshapirodnl host!user<@domain> 160742575Speter###################################################################### 160842575Speter 160942575SpeterSCanonAddr 161064562SgshapiroR$* $: $>Parse0 $>canonify $1 make domain canonical 161164562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 161242575SpeterR< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 161342575SpeterR$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 161442575SpeterR$* < @ $+ > : $* $3 $1 < @ $2 > 161564562Sgshapirodnl') 161642575Speter 161742575Speter###################################################################### 161838032Speter### ParseRecipient -- Strip off hosts in $=R as well as possibly 161938032Speter### $* $=m or the access database. 162038032Speter### Check user portion for host separators. 162138032Speter### 162238032Speter### Parameters: 162338032Speter### $1 -- full recipient address 162438032Speter### 162538032Speter### Returns: 162638032Speter### parsed, non-local-relaying address 162738032Speter###################################################################### 162838032Speter 162938032SpeterSParseRecipient 163064562Sgshapirodnl mark and canonify address 163142575SpeterR$* $: <?> $>CanonAddr $1 163264562Sgshapirodnl workspace: <?> localpart<@domain[.]> 163342575SpeterR<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 163464562Sgshapirodnl workspace: <?> localpart<@domain> 163542575SpeterR<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 163638032Speter 163738032Speter# if no $=O character, no host in the user portion, we are done 163842575SpeterR<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 163964562Sgshapirodnl no $=O in localpart: return 164042575SpeterR<?> $* $@ $1 164138032Speter 164290792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O 164364562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY> 164438032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 164538032Speter# if we relay, check username portion for user%host so host can be checked also 164642575SpeterR<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 164764562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 164864562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 164990792Sgshapiro 165090792Sgshapirodnl what if access map returns something else than RELAY? 165190792Sgshapirodnl we are only interested in RELAY entries... 165290792Sgshapirodnl other To: entries: blacklist recipient; generic entries? 165390792Sgshapirodnl if it is an error we probably do not want to relay anyway 165438032Speterifdef(`_RELAY_HOSTS_ONLY_', 165542575Speter`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 165664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 165764562SgshapiroR<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 165842575SpeterR<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 165942575Speter`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 166064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 166190792SgshapiroR<NO> $* < @ $+ > $: $>D <$2> <NO> <+ To> <$1 < @ $2 >> 166242575SpeterR<$+> <$+> $: <$1> $2',`dnl')') 166338032Speter 166464562Sgshapiro 166590792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl 166690792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain? 166790792SgshapiroR<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 166890792SgshapiroR<MX> < : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 166990792Sgshapirodnl yes: mark it as <RELAY> 167090792SgshapiroR<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 167190792Sgshapirodnl no: put old <NO> mark back 167290792SgshapiroR<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 167390792Sgshapiro 167490792Sgshapirodnl do we relay to this recipient domain? 167542575SpeterR<RELAY> $* < @ $* > $@ $>ParseRecipient $1 167690792Sgshapirodnl something else 167790792SgshapiroR<$+> $* $@ $2 167842575Speter 167964562Sgshapiro 168038032Speter###################################################################### 168138032Speter### check_relay -- check hostname/address on SMTP startup 168238032Speter###################################################################### 168338032Speter 168438032SpeterSLocal_check_relay 168564562SgshapiroScheck`'_U_`'relay 168638032SpeterR$* $: $1 $| $>"Local_check_relay" $1 168738032SpeterR$* $| $* $| $#$* $#$3 168838032SpeterR$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 168938032Speter 169038032SpeterSBasic_check_relay 169138032Speter# check for deferred delivery mode 169298121SgshapiroR$* $: < $&{deliveryMode} > $1 169338032SpeterR< d > $* $@ deferred 169438032SpeterR< $* > $* $: $2 169538032Speter 169664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 169766494Sgshapirodnl workspace: {client_name} $| {client_addr} 169890792SgshapiroR$+ $| $+ $: $>D < $1 > <?> <+ Connect> < $2 > 169966494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 170090792SgshapiroR<?> <$+> $: $>A < $1 > <?> <+ Connect> <> no: another lookup 170190792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) 170290792SgshapiroR<?> <$*> $: 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"') 170690792SgshapiroR<DISCARD> <$*> $#discard $: discard 170790792Sgshapiroifdef(`_FFR_QUARANTINE', 170890792Sgshapiro`R<QUARANTINE:$+> <$*> $#error $@ quarantine $: $1', `dnl') 170964562Sgshapirodnl error tag 171066494SgshapiroR<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 171166494SgshapiroR<ERROR:$+> <$*> $#error $: $1 171290792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 171364562Sgshapirodnl generic error from access map 171466494SgshapiroR<$+> <$*> $#error $: $1', `dnl') 171538032Speter 171664562Sgshapiroifdef(`_RBL_',`dnl 171764562Sgshapiro# DNS based IP address spam list 171890792Sgshapirodnl workspace: ignored... 171938032SpeterR$* $: $&{client_addr} 172064562SgshapiroR$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 172164562SgshapiroR<?>OK $: OKSOFAR 172298121SgshapiroR<?>$+ $#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"', 172338032Speter`dnl') 172464562Sgshapiroundivert(8) 172538032Speter 172638032Speter###################################################################### 172738032Speter### check_mail -- check SMTP ``MAIL FROM:'' command argument 172838032Speter###################################################################### 172938032Speter 173038032SpeterSLocal_check_mail 173164562SgshapiroScheck`'_U_`'mail 173238032SpeterR$* $: $1 $| $>"Local_check_mail" $1 173338032SpeterR$* $| $#$* $#$2 173438032SpeterR$* $| $* $@ $>"Basic_check_mail" $1 173538032Speter 173638032SpeterSBasic_check_mail 173738032Speter# check for deferred delivery mode 173898121SgshapiroR$* $: < $&{deliveryMode} > $1 173938032SpeterR< d > $* $@ deferred 174038032SpeterR< $* > $* $: $2 174138032Speter 174264562Sgshapiro# authenticated? 174364562Sgshapirodnl done first: we can require authentication for every mail transaction 174464562Sgshapirodnl workspace: address as given by MAIL FROM: (sender) 174564562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 174664562SgshapiroR$* $| $#$+ $#$2 174764562Sgshapirodnl undo damage: remove result of tls_client call 174864562SgshapiroR$* $| $* $: $1 174938032Speter 175064562Sgshapirodnl workspace: address as given by MAIL FROM: 175164562SgshapiroR<> $@ <OK> we MUST accept <> (RFC 1123) 175238032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 175364562Sgshapirodnl do some additional checks 175464562Sgshapirodnl no user@host 175564562Sgshapirodnl no user@localhost (if nonlocal sender) 175664562Sgshapirodnl this is a pretty simple canonification, it will not catch every case 175764562Sgshapirodnl just make sure the address has <> around it (which is required by 175864562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...) 175964562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will 176064562Sgshapirodnl not be modified by host lookups. 176164562SgshapiroR$+ $: <?> $1 176264562SgshapiroR<?><$+> $: <@> <$1> 176364562SgshapiroR<?>$+ $: <@> <$1> 176464562Sgshapirodnl workspace: <@> <address> 176564562Sgshapirodnl prepend daemon_flags 176664562SgshapiroR$* $: $&{daemon_flags} $| $1 176764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 176864562Sgshapirodnl do not allow these at all or only from local systems? 176964562SgshapiroR$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 177064562Sgshapirodnl accept unqualified sender: change mark to avoid test 177164562SgshapiroR$* u $* $| <@> < $* > $: <?> < $3 > 177264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 177364562Sgshapirodnl or: <? ${client_name} > <address> 177464562Sgshapirodnl or: <?> <address> 177564562Sgshapirodnl remove daemon_flags 177664562SgshapiroR$* $| $* $: $2 177738032Speter# handle case of @localhost on address 177864562SgshapiroR<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 177964562SgshapiroR<@> < $* @ [127.0.0.1] > 178064562Sgshapiro $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 178164562SgshapiroR<@> < $* @ localhost.$m > 178264562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.$m > 178338032Speterifdef(`_NO_UUCP_', `dnl', 178464562Sgshapiro`R<@> < $* @ localhost.UUCP > 178564562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 178664562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 178764562Sgshapirodnl or: <@> <address> 178864562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 178964562SgshapiroR<@> $* $: $1 no localhost as domain 179064562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 179164562Sgshapirodnl or: <address> 179264562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 179364562SgshapiroR<? $=w> $* $: $2 local client: ok 179490792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address" 179564562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 179664562SgshapiroR<?> $* $: $1') 179764562Sgshapirodnl workspace: address (or <address>) 179864562SgshapiroR$* $: <?> $>CanonAddr $1 canonify sender address and mark it 179964562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 180064562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed 180164562SgshapiroR<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 180264562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 1803102528SgshapiroR<?> $* < @ $* $=P > $: <_RES_OK_> $1 < @ $2 $3 > 180464562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ? or OK 180598121Sgshapirodnl A sender address with my local host name ($j) is safe 1806102528SgshapiroR<?> $* < @ $j > $: <_RES_OK_> $1 < @ $j > 180764562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 180890792Sgshapiro`R<?> $* < @ $+ > $: <_RES_OK_> $1 < @ $2 > ... unresolvable OK', 180964562Sgshapiro`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 181064562SgshapiroR<? $* <$->> $* < @ $+ > 181164562Sgshapiro $: <$2> $3 < @ $4 >') 181290792Sgshapirodnl workspace <mark> CanonicalAddress where mark is ?, _RES_OK_, PERM, TEMP 181364562Sgshapirodnl mark is ? iff the address is user (wo @domain) 181438032Speter 181564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 181664562Sgshapiro# check sender address: user@address, user@, address 181764562Sgshapirodnl should we remove +ext from user? 181890792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP 181990792SgshapiroR<$+> $+ < @ $* > $: @<$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 182490792SgshapiroR@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <> 182564562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result> 182664562SgshapiroR<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 182764562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress> 182838032Speter# 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) 183538032Speter 183638032Speterifdef(`_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 184190792SgshapiroR$* u $* $| <?> $* $: <_RES_OK_> $3 184264562Sgshapirodnl remove daemon_flags 184364562SgshapiroR$* $| $* $: $2 184438032SpeterR<?> $* $: < ? $&{client_name} > $1 1845102528SgshapiroR<?> $* $@ <_RES_OK_> ...local unqualed ok 184690792SgshapiroR<? $+> $* $#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f 184738032Speter ...remote is not') 184838032Speter# check results 184964562SgshapiroR<?> $* $: @ $1 mark address: nothing known about it 185090792SgshapiroR<$={ResOk}> $* $@ <_RES_OK_> domain ok: stop 185164562SgshapiroR<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 185290792SgshapiroR<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 185538032SpeterR<DISCARD> $* $#discard $: discard 185690792Sgshapiroifdef(`_FFR_QUARANTINE', 185790792Sgshapiro`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 186290792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 186364562Sgshapirodnl generic error from access map 186464562SgshapiroR<$+> $* $#error $: $1 error from access db', 186538032Speter`dnl') 186638032Speter 186738032Speter###################################################################### 186838032Speter### check_rcpt -- check SMTP ``RCPT TO:'' command argument 186938032Speter###################################################################### 187038032Speter 187138032SpeterSLocal_check_rcpt 187264562SgshapiroScheck`'_U_`'rcpt 187338032SpeterR$* $: $1 $| $>"Local_check_rcpt" $1 187438032SpeterR$* $| $#$* $#$2 187538032SpeterR$* $| $* $@ $>"Basic_check_rcpt" $1 187638032Speter 187738032SpeterSBasic_check_rcpt 187890792Sgshapiro# empty address? 187990792SgshapiroR<> $#error $@ nouser $: "553 User address required" 188090792SgshapiroR$@ $#error $@ nouser $: "553 User address required" 188138032Speter# check for deferred delivery mode 188298121SgshapiroR$* $: < $&{deliveryMode} > $1 188338032SpeterR< d > $* $@ deferred 188438032SpeterR< $* > $* $: $2 188538032Speter 188664562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 188790792Sgshapirodnl this code checks for user@host where host is not a FQHN. 188890792Sgshapirodnl it is not activated. 188990792Sgshapirodnl notice: code to check for a recipient without a domain name is 189090792Sgshapirodnl available down below; look for the same macro. 189190792Sgshapirodnl this check is done here because the name might be qualified by the 189290792Sgshapirodnl canonicalization. 189390792Sgshapiro# require fully qualified domain part? 189490792Sgshapirodnl very simple canonification: make sure the address is in < > 189564562SgshapiroR$+ $: <?> $1 189690792SgshapiroR<?> <$+> $: <@> <$1> 189790792SgshapiroR<?> $+ $: <@> <$1> 189890792SgshapiroR<@> < postmaster > $: postmaster 189990792SgshapiroR<@> < $* @ $+ . $+ > $: < $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? 190490792SgshapiroR$* r $* $| <@> < $* @ $* > $: < ? $&{client_name} > < $3 @ $4 > 190564562SgshapiroR<?> < $* > $: <$1> 190664562SgshapiroR<? $=w> < $* > $: <$1> 190790792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "553 Fully qualified domain name required" 190864562Sgshapirodnl remove daemon_flags for other cases 190964562SgshapiroR$* $| <@> $* $: $2', `dnl') 191064562Sgshapiro 191190792Sgshapirodnl ################################################################## 191290792Sgshapirodnl call subroutines for recipient and relay 191390792Sgshapirodnl possible returns from subroutines: 191490792Sgshapirodnl $#TEMP temporary failure 191590792Sgshapirodnl $#error permanent failure (or temporary if from access map) 191690792Sgshapirodnl $#other stop processing 191790792Sgshapirodnl RELAY RELAYing allowed 191890792Sgshapirodnl other otherwise 191990792Sgshapiro###################################################################### 192090792SgshapiroR$* $: $1 $| @ $>"Rcpt_ok" $1 192190792Sgshapirodnl temporary failure? remove mark @ and remember 192290792SgshapiroR$* $| @ $#TEMP $+ $: $1 $| T $2 192390792Sgshapirodnl error or ok (stop) 192490792SgshapiroR$* $| @ $#$* $#$2 192590792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 192690792SgshapiroR$* $| @ RELAY $@ RELAY 192790792Sgshapirodnl something else: call check sender (relay) 192890792SgshapiroR$* $| @ $* $: O $| $>"Relay_ok" $1 192990792Sgshapirodnl temporary failure: call check sender (relay) 193090792SgshapiroR$* $| T $+ $: T $2 $| $>"Relay_ok" $1 193190792Sgshapirodnl temporary failure? return that 193290792SgshapiroR$* $| $#TEMP $+ $#error $2 193390792Sgshapirodnl error or ok (stop) 193490792SgshapiroR$* $| $#$* $#$2 193590792SgshapiroR$* $| RELAY $@ RELAY 193690792Sgshapirodnl something else: return previous temp failure 193790792SgshapiroR T $+ $| $* $#error $1 193890792Sgshapiro# anything else is bogus 193990792SgshapiroR$* $#error $@ 5.7.1 $: confRELAY_MSG 194090792Sgshapirodivert(0) 194190792Sgshapiro 194290792Sgshapiro###################################################################### 194390792Sgshapiro### Rcpt_ok: is the recipient ok? 194490792Sgshapirodnl input: recipient address (RCPT TO) 194590792Sgshapirodnl output: see explanation at call 194690792Sgshapiro###################################################################### 194790792SgshapiroSRcpt_ok 194838032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl 194942575SpeterR$* $: $>CanonAddr $1 195038032SpeterR$* < @ $* . > $1 < @ $2 > strip trailing dots', 195138032Speter`R$* $: $>ParseRecipient $1 strip relayable hosts') 195238032Speter 195342575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl 195442575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl 195542575Speter# unlimited bestmx 195642575SpeterR$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 195742575Speter`dnl 195842575Speter# limit bestmx to $=B 195943730SpeterR$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 196090792SgshapiroR$* $=O $* < @ $* @@ $=w . > $* $@ $>"Rcpt_ok" $1 $2 $3 196142575SpeterR$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 196242575SpeterR$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 196342575Speter 196438032Speterifdef(`_BLACKLIST_RCPT_',`dnl 196564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 196638032Speter# blacklist local users or any host from receiving mail 196738032SpeterR$* $: <?> $1 196864562Sgshapirodnl 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) 197090792SgshapiroR<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2> 197190792SgshapiroR<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2> 197264562SgshapiroR<?> $+ $: <> <$1> $| <U:$1@> 197364562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 197464562Sgshapirodnl will only return user<@domain when "reversing" the args 197590792SgshapiroR<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+ To> $| <$2> <> 197664562SgshapiroR<@> <$*> $| <$*> $: <$2> <$1> reverse result 197764562SgshapiroR<?> <$*> $: @ $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. 198264562SgshapiroR<$={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: 198764562Sgshapirodnl we have to filter these because otherwise they would be interpreted 198864562Sgshapirodnl as generic error message... 198964562Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 199064562Sgshapirodnl that would make a lot of things easier. 199164562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)? 199264562SgshapiroR<$={SpamTag}> <$*> $: @ $2 mark address as no match') 199390792SgshapiroR<REJECT> $* $#error $@ 5.2.1 $: confRCPTREJ_MSG 199464562SgshapiroR<DISCARD> $* $#discard $: discard 199590792Sgshapiroifdef(`_FFR_QUARANTINE', 199690792Sgshapiro`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 199764562Sgshapirodnl error tag 199864562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 199964562SgshapiroR<ERROR:$+> $* $#error $: $1 200090792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 200164562Sgshapirodnl generic error from access map 200264562SgshapiroR<$+> $* $#error $: $1 error from access db 200364562SgshapiroR@ $* $1 remove mark', `dnl')', `dnl') 200438032Speter 200590792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 200690792Sgshapiro# authenticated via TLS? 200790792SgshapiroR$* $: $1 $| $>RelayTLS client authenticated? 200890792SgshapiroR$* $| $# $+ $# $2 error/ok? 200990792SgshapiroR$* $| $* $: $1 no 201064562Sgshapiro 201190792SgshapiroR$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type} 201290792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth 201390792SgshapiroR$* $| $# $* $# $2 201490792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech} 201590792SgshapiroR$* $| NO $: $1 201690792SgshapiroR$* $| $* $: $1 $| $&{auth_type} 201790792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ] 201864562Sgshapirodnl empty ${auth_type}? 201964562SgshapiroR$* $| $: $1 202064562Sgshapirodnl mechanism ${auth_type} accepted? 202164562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below 202290792SgshapiroR$* $| $={TrustAuthMech} $# RELAY 202390792Sgshapirodnl remove ${auth_type} 202464562SgshapiroR$* $| $* $: $1 202571345Sgshapirodnl workspace: localpart<@domain> | localpart 202664562Sgshapiroifelse(defn(`_NO_UUCP_'), `r', 202771345Sgshapiro`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 202871345SgshapiroR$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 202938032Speter# anything terminating locally is ok 203038032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 203190792SgshapiroR$+ < @ $* $=m > $@ RELAY', `dnl') 203290792SgshapiroR$+ < @ $=w > $@ RELAY 203338032Speterifdef(`_RELAY_HOSTS_ONLY_', 203490792Sgshapiro`R$+ < @ $=R > $@ RELAY 203564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 203664562SgshapiroR$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 203764562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 203864562SgshapiroR<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 203990792Sgshapiro`R$+ < @ $* $=R > $@ RELAY 204064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 204190792SgshapiroR$+ < @ $+ > $: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')') 204264562Sgshapiroifdef(`_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') 204638032SpeterR<$*> <$*> $: $2',`dnl') 204738032Speter 204864562Sgshapiro 204938032Speterifdef(`_RELAY_MX_SERVED_', `dnl 205038032Speter# 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... 205390792SgshapiroR< : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 205490792SgshapiroR<$* : $=w . : $*> $* $@ RELAY 205542575SpeterR< : $* : > $* $: $2', 205638032Speter`dnl') 205738032Speter 205838032Speter# check for local user (i.e. unqualified address) 205938032SpeterR$* $: <?> $1 206042575SpeterR<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 206138032Speter# 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: 206464562Sgshapirodnl RequireFQDN ?) 206564562Sgshapirodnl postmaster must be accepted without domain (DRUMS) 206664562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 206790792SgshapiroR<?> postmaster $@ OK 206864562Sgshapiro# require qualified recipient? 206964562Sgshapirodnl prepend daemon_flags 207064562SgshapiroR<?> $+ $: $&{daemon_flags} $| <?> $1 207164562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart 207264562Sgshapirodnl do not allow these at all or only from local systems? 207364562Sgshapirodnl r flag? add client_name 207464562SgshapiroR$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 207564562Sgshapirodnl no r flag: relay to local user (only local part) 207664562Sgshapiro# no qualified recipient required 207790792SgshapiroR$* $| <?> $+ $@ RELAY 207864562Sgshapirodnl client_name is empty 207990792SgshapiroR<?> <?> $+ $@ RELAY 208064562Sgshapirodnl client_name is local 208190792SgshapiroR<? $=w> <?> $+ $@ RELAY 208264562Sgshapirodnl client_name is not local 208364562SgshapiroR<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 208464562Sgshapirodnl no qualified recipient required 208590792SgshapiroR<?> $+ $@ RELAY') 208664562Sgshapirodnl it is a remote user: remove mark and then check client 208738032SpeterR<$+> $* $: $2 208864562Sgshapirodnl currently the recipient address is not used below 208938032Speter 209090792Sgshapiro###################################################################### 209190792Sgshapiro### Relay_ok: is the relay/sender ok? 209290792Sgshapirodnl input: ignored 209390792Sgshapirodnl output: see explanation at call 209490792Sgshapiro###################################################################### 209590792SgshapiroSRelay_ok 209638032Speter# anything originating locally is ok 209764562Sgshapiro# check IP address 209864562SgshapiroR$* $: $&{client_addr} 209990792SgshapiroR$@ $@ RELAY originated locally 210090792SgshapiroR0 $@ RELAY originated locally 210190792SgshapiroR$=R $* $@ RELAY relayable IP address 210264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 210390792SgshapiroR$* $: $>A <$1> <?> <+ Connect> <$1> 210490792SgshapiroR<RELAY> $* $@ RELAY relayable IP address 2105102528Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl 2106102528Sgshapirodnl this will cause rejections in cases like: 2107102528Sgshapirodnl Connect:My.Host.Domain RELAY 2108102528Sgshapirodnl Connect:My.Net REJECT 2109102528Sgshapirodnl since in check_relay client_name is checked before client_addr 2110102528SgshapiroR<REJECT> $* $@ REJECT rejected IP address') 211190792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 211264562SgshapiroR<$*> <$*> $: $2', `dnl') 211364562SgshapiroR$* $: [ $1 ] put brackets around it... 211490792SgshapiroR$=w $@ RELAY ... and see if it is local 211564562Sgshapiro 211664562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 211764562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 211864562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl 211964562Sgshapirodnl input: {client_addr} or something "broken" 212064562Sgshapirodnl just throw the input away; we do not need it. 212164562Sgshapiro# check whether FROM is allowed to use system as relay 212264562SgshapiroR$* $: <?> $>CanonAddr $&f 212390792SgshapiroR<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 212464562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl 212564562Sgshapiro# check whether local FROM is ok 212690792SgshapiroR<?> $+ < @ $=w > $@ RELAY FROM local', `dnl') 212764562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl 212894334SgshapiroR<?> $+ < @ $+ > $: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <> 212990792SgshapiroR<@> <RELAY> $@ RELAY RELAY FROM sender ok 213090792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 213190792Sgshapiro', `dnl 213290792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', 213390792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 213464562Sgshapiro')', 213564562Sgshapiro`dnl') 213664562Sgshapirodnl')', `dnl') 213790792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind. 213890792Sgshapirodnl it does not matter in this case because the following rule ignores 213990792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace. 214064562Sgshapiro 214164562Sgshapiro# check client name: first: did it resolve? 214264562Sgshapirodnl input: ignored 214364562SgshapiroR$* $: < $&{client_resolve} > 214490792SgshapiroR<TEMP> $#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 214564562SgshapiroR<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 214664562SgshapiroR<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 214764562Sgshapirodnl ${client_resolve} should be OK, so go ahead 214890792SgshapiroR$* $: <@> $&{client_name} 214990792Sgshapirodnl should not be necessary since it has been done for client_addr already 215090792SgshapiroR<@> $@ RELAY 215190792Sgshapirodnl workspace: <@> ${client_name} (not empty) 215238032Speter# pass to name server to make hostname canonical 215390792SgshapiroR<@> $* $=P $:<?> $1 $2 215490792SgshapiroR<@> $+ $:<?> $[ $1 $] 215590792Sgshapirodnl workspace: <?> ${client_name} (canonified) 215664562SgshapiroR$* . $1 strip trailing dots 215738032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 215890792SgshapiroR<?> $* $=m $@ RELAY', `dnl') 215990792SgshapiroR<?> $=w $@ RELAY 216038032Speterifdef(`_RELAY_HOSTS_ONLY_', 216190792Sgshapiro`R<?> $=R $@ RELAY 216264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 216364562SgshapiroR<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 216464562SgshapiroR<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 216590792Sgshapiro`R<?> $* $=R $@ RELAY 216664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 216790792SgshapiroR<?> $* $: $>D <$1> <?> <+ Connect> <$1>',`dnl')') 216864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 216990792SgshapiroR<RELAY> $* $@ RELAY 217090792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 217138032SpeterR<$*> <$*> $: $2',`dnl') 217290792Sgshapirodnl end of _PROMISCUOUS_RELAY_ 217364562Sgshapirodivert(0) 217464562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 217564562Sgshapiro# turn a canonical address in the form user<@domain> 217664562Sgshapiro# qualify unqual. addresses with $j 217764562Sgshapirodnl it might have been only user (without <@domain>) 217864562SgshapiroSFullAddr 217964562SgshapiroR$* <@ $+ . > $1 <@ $2 > 218064562SgshapiroR$* <@ $* > $@ $1 <@ $2 > 218164562SgshapiroR$+ $@ $1 <@ $j > 218238032Speter 218364562Sgshapiro# call all necessary rulesets 218464562SgshapiroScheck_rcpt 218564562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset 218664562Sgshapirodnl which is the correct DSN code? 218764562Sgshapiro# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 218864562SgshapiroR$+ $: $1 $| $>checkrcpt $1 218964562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 219064562SgshapiroR$+ $| $#$* $#$2 219164562SgshapiroR$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 219264562Sgshapiroifdef(`_SPAM_FH_', 219364562Sgshapiro`dnl lookup user@ and user@address 219464562Sgshapiroifdef(`_ACCESS_TABLE_', `', 219564562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 219664562Sgshapiro')')dnl 219764562Sgshapirodnl one of the next two rules is supposed to match 219864562Sgshapirodnl this code has been copied from BLACKLIST... etc 219964562Sgshapirodnl and simplified by omitting some < >. 220090792SgshapiroR<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@> 220190792SgshapiroR<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > 220264562Sgshapirodnl R<?> $@ something_is_very_wrong_here 220390792Sgshapiro# lookup the addresses only with Spam tag 220490792SgshapiroR<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <> 220564562SgshapiroR<@> $* $| $* $: $2 $1 reverse result 220664562Sgshapirodnl', `dnl') 220764562Sgshapiroifdef(`_SPAM_FRIEND_', 220864562Sgshapiro`# is the recipient a spam friend? 220964562Sgshapiroifdef(`_SPAM_HATER_', 221064562Sgshapiro `errprint(`*** ERROR: define either SpamHater or SpamFriend 221164562Sgshapiro')', `dnl') 221290792SgshapiroR<FRIEND> $+ $@ SPAMFRIEND 221364562SgshapiroR<$*> $+ $: $2', 221464562Sgshapiro`dnl') 221564562Sgshapiroifdef(`_SPAM_HATER_', 221664562Sgshapiro`# is the recipient no spam hater? 221790792SgshapiroR<HATER> $+ $: $1 spam hater: continue checks 221864562SgshapiroR<$*> $+ $@ NOSPAMHATER everyone else: stop 221964562Sgshapirodnl',`dnl') 222064562Sgshapirodnl run further checks: check_mail 222164562Sgshapirodnl should we "clean up" $&f? 222290792Sgshapiroifdef(`_FFR_MAIL_MACRO', 222390792Sgshapiro`R$* $: $1 $| $>checkmail $&{mail_from}', 222490792Sgshapiro`R$* $: $1 $| $>checkmail <$&f>') 222594334Sgshapirodnl recipient (canonical format) $| result of checkmail 222664562SgshapiroR$* $| $#$* $#$2 222764562Sgshapirodnl run further checks: check_relay 222894334SgshapiroR$* $| $* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 222964562SgshapiroR$* $| $#$* $#$2 223038032SpeterR$* $| $* $: $1 223138032Speter', `dnl') 223290792Sgshapiro 223390792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 223464562Sgshapiro###################################################################### 223590792Sgshapiro### F: LookUpFull -- search for an entry in access database 223690792Sgshapiro### 223790792Sgshapiro### lookup of full key (which should be an address) and 223890792Sgshapiro### variations if +detail exists: +* and without +detail 223990792Sgshapiro### 224090792Sgshapiro### Parameters: 224190792Sgshapiro### <$1> -- key 224290792Sgshapiro### <$2> -- default (what to return if not found in db) 224390792Sgshapirodnl must not be empty 224490792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 224590792Sgshapiro### ! does lookup only with tag 224690792Sgshapiro### + does lookup with and without tag 224790792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 224890792Sgshapirodnl returns: <default> <passthru> 224990792Sgshapirodnl <result> <passthru> 225090792Sgshapiro###################################################################### 225190792Sgshapiro 225290792SgshapiroSF 225390792Sgshapirodnl workspace: <key> <def> <o tag> <thru> 225490792Sgshapirodnl full lookup 225590792Sgshapirodnl 2 3 4 5 225690792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 225790792Sgshapirodnl no match, try without tag 225890792Sgshapirodnl 1 2 3 4 225990792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 226090792Sgshapirodnl no match, +detail: try +* 226190792Sgshapirodnl 1 2 3 4 5 6 7 226290792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 226390792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 226490792Sgshapirodnl no match, +detail: try +* without tag 226590792Sgshapirodnl 1 2 3 4 5 6 226690792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 226790792Sgshapiro $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 226890792Sgshapirodnl no match, +detail: try without +detail 226990792Sgshapirodnl 1 2 3 4 5 6 7 227090792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 227190792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 227290792Sgshapirodnl no match, +detail: try without +detail and without tag 227390792Sgshapirodnl 1 2 3 4 5 6 227490792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 227590792Sgshapiro $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 227690792Sgshapirodnl no match, return <default> <passthru> 227790792Sgshapirodnl 1 2 3 4 5 227890792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 227990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 228090792Sgshapirodnl 2 3 4 5 228190792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 228290792Sgshapirodnl match, return <match> <passthru> 228390792Sgshapirodnl 2 3 4 5 228490792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 228590792Sgshapiro 228690792Sgshapiro###################################################################### 228790792Sgshapiro### E: LookUpExact -- search for an entry in access database 228890792Sgshapiro### 228990792Sgshapiro### Parameters: 229090792Sgshapiro### <$1> -- key 229190792Sgshapiro### <$2> -- default (what to return if not found in db) 229290792Sgshapirodnl must not be empty 229390792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 229490792Sgshapiro### ! does lookup only with tag 229590792Sgshapiro### + does lookup with and without tag 229690792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 229790792Sgshapirodnl returns: <default> <passthru> 229890792Sgshapirodnl <result> <passthru> 229990792Sgshapiro###################################################################### 230090792Sgshapiro 230190792SgshapiroSE 230290792Sgshapirodnl 2 3 4 5 230390792SgshapiroR<$*> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 230490792Sgshapirodnl no match, try without tag 230590792Sgshapirodnl 1 2 3 4 230690792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 230790792Sgshapirodnl no match, return default passthru 230890792Sgshapirodnl 1 2 3 4 5 230990792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 231090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 231190792Sgshapirodnl 2 3 4 5 231290792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 231390792Sgshapirodnl match, return <match> <passthru> 231490792Sgshapirodnl 2 3 4 5 231590792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 231690792Sgshapiro 231790792Sgshapiro###################################################################### 231890792Sgshapiro### U: LookUpUser -- search for an entry in access database 231990792Sgshapiro### 232090792Sgshapiro### lookup of key (which should be a local part) and 232190792Sgshapiro### variations if +detail exists: +* and without +detail 232290792Sgshapiro### 232390792Sgshapiro### Parameters: 232490792Sgshapiro### <$1> -- key (user@) 232590792Sgshapiro### <$2> -- default (what to return if not found in db) 232690792Sgshapirodnl must not be empty 232790792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 232890792Sgshapiro### ! does lookup only with tag 232990792Sgshapiro### + does lookup with and without tag 233090792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 233190792Sgshapirodnl returns: <default> <passthru> 233290792Sgshapirodnl <result> <passthru> 233390792Sgshapiro###################################################################### 233490792Sgshapiro 233590792SgshapiroSU 233690792Sgshapirodnl user lookups are always with trailing @ 233790792Sgshapirodnl 2 3 4 5 233890792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 233990792Sgshapirodnl no match, try without tag 234090792Sgshapirodnl 1 2 3 4 234190792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 234290792Sgshapirodnl do not remove the @ from the lookup: 234390792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup 234490792Sgshapirodnl no match, +detail: try +* 234590792Sgshapirodnl 1 2 3 4 5 6 234690792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 234790792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 234890792Sgshapirodnl no match, +detail: try +* without tag 234990792Sgshapirodnl 1 2 3 4 5 235090792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 235190792Sgshapiro $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 235290792Sgshapirodnl no match, +detail: try without +detail 235390792Sgshapirodnl 1 2 3 4 5 6 235490792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 235590792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 235690792Sgshapirodnl no match, +detail: try without +detail and without tag 235790792Sgshapirodnl 1 2 3 4 5 235890792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 235990792Sgshapiro $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 236090792Sgshapirodnl no match, return <default> <passthru> 236190792Sgshapirodnl 1 2 3 4 5 236290792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 236390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 236490792Sgshapirodnl 2 3 4 5 236590792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 236690792Sgshapirodnl match, return <match> <passthru> 236790792Sgshapirodnl 2 3 4 5 236890792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 236990792Sgshapiro 237090792Sgshapiro###################################################################### 237164562Sgshapiro### SearchList: search a list of items in the access map 237264562Sgshapiro### Parameters: 237364562Sgshapiro### <exact tag> $| <mark:address> <mark:address> ... <> 237464562Sgshapirodnl maybe we should have a @ (again) in front of the mark to 237564562Sgshapirodnl avoid errorneous matches (with error messages?) 237664562Sgshapirodnl if we can make sure that tag is always a single token 237764562Sgshapirodnl then we can omit the delimiter $|, otherwise we need it 237890792Sgshapirodnl to avoid errorneous matchs (first rule: D: if there 237964562Sgshapirodnl is that mark somewhere in the list, it will be taken). 238064562Sgshapirodnl moreover, we can do some tricks to enforce lookup with 238164562Sgshapirodnl the tag only, e.g.: 238264562Sgshapiro### where "exact" is either "+" or "!": 238364562Sgshapiro### <+ TAG> lookup with and w/o tag 238464562Sgshapiro### <! TAG> lookup with tag 238564562Sgshapirodnl Warning: + and ! should be in OperatorChars (otherwise there must be 238664562Sgshapirodnl a blank between them and the tag. 238764562Sgshapiro### possible values for "mark" are: 238890792Sgshapiro### D: recursive host lookup (LookUpDomain) 238964562Sgshapirodnl A: recursive address lookup (LookUpAddress) [not yet required] 239064562Sgshapiro### E: exact lookup, no modifications 239164562Sgshapiro### F: full lookup, try user+ext@domain and user@domain 239264562Sgshapiro### U: user lookup, try user+ext and user (input must have trailing @) 239364562Sgshapiro### return: <RHS of lookup> or <?> (not found) 239464562Sgshapiro###################################################################### 239538032Speter 239664562Sgshapiro# class with valid marks for SearchList 239764562Sgshapirodnl if A is activated: add it 239890792SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A') 239964562SgshapiroSSearchList 240090792Sgshapiro# just call the ruleset with the name of the tag... nice trick... 240190792Sgshapirodnl 2 3 4 240290792SgshapiroR<$+> $| <$={src}:$*> <$*> $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <> 240390792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <> 240490792Sgshapirodnl no match and nothing left: return 240590792SgshapiroR<$+> $| <> $| <?> <> $@ <?> 240690792Sgshapirodnl no match but something left: continue 240790792SgshapiroR<$+> $| <$+> $| <?> <> $@ $>SearchList <$1> $| <$2> 240890792Sgshapirodnl match: return 240990792SgshapiroR<$+> $| <$*> $| <$+> <> $@ <$3> 241064562Sgshapirodnl return result from recursive invocation 241190792SgshapiroR<$+> $| <$+> $@ <$2> 241290792Sgshapirodnl endif _ACCESS_TABLE_ 241390792Sgshapirodivert(0) 241438032Speter 241590792Sgshapiro###################################################################### 241690792Sgshapiro### trust_auth: is user trusted to authenticate as someone else? 241790792Sgshapiro### 241890792Sgshapiro### Parameters: 241990792Sgshapiro### $1: AUTH= parameter from MAIL command 242090792Sgshapiro###################################################################### 242190792Sgshapiro 242290792Sgshapirodnl empty ruleset definition so it can be called 242390792SgshapiroSLocal_trust_auth 242464562SgshapiroStrust_auth 242564562SgshapiroR$* $: $&{auth_type} $| $1 242664562Sgshapiro# required by RFC 2554 section 4. 242764562SgshapiroR$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 242864562Sgshapirodnl seems to be useful... 242964562SgshapiroR$* $| $&{auth_authen} $@ identical 243064562SgshapiroR$* $| <$&{auth_authen}> $@ identical 243164562Sgshapirodnl call user supplied code 243264562SgshapiroR$* $| $* $: $1 $| $>"Local_trust_auth" $1 243364562SgshapiroR$* $| $#$* $#$2 243464562Sgshapirodnl default: error 243564562SgshapiroR$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 243664562Sgshapiro 243790792Sgshapiro###################################################################### 243890792Sgshapiro### Relay_Auth: allow relaying based on authentication? 243990792Sgshapiro### 244090792Sgshapiro### Parameters: 244190792Sgshapiro### $1: ${auth_type} 244290792Sgshapiro###################################################################### 244390792SgshapiroSLocal_Relay_Auth 244464562Sgshapiro 244590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 244690792Sgshapiro###################################################################### 244790792Sgshapiro### srv_features: which features to offer to a client? 244890792Sgshapiro### (done in server) 244990792Sgshapiro###################################################################### 245090792SgshapiroSsrv_features 245190792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl 245290792SgshapiroR$* $: $1 $| $>"Local_srv_features" $1 245390792SgshapiroR$* $| $#$* $#$2 245490792SgshapiroR$* $| $* $: $1', `dnl') 245590792SgshapiroR$* $: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <> 245690792SgshapiroR<?>$* $: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <> 245790792SgshapiroR<?>$* $: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)> 245864562SgshapiroR<?>$* $@ OK 245990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 246090792SgshapiroR<$* _ATMPF_>$* $#temp', `dnl') 246190792SgshapiroR<$+>$* $# $1 246264562Sgshapiro 246390792Sgshapiro###################################################################### 246490792Sgshapiro### try_tls: try to use STARTTLS? 246590792Sgshapiro### (done in client) 246690792Sgshapiro###################################################################### 246764562SgshapiroStry_tls 246890792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl 246990792SgshapiroR$* $: $1 $| $>"Local_try_tls" $1 247090792SgshapiroR$* $| $#$* $#$2 247190792SgshapiroR$* $| $* $: $1', `dnl') 247290792SgshapiroR$* $: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <> 247390792SgshapiroR<?>$* $: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <> 247490792SgshapiroR<?>$* $: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)> 247564562SgshapiroR<?>$* $@ OK 247690792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 247790792SgshapiroR<$* _ATMPF_>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 247871345SgshapiroR<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 2479102528Sgshapiro 248090792Sgshapiro###################################################################### 248190792Sgshapiro### tls_rcpt: is connection with server "good" enough? 248290792Sgshapiro### (done in client, per recipient) 248390792Sgshapirodnl called from deliver() before RCPT command 248490792Sgshapiro### 248590792Sgshapiro### Parameters: 248690792Sgshapiro### $1: recipient 248790792Sgshapiro###################################################################### 248890792SgshapiroStls_rcpt 248990792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl 249090792SgshapiroR$* $: $1 $| $>"Local_tls_rcpt" $1 249190792SgshapiroR$* $| $#$* $#$2 249290792SgshapiroR$* $| $* $: $1', `dnl') 249390792Sgshapirodnl store name of other side 249490792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 249590792Sgshapirodnl canonify recipient address 249690792SgshapiroR$+ $: <?> $>CanonAddr $1 249790792Sgshapirodnl strip trailing dots 249890792SgshapiroR<?> $+ < @ $+ . > <?> $1 <@ $2 > 249990792Sgshapirodnl full address? 250090792SgshapiroR<?> $+ < @ $+ > $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:> 250190792Sgshapirodnl only localpart? 250290792SgshapiroR<?> $+ $: $1 $| <U:$1@> <E:> 250390792Sgshapirodnl look it up 250490792Sgshapirodnl also look up a default value via E: 250590792SgshapiroR$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <> 250690792Sgshapirodnl found nothing: stop here 250790792SgshapiroR$* $| <?> $@ OK 250890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 250990792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 251090792Sgshapirodnl use the generic routine (for now) 251190792SgshapiroR$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>') 251264562Sgshapiro 251390792Sgshapiro###################################################################### 251490792Sgshapiro### tls_client: is connection with client "good" enough? 251590792Sgshapiro### (done in server) 251690792Sgshapiro### 251790792Sgshapiro### Parameters: 251890792Sgshapiro### ${verify} $| (MAIL|STARTTLS) 251990792Sgshapiro###################################################################### 252064562Sgshapirodnl MAIL: called from check_mail 252164562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted 252264562SgshapiroStls_client 252390792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl 252490792SgshapiroR$* $: $1 $| $>"Local_tls_client" $1 252590792SgshapiroR$* $| $#$* $#$2 252690792SgshapiroR$* $| $* $: $1', `dnl') 252764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 252890792Sgshapirodnl store name of other side 252990792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 253064562Sgshapirodnl ignore second arg for now 253164562Sgshapirodnl maybe use it to distinguish permanent/temporary error? 253264562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered) 253364562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed) 253490792SgshapiroR$* $| $* $: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <> 253590792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <> 253664562Sgshapirodnl do a default lookup: just TLS_CLT_TAG 253764562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 253890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 253990792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 254090792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 254190792SgshapiroR$* $| $* $@ $>"TLS_connection" $1') 254264562Sgshapiro 254390792Sgshapiro###################################################################### 254490792Sgshapiro### tls_server: is connection with server "good" enough? 254590792Sgshapiro### (done in client) 254690792Sgshapiro### 254790792Sgshapiro### Parameter: 254890792Sgshapiro### ${verify} 254990792Sgshapiro###################################################################### 255064562Sgshapirodnl i.e. has the server been authenticated and is encryption active? 255164562Sgshapirodnl called from deliver() after STARTTLS command 255264562SgshapiroStls_server 255390792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl 255490792SgshapiroR$* $: $1 $| $>"Local_tls_server" $1 255590792SgshapiroR$* $| $#$* $#$2 255690792SgshapiroR$* $| $* $: $1', `dnl') 255764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 255890792Sgshapirodnl store name of other side 255990792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 256090792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <> 256190792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <> 256264562Sgshapirodnl do a default lookup: just TLS_SRV_TAG 256364562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 256490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 256590792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 256690792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 256790792SgshapiroR$* $@ $>"TLS_connection" $1') 256864562Sgshapiro 256990792Sgshapiro###################################################################### 257090792Sgshapiro### TLS_connection: is TLS connection "good" enough? 257190792Sgshapiro### 257290792Sgshapiro### Parameters: 257364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 257490792Sgshapiro### ${verify} $| <Requirement> [<>]', `dnl 257590792Sgshapiro### ${verify}') 257690792Sgshapiro### Requirement: RHS from access map, may be ? for none. 257790792Sgshapirodnl syntax for Requirement: 257890792Sgshapirodnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions] 257990792Sgshapirodnl extensions: could be a list of further requirements 258090792Sgshapirodnl for now: CN:string {cn_subject} == string 258190792Sgshapiro###################################################################### 258290792SgshapiroSTLS_connection 258390792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error 258490792Sgshapirodnl deal with TLS handshake failures: abort 258590792SgshapiroRSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake." 258690792Sgshapirodivert(-1)') 258764562Sgshapirodnl common ruleset for tls_{client|server} 258890792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>] 258964562Sgshapirodnl remove optional <> 259064562SgshapiroR$* $| <$*>$* $: $1 $| <$2> 259190792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup> 259290792Sgshapiro# create the appropriate error codes 259364562Sgshapirodnl permanent or temporary error? 259464562SgshapiroR$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 259564562SgshapiroR$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 259664562Sgshapirodnl default case depends on TLS_PERM_ERR 259764562SgshapiroR$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 259890792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup> 259990792Sgshapiro# deal with TLS handshake failures: abort 260064562SgshapiroRSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 260164562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 260264562Sgshapirodnl use default error 260364562SgshapiroRSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 260490792SgshapiroR$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1 260590792Sgshapirodnl separate optional requirements 260690792SgshapiroR$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1 260790792SgshapiroR$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> <> $1 260890792Sgshapirodnl separate optional requirements 260990792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$* $: <$2> <$3:$4> <$5> $1 261064562Sgshapirodnl some other value in access map: accept 261164562Sgshapirodnl this also allows to override the default case (if used) 261264562SgshapiroR$* $| $* $@ OK 261364562Sgshapiro# authentication required: give appropriate error 261464562Sgshapiro# other side did authenticate (via STARTTLS) 261590792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify} 261664562Sgshapirodnl only verification required and it succeeded 261790792SgshapiroR<$*><VERIFY> <> OK $@ OK 261890792Sgshapirodnl verification required and it succeeded but extensions are given 261990792Sgshapirodnl change it to <SMTP:ESC> <REQ:0> <extensions> 262090792SgshapiroR<$*><VERIFY> <$+> OK $: <$1> <REQ:0> <$2> 262164562Sgshapirodnl verification required + some level of encryption 262290792SgshapiroR<$*><VERIFY:$-> <$*> OK $: <$1> <REQ:$2> <$3> 262364562Sgshapirodnl just some level of encryption required 262490792SgshapiroR<$*><ENCR:$-> <$*> $* $: <$1> <REQ:$2> <$3> 262590792Sgshapirodnl workspace: 262690792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]> <[extensions]> {verify} (!= OK) 262790792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits> <[extensions]> 262890792Sgshapirodnl verification required but ${verify} is not set (case 1.) 262990792SgshapiroR<$-:$+><VERIFY $*> <$*> $#error $@ $2 $: $1 " authentication required" 263090792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL $#error $@ $2 $: $1 " authentication failed" 263190792SgshapiroR<$-:$+><VERIFY $*> <$*> NO $#error $@ $2 $: $1 " not authenticated" 263290792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT $#error $@ $2 $: $1 " no authentication requested" 263390792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 263464562Sgshapirodnl some other value for ${verify} 263590792SgshapiroR<$-:$+><VERIFY $*> <$*> $+ $#error $@ $2 $: $1 " authentication failure " $4 263690792Sgshapirodnl some level of encryption required: get the maximum level (case 2.) 263790792SgshapiroR<$*><REQ:$-> <$*> $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf} 263864562Sgshapirodnl compare required bits with actual bits 263990792SgshapiroR<$*><REQ:$-> <$*> $- $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $) 264090792SgshapiroR<$-:$+><$-:$-> <$*> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 264190792Sgshapirodnl strength requirements fulfilled 264290792Sgshapirodnl TLS Additional Requirements Separator 264390792Sgshapirodnl this should be something which does not appear in the extensions itself 264490792Sgshapirodnl @ could be part of a CN, DN, etc... 264590792Sgshapirodnl use < > ? those are encoded in CN, DN, ... 264690792Sgshapirodefine(`_TLS_ARS_', `++')dnl 264790792Sgshapirodnl workspace: 264890792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare 264990792SgshapiroR<$-:$+><$-:$-> <$*> $* $: <$1:$2 _TLS_ARS_ $5> 265090792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions> 265190792Sgshapirodnl continue: check extensions 265290792SgshapiroR<$-:$+ _TLS_ARS_ > $@ OK 265390792Sgshapirodnl split extensions into own list 265490792SgshapiroR<$-:$+ _TLS_ARS_ $+ > $: <$1:$2> <$3> 265590792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ > <$1:$2> <$3> <$4> 265690792SgshapiroR<$-:$+> $+ $@ $>"TLS_req" $3 $| <$1:$2> 265764562Sgshapiro 265890792Sgshapiro###################################################################### 265990792Sgshapiro### TLS_req: check additional TLS requirements 266090792Sgshapiro### 266190792Sgshapiro### Parameters: [<list> <of> <req>] $| <$-:$+> 266290792Sgshapiro### $-: SMTP reply code 266390792Sgshapiro### $+: Enhanced Status Code 266490792Sgshapirodnl further requirements for this ruleset: 266590792Sgshapirodnl name of "other side" is stored is {TLS_name} (client/server_name) 266690792Sgshapirodnl 266790792Sgshapirodnl currently only CN[:common_name] is implemented 266890792Sgshapirodnl right now this is only a logical AND 266990792Sgshapirodnl i.e. all requirements must be true 267090792Sgshapirodnl how about an OR? CN must be X or CN must be Y or .. 267190792Sgshapirodnl use a macro to compute this as a trivial sequential 267290792Sgshapirodnl operations (no precedences etc)? 267390792Sgshapiro###################################################################### 267490792SgshapiroSTLS_req 267590792Sgshapirodnl no additional requirements: ok 267690792SgshapiroR $| $+ $@ OK 267790792Sgshapirodnl require CN: but no CN specified: use name of other side 267890792SgshapiroR<CN> $* $| <$+> $: <CN:$&{TLS_Name}> $1 $| <$2> 267990792Sgshapirodnl match, check rest 268090792SgshapiroR<CN:$&{cn_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 268190792Sgshapirodnl CN does not match 268290792Sgshapirodnl 1 2 3 4 268390792SgshapiroR<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1 268490792Sgshapirodnl cert subject 268590792SgshapiroR<CS:$&{cert_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 268690792Sgshapirodnl CS does not match 268790792Sgshapirodnl 1 2 3 4 268890792SgshapiroR<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CERT Subject " $&{cert_subject} " does not match " $1 268990792Sgshapirodnl match, check rest 269090792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 269190792Sgshapirodnl CI does not match 269290792Sgshapirodnl 1 2 3 4 269390792SgshapiroR<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CERT Issuer " $&{cert_issuer} " does not match " $1 269490792Sgshapirodnl return from recursive call 269590792SgshapiroROK $@ OK 269690792Sgshapiro 269790792Sgshapiro###################################################################### 269890792Sgshapiro### max: return the maximum of two values separated by : 269990792Sgshapiro### 270090792Sgshapiro### Parameters: [$-]:[$-] 270190792Sgshapiro###################################################################### 270264562SgshapiroSmax 270364562SgshapiroR: $: 0 270464562SgshapiroR:$- $: $1 270564562SgshapiroR$-: $: $1 270664562SgshapiroR$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 270764562SgshapiroRTRUE:$-:$- $: $2 270890792SgshapiroR$-:$-:$- $: $2 270990792Sgshapirodnl endif _ACCESS_TABLE_ 271090792Sgshapirodivert(0) 271164562Sgshapiro 271290792Sgshapiro###################################################################### 271390792Sgshapiro### RelayTLS: allow relaying based on TLS authentication 271490792Sgshapiro### 271590792Sgshapiro### Parameters: 271690792Sgshapiro### none 271790792Sgshapiro###################################################################### 271890792SgshapiroSRelayTLS 271964562Sgshapiro# authenticated? 272064562Sgshapirodnl we do not allow relaying for anyone who can present a cert 272164562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns 272264562Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow 272364562Sgshapirodnl them to abuse our server (they might be easier to get hold of, 272464562Sgshapirodnl but anyway). 272564562Sgshapirodnl so here is the trick: if the verification succeeded 272664562Sgshapirodnl we look up the cert issuer in the access map 272764562Sgshapirodnl (maybe after extracting a part with a regular expression) 272864562Sgshapirodnl if this returns RELAY we relay without further questions 272964562Sgshapirodnl if it returns SUBJECT we perform a similar check on the 273064562Sgshapirodnl cert subject. 273164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 273290792SgshapiroR$* $: <?> $&{verify} 273390792SgshapiroR<?> OK $: OK authenticated: continue 273490792SgshapiroR<?> $* $@ NO not authenticated 273564562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 273690792SgshapiroR$* $: $(CERTIssuer $&{cert_issuer} $)', 273790792Sgshapiro`R$* $: $&{cert_issuer}') 273890792SgshapiroR$+ $: $(access CERTISSUER`'_TAG_DELIM_`'$1 $) 273964562Sgshapirodnl use $# to stop further checks (delay_check) 274090792SgshapiroRRELAY $# RELAY 274164562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 274290792SgshapiroRSUBJECT $: <@> $(CERTSubject $&{cert_subject} $)', 274390792Sgshapiro`RSUBJECT $: <@> $&{cert_subject}') 274490792SgshapiroR<@> $+ $: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $) 274590792SgshapiroR<@> RELAY $# RELAY 274690792SgshapiroR$* $: NO', `dnl') 274764562Sgshapiro 274890792Sgshapiro###################################################################### 274990792Sgshapiro### authinfo: lookup authinfo in the access map 275090792Sgshapiro### 275190792Sgshapiro### Parameters: 275290792Sgshapiro### $1: {server_name} 275390792Sgshapiro### $2: {server_addr} 275490792Sgshapirodnl both are currently ignored 275590792Sgshapirodnl if it should be done via another map, we either need to restrict 275690792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another 275790792Sgshapirodnl parameter which I want to avoid, it's quite complex already) 275890792Sgshapiro###################################################################### 275990792Sgshapirodnl omit this ruleset if neither is defined? 276090792Sgshapirodnl it causes DefaultAuthInfo to be ignored 276190792Sgshapirodnl (which may be considered a good thing). 276290792SgshapiroSauthinfo 276390792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl 276490792SgshapiroR$* $: <$(authinfo AuthInfo:$&{server_name} $: ? $)> 276590792SgshapiroR<?> $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)> 276690792SgshapiroR<?> $: <$(authinfo AuthInfo: $: ? $)> 276790792SgshapiroR<?> $@ no no authinfo available 276890792SgshapiroR<$*> $# $1 276990792Sgshapirodnl', `dnl 277090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 277190792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <> 277290792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <> 277390792SgshapiroR$* $| <?>$* $: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <> 277490792SgshapiroR$* $| <?>$* $@ no no authinfo available 277590792SgshapiroR$* $| <$*> <> $# $2 277690792Sgshapirodnl', `dnl')') 277790792Sgshapiro 277864562Sgshapiroundivert(9)dnl LOCAL_RULESETS 277938032Speter# 278038032Speter###################################################################### 278138032Speter###################################################################### 278238032Speter##### 278364562Sgshapiro`##### MAIL FILTER DEFINITIONS' 278464562Sgshapiro##### 278564562Sgshapiro###################################################################### 278664562Sgshapiro###################################################################### 278790792Sgshapiro_MAIL_FILTERS_ 278864562Sgshapiro# 278964562Sgshapiro###################################################################### 279064562Sgshapiro###################################################################### 279164562Sgshapiro##### 279238032Speter`##### MAILER DEFINITIONS' 279338032Speter##### 279438032Speter###################################################################### 279538032Speter###################################################################### 279664562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS 279766494Sgshapiro 2798