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