proto.m4 revision 266527
138032Speterdivert(-1) 238032Speter# 3261194Sgshapiro# Copyright (c) 1998-2010 Proofpoint, 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 16266527SgshapiroVERSIONID(`$Id: proto.m4,v 8.762 2013-11-22 20:51:13 ca Exp $') 1738032Speter 1864562Sgshapiro# level CF_LEVEL config file format 19223067SgshapiroV`'CF_LEVEL`'ifdef(`NO_VENDOR',`', `/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? 391157001Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `0') 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 399168515Sgshapiro# key for shared memory; 0 to turn off, -1 to auto-select 40090792Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0') 40190792Sgshapiro 402168515Sgshapiro# file to store auto-selected key for shared memory (SharedMemoryKey = -1) 403168515Sgshapiro_OPTION(SharedMemoryKeyFile, `confSHARED_MEMORY_KEY_FILE', `') 40494334Sgshapiro 40538032Speter# timeouts (many of these) 40664562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m') 40764562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m') 40890792Sgshapiro_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s') 40964562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m') 41064562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m') 41164562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m') 41264562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h') 41364562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m') 41464562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h') 41564562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h') 41664562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m') 41764562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m') 41864562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m') 41964562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h') 42064562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s') 42164562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s') 42264562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m') 42364562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d') 42464562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d') 42564562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d') 42664562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d') 427132943Sgshapiro_OPTION(Timeout.queuereturn.dsn, `confTO_QUEUERETURN_DSN', `5d') 42864562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h') 42964562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h') 43064562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h') 43164562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h') 432132943Sgshapiro_OPTION(Timeout.queuewarn.dsn, `confTO_QUEUEWARN_DSN', `4h') 43364562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m') 43464562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s') 43564562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s') 43664562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s') 43764562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4') 43864562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4') 43964562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4') 44090792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m') 44190792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m') 44290792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h') 44338032Speter 44490792Sgshapiro# time for DeliverBy; extension disabled if less than 0 44590792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0') 44690792Sgshapiro 44738032Speter# should we not prune routes in route-addr syntax addresses? 44864562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False') 44938032Speter 45038032Speter# queue up everything before forking? 45164562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True') 45238032Speter 45338032Speter# status file 454168515Sgshapiro_OPTION(StatusFile, `STATUS_FILE') 45538032Speter 45638032Speter# time zone handling: 45738032Speter# if undefined, use system default 45838032Speter# if defined but null, use TZ envariable passed in 45938032Speter# if defined and non-null, use that info 46038032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=', 46138032Speter confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=', 46238032Speter `O TimeZoneSpec=confTIME_ZONE') 46338032Speter 46438032Speter# default UID (can be username or userid:groupid) 46564562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull') 46638032Speter 46738032Speter# list of locations of user database file (null means no lookup) 46864562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb') 46938032Speter 47038032Speter# fallback MX host 47164562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net') 47238032Speter 473132943Sgshapiro# fallback smart host 474132943Sgshapiro_OPTION(FallbackSmartHost, `confFALLBACK_SMARTHOST', `fall.back.host.net') 475132943Sgshapiro 47638032Speter# if we are the best MX host for a site, try it directly instead of config err 47764562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False') 47838032Speter 47938032Speter# load average at which we just queue messages 48064562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8') 48138032Speter 48238032Speter# load average at which we refuse connections 48364562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12') 48438032Speter 485132943Sgshapiro# log interval when refusing connections for this long 486132943Sgshapiro_OPTION(RejectLogInterval, `confREJECT_LOG_INTERVAL', `3h') 487132943Sgshapiro 48890792Sgshapiro# load average at which we delay connections; 0 means no limit 48990792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0') 49090792Sgshapiro 49138032Speter# maximum number of children we allow at one time 49298841Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0') 49338032Speter 49438032Speter# maximum number of new connections per second 49571345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0') 49638032Speter 497132943Sgshapiro# Width of the window 498132943Sgshapiro_OPTION(ConnectionRateWindowSize, `confCONNECTION_RATE_WINDOW_SIZE', `60s') 499132943Sgshapiro 50038032Speter# work recipient factor 50164562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') 50238032Speter 50338032Speter# deliver each queued job in a separate process? 50464562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False') 50538032Speter 50638032Speter# work class factor 50764562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800') 50838032Speter 50938032Speter# work time factor 51064562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000') 51138032Speter 51238032Speter# default character set 513141858Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `unknown-8bit') 51438032Speter 51590792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others) 51664562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch') 51738032Speter 51838032Speter# hosts file (normally /etc/hosts) 51964562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts') 52038032Speter 52138032Speter# dialup line delay on connection failure 522157001Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `0s') 52338032Speter 52438032Speter# action to take if there are no recipients in the message 525157001Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `none') 52638032Speter 52738032Speter# chrooted environment for writing to files 528157001Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `') 52938032Speter 53038032Speter# are colons OK in addresses? 53164562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True') 53238032Speter 53338032Speter# shall I avoid expanding CNAMEs (violates protocols)? 53464562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False') 53538032Speter 53638032Speter# SMTP initial login message (old $e macro) 53764562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b') 53838032Speter 53938032Speter# UNIX initial From header format (old $l macro) 54064562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d') 54138032Speter 54238032Speter# From: lines that have embedded newlines are unwrapped onto one line 54364562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False') 54438032Speter 54538032Speter# Allow HELO SMTP command that does not `include' a host name 54664562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False') 54738032Speter 54838032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic) 54964562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.') 55038032Speter 55138032Speter# delimiter (operator) characters (old $o macro) 55264562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]') 55338032Speter 55438032Speter# shall I avoid calling initgroups(3) because of high NIS costs? 55564562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False') 55638032Speter 55738032Speter# are group-writable `:include:' and .forward files (un)trustworthy? 55890792Sgshapiro# True (the default) means they are not trustworthy. 55964562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True') 56090792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES', 56190792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL. 56290792Sgshapiro')') 56338032Speter 56438032Speter# where do errors that occur when sending errors get sent? 56564562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster') 56638032Speter 567168515Sgshapiro# issue temporary errors (4xy) instead of permanent errors (5xy)? 568168515Sgshapiro_OPTION(SoftBounce, `confSOFT_BOUNCE', `False') 569168515Sgshapiro 57064562Sgshapiro# where to save bounces if all else fails 57164562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter') 57264562Sgshapiro 57338032Speter# what user id do we assume for the majority of the processing? 57464562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail') 57538032Speter 57638032Speter# maximum number of recipients per SMTP envelope 577132943Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `0') 57838032Speter 57990792Sgshapiro# limit the rate recipients per SMTP envelope are accepted 58090792Sgshapiro# once the threshold number of recipients have been rejected 581132943Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `0') 58290792Sgshapiro 583203004Sgshapiro 58438032Speter# shall we get local names from our installed interfaces? 58564562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 58638032Speter 58764562Sgshapiro# Return-Receipt-To: header implies DSN request 58864562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 58964562Sgshapiro 59064562Sgshapiro# override connection address (for testing) 59164562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 59264562Sgshapiro 59364562Sgshapiro# Trusted user for file ownership and starting the daemon 59464562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root') 59564562Sgshapiro 59664562Sgshapiro# Control socket for daemon management 59764562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 59864562Sgshapiro 59964562Sgshapiro# Maximum MIME header length to protect MUAs 600132943Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0') 60164562Sgshapiro 60264562Sgshapiro# Maximum length of the sum of all headers 60364562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768') 60464562Sgshapiro 60564562Sgshapiro# Maximum depth of alias recursion 60664562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10') 60764562Sgshapiro 60864562Sgshapiro# location of pid file 60964562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid') 61064562Sgshapiro 61164562Sgshapiro# Prefix string for the process title shown on 'ps' listings 61264562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix') 61364562Sgshapiro 61464562Sgshapiro# Data file (df) memory-buffer file maximum size 61564562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096') 61664562Sgshapiro 61764562Sgshapiro# Transcript file (xf) memory-buffer file maximum size 61864562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096') 61964562Sgshapiro 62090792Sgshapiro# lookup type to find information about local mailboxes 62190792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw') 62290792Sgshapiro 623132943Sgshapiro# override compile time flag REQUIRES_DIR_FSYNC 624132943Sgshapiro_OPTION(RequiresDirfsync, `confREQUIRES_DIR_FSYNC', `true') 625132943Sgshapiro 62664562Sgshapiro# list of authentication mechanisms 62790792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5') 62864562Sgshapiro 629132943Sgshapiro# Authentication realm 630132943Sgshapiro_OPTION(AuthRealm, `confAUTH_REALM', `') 631132943Sgshapiro 63264562Sgshapiro# default authentication information for outgoing connections 63364562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info') 63464562Sgshapiro 63564562Sgshapiro# SMTP AUTH flags 63664562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `') 63764562Sgshapiro 63890792Sgshapiro# SMTP AUTH maximum encryption strength 63990792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `') 64090792Sgshapiro 64190792Sgshapiro# SMTP STARTTLS server options 64290792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `') 64390792Sgshapiro 644203004Sgshapiro 64564562Sgshapiro# Input mail filters 64664562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 64764562Sgshapiro 64898841Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl 64964562Sgshapiro# Milter options 65090792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `') 65164562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 65264562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') 65364562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') 654125820Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `') 655168515Sgshapiro_OPTION(Milter.macros.eom, `confMILTER_MACROS_EOM', `') 656168515Sgshapiro_OPTION(Milter.macros.eoh, `confMILTER_MACROS_EOH', `') 657168515Sgshapiro_OPTION(Milter.macros.data, `confMILTER_MACROS_DATA', `')') 65864562Sgshapiro 65964562Sgshapiro# CA directory 660110560Sgshapiro_OPTION(CACertPath, `confCACERT_PATH', `') 66164562Sgshapiro# CA file 662110560Sgshapiro_OPTION(CACertFile, `confCACERT', `') 66364562Sgshapiro# Server Cert 66464562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `') 66564562Sgshapiro# Server private key 66664562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `') 66764562Sgshapiro# Client Cert 66864562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `') 66964562Sgshapiro# Client private key 67064562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 671132943Sgshapiro# File containing certificate revocation lists 672132943Sgshapiro_OPTION(CRLFile, `confCRL', `') 67364562Sgshapiro# DHParameters (only required if DSA/DH is used) 67464562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `') 67564562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL) 67664562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `') 67764562Sgshapiro 678168515Sgshapiro# Maximum number of "useless" commands before slowing down 679168515Sgshapiro_OPTION(MaxNOOPCommands, `confMAX_NOOP_COMMANDS', `20') 680168515Sgshapiro 681168515Sgshapiro# Name to use for EHLO (defaults to $j) 682168515Sgshapiro_OPTION(HeloName, `confHELO_NAME') 683168515Sgshapiro 68490792Sgshapiro############################ 68590792Sgshapiro`# QUEUE GROUP DEFINITIONS #' 68690792Sgshapiro############################ 68790792Sgshapiro_QUEUE_GROUP_ 68842575Speter 68938032Speter########################### 69038032Speter# Message precedences # 69138032Speter########################### 69238032Speter 69338032SpeterPfirst-class=0 69438032SpeterPspecial-delivery=100 69538032SpeterPlist=-30 69638032SpeterPbulk=-60 69738032SpeterPjunk=-100 69838032Speter 69938032Speter##################### 70038032Speter# Trusted users # 70138032Speter##################### 70238032Speter 70338032Speter# this is equivalent to setting class "t" 70464562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 70538032SpeterTroot 70638032SpeterTdaemon 70738032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp') 70838032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 70938032Speter 71038032Speter######################### 71138032Speter# Format of headers # 71238032Speter######################### 71338032Speter 71438032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl 715132943Sgshapiroifdef(`confMESSAGEID_HEADER',, `define(`confMESSAGEID_HEADER', `<$t.$i@$j>')')dnl 71638032SpeterH?P?Return-Path: <$g> 71738032SpeterHReceived: confRECEIVED_HEADER 71838032SpeterH?D?Resent-Date: $a 71938032SpeterH?D?Date: $a 72038032SpeterH?F?Resent-From: confFROM_HEADER 72138032SpeterH?F?From: confFROM_HEADER 72238032SpeterH?x?Full-Name: $x 72338032Speter# HPosted-Date: $a 72438032Speter# H?l?Received-Date: $b 725132943SgshapiroH?M?Resent-Message-Id: confMESSAGEID_HEADER 726132943SgshapiroH?M?Message-Id: confMESSAGEID_HEADER 72764562Sgshapiro 72838032Speter# 72938032Speter###################################################################### 73038032Speter###################################################################### 73138032Speter##### 73238032Speter##### REWRITING RULES 73338032Speter##### 73438032Speter###################################################################### 73538032Speter###################################################################### 73638032Speter 73738032Speter############################################ 73838032Speter### Ruleset 3 -- Name Canonicalization ### 73938032Speter############################################ 74064562SgshapiroScanonify=3 74138032Speter 74238032Speter# handle null input (translate to <@> special case) 74338032SpeterR$@ $@ <@> 74438032Speter 74538032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon 74638032SpeterR$* $: $1 <@> mark addresses 74738032SpeterR$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> 74838032SpeterR@ $* <@> $: @ $1 unmark @host:... 74990792SgshapiroR$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr 75038032SpeterR$* :: $* <@> $: $1 :: $2 unmark node::addr 75138032SpeterR:`include': $* <@> $: :`include': $1 unmark :`include':... 75238032SpeterR$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon 75338032SpeterR$* : $* <@> $: $2 strip colon if marked 75438032SpeterR$* <@> $: $1 unmark 75538032SpeterR$* ; $1 strip trailing semi 75671345SgshapiroR$* < $+ :; > $* $@ $2 :; <@> catch <list:;> 75738032SpeterR$* < $* ; > $1 < $2 > bogus bracketed semi 75838032Speter 75938032Speter# null input now results from list:; syntax 76038032SpeterR$@ $@ :; <@> 76138032Speter 76238032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item 76338032SpeterR$* $: < $1 > housekeeping <> 76438032SpeterR$+ < $* > < $2 > strip excess on left 76538032SpeterR< $* > $+ < $1 > strip excess on right 76638032SpeterR<> $@ < @ > MAIL FROM:<> case 76738032SpeterR< $+ > $: $1 remove housekeeping <> 76838032Speter 76964562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 77038032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 77138032SpeterR@ $+ , $+ @ $1 : $2 change all "," to ":" 77238032Speter 77338032Speter# localize and dispose of route-based addresses 77490792Sgshapirodnl XXX: IPv6 colon conflict 77590792Sgshapiroifdef(`NO_NETINET6', `dnl', 77690792Sgshapiro`R@ [$+] : $+ $@ $>Canonify2 < @ [$1] > : $2 handle <route-addr>') 77764562SgshapiroR@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 77864562Sgshapirodnl',`dnl 77964562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d> 78064562SgshapiroR@ $+ , $+ $2 78190792Sgshapiroifdef(`NO_NETINET6', `dnl', 78290792Sgshapiro`R@ [ $* ] : $+ $2') 78364562SgshapiroR@ $+ : $+ $2 78464562Sgshapirodnl') 78538032Speter 78638032Speter# find focus for list syntax 78764562SgshapiroR $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 78838032SpeterR $+ : $* ; $@ $1 : $2; list syntax 78938032Speter 79038032Speter# find focus for @ syntax addresses 79138032SpeterR$+ @ $+ $: $1 < @ $2 > focus on domain 79238032SpeterR$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 79364562SgshapiroR$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 79438032Speter 79590792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here. 79690792Sgshapirodnl # do some sanity checking 79790792Sgshapirodnl R$* < @ $~[ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 79838032Speter 79938032Speterifdef(`_NO_UUCP_', `dnl', 80038032Speter`# convert old-style addresses to a domain-based address 80164562SgshapiroR$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 80264562SgshapiroR$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 80364562SgshapiroR$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 80438032Speter') 80538032Speterifdef(`_USE_DECNET_SYNTAX_', 80638032Speter`# convert node::user addresses into a domain-based address 80764562SgshapiroR$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 80864562SgshapiroR$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 80938032Speter', 81038032Speter `dnl') 81138032Speter# if we have % signs, take the rightmost one 81238032SpeterR$* % $* $1 @ $2 First make them all @s. 81338032SpeterR$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 81464562SgshapiroR$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 81538032Speter 81638032Speter# else we must be a local name 81764562SgshapiroR$* $@ $>Canonify2 $1 81838032Speter 81938032Speter 82038032Speter################################################ 82138032Speter### Ruleset 96 -- bottom half of ruleset 3 ### 82238032Speter################################################ 82338032Speter 82464562SgshapiroSCanonify2=96 82538032Speter 82638032Speter# handle special cases for local names 82738032SpeterR$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 82838032SpeterR$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 82938032Speterifdef(`_NO_UUCP_', `dnl', 83038032Speter`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 83164562Sgshapiro 83290792Sgshapiro# check for IPv4/IPv6 domain literal 83390792SgshapiroR$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr] 83438032SpeterR$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 83538032SpeterR$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 83638032Speter 83764562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl 83838032Speter# look up domains in the domain table 83938032SpeterR$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 84038032Speter 84164562Sgshapiroundivert(2)dnl LOCAL_RULE_3 84238032Speter 84364562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl 84438032Speter# handle BITNET mapping 84538032SpeterR$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 84638032Speter 84764562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl 84838032Speter# handle UUCP mapping 84938032SpeterR$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 85038032Speter 85138032Speterifdef(`_NO_UUCP_', `dnl', 85238032Speter`ifdef(`UUCP_RELAY', 85338032Speter`# pass UUCP addresses straight through 85438032SpeterR$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 85538032Speter`# if really UUCP, handle it immediately 85638032Speterifdef(`_CLASS_U_', 85738032Speter`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 85838032Speterifdef(`_CLASS_V_', 85938032Speter`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 86038032Speterifdef(`_CLASS_W_', 86138032Speter`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 86238032Speterifdef(`_CLASS_X_', 86338032Speter`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 86438032Speterifdef(`_CLASS_Y_', 86538032Speter`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 86638032Speter 86738032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl 86838032Speter# try UUCP traffic as a local address 86938032SpeterR$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 87038032SpeterR$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 87138032Speter')') 87264562Sgshapiro# hostnames ending in class P are always canonical 87364562SgshapiroR$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 87464562Sgshapirodnl apply the next rule only for hostnames not in class P 87564562Sgshapirodnl this even works for phrases in class P since . is in class P 87664562Sgshapirodnl which daemon flags are set? 87764562SgshapiroR$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 87864562Sgshapirodnl the other rules in this section only apply if the hostname 87964562Sgshapirodnl does not end in class P hence no further checks are done here 88064562Sgshapirodnl if this ever changes make sure the lookups are "protected" again! 88164562Sgshapiroifdef(`_NO_CANONIFY_', `dnl 88264562Sgshapirodnl do not canonify unless: 88364562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection 88464562Sgshapirodnl with class P is non-empty) 88564562Sgshapirodnl or {daemon_flags} has c set 88664562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify} 88764562SgshapiroR$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 88864562Sgshapiro# pass to name server to make hostname canonical if requested 88964562SgshapiroR$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 89064562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 89164562SgshapiroR$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 89264562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work 89364562SgshapiroR$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 89464562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl 89564562Sgshapirodnl this should only apply to unqualified hostnames 89664562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar 89764562Sgshapirodnl then $- does not work. 89864562Sgshapiro# lookup unqualified hostnames 89990792SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 90064562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless: 90164562Sgshapirodnl {daemon_flags} contains CC (do not canonify) 90271345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work 90371345Sgshapirodnl should we do this for every hostname: even unqualified? 90471345SgshapiroR$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 90564562SgshapiroR$* CC $* $| $* $: $3 90690792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl 90790792Sgshapiro# do not canonify header addresses 90890792SgshapiroR$* $| $* < @ $* $~P > $* $: $&{addr_type} $| $2 < @ $3 $4 > $5 90990792SgshapiroR$* h $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 91090792SgshapiroR$* h $* $| $* $: $3', `dnl') 91138032Speter# pass to name server to make hostname canonical 91264562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 91364562Sgshapirodnl remove {daemon_flags} for other cases 91464562SgshapiroR$* $| $* $: $2 91538032Speter 91638032Speter# local host aliases and pseudo-domains are always canonical 91738032SpeterR$* < @ $=w > $* $: $1 < @ $2 . > $3 91838032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 91938032Speter`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 92038032Speter`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 92164562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 92264562Sgshapirodnl virtual hosts are also canonical 92364562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 92464562Sgshapiro`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 92564562Sgshapiro`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 92664562Sgshapiro`dnl') 92790792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 92890792Sgshapirodnl hosts for genericstable are also canonical 92990792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_', 93090792Sgshapiro`R$* < @ $* $=G > $* $: $1 < @ $2 $3 . > $4', 93190792Sgshapiro`R$* < @ $=G > $* $: $1 < @ $2 . > $3')', 93290792Sgshapiro`dnl') 93364562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added 93464562Sgshapirodnl by one of the rules before 93538032SpeterR$* < @ $* . . > $* $1 < @ $2 . > $3 93638032Speter 93738032Speter 93838032Speter################################################## 93938032Speter### Ruleset 4 -- Final Output Post-rewriting ### 94038032Speter################################################## 94164562SgshapiroSfinal=4 94238032Speter 94371345SgshapiroR$+ :; <@> $@ $1 : handle <list:;> 94438032SpeterR$* <@> $@ handle <> and list:; 94538032Speter 94638032Speter# strip trailing dot off possibly canonical name 94738032SpeterR$* < @ $+ . > $* $1 < @ $2 > $3 94838032Speter 94964562Sgshapiro# eliminate internal code 95038032SpeterR$* < @ *LOCAL* > $* $1 < @ $j > $2 95138032Speter 95238032Speter# externalize local domain info 95338032SpeterR$* < $+ > $* $1 $2 $3 defocus 95438032SpeterR@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 95538032SpeterR@ $* $@ @ $1 ... and exit 95638032Speter 95738032Speterifdef(`_NO_UUCP_', `dnl', 95838032Speter`# UUCP must always be presented in old form 95938032SpeterR$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 96038032Speter 96138032Speterifdef(`_USE_DECNET_SYNTAX_', 96238032Speter`# put DECnet back in :: form 96338032SpeterR$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 96438032Speter `dnl') 96538032Speter# delete duplicate local names 96638032SpeterR$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 96738032Speter 96838032Speter 96938032Speter 97038032Speter############################################################## 97138032Speter### Ruleset 97 -- recanonicalize and call ruleset zero ### 97238032Speter### (used for recursive calls) ### 97338032Speter############################################################## 97438032Speter 97564562SgshapiroSRecurse=97 97664562SgshapiroR$* $: $>canonify $1 97764562SgshapiroR$* $@ $>parse $1 97838032Speter 97938032Speter 98038032Speter###################################### 98138032Speter### Ruleset 0 -- Parse Address ### 98238032Speter###################################### 98338032Speter 98464562SgshapiroSparse=0 98538032Speter 98638032SpeterR$* $: $>Parse0 $1 initial parsing 98738032SpeterR<@> $#_LOCAL_ $: <@> special case error msgs 98864562SgshapiroR$* $: $>ParseLocal $1 handle local hacks 98938032SpeterR$* $: $>Parse1 $1 final parsing 99038032Speter 99138032Speter# 99238032Speter# Parse0 -- do initial syntax checking and eliminate local addresses. 99338032Speter# This should either return with the (possibly modified) input 99438032Speter# or return with a #error mailer. It should not return with a 99538032Speter# #mailer other than the #error mailer. 99638032Speter# 99738032Speter 99838032SpeterSParse0 99938032SpeterR<@> $@ <@> special case error msgs 100090792SgshapiroR$* : $* ; <@> $#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses" 100164562SgshapiroR@ <@ $* > < @ $1 > catch "@@host" bogosity 100290792SgshapiroR<@ $+> $#error $@ 5.1.3 $: "_CODE553 User address required" 100390792SgshapiroR$+ <@> $#error $@ 5.1.3 $: "_CODE553 Hostname required" 100438032SpeterR$* $: <> $1 100590792Sgshapirodnl allow tricks like [host1]:[host2] 100690792SgshapiroR<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4 100790792SgshapiroR<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4 100890792Sgshapirodnl but no a@[b]c 100990792SgshapiroR<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid address" 101090792SgshapiroR<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 101190792SgshapiroR<> $* <$* : $* > $* $#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part" 101238032SpeterR<> $* $1 101390792SgshapiroR$* < @ . $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 101490792SgshapiroR$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 101590792Sgshapirodnl no a@b@ 101690792SgshapiroR$* < @ $* @ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid route address" 101790792Sgshapirodnl no a@b@c 101890792SgshapiroR$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 101964562Sgshapirodnl comma only allowed before @; this check is not complete 102090792SgshapiroR$* , $~O $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 102138032Speter 102290792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks 102390792SgshapiroR$* . < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot" 102490792SgshapiroR. $* < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot" 102590792Sgshapirodnl', `dnl') 102690792Sgshapiro 102738032Speter# now delete the local info -- note $=O to find characters that cause forwarding 102864562SgshapiroR$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 102964562SgshapiroR< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 103038032SpeterR$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 103190792SgshapiroR< @ $+ > $#error $@ 5.1.3 $: "_CODE553 User address required" 103264562SgshapiroR$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 103338032SpeterR$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 103490792SgshapiroR< @ *LOCAL* > $#error $@ 5.1.3 $: "_CODE553 User address required" 103538032SpeterR$* $=O $* < @ *LOCAL* > 103664562Sgshapiro $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 103738032SpeterR$* < @ *LOCAL* > $: $1 103838032Speter 103938032Speter# 104038032Speter# Parse1 -- the bottom half of ruleset 0. 104138032Speter# 104238032Speter 104338032SpeterSParse1 104464562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 104564562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute} 104690792SgshapiroR$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <> 104790792SgshapiroR$+ < @ $={LDAPRouteEquiv} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>', 104864562Sgshapiro`dnl') 104964562Sgshapiro 105038032Speterifdef(`_MAILER_smtp_', 105138032Speter`# handle numeric address spec 105264562Sgshapirodnl there is no check whether this is really an IP number 105364562SgshapiroR$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 1054112810SgshapiroR$* < @ [ $+ ] > $* $: $1 < @ [ $2 ] : $S > $3 Add smart host to path 105590792SgshapiroR$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 105664562SgshapiroR$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 105764562SgshapiroR$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 105838032Speter `dnl') 105938032Speter 106064562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 106138032Speter# handle virtual users 106290792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 106390792Sgshapirodnl this is not a documented option 106490792Sgshapirodnl it stops looping in virtusertable mapping if input and output 106590792Sgshapirodnl are identical, i.e., if address A is mapped to A. 106690792Sgshapirodnl it does not deal with multi-level recursion 106790792Sgshapiro# handle full domains in RHS of virtusertable 106890792SgshapiroR$+ < @ $+ > $: $(macro {RecipientAddress} $) $1 < @ $2 > 106990792SgshapiroR$+ < @ $+ > $: <?> $1 < @ $2 > $| $>final $1 < @ $2 > 107090792SgshapiroR<?> $+ $| $+ $: $1 $(macro {RecipientAddress} $@ $2 $) 107190792SgshapiroR<?> $+ $| $* $: $1', 107290792Sgshapiro`dnl') 107364562SgshapiroR$+ $: <!> $1 Mark for lookup 107490792Sgshapirodnl input: <!> local<@domain> 107564562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 107664562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 107764562Sgshapiro`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 107890792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain> 107964562SgshapiroR<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 108090792Sgshapirodnl if <@> local<@domain>: no match but try lookup 108190792Sgshapirodnl user+detail: try user++@domain if detail not empty 108290792SgshapiroR<@> $+ + $+ < @ $* . > 108390792Sgshapiro $: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 108490792Sgshapirodnl user+detail: try user+*@domain 108538032SpeterR<@> $+ + $* < @ $* . > 108690792Sgshapiro $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 108790792Sgshapirodnl user+detail: try user@domain 108838032SpeterR<@> $+ + $* < @ $* . > 108990792Sgshapiro $: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 109064562Sgshapirodnl try default entry: @domain 109190792Sgshapirodnl ++@domain 109290792SgshapiroR<@> $+ + $+ < @ $+ . > $: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 109364562Sgshapirodnl +*@domain 109490792SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 109564562Sgshapirodnl @domain if +detail exists 109698121Sgshapirodnl if no match, change marker to prevent a second @domain lookup 109798121SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . > 109898121Sgshapirodnl without +detail 109938032SpeterR<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 110090792Sgshapirodnl no match 110138032SpeterR<@> $+ $: $1 110290792Sgshapirodnl remove mark 110364562SgshapiroR<!> $+ $: $1 110464562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 110538032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 110690792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 110790792Sgshapiro# check virtuser input address against output address, if same, skip recursion 110890792SgshapiroR< $+ > $+ < @ $+ > $: < $1 > $2 < @ $3 > $| $1 110990792Sgshapiro# it is the same: stop now 111090792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress} $: $>ParseLocal $>Parse0 $>canonify $1 111190792SgshapiroR< $+ > $+ < @ $+ > $| $* $: < $1 > $2 < @ $3 > 111290792Sgshapirodnl', `dnl') 111380785Sgshapirodnl this is not a documented option 111480785Sgshapirodnl it performs no looping at all for virtusertable 111577349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_', 111677349Sgshapiro`R< $+ > $+ < @ $+ > $: $>ParseLocal $>Parse0 $>canonify $1', 111777349Sgshapiro`R< $+ > $+ < @ $+ > $: $>Recurse $1') 111877349Sgshapirodnl', `dnl') 111938032Speter 112038032Speter# short circuit local delivery so forwarded email works 112138032Speterifdef(`_MAILER_usenet_', `dnl 112264562SgshapiroR$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 112366494Sgshapiro 112466494Sgshapiro 112538032Speterifdef(`_STICKY_LOCAL_DOMAIN_', 112638032Speter`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 112764562SgshapiroR< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 112864562Sgshapirodnl $H empty (but @$=w.) 112938032SpeterR< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 113038032SpeterR< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 113164562Sgshapiro`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 113238032SpeterR$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 113338032Speter 113464562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 113538032Speter# not local -- try mailer table lookup 113638032SpeterR$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 113738032SpeterR< $+ . > $* $: < $1 > $2 strip trailing dot 113838032SpeterR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 113964562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 114064562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 114164562SgshapiroR< $+ > $* $: $>Mailertable <$1> $2 try domain', 114238032Speter`dnl') 114364562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)' 114438032Speter 114538032Speterifdef(`_NO_UUCP_', `dnl', 114638032Speter`# resolve remotely connected UUCP links (if any) 114738032Speterifdef(`_CLASS_V_', 114864562Sgshapiro`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 114938032Speter `dnl') 115038032Speterifdef(`_CLASS_W_', 115164562Sgshapiro`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 115238032Speter `dnl') 115338032Speterifdef(`_CLASS_X_', 115464562Sgshapiro`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 115538032Speter `dnl')') 115638032Speter 115738032Speter# resolve fake top level domains by forwarding to other hosts 115838032Speterifdef(`BITNET_RELAY', 115964562Sgshapiro`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 116038032Speter `dnl') 116138032Speterifdef(`DECNET_RELAY', 116264562Sgshapiro`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 116338032Speter `dnl') 116438032Speterifdef(`_MAILER_pop_', 116538032Speter`R$+ < @ POP. > $#pop $: $1 user@POP', 116638032Speter `dnl') 116738032Speterifdef(`_MAILER_fax_', 116838032Speter`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 116938032Speter`ifdef(`FAX_RELAY', 117064562Sgshapiro`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 117138032Speter `dnl')') 117238032Speter 117338032Speterifdef(`UUCP_RELAY', 117438032Speter`# forward non-local UUCP traffic to our UUCP relay 117564562SgshapiroR$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 117638032Speter`ifdef(`_MAILER_uucp_', 117738032Speter`# forward other UUCP traffic straight to UUCP 117838032SpeterR$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 117938032Speter `dnl')') 118038032Speterifdef(`_MAILER_usenet_', ` 118138032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup 118264562SgshapiroR$+ . USENET $#usenet $@ usenet $: $1', 118338032Speter `dnl') 118438032Speter 118538032Speterifdef(`_LOCAL_RULES_', 118638032Speter`# figure out what should stay in our local mail system 118738032Speterundivert(1)', `dnl') 118838032Speter 118938032Speter# pass names that still have a host to a smarthost (if defined) 119064562SgshapiroR$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 119138032Speter 119238032Speter# deal with other remote names 119338032Speterifdef(`_MAILER_smtp_', 119464562Sgshapiro`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 119590792Sgshapiro`R$* < @$* > $* $#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2') 119638032Speter 119738032Speter# handle locally delivered names 119864562SgshapiroR$=L $#_LOCAL_ $: @ $1 special local names 119938032SpeterR$+ $#_LOCAL_ $: $1 regular local names 120038032Speter 120138032Speter########################################################################### 120238032Speter### Ruleset 5 -- special rewriting after aliases have been expanded ### 120338032Speter########################################################################### 120438032Speter 120564562SgshapiroSLocal_localaddr 120664562SgshapiroSlocaladdr=5 120764562SgshapiroR$+ $: $1 $| $>"Local_localaddr" $1 120890792SgshapiroR$+ $| $#ok $@ $1 no change 120964562SgshapiroR$+ $| $#$* $#$2 121064562SgshapiroR$+ $| $* $: $1 121138032Speter 121290792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 121390792Sgshapiro# Preserve rcpt_host in {Host} 121490792SgshapiroR$+ $: $1 $| $&h $| $&{Host} check h and {Host} 121590792SgshapiroR$+ $| $| $: $(macro {Host} $@ $) $1 no h or {Host} 121690792SgshapiroR$+ $| $| $+ $: $1 h not set, {Host} set 121790792SgshapiroR$+ $| +$* $| $* $: $1 h is +detail, {Host} set 121895154SgshapiroR$+ $| $* @ $+ $| $* $: $(macro {Host} $@ @$3 $) $1 set {Host} to host in h 121990792SgshapiroR$+ $| $+ $| $* $: $(macro {Host} $@ @$2 $) $1 set {Host} to h 122090792Sgshapiro')dnl 122190792Sgshapiro 122290792Sgshapiroifdef(`_FFR_5_', `dnl 122366494Sgshapiro# Preserve host in a macro 122466494SgshapiroR$+ $: $(macro {LocalAddrHost} $) $1 122566494SgshapiroR$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 122666494Sgshapiro 122790792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl 122838032Speter# deal with plussed users so aliases work nicely 122966494SgshapiroR$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 123066494SgshapiroR$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 123166494Sgshapiro') 123238032Speter# prepend an empty "forward host" on the front 123338032SpeterR$+ $: <> $1 123438032Speter 123538032Speterifdef(`LUSER_RELAY', `dnl 123638032Speter# send unrecognized local users to a relay host 123790792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 123866494SgshapiroR< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 123966494SgshapiroR< > $+ $: < ? $L > < > $(user $1 $) look up user 124066494SgshapiroR< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 124166494SgshapiroR< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 124264562SgshapiroR< > $+ $: < $L > $(user $1 $) look up user 124390792SgshapiroR< $* > $+ <> $: < > $2 found; strip $L') 124490792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 124590792SgshapiroR< $+ > $+ $: < $1 > $2 $&{Host}') 124690792Sgshapirodnl') 124738032Speter 124890792Sgshapiroifdef(`MAIL_HUB', `dnl 124990792SgshapiroR< > $+ $: < $H > $1 try hub', `dnl') 125090792Sgshapiroifdef(`LOCAL_RELAY', `dnl 125190792SgshapiroR< > $+ $: < $R > $1 try relay', `dnl') 125290792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 125390792SgshapiroR< > $+ $@ $1', `dnl 125464562SgshapiroR< > $+ $: < > < $1 <> $&h > nope, restore +detail 125590792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 125690792SgshapiroR< > < $+ @ $+ <> + $* > $: < > < $1 + $3 @ $2 > check whether +detail') 125764562SgshapiroR< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 125864562SgshapiroR< > < $+ <> $* > $: < > < $1 > else discard 125938032SpeterR< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 126066494SgshapiroR< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 126138032SpeterR< > < $+ > $@ $1 no +detail 126243730SpeterR$+ $: $1 <> $&h add +detail back in 126390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 126490792SgshapiroR$+ @ $+ <> + $* $: $1 + $3 @ $2 check whether +detail') 126543730SpeterR$+ <> + $* $: $1 + $2 check whether +detail 126666494SgshapiroR$+ <> $* $: $1 else discard') 126764562SgshapiroR< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 126864562SgshapiroR< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 126990792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 127090792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 127190792SgshapiroR< $~[ : $+ > $+ @ $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $4 >') 127290792SgshapiroR< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 127390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 127490792SgshapiroR< $+ > $+ @ $+ $@ $>MailerToTriple < $1 > $2 < @ $3 >') 127564562SgshapiroR< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 127638032Speter 127764562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 127890792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 127938032Speter################################################################### 128090792Sgshapiro### Ruleset LDAPMailertable -- mailertable lookup for LDAP ### 128190792Sgshapirodnl input: <Domain> FullAddress 128290792Sgshapiro################################################################### 128390792Sgshapiro 128490792SgshapiroSLDAPMailertable 128590792SgshapiroR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 128690792SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check resolved? 128790792SgshapiroR< $+ > $* $: < $1 > $>Mailertable <$1> $2 try domain 128890792SgshapiroR< $+ > $#$* $#$2 found 128990792SgshapiroR< $+ > $* $#_RELAY_ $@ $1 $: $2 not found, direct relay', 129090792Sgshapiro`dnl') 129190792Sgshapiro 129290792Sgshapiro################################################################### 129338032Speter### Ruleset 90 -- try domain part of mailertable entry ### 129464562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 129538032Speter################################################################### 129638032Speter 129764562SgshapiroSMailertable=90 129864562Sgshapirodnl shift and check 129964562Sgshapirodnl %2 is not documented in cf/README 130038032SpeterR$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 130164562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 130264562SgshapiroR$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 130364562SgshapiroR$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 130464562Sgshapirodnl is $2 always empty? 130538032SpeterR$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 130664562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 130764562Sgshapirodnl return full address 130838032SpeterR< $* > $* $@ $2 no mailertable match', 130938032Speter`dnl') 131038032Speter 131138032Speter################################################################### 131238032Speter### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 131364562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest 131464562Sgshapirodnl <> address -> address 131564562Sgshapirodnl <error:d.s.n:text> -> error 1316120256Sgshapirodnl <error:keyword:text> -> error 131764562Sgshapirodnl <error:text> -> error 131864562Sgshapirodnl <mailer:user@host> lp<@domain>rest -> mailer host user 131964562Sgshapirodnl <mailer:host> address -> mailer host address 132064562Sgshapirodnl <localdomain> address -> address 132164562Sgshapirodnl <host> address -> relay host address 132238032Speter################################################################### 132338032Speter 132464562SgshapiroSMailerToTriple=95 132538032SpeterR< > $* $@ $1 strip off null relay 132664562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 1327120256SgshapiroR< error : $- : $+ > $* $#error $@ $(dequote $1 $) $: $2 1328120256SgshapiroR< error : $+ > $* $#error $: $1 132938032SpeterR< local : $* > $* $>CanonLocal < $1 > $2 133090792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 133190792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 133290792SgshapiroR< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 133338032SpeterR< $=w > $* $@ $2 delete local host 133438032SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 133538032Speter 133638032Speter################################################################### 133738032Speter### Ruleset CanonLocal -- canonify local: syntax ### 133864562Sgshapirodnl input: <user> address 133964562Sgshapirodnl <x> <@host> : rest -> Recurse rest 134064562Sgshapirodnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 134164562Sgshapirodnl <> user <@host> rest -> local user@host user 134264562Sgshapirodnl <> user -> local user user 134364562Sgshapirodnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 134464562Sgshapirodnl <user> lp <@host> rest -> local lp@host user 134564562Sgshapirodnl <user> lp -> local lp user 134638032Speter################################################################### 134738032Speter 134838032SpeterSCanonLocal 134943730Speter# strip local host from routed addresses 135064562SgshapiroR< $* > < @ $+ > : $+ $@ $>Recurse $3 135164562SgshapiroR< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 135243730Speter 135338032Speter# strip trailing dot from any host name that may appear 135438032SpeterR< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 135538032Speter 135638032Speter# handle local: syntax -- use old user, either with or without host 135738032SpeterR< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 135838032SpeterR< > $+ $#_LOCAL_ $@ $1 $: $1 135938032Speter 136038032Speter# handle local:user@host syntax -- ignore host part 136138032SpeterR< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 136238032Speter 136338032Speter# handle local:user syntax 136438032SpeterR< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 136538032SpeterR< $+ > $* $#_LOCAL_ $@ $2 $: $1 136638032Speter 136738032Speter################################################################### 136838032Speter### Ruleset 93 -- convert header names to masqueraded form ### 136938032Speter################################################################### 137038032Speter 137164562SgshapiroSMasqHdr=93 137238032Speter 137364562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 137438032Speter# handle generics database 137538032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_', 137664562Sgshapirodnl if generics should be applied add a @ as mark 137738032Speter`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 137838032Speter`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 137938032SpeterR$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 138064562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @ 138164562Sgshapirodnl ignore the first case for now 138264562Sgshapirodnl if it has the mark lookup full address 138390792Sgshapirodnl broken: %1 is full address not just detail 138464562SgshapiroR< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 138564562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain> 138664562Sgshapirodnl no match, try user+detail@domain 138764562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 138864562Sgshapiro $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 138964562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 139064562Sgshapiro $: < $(generics $1@$3 $: $) > $4 < @ $5 > 139164562Sgshapirodnl no match, remove mark 139264562SgshapiroR<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 139364562Sgshapirodnl no match, try @domain for exceptions 139464562SgshapiroR< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 139564562Sgshapirodnl workspace: ... or <match> user <@domain> 139664562Sgshapirodnl no match, try local part 139738032SpeterR< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 139864562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 139964562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 140064562SgshapiroR< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 140164562SgshapiroR< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 140238032SpeterR< > $* $: $1 not found', 140338032Speter`dnl') 140438032Speter 140564562Sgshapiro# do not masquerade anything in class N 140664562SgshapiroR$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 140764562Sgshapiro 140890792Sgshapiroifdef(`MASQUERADE_NAME', `dnl 140938032Speter# special case the users that should be exposed 141038032SpeterR$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 141138032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 141238032Speter`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 141338032Speter`R$=E < @ $=M . > $@ $1 < @ $2 . >') 141438032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 141538032Speter`R$=E < @ $=w . > $@ $1 < @ $2 . >') 141638032Speter 141738032Speter# handle domain-specific masquerading 141838032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 141938032Speter`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 142038032Speter`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 142138032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 142238032Speter`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 142338032SpeterR$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 142438032SpeterR$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 142538032SpeterR$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 142690792Sgshapirodnl', `dnl no masquerading 142790792Sgshapirodnl just fix *LOCAL* leftovers 142890792SgshapiroR$* < @ *LOCAL* > $@ $1 < @ $j . >') 142938032Speter 143038032Speter################################################################### 143138032Speter### Ruleset 94 -- convert envelope names to masqueraded form ### 143238032Speter################################################################### 143338032Speter 143464562SgshapiroSMasqEnv=94 143538032Speterifdef(`_MASQUERADE_ENVELOPE_', 143664562Sgshapiro`R$+ $@ $>MasqHdr $1', 143738032Speter`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 143838032Speter 143938032Speter################################################################### 144038032Speter### Ruleset 98 -- local part of ruleset zero (can be null) ### 144138032Speter################################################################### 144238032Speter 144364562SgshapiroSParseLocal=98 144464562Sgshapiroundivert(3)dnl LOCAL_RULE_0 144538032Speter 144664562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 144790792Sgshapiro###################################################################### 144890792Sgshapiro### LDAPExpand: Expand address using LDAP routing 144990792Sgshapiro### 145090792Sgshapiro### Parameters: 145190792Sgshapiro### <$1> -- parsed address (user < @ domain . >) (pass through) 145290792Sgshapiro### <$2> -- RFC822 address (user @ domain) (used for lookup) 145390792Sgshapiro### <$3> -- +detail information 145490792Sgshapiro### 145590792Sgshapiro### Returns: 145690792Sgshapiro### Mailer triplet ($#mailer $@ host $: address) 145790792Sgshapiro### Parsed address (user < @ domain . >) 145890792Sgshapiro###################################################################### 145990792Sgshapiro 1460132943Sgshapiro# SMTP operation modes 1461132943SgshapiroC{SMTPOpModes} s d D 1462132943Sgshapiro 146364562SgshapiroSLDAPExpand 146464562Sgshapiro# do the LDAP lookups 146590792SgshapiroR<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3> 146664562Sgshapiro 1467132943Sgshapiro# look for temporary failures and... 1468132943SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*> $: $&{opMode} $| TMPF <$&{addr_type}> $| $3 1469132943SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*> $: $&{opMode} $| TMPF <$&{addr_type}> $| $3 1470132943Sgshapiroifelse(_LDAP_ROUTE_MAPTEMP_, `_TEMPFAIL_', `dnl 1471132943Sgshapiro# ... temp fail RCPT SMTP commands 1472132943SgshapiroR$={SMTPOpModes} $| TMPF <e r> $| $+ $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."') 1473132943Sgshapiro# ... return original address for MTA to queue up 1474132943SgshapiroR$* $| TMPF <$*> $| $+ $@ $3 147594334Sgshapiro 147664562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost, 147764562Sgshapiro# return the new mailRoutingAddress 147890792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 147990792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2 148090792SgshapiroR<$+@$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $5 @ $2') 148190792SgshapiroR<$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 148290792SgshapiroR<$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 148364562Sgshapiro 148498121Sgshapiro 148564562Sgshapiro# if mailRoutingAddress and non-local mailHost, 148664562Sgshapiro# relay to mailHost with new mailRoutingAddress 148790792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 148890792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 148990792Sgshapiro# check mailertable for host, relay from there 149090792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$3> $>canonify $1 $6 @ $2', 149190792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')') 149290792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 149390792Sgshapiro# check mailertable for host, relay from there 149490792SgshapiroR<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1', 149590792Sgshapiro`R<$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $2 $: $>canonify $1') 149664562Sgshapiro 149764562Sgshapiro# if no mailRoutingAddress and local mailHost, 149864562Sgshapiro# return original address 149990792SgshapiroR<> <$=w> <$+> <$+> <$*> $@ $2 150064562Sgshapiro 150198121Sgshapiro 150264562Sgshapiro# if no mailRoutingAddress and non-local mailHost, 150364562Sgshapiro# relay to mailHost with original address 150490792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 150590792Sgshapiro# check mailertable for host, relay from there 150690792SgshapiroR<> <$+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2', 150790792Sgshapiro`R<> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $1 $: $2') 150864562Sgshapiro 150990792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_', 151090792Sgshapiro`# if no mailRoutingAddress and no mailHost, 151190792Sgshapiro# try without +detail 151290792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl 151390792Sgshapiro 1514203004Sgshapiroifdef(`_LDAP_ROUTE_NODOMAIN_', ` 1515203004Sgshapiro# pretend we did the @domain lookup 1516203004SgshapiroR<> <> <$+> <$+ @ $+> <$*> $: <> <> <$1> <@ $3> <$4>', ` 151790792Sgshapiro# if still no mailRoutingAddress and no mailHost, 151864562Sgshapiro# try @domain 151990792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 152090792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <@ $4> <+$3>') 1521132943SgshapiroR<> <> <$+> <$+ @ $+> <$*> $@ $>LDAPExpand <$1> <@ $3> <$4>') 152264562Sgshapiro 152364562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt, 152464562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 152564562Sgshapiro# user does not exist 152690792SgshapiroR<> <> <$+> <@ $+> <$*> $: <?> < $&{addr_type} > < $1 > 152790792Sgshapiro# only give error for envelope recipient 152890792SgshapiroR<?> <e r> <$+> $#error $@ nouser $: "550 User unknown" 1529132943Sgshapiroifdef(`_LDAP_SENDER_MUST_EXIST_', `dnl 1530132943Sgshapiro# and the sender too 1531132943SgshapiroR<?> <e s> <$+> $#error $@ nouser $: "550 User unknown"') 153290792SgshapiroR<?> <$*> <$+> $@ $2', 153364562Sgshapiro`dnl 153464562Sgshapiro# return the original address 1535244833SgshapiroR<> <> <$+> <@ $+> <$*> $@ $1') 1536244833Sgshapiro') 153764562Sgshapiro 1538244833Sgshapiro 153964562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 154064562Sgshapiro')') 154190792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 154238032Speter###################################################################### 154390792Sgshapiro### D: LookUpDomain -- search for domain in access database 154438032Speter### 154538032Speter### Parameters: 154638032Speter### <$1> -- key (domain name) 154738032Speter### <$2> -- default (what to return if not found in db) 154864562Sgshapirodnl must not be empty 154990792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 155064562Sgshapiro### ! does lookup only with tag 155164562Sgshapiro### + does lookup with and without tag 155290792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 155364562Sgshapirodnl returns: <default> <passthru> 155464562Sgshapirodnl <result> <passthru> 155538032Speter###################################################################### 155638032Speter 155790792SgshapiroSD 155864562Sgshapirodnl workspace <key> <default> <passthru> <mark> 155964562Sgshapirodnl lookup with tag (in front, no delimiter here) 156090792Sgshapirodnl 2 3 4 5 156190792SgshapiroR<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 156264562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 156364562Sgshapirodnl lookup without tag? 156490792Sgshapirodnl 1 2 3 4 156590792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 156690792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest 156790792Sgshapirodnl XXX apply this also to IP addresses? 156890792Sgshapirodnl currently it works the wrong way round for [1.2.3.4] 156990792Sgshapirodnl 1 2 3 4 5 6 157090792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6> 157190792Sgshapirodnl 1 2 3 4 5 157290792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl') 157390792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 157490792Sgshapirodnl found SKIP: return <default> and <passthru> 157590792Sgshapirodnl 1 2 3 4 5 157690792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 157790792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!) 157890792Sgshapirodnl 1 2 3 4 5 6 157990792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*> $@ $>D <[$1]> <$3> <$4 $5> <$6> 158090792Sgshapiroifdef(`NO_NETINET6', `dnl', 158190792Sgshapiro`dnl not found: IPv6 net 158290792Sgshapirodnl (could be merged with previous rule if we have a class containing .:) 158390792Sgshapirodnl 1 2 3 4 5 6 158490792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6> 158590792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>') 158664562Sgshapirodnl not found, but subdomain: try again 158790792Sgshapirodnl 1 2 3 4 5 6 158890792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6> 158990792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag: 159090792Sgshapirodnl 1 2 3 4 159190792SgshapiroR<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl') 159290792Sgshapirodnl not found, no subdomain: return <default> and <passthru> 159390792Sgshapirodnl 1 2 3 4 5 159490792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 159590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 159690792Sgshapirodnl 2 3 4 5 6 159790792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 159890792Sgshapirodnl return <result of lookup> and <passthru> 159990792Sgshapirodnl 2 3 4 5 6 160090792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 160138032Speter 160238032Speter###################################################################### 160390792Sgshapiro### A: LookUpAddress -- search for host address in access database 160438032Speter### 160538032Speter### Parameters: 160638032Speter### <$1> -- key (dot quadded host address) 160738032Speter### <$2> -- default (what to return if not found in db) 160864562Sgshapirodnl must not be empty 160990792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 161064562Sgshapiro### ! does lookup only with tag 161164562Sgshapiro### + does lookup with and without tag 161290792Sgshapiro### <$4> -- passthru (additional data passed through) 161364562Sgshapirodnl returns: <default> <passthru> 161464562Sgshapirodnl <result> <passthru> 161538032Speter###################################################################### 161638032Speter 161790792SgshapiroSA 161864562Sgshapirodnl lookup with tag 161990792Sgshapirodnl 2 3 4 5 162090792SgshapiroR<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 162164562Sgshapirodnl lookup without tag 162290792Sgshapirodnl 1 2 3 4 162390792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 162490792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru> 162590792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 162690792Sgshapirodnl found SKIP: return <default> and <passthru> 162790792Sgshapirodnl 1 2 3 4 5 162890792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 162990792Sgshapiroifdef(`NO_NETINET6', `dnl', 163090792Sgshapiro`dnl no match; IPv6: remove last part 163190792Sgshapirodnl 1 2 3 4 5 6 163290792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 163390792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>') 163464562Sgshapirodnl no match; IPv4: remove last part 163590792Sgshapirodnl 1 2 3 4 5 6 163690792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 163764562Sgshapirodnl no match: return default 163890792Sgshapirodnl 1 2 3 4 5 163990792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 164090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 164190792Sgshapirodnl 2 3 4 5 6 164290792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 164364562Sgshapirodnl match: return result 164490792Sgshapirodnl 2 3 4 5 6 164590792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 164690792Sgshapirodnl endif _ACCESS_TABLE_ 164790792Sgshapirodivert(0) 164838032Speter###################################################################### 164942575Speter### CanonAddr -- Convert an address into a standard form for 165042575Speter### relay checking. Route address syntax is 165142575Speter### crudely converted into a %-hack address. 165242575Speter### 165342575Speter### Parameters: 165442575Speter### $1 -- full recipient address 165542575Speter### 165642575Speter### Returns: 165742575Speter### parsed address, not in source route form 165864562Sgshapirodnl user%host%host<@domain> 165964562Sgshapirodnl host!user<@domain> 166042575Speter###################################################################### 166142575Speter 166242575SpeterSCanonAddr 166364562SgshapiroR$* $: $>Parse0 $>canonify $1 make domain canonical 166464562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 166542575SpeterR< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 166642575SpeterR$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 166742575SpeterR$* < @ $+ > : $* $3 $1 < @ $2 > 166864562Sgshapirodnl') 166942575Speter 167042575Speter###################################################################### 167138032Speter### ParseRecipient -- Strip off hosts in $=R as well as possibly 167238032Speter### $* $=m or the access database. 167338032Speter### Check user portion for host separators. 167438032Speter### 167538032Speter### Parameters: 167638032Speter### $1 -- full recipient address 167738032Speter### 167838032Speter### Returns: 167938032Speter### parsed, non-local-relaying address 168038032Speter###################################################################### 168138032Speter 168238032SpeterSParseRecipient 168364562Sgshapirodnl mark and canonify address 168442575SpeterR$* $: <?> $>CanonAddr $1 168564562Sgshapirodnl workspace: <?> localpart<@domain[.]> 168642575SpeterR<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 168764562Sgshapirodnl workspace: <?> localpart<@domain> 168842575SpeterR<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 168938032Speter 169038032Speter# if no $=O character, no host in the user portion, we are done 169142575SpeterR<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 169264562Sgshapirodnl no $=O in localpart: return 169342575SpeterR<?> $* $@ $1 169438032Speter 169590792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O 169664562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY> 169738032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 169838032Speter# if we relay, check username portion for user%host so host can be checked also 169942575SpeterR<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 170064562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 170164562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 170290792Sgshapiro 170390792Sgshapirodnl what if access map returns something else than RELAY? 170490792Sgshapirodnl we are only interested in RELAY entries... 170590792Sgshapirodnl other To: entries: blacklist recipient; generic entries? 170690792Sgshapirodnl if it is an error we probably do not want to relay anyway 170738032Speterifdef(`_RELAY_HOSTS_ONLY_', 170842575Speter`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 170964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 171064562SgshapiroR<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 171142575SpeterR<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 171242575Speter`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 171364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 171490792SgshapiroR<NO> $* < @ $+ > $: $>D <$2> <NO> <+ To> <$1 < @ $2 >> 171542575SpeterR<$+> <$+> $: <$1> $2',`dnl')') 171638032Speter 171764562Sgshapiro 171890792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl 171990792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain? 172090792SgshapiroR<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 1721132943SgshapiroR<MX> < : $* <TEMP> : > $* $#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1 172290792Sgshapirodnl yes: mark it as <RELAY> 172390792SgshapiroR<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 172490792Sgshapirodnl no: put old <NO> mark back 172590792SgshapiroR<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 172690792Sgshapiro 172790792Sgshapirodnl do we relay to this recipient domain? 172842575SpeterR<RELAY> $* < @ $* > $@ $>ParseRecipient $1 172990792Sgshapirodnl something else 173090792SgshapiroR<$+> $* $@ $2 173142575Speter 173264562Sgshapiro 173338032Speter###################################################################### 173438032Speter### check_relay -- check hostname/address on SMTP startup 173538032Speter###################################################################### 173638032Speter 1737132943Sgshapiroifdef(`_CONTROL_IMMEDIATE_',`dnl 1738132943SgshapiroScheck_relay 1739132943Sgshapiroifdef(`_RATE_CONTROL_IMMEDIATE_',`dnl 1740132943Sgshapirodnl workspace: ignored... 1741132943SgshapiroR$* $: $>"RateControl" dummy', `dnl') 1742132943Sgshapiroifdef(`_CONN_CONTROL_IMMEDIATE_',`dnl 1743132943Sgshapirodnl workspace: ignored... 1744132943SgshapiroR$* $: $>"ConnControl" dummy', `dnl') 1745132943Sgshapirodnl') 1746132943Sgshapiro 174738032SpeterSLocal_check_relay 174864562SgshapiroScheck`'_U_`'relay 1749132943Sgshapiroifdef(`_USE_CLIENT_PTR_',`dnl 1750132943SgshapiroR$* $| $* $: $&{client_ptr} $| $2', `dnl') 175138032SpeterR$* $: $1 $| $>"Local_check_relay" $1 175238032SpeterR$* $| $* $| $#$* $#$3 175338032SpeterR$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 175438032Speter 175538032SpeterSBasic_check_relay 175638032Speter# check for deferred delivery mode 175798121SgshapiroR$* $: < $&{deliveryMode} > $1 175838032SpeterR< d > $* $@ deferred 175938032SpeterR< $* > $* $: $2 176038032Speter 176164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 176266494Sgshapirodnl workspace: {client_name} $| {client_addr} 176390792SgshapiroR$+ $| $+ $: $>D < $1 > <?> <+ Connect> < $2 > 176466494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 1765110560Sgshapirodnl OR $| $+ if client_name is empty 1766110560SgshapiroR $| $+ $: $>A < $1 > <?> <+ Connect> <> empty client_name 1767110560Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 176890792SgshapiroR<?> <$+> $: $>A < $1 > <?> <+ Connect> <> no: another lookup 176990792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) 177090792SgshapiroR<?> <$*> $: OK found nothing 177190792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK 177290792SgshapiroR<$={Accept}> <$*> $@ $1 return value of lookup 1773132943SgshapiroR<REJECT> <$*> $#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"') 177490792SgshapiroR<DISCARD> <$*> $#discard $: discard 1775132943SgshapiroR<QUARANTINE:$+> <$*> $#error $@ quarantine $: $1 177664562Sgshapirodnl error tag 177766494SgshapiroR<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 177866494SgshapiroR<ERROR:$+> <$*> $#error $: $1 177990792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 178064562Sgshapirodnl generic error from access map 178166494SgshapiroR<$+> <$*> $#error $: $1', `dnl') 178238032Speter 178364562Sgshapiroifdef(`_RBL_',`dnl 178464562Sgshapiro# DNS based IP address spam list 178590792Sgshapirodnl workspace: ignored... 178638032SpeterR$* $: $&{client_addr} 178764562SgshapiroR$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 178864562SgshapiroR<?>OK $: OKSOFAR 178998121SgshapiroR<?>$+ $#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"', 179038032Speter`dnl') 1791132943Sgshapiroifdef(`_RATE_CONTROL_',`dnl 1792132943Sgshapiroifdef(`_RATE_CONTROL_IMMEDIATE_',`', `dnl 1793132943Sgshapirodnl workspace: ignored... 1794132943SgshapiroR$* $: $>"RateControl" dummy')', `dnl') 1795132943Sgshapiroifdef(`_CONN_CONTROL_',`dnl 1796132943Sgshapiroifdef(`_CONN_CONTROL_IMMEDIATE_',`',`dnl 1797132943Sgshapirodnl workspace: ignored... 1798132943SgshapiroR$* $: $>"ConnControl" dummy')', `dnl') 1799223067Sgshapiroundivert(8)dnl LOCAL_DNSBL 1800168515Sgshapiroifdef(`_REQUIRE_RDNS_', `dnl 1801168515SgshapiroR$* $: $&{client_addr} $| $&{client_resolve} 1802168515SgshapiroR$=R $* $@ RELAY We relay for these 1803168515SgshapiroR$* $| OK $@ OK Resolves. 1804168515SgshapiroR$* $| FAIL $#error $@ 5.7.1 $: 550 Fix reverse DNS for $1 1805168515SgshapiroR$* $| TEMP $#error $@ 4.1.8 $: 451 Client IP address $1 does not resolve 1806168515SgshapiroR$* $| FORGED $#error $@ 4.1.8 $: 451 Possibly forged hostname for $1 1807168515Sgshapiro', `dnl') 180838032Speter 180938032Speter###################################################################### 181038032Speter### check_mail -- check SMTP ``MAIL FROM:'' command argument 181138032Speter###################################################################### 181238032Speter 181338032SpeterSLocal_check_mail 181464562SgshapiroScheck`'_U_`'mail 181538032SpeterR$* $: $1 $| $>"Local_check_mail" $1 181638032SpeterR$* $| $#$* $#$2 181738032SpeterR$* $| $* $@ $>"Basic_check_mail" $1 181838032Speter 181938032SpeterSBasic_check_mail 182038032Speter# check for deferred delivery mode 182198121SgshapiroR$* $: < $&{deliveryMode} > $1 182238032SpeterR< d > $* $@ deferred 182338032SpeterR< $* > $* $: $2 182438032Speter 182564562Sgshapiro# authenticated? 182664562Sgshapirodnl done first: we can require authentication for every mail transaction 182764562Sgshapirodnl workspace: address as given by MAIL FROM: (sender) 182864562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 182964562SgshapiroR$* $| $#$+ $#$2 183064562Sgshapirodnl undo damage: remove result of tls_client call 183164562SgshapiroR$* $| $* $: $1 183238032Speter 183364562Sgshapirodnl workspace: address as given by MAIL FROM: 183464562SgshapiroR<> $@ <OK> we MUST accept <> (RFC 1123) 183538032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 183664562Sgshapirodnl do some additional checks 183764562Sgshapirodnl no user@host 183864562Sgshapirodnl no user@localhost (if nonlocal sender) 183964562Sgshapirodnl this is a pretty simple canonification, it will not catch every case 184064562Sgshapirodnl just make sure the address has <> around it (which is required by 184164562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...) 184264562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will 184364562Sgshapirodnl not be modified by host lookups. 184464562SgshapiroR$+ $: <?> $1 184564562SgshapiroR<?><$+> $: <@> <$1> 184664562SgshapiroR<?>$+ $: <@> <$1> 184764562Sgshapirodnl workspace: <@> <address> 184864562Sgshapirodnl prepend daemon_flags 184964562SgshapiroR$* $: $&{daemon_flags} $| $1 185064562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 185164562Sgshapirodnl do not allow these at all or only from local systems? 185264562SgshapiroR$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 185364562Sgshapirodnl accept unqualified sender: change mark to avoid test 185464562SgshapiroR$* u $* $| <@> < $* > $: <?> < $3 > 185564562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 185664562Sgshapirodnl or: <? ${client_name} > <address> 185764562Sgshapirodnl or: <?> <address> 185864562Sgshapirodnl remove daemon_flags 185964562SgshapiroR$* $| $* $: $2 186038032Speter# handle case of @localhost on address 186164562SgshapiroR<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 186264562SgshapiroR<@> < $* @ [127.0.0.1] > 186364562Sgshapiro $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 186464562SgshapiroR<@> < $* @ localhost.$m > 186564562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.$m > 186638032Speterifdef(`_NO_UUCP_', `dnl', 186764562Sgshapiro`R<@> < $* @ localhost.UUCP > 186864562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 186964562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 187064562Sgshapirodnl or: <@> <address> 187164562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 187264562SgshapiroR<@> $* $: $1 no localhost as domain 187364562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 187464562Sgshapirodnl or: <address> 187564562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 187664562SgshapiroR<? $=w> $* $: $2 local client: ok 187790792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address" 187864562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 187964562SgshapiroR<?> $* $: $1') 188064562Sgshapirodnl workspace: address (or <address>) 188164562SgshapiroR$* $: <?> $>CanonAddr $1 canonify sender address and mark it 188264562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 188364562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed 188464562SgshapiroR<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 188564562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 1886102528SgshapiroR<?> $* < @ $* $=P > $: <_RES_OK_> $1 < @ $2 $3 > 188764562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ? or OK 188898121Sgshapirodnl A sender address with my local host name ($j) is safe 1889102528SgshapiroR<?> $* < @ $j > $: <_RES_OK_> $1 < @ $j > 189064562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 189190792Sgshapiro`R<?> $* < @ $+ > $: <_RES_OK_> $1 < @ $2 > ... unresolvable OK', 189264562Sgshapiro`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 189364562SgshapiroR<? $* <$->> $* < @ $+ > 189464562Sgshapiro $: <$2> $3 < @ $4 >') 189590792Sgshapirodnl workspace <mark> CanonicalAddress where mark is ?, _RES_OK_, PERM, TEMP 189664562Sgshapirodnl mark is ? iff the address is user (wo @domain) 189738032Speter 189864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 189964562Sgshapiro# check sender address: user@address, user@, address 190064562Sgshapirodnl should we remove +ext from user? 190190792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP 190290792SgshapiroR<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3> 190364562SgshapiroR<$+> $+ $: @<$1> <$2> $| <U:$2@> 190464562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 190564562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 190664562Sgshapirodnl will only return user<@domain when "reversing" the args 190790792SgshapiroR@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <> 190864562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result> 190964562SgshapiroR<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 191064562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress> 191138032Speter# retransform for further use 191264562Sgshapirodnl required form: 191364562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress 191464562SgshapiroR<?> <$+> <$*> $: <$1> $2 no match 191564562SgshapiroR<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 191664562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress 191764562Sgshapirodnl mark is ? iff the address is user (wo @domain) 191838032Speter 191938032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 192038032Speter# handle case of no @domain on address 192164562Sgshapirodnl prepend daemon_flags 192264562SgshapiroR<?> $* $: $&{daemon_flags} $| <?> $1 192364562Sgshapirodnl accept unqualified sender: change mark to avoid test 192490792SgshapiroR$* u $* $| <?> $* $: <_RES_OK_> $3 192564562Sgshapirodnl remove daemon_flags 192664562SgshapiroR$* $| $* $: $2 1927110560SgshapiroR<?> $* $: < ? $&{client_addr} > $1 1928102528SgshapiroR<?> $* $@ <_RES_OK_> ...local unqualed ok 192990792SgshapiroR<? $+> $* $#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f 193038032Speter ...remote is not') 193138032Speter# check results 193264562SgshapiroR<?> $* $: @ $1 mark address: nothing known about it 1933168515SgshapiroR<$={ResOk}> $* $: @ $2 domain ok 193464562SgshapiroR<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 193590792SgshapiroR<PERM> $* $#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist" 193664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 193790792SgshapiroR<$={Accept}> $* $# $1 accept from access map 193838032SpeterR<DISCARD> $* $#discard $: discard 1939132943SgshapiroR<QUARANTINE:$+> $* $#error $@ quarantine $: $1 1940132943SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"') 194164562Sgshapirodnl error tag 194264562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 194364562SgshapiroR<ERROR:$+> $* $#error $: $1 194490792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 194564562Sgshapirodnl generic error from access map 194664562SgshapiroR<$+> $* $#error $: $1 error from access db', 194738032Speter`dnl') 1948168515Sgshapirodnl workspace: @ CanonicalAddress (i.e. address in canonical form localpart<@host>) 194938032Speter 1950168515Sgshapiroifdef(`_BADMX_CHK_', `dnl 1951168515SgshapiroR@ $*<@$+>$* $: $1<@$2>$3 $| $>BadMX $2 1952168515SgshapiroR$* $| $#$* $#$2 1953168515Sgshapiro 1954168515SgshapiroSBadMX 1955168515Sgshapiro# Look up MX records and ferret away a copy of the original address. 1956168515Sgshapiro# input: domain part of address to check 1957168515SgshapiroR$+ $:<MX><$1><:$(mxlist $1$):><:> 1958168515Sgshapiro# workspace: <MX><domain><: mxlist-result $><:> 1959168515SgshapiroR<MX><$+><:$*<TEMP>:><$*> $#error $@ 4.1.2 $: "450 MX lookup failure for "$1 1960168515Sgshapiro# workspace: <MX> <original destination> <unchecked mxlist> <checked mxlist> 1961168515Sgshapiro# Recursively run badmx check on each mx. 1962168515SgshapiroR<MX><$*><:$+:$*><:$*> <MX><$1><:$3><: $4 $(badmx $2 $):> 1963168515Sgshapiro# See if any of them fail. 1964182352SgshapiroR<MX><$*><$*><$*<BADMX>:$*> $#error $@ 5.1.2 $:"550 Illegal MX record for host "$1 1965168515Sgshapiro# Reverse the mxlists so we can use the same argument order again. 1966168515SgshapiroR<MX><$*><$*><$*> $:<MX><$1><$3><$2> 1967168515SgshapiroR<MX><$*><:$+:$*><:$*> <MX><$1><:$3><:$4 $(dnsA $2 $) :> 1968168515Sgshapiro 1969168515Sgshapiro# Reverse the lists so we can use the same argument order again. 1970168515SgshapiroR<MX><$*><$*><$*> $:<MX><$1><$3><$2> 1971168515SgshapiroR<MX><$*><:$+:$*><:$*> <MX><$1><:$3><:$4 $(BadMXIP $2 $) :> 1972168515Sgshapiro 1973182352SgshapiroR<MX><$*><$*><$*<BADMXIP>:$*> $#error $@ 5.1.2 $:"550 Invalid MX record for host "$1', 1974168515Sgshapiro`dnl') 1975168515Sgshapiro 1976168515Sgshapiro 197738032Speter###################################################################### 197838032Speter### check_rcpt -- check SMTP ``RCPT TO:'' command argument 197938032Speter###################################################################### 198038032Speter 198138032SpeterSLocal_check_rcpt 198264562SgshapiroScheck`'_U_`'rcpt 198338032SpeterR$* $: $1 $| $>"Local_check_rcpt" $1 198438032SpeterR$* $| $#$* $#$2 198538032SpeterR$* $| $* $@ $>"Basic_check_rcpt" $1 198638032Speter 198738032SpeterSBasic_check_rcpt 198890792Sgshapiro# empty address? 198990792SgshapiroR<> $#error $@ nouser $: "553 User address required" 199090792SgshapiroR$@ $#error $@ nouser $: "553 User address required" 199138032Speter# check for deferred delivery mode 199298121SgshapiroR$* $: < $&{deliveryMode} > $1 199338032SpeterR< d > $* $@ deferred 199438032SpeterR< $* > $* $: $2 199538032Speter 199664562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 199790792Sgshapirodnl this code checks for user@host where host is not a FQHN. 199890792Sgshapirodnl it is not activated. 199990792Sgshapirodnl notice: code to check for a recipient without a domain name is 200090792Sgshapirodnl available down below; look for the same macro. 200190792Sgshapirodnl this check is done here because the name might be qualified by the 200290792Sgshapirodnl canonicalization. 200390792Sgshapiro# require fully qualified domain part? 200490792Sgshapirodnl very simple canonification: make sure the address is in < > 200564562SgshapiroR$+ $: <?> $1 200690792SgshapiroR<?> <$+> $: <@> <$1> 200790792SgshapiroR<?> $+ $: <@> <$1> 200890792SgshapiroR<@> < postmaster > $: postmaster 2009110560SgshapiroR<@> < $* @ $+ . $+ > $: < $1 @ $2 . $3 > 201064562Sgshapirodnl prepend daemon_flags 201190792SgshapiroR<@> $* $: $&{daemon_flags} $| <@> $1 201264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 2013159609Sgshapirodnl _r_equire qual.rcpt: ok 2014120256SgshapiroR$* r $* $| <@> < $+ @ $+ > $: < $3 @ $4 > 201564562Sgshapirodnl do not allow these at all or only from local systems? 2016120256SgshapiroR$* r $* $| <@> < $* > $: < ? $&{client_name} > < $3 > 201764562SgshapiroR<?> < $* > $: <$1> 201864562SgshapiroR<? $=w> < $* > $: <$1> 201990792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "553 Fully qualified domain name required" 202064562Sgshapirodnl remove daemon_flags for other cases 202164562SgshapiroR$* $| <@> $* $: $2', `dnl') 202264562Sgshapiro 202390792Sgshapirodnl ################################################################## 202490792Sgshapirodnl call subroutines for recipient and relay 202590792Sgshapirodnl possible returns from subroutines: 202690792Sgshapirodnl $#TEMP temporary failure 202790792Sgshapirodnl $#error permanent failure (or temporary if from access map) 202890792Sgshapirodnl $#other stop processing 202990792Sgshapirodnl RELAY RELAYing allowed 203090792Sgshapirodnl other otherwise 203190792Sgshapiro###################################################################### 203290792SgshapiroR$* $: $1 $| @ $>"Rcpt_ok" $1 203390792Sgshapirodnl temporary failure? remove mark @ and remember 203490792SgshapiroR$* $| @ $#TEMP $+ $: $1 $| T $2 203590792Sgshapirodnl error or ok (stop) 203690792SgshapiroR$* $| @ $#$* $#$2 203790792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 203890792SgshapiroR$* $| @ RELAY $@ RELAY 203990792Sgshapirodnl something else: call check sender (relay) 204090792SgshapiroR$* $| @ $* $: O $| $>"Relay_ok" $1 204190792Sgshapirodnl temporary failure: call check sender (relay) 204290792SgshapiroR$* $| T $+ $: T $2 $| $>"Relay_ok" $1 204390792Sgshapirodnl temporary failure? return that 204490792SgshapiroR$* $| $#TEMP $+ $#error $2 204590792Sgshapirodnl error or ok (stop) 204690792SgshapiroR$* $| $#$* $#$2 204790792SgshapiroR$* $| RELAY $@ RELAY 204890792Sgshapirodnl something else: return previous temp failure 204990792SgshapiroR T $+ $| $* $#error $1 205090792Sgshapiro# anything else is bogus 205190792SgshapiroR$* $#error $@ 5.7.1 $: confRELAY_MSG 205290792Sgshapirodivert(0) 205390792Sgshapiro 205490792Sgshapiro###################################################################### 205590792Sgshapiro### Rcpt_ok: is the recipient ok? 205690792Sgshapirodnl input: recipient address (RCPT TO) 205790792Sgshapirodnl output: see explanation at call 205890792Sgshapiro###################################################################### 205990792SgshapiroSRcpt_ok 206038032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl 206142575SpeterR$* $: $>CanonAddr $1 206238032SpeterR$* < @ $* . > $1 < @ $2 > strip trailing dots', 206338032Speter`R$* $: $>ParseRecipient $1 strip relayable hosts') 206438032Speter 206542575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl 206642575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl 206742575Speter# unlimited bestmx 206842575SpeterR$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 206942575Speter`dnl 207042575Speter# limit bestmx to $=B 207143730SpeterR$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 207290792SgshapiroR$* $=O $* < @ $* @@ $=w . > $* $@ $>"Rcpt_ok" $1 $2 $3 207342575SpeterR$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 207442575SpeterR$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 207542575Speter 207638032Speterifdef(`_BLACKLIST_RCPT_',`dnl 207764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 207838032Speter# blacklist local users or any host from receiving mail 207938032SpeterR$* $: <?> $1 208064562Sgshapirodnl user is now tagged with @ to be consistent with check_mail 208164562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user) 208290792SgshapiroR<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2> 208390792SgshapiroR<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2> 208464562SgshapiroR<?> $+ $: <> <$1> $| <U:$1@> 208564562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 208664562Sgshapirodnl will only return user<@domain when "reversing" the args 208790792SgshapiroR<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+ To> $| <$2> <> 208864562SgshapiroR<@> <$*> $| <$*> $: <$2> <$1> reverse result 208964562SgshapiroR<?> <$*> $: @ $1 mark address as no match 209090792Sgshapirodnl we may have to filter here because otherwise some RHSs 209190792Sgshapirodnl would be interpreted as generic error messages... 209290792Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 209390792Sgshapirodnl that would make a lot of things easier. 209464562SgshapiroR<$={Accept}> <$*> $: @ $2 mark address as no match 209590792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 209690792SgshapiroR<SKIP> <$*> $: @ $1 mark address as no match', `dnl') 209790792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl 209890792Sgshapirodnl compatility with 8.11/8.10: 209964562Sgshapirodnl we have to filter these because otherwise they would be interpreted 210064562Sgshapirodnl as generic error message... 210164562Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 210264562Sgshapirodnl that would make a lot of things easier. 210364562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)? 210464562SgshapiroR<$={SpamTag}> <$*> $: @ $2 mark address as no match') 210590792SgshapiroR<REJECT> $* $#error $@ 5.2.1 $: confRCPTREJ_MSG 210664562SgshapiroR<DISCARD> $* $#discard $: discard 2107132943SgshapiroR<QUARANTINE:$+> $* $#error $@ quarantine $: $1 210864562Sgshapirodnl error tag 210964562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 211064562SgshapiroR<ERROR:$+> $* $#error $: $1 211190792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 211264562Sgshapirodnl generic error from access map 211364562SgshapiroR<$+> $* $#error $: $1 error from access db 211464562SgshapiroR@ $* $1 remove mark', `dnl')', `dnl') 211538032Speter 211690792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 211790792Sgshapiro# authenticated via TLS? 211890792SgshapiroR$* $: $1 $| $>RelayTLS client authenticated? 211990792SgshapiroR$* $| $# $+ $# $2 error/ok? 212090792SgshapiroR$* $| $* $: $1 no 212164562Sgshapiro 212290792SgshapiroR$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type} 212390792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth 212490792SgshapiroR$* $| $# $* $# $2 212590792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech} 212690792SgshapiroR$* $| NO $: $1 212790792SgshapiroR$* $| $* $: $1 $| $&{auth_type} 212890792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ] 212964562Sgshapirodnl empty ${auth_type}? 213064562SgshapiroR$* $| $: $1 213164562Sgshapirodnl mechanism ${auth_type} accepted? 213264562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below 213390792SgshapiroR$* $| $={TrustAuthMech} $# RELAY 213490792Sgshapirodnl remove ${auth_type} 213564562SgshapiroR$* $| $* $: $1 213671345Sgshapirodnl workspace: localpart<@domain> | localpart 213764562Sgshapiroifelse(defn(`_NO_UUCP_'), `r', 213871345Sgshapiro`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 213971345SgshapiroR$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 214038032Speter# anything terminating locally is ok 214138032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 214290792SgshapiroR$+ < @ $* $=m > $@ RELAY', `dnl') 214390792SgshapiroR$+ < @ $=w > $@ RELAY 214438032Speterifdef(`_RELAY_HOSTS_ONLY_', 214590792Sgshapiro`R$+ < @ $=R > $@ RELAY 214664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 2147203004Sgshapiroifdef(`_RELAY_FULL_ADDR_', `dnl 2148203004SgshapiroR$+ < @ $+ > $: <$(access To:$1@$2 $: ? $)> <$1 < @ $2 >> 2149203004SgshapiroR<?> <$+ < @ $+ >> $: <$(access To:$2 $: ? $)> <$1 < @ $2 >>',` 2150203004SgshapiroR$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >>') 215164562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 215264562SgshapiroR<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 215390792Sgshapiro`R$+ < @ $* $=R > $@ RELAY 215464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 2155132943Sgshapiroifdef(`_RELAY_FULL_ADDR_', `dnl 2156132943SgshapiroR$+ < @ $+ > $: $1 < @ $2 > $| $>SearchList <+ To> $| <F:$1@$2> <D:$2> <F:$1@> <> 2157132943SgshapiroR$+ < @ $+ > $| <$*> $: <$3> <$1 <@ $2>> 2158132943SgshapiroR$+ < @ $+ > $| $* $: <$3> <$1 <@ $2>>', 2159132943Sgshapiro`R$+ < @ $+ > $: $>D <$2> <?> <+ To> <$1 < @ $2 >>')')') 216064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 216164562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 216290792SgshapiroR<RELAY> $* $@ RELAY 216390792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 216438032SpeterR<$*> <$*> $: $2',`dnl') 216538032Speter 216664562Sgshapiro 216738032Speterifdef(`_RELAY_MX_SERVED_', `dnl 216838032Speter# allow relaying for hosts which we MX serve 216964562SgshapiroR$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 217064562Sgshapirodnl this must not necessarily happen if the client is checked first... 2171132943SgshapiroR< : $* <TEMP> : > $* $#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1 217290792SgshapiroR<$* : $=w . : $*> $* $@ RELAY 217342575SpeterR< : $* : > $* $: $2', 217438032Speter`dnl') 217538032Speter 217638032Speter# check for local user (i.e. unqualified address) 217738032SpeterR$* $: <?> $1 217842575SpeterR<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 217938032Speter# local user is ok 218064562Sgshapirodnl is it really? the standard requires user@domain, not just user 218164562Sgshapirodnl but we should accept it anyway (maybe making it an option: 218264562Sgshapirodnl RequireFQDN ?) 218364562Sgshapirodnl postmaster must be accepted without domain (DRUMS) 218464562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 218590792SgshapiroR<?> postmaster $@ OK 218664562Sgshapiro# require qualified recipient? 218764562Sgshapirodnl prepend daemon_flags 218864562SgshapiroR<?> $+ $: $&{daemon_flags} $| <?> $1 218964562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart 219064562Sgshapirodnl do not allow these at all or only from local systems? 219164562Sgshapirodnl r flag? add client_name 219264562SgshapiroR$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 219364562Sgshapirodnl no r flag: relay to local user (only local part) 219464562Sgshapiro# no qualified recipient required 219590792SgshapiroR$* $| <?> $+ $@ RELAY 219664562Sgshapirodnl client_name is empty 219790792SgshapiroR<?> <?> $+ $@ RELAY 219864562Sgshapirodnl client_name is local 219990792SgshapiroR<? $=w> <?> $+ $@ RELAY 220064562Sgshapirodnl client_name is not local 220164562SgshapiroR<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 220264562Sgshapirodnl no qualified recipient required 220390792SgshapiroR<?> $+ $@ RELAY') 220464562Sgshapirodnl it is a remote user: remove mark and then check client 220538032SpeterR<$+> $* $: $2 220664562Sgshapirodnl currently the recipient address is not used below 220738032Speter 220890792Sgshapiro###################################################################### 220990792Sgshapiro### Relay_ok: is the relay/sender ok? 221090792Sgshapirodnl input: ignored 221190792Sgshapirodnl output: see explanation at call 221290792Sgshapiro###################################################################### 221390792SgshapiroSRelay_ok 221438032Speter# anything originating locally is ok 221564562Sgshapiro# check IP address 221664562SgshapiroR$* $: $&{client_addr} 221790792SgshapiroR$@ $@ RELAY originated locally 221890792SgshapiroR0 $@ RELAY originated locally 2219110560SgshapiroR127.0.0.1 $@ RELAY originated locally 2220110560SgshapiroRIPv6:::1 $@ RELAY originated locally 222190792SgshapiroR$=R $* $@ RELAY relayable IP address 222264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 222390792SgshapiroR$* $: $>A <$1> <?> <+ Connect> <$1> 222490792SgshapiroR<RELAY> $* $@ RELAY relayable IP address 2225102528Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl 2226102528Sgshapirodnl this will cause rejections in cases like: 2227102528Sgshapirodnl Connect:My.Host.Domain RELAY 2228102528Sgshapirodnl Connect:My.Net REJECT 2229102528Sgshapirodnl since in check_relay client_name is checked before client_addr 2230102528SgshapiroR<REJECT> $* $@ REJECT rejected IP address') 223190792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 223264562SgshapiroR<$*> <$*> $: $2', `dnl') 223364562SgshapiroR$* $: [ $1 ] put brackets around it... 223490792SgshapiroR$=w $@ RELAY ... and see if it is local 223564562Sgshapiro 223664562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 223764562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 223864562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl 223964562Sgshapirodnl input: {client_addr} or something "broken" 224064562Sgshapirodnl just throw the input away; we do not need it. 224164562Sgshapiro# check whether FROM is allowed to use system as relay 224264562SgshapiroR$* $: <?> $>CanonAddr $&f 224390792SgshapiroR<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 224464562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl 224564562Sgshapiro# check whether local FROM is ok 224690792SgshapiroR<?> $+ < @ $=w > $@ RELAY FROM local', `dnl') 224764562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl 224894334SgshapiroR<?> $+ < @ $+ > $: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <> 224990792SgshapiroR<@> <RELAY> $@ RELAY RELAY FROM sender ok 225090792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 225190792Sgshapiro', `dnl 225290792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', 225390792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 225464562Sgshapiro')', 225564562Sgshapiro`dnl') 225664562Sgshapirodnl')', `dnl') 225790792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind. 225890792Sgshapirodnl it does not matter in this case because the following rule ignores 225990792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace. 226064562Sgshapiro 226164562Sgshapiro# check client name: first: did it resolve? 226264562Sgshapirodnl input: ignored 226364562SgshapiroR$* $: < $&{client_resolve} > 2264132943SgshapiroR<TEMP> $#TEMP $@ 4.4.0 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 226564562SgshapiroR<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 226664562SgshapiroR<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 226764562Sgshapirodnl ${client_resolve} should be OK, so go ahead 226890792SgshapiroR$* $: <@> $&{client_name} 226990792Sgshapirodnl should not be necessary since it has been done for client_addr already 2270110560Sgshapirodnl this rule actually may cause a problem if {client_name} resolves to "" 2271110560Sgshapirodnl however, this should not happen since the forward lookup should fail 2272110560Sgshapirodnl and {client_resolve} should be TEMP or FAIL. 2273110560Sgshapirodnl nevertheless, removing the rule doesn't hurt. 2274110560Sgshapirodnl R<@> $@ RELAY 227590792Sgshapirodnl workspace: <@> ${client_name} (not empty) 227638032Speter# pass to name server to make hostname canonical 227790792SgshapiroR<@> $* $=P $:<?> $1 $2 227890792SgshapiroR<@> $+ $:<?> $[ $1 $] 227990792Sgshapirodnl workspace: <?> ${client_name} (canonified) 228064562SgshapiroR$* . $1 strip trailing dots 228138032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 228290792SgshapiroR<?> $* $=m $@ RELAY', `dnl') 228390792SgshapiroR<?> $=w $@ RELAY 228438032Speterifdef(`_RELAY_HOSTS_ONLY_', 228590792Sgshapiro`R<?> $=R $@ RELAY 228664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 228764562SgshapiroR<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 228864562SgshapiroR<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 228990792Sgshapiro`R<?> $* $=R $@ RELAY 229064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 229190792SgshapiroR<?> $* $: $>D <$1> <?> <+ Connect> <$1>',`dnl')') 229264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 229390792SgshapiroR<RELAY> $* $@ RELAY 229490792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 229538032SpeterR<$*> <$*> $: $2',`dnl') 229690792Sgshapirodnl end of _PROMISCUOUS_RELAY_ 229764562Sgshapirodivert(0) 229864562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 229964562Sgshapiro# turn a canonical address in the form user<@domain> 230064562Sgshapiro# qualify unqual. addresses with $j 230164562Sgshapirodnl it might have been only user (without <@domain>) 230264562SgshapiroSFullAddr 230364562SgshapiroR$* <@ $+ . > $1 <@ $2 > 230464562SgshapiroR$* <@ $* > $@ $1 <@ $2 > 230564562SgshapiroR$+ $@ $1 <@ $j > 230638032Speter 2307120256SgshapiroSDelay_TLS_Clt 2308110560Sgshapiro# authenticated? 2309110560Sgshapirodnl code repeated here from Basic_check_mail 2310110560Sgshapirodnl only called from check_rcpt in delay mode if checkrcpt returns $# 2311110560SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 2312110560SgshapiroR$* $| $#$+ $#$2 2313110560Sgshapirodnl return result from checkrcpt 2314120256SgshapiroR$* $| $* $# $1 2315110560SgshapiroR$* $# $1 2316110560Sgshapiro 2317120256SgshapiroSDelay_TLS_Clt2 2318110560Sgshapiro# authenticated? 2319110560Sgshapirodnl code repeated here from Basic_check_mail 2320110560Sgshapirodnl only called from check_rcpt in delay mode if stopping due to Friend/Hater 2321110560SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 2322110560SgshapiroR$* $| $#$+ $#$2 2323110560Sgshapirodnl return result from friend/hater check 2324120256SgshapiroR$* $| $* $@ $1 2325110560SgshapiroR$* $@ $1 2326110560Sgshapiro 232764562Sgshapiro# call all necessary rulesets 232864562SgshapiroScheck_rcpt 232964562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset 233064562Sgshapirodnl which is the correct DSN code? 233164562Sgshapiro# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 2332110560Sgshapiro 233364562SgshapiroR$+ $: $1 $| $>checkrcpt $1 233464562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 2335110560Sgshapirodnl on error (or discard) stop now 2336110560SgshapiroR$+ $| $#error $* $#error $2 2337110560SgshapiroR$+ $| $#discard $* $#discard $2 2338110560Sgshapirodnl otherwise call tls_client; see above 2339120256SgshapiroR$+ $| $#$* $@ $>"Delay_TLS_Clt" $2 234064562SgshapiroR$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 234164562Sgshapiroifdef(`_SPAM_FH_', 234264562Sgshapiro`dnl lookup user@ and user@address 234364562Sgshapiroifdef(`_ACCESS_TABLE_', `', 234464562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 234564562Sgshapiro')')dnl 234664562Sgshapirodnl one of the next two rules is supposed to match 234764562Sgshapirodnl this code has been copied from BLACKLIST... etc 234864562Sgshapirodnl and simplified by omitting some < >. 234990792SgshapiroR<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@> 235090792SgshapiroR<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > 235164562Sgshapirodnl R<?> $@ something_is_very_wrong_here 235290792Sgshapiro# lookup the addresses only with Spam tag 235390792SgshapiroR<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <> 235464562SgshapiroR<@> $* $| $* $: $2 $1 reverse result 235564562Sgshapirodnl', `dnl') 235664562Sgshapiroifdef(`_SPAM_FRIEND_', 235764562Sgshapiro`# is the recipient a spam friend? 235864562Sgshapiroifdef(`_SPAM_HATER_', 2359110560Sgshapiro `errprint(`*** ERROR: define either Hater or Friend -- not both. 236064562Sgshapiro')', `dnl') 2361120256SgshapiroR<FRIEND> $+ $@ $>"Delay_TLS_Clt2" SPAMFRIEND 236264562SgshapiroR<$*> $+ $: $2', 236364562Sgshapiro`dnl') 236464562Sgshapiroifdef(`_SPAM_HATER_', 236564562Sgshapiro`# is the recipient no spam hater? 236690792SgshapiroR<HATER> $+ $: $1 spam hater: continue checks 2367120256SgshapiroR<$*> $+ $@ $>"Delay_TLS_Clt2" NOSPAMHATER everyone else: stop 236864562Sgshapirodnl',`dnl') 2369168515Sgshapiro 237064562Sgshapirodnl run further checks: check_mail 237164562Sgshapirodnl should we "clean up" $&f? 237290792Sgshapiroifdef(`_FFR_MAIL_MACRO', 237390792Sgshapiro`R$* $: $1 $| $>checkmail $&{mail_from}', 237490792Sgshapiro`R$* $: $1 $| $>checkmail <$&f>') 237594334Sgshapirodnl recipient (canonical format) $| result of checkmail 237664562SgshapiroR$* $| $#$* $#$2 237764562Sgshapirodnl run further checks: check_relay 237894334SgshapiroR$* $| $* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 237964562SgshapiroR$* $| $#$* $#$2 238038032SpeterR$* $| $* $: $1 238138032Speter', `dnl') 238290792Sgshapiro 2383168515Sgshapiroifdef(`_BLOCK_BAD_HELO_', `dnl 2384168515SgshapiroR$* $: $1 $| <$&{auth_authen}> Get auth info 2385168515Sgshapirodnl Bypass the test for users who have authenticated. 2386168515SgshapiroR$* $| <$+> $: $1 skip if auth 2387168515SgshapiroR$* $| <$*> $: $1 $| <$&{client_addr}> [$&s] Get connection info 2388168515Sgshapirodnl Bypass for local clients -- IP address starts with $=R 2389168515SgshapiroR$* $| <$=R $*> [$*] $: $1 skip if local client 2390168515Sgshapirodnl Bypass a "sendmail -bs" session, which use 0 for client ip address 2391168515SgshapiroR$* $| <0> [$*] $: $1 skip if sendmail -bs 2392168515Sgshapirodnl Reject our IP - assumes "[ip]" is in class $=w 2393168515SgshapiroR$* $| <$*> $=w $#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s 2394168515Sgshapirodnl Reject our hostname 2395168515SgshapiroR$* $| <$*> [$=w] $#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s 2396168515Sgshapirodnl Pass anything else with a "." in the domain parameter 2397168515SgshapiroR$* $| <$*> [$+.$+] $: $1 qualified domain ok 2398261194Sgshapirodnl Pass IPv6: address literals 2399261194SgshapiroR$* $| <$*> [IPv6:$+] $: $1 qualified domain ok 2400168515Sgshapirodnl Reject if there was no "." or only an initial or final "." 2401168515SgshapiroR$* $| <$*> [$*] $#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s 2402168515Sgshapirodnl Clean up the workspace 2403168515SgshapiroR$* $| $* $: $1 2404168515Sgshapiro', `dnl') 2405168515Sgshapiro 240690792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 240764562Sgshapiro###################################################################### 240890792Sgshapiro### F: LookUpFull -- search for an entry in access database 240990792Sgshapiro### 241090792Sgshapiro### lookup of full key (which should be an address) and 241190792Sgshapiro### variations if +detail exists: +* and without +detail 241290792Sgshapiro### 241390792Sgshapiro### Parameters: 241490792Sgshapiro### <$1> -- key 241590792Sgshapiro### <$2> -- default (what to return if not found in db) 241690792Sgshapirodnl must not be empty 241790792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 241890792Sgshapiro### ! does lookup only with tag 241990792Sgshapiro### + does lookup with and without tag 242090792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 242190792Sgshapirodnl returns: <default> <passthru> 242290792Sgshapirodnl <result> <passthru> 242390792Sgshapiro###################################################################### 242490792Sgshapiro 242590792SgshapiroSF 242690792Sgshapirodnl workspace: <key> <def> <o tag> <thru> 242790792Sgshapirodnl full lookup 242890792Sgshapirodnl 2 3 4 5 242990792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 243090792Sgshapirodnl no match, try without tag 243190792Sgshapirodnl 1 2 3 4 243290792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 243390792Sgshapirodnl no match, +detail: try +* 243490792Sgshapirodnl 1 2 3 4 5 6 7 243590792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 243690792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 243790792Sgshapirodnl no match, +detail: try +* without tag 243890792Sgshapirodnl 1 2 3 4 5 6 243990792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 244090792Sgshapiro $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 244190792Sgshapirodnl no match, +detail: try without +detail 244290792Sgshapirodnl 1 2 3 4 5 6 7 244390792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 244490792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 244590792Sgshapirodnl no match, +detail: try without +detail and without tag 244690792Sgshapirodnl 1 2 3 4 5 6 244790792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 244890792Sgshapiro $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 244990792Sgshapirodnl no match, return <default> <passthru> 245090792Sgshapirodnl 1 2 3 4 5 245190792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 245290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 245390792Sgshapirodnl 2 3 4 5 245490792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 245590792Sgshapirodnl match, return <match> <passthru> 245690792Sgshapirodnl 2 3 4 5 245790792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 245890792Sgshapiro 245990792Sgshapiro###################################################################### 246090792Sgshapiro### E: LookUpExact -- search for an entry in access database 246190792Sgshapiro### 246290792Sgshapiro### Parameters: 246390792Sgshapiro### <$1> -- key 246490792Sgshapiro### <$2> -- default (what to return if not found in db) 246590792Sgshapirodnl must not be empty 246690792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 246790792Sgshapiro### ! does lookup only with tag 246890792Sgshapiro### + does lookup with and without tag 246990792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 247090792Sgshapirodnl returns: <default> <passthru> 247190792Sgshapirodnl <result> <passthru> 247290792Sgshapiro###################################################################### 247390792Sgshapiro 247490792SgshapiroSE 247590792Sgshapirodnl 2 3 4 5 247690792SgshapiroR<$*> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 247790792Sgshapirodnl no match, try without tag 247890792Sgshapirodnl 1 2 3 4 247990792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 248090792Sgshapirodnl no match, return default passthru 248190792Sgshapirodnl 1 2 3 4 5 248290792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 248390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 248490792Sgshapirodnl 2 3 4 5 248590792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 248690792Sgshapirodnl match, return <match> <passthru> 248790792Sgshapirodnl 2 3 4 5 248890792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 248990792Sgshapiro 249090792Sgshapiro###################################################################### 249190792Sgshapiro### U: LookUpUser -- search for an entry in access database 249290792Sgshapiro### 249390792Sgshapiro### lookup of key (which should be a local part) and 249490792Sgshapiro### variations if +detail exists: +* and without +detail 249590792Sgshapiro### 249690792Sgshapiro### Parameters: 249790792Sgshapiro### <$1> -- key (user@) 249890792Sgshapiro### <$2> -- default (what to return if not found in db) 249990792Sgshapirodnl must not be empty 250090792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 250190792Sgshapiro### ! does lookup only with tag 250290792Sgshapiro### + does lookup with and without tag 250390792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 250490792Sgshapirodnl returns: <default> <passthru> 250590792Sgshapirodnl <result> <passthru> 250690792Sgshapiro###################################################################### 250790792Sgshapiro 250890792SgshapiroSU 250990792Sgshapirodnl user lookups are always with trailing @ 251090792Sgshapirodnl 2 3 4 5 251190792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 251290792Sgshapirodnl no match, try without tag 251390792Sgshapirodnl 1 2 3 4 251490792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 251590792Sgshapirodnl do not remove the @ from the lookup: 251690792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup 251790792Sgshapirodnl no match, +detail: try +* 251890792Sgshapirodnl 1 2 3 4 5 6 251990792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 252090792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 252190792Sgshapirodnl no match, +detail: try +* without tag 252290792Sgshapirodnl 1 2 3 4 5 252390792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 252490792Sgshapiro $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 252590792Sgshapirodnl no match, +detail: try without +detail 252690792Sgshapirodnl 1 2 3 4 5 6 252790792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 252890792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 252990792Sgshapirodnl no match, +detail: try without +detail and without tag 253090792Sgshapirodnl 1 2 3 4 5 253190792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 253290792Sgshapiro $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 253390792Sgshapirodnl no match, return <default> <passthru> 253490792Sgshapirodnl 1 2 3 4 5 253590792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 253690792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 253790792Sgshapirodnl 2 3 4 5 253890792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 253990792Sgshapirodnl match, return <match> <passthru> 254090792Sgshapirodnl 2 3 4 5 254190792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 254290792Sgshapiro 254390792Sgshapiro###################################################################### 254464562Sgshapiro### SearchList: search a list of items in the access map 254564562Sgshapiro### Parameters: 254664562Sgshapiro### <exact tag> $| <mark:address> <mark:address> ... <> 254764562Sgshapirodnl maybe we should have a @ (again) in front of the mark to 254864562Sgshapirodnl avoid errorneous matches (with error messages?) 254964562Sgshapirodnl if we can make sure that tag is always a single token 255064562Sgshapirodnl then we can omit the delimiter $|, otherwise we need it 255190792Sgshapirodnl to avoid errorneous matchs (first rule: D: if there 255264562Sgshapirodnl is that mark somewhere in the list, it will be taken). 255364562Sgshapirodnl moreover, we can do some tricks to enforce lookup with 255464562Sgshapirodnl the tag only, e.g.: 255564562Sgshapiro### where "exact" is either "+" or "!": 255664562Sgshapiro### <+ TAG> lookup with and w/o tag 255764562Sgshapiro### <! TAG> lookup with tag 255864562Sgshapirodnl Warning: + and ! should be in OperatorChars (otherwise there must be 255964562Sgshapirodnl a blank between them and the tag. 256064562Sgshapiro### possible values for "mark" are: 256190792Sgshapiro### D: recursive host lookup (LookUpDomain) 256264562Sgshapirodnl A: recursive address lookup (LookUpAddress) [not yet required] 256364562Sgshapiro### E: exact lookup, no modifications 256464562Sgshapiro### F: full lookup, try user+ext@domain and user@domain 256564562Sgshapiro### U: user lookup, try user+ext and user (input must have trailing @) 256664562Sgshapiro### return: <RHS of lookup> or <?> (not found) 256764562Sgshapiro###################################################################### 256838032Speter 256964562Sgshapiro# class with valid marks for SearchList 257064562Sgshapirodnl if A is activated: add it 2571132943SgshapiroC{Src}E F D U ifdef(`_FFR_SRCHLIST_A', `A') 257264562SgshapiroSSearchList 257390792Sgshapiro# just call the ruleset with the name of the tag... nice trick... 257490792Sgshapirodnl 2 3 4 2575132943SgshapiroR<$+> $| <$={Src}:$*> <$*> $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <> 257690792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <> 257790792Sgshapirodnl no match and nothing left: return 257890792SgshapiroR<$+> $| <> $| <?> <> $@ <?> 257990792Sgshapirodnl no match but something left: continue 258090792SgshapiroR<$+> $| <$+> $| <?> <> $@ $>SearchList <$1> $| <$2> 258190792Sgshapirodnl match: return 258290792SgshapiroR<$+> $| <$*> $| <$+> <> $@ <$3> 258364562Sgshapirodnl return result from recursive invocation 258490792SgshapiroR<$+> $| <$+> $@ <$2> 258590792Sgshapirodnl endif _ACCESS_TABLE_ 258690792Sgshapirodivert(0) 258738032Speter 258890792Sgshapiro###################################################################### 258990792Sgshapiro### trust_auth: is user trusted to authenticate as someone else? 259090792Sgshapiro### 259190792Sgshapiro### Parameters: 259290792Sgshapiro### $1: AUTH= parameter from MAIL command 259390792Sgshapiro###################################################################### 259490792Sgshapiro 259590792Sgshapirodnl empty ruleset definition so it can be called 259690792SgshapiroSLocal_trust_auth 259764562SgshapiroStrust_auth 259864562SgshapiroR$* $: $&{auth_type} $| $1 259964562Sgshapiro# required by RFC 2554 section 4. 260064562SgshapiroR$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 260164562Sgshapirodnl seems to be useful... 260264562SgshapiroR$* $| $&{auth_authen} $@ identical 260364562SgshapiroR$* $| <$&{auth_authen}> $@ identical 260464562Sgshapirodnl call user supplied code 2605120256SgshapiroR$* $| $* $: $1 $| $>"Local_trust_auth" $2 260664562SgshapiroR$* $| $#$* $#$2 260764562Sgshapirodnl default: error 260864562SgshapiroR$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 260964562Sgshapiro 261090792Sgshapiro###################################################################### 261190792Sgshapiro### Relay_Auth: allow relaying based on authentication? 261290792Sgshapiro### 261390792Sgshapiro### Parameters: 261490792Sgshapiro### $1: ${auth_type} 261590792Sgshapiro###################################################################### 261690792SgshapiroSLocal_Relay_Auth 261764562Sgshapiro 261890792Sgshapiro###################################################################### 261990792Sgshapiro### srv_features: which features to offer to a client? 262090792Sgshapiro### (done in server) 262190792Sgshapiro###################################################################### 262290792SgshapiroSsrv_features 262390792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl 262490792SgshapiroR$* $: $1 $| $>"Local_srv_features" $1 262590792SgshapiroR$* $| $#$* $#$2 262690792SgshapiroR$* $| $* $: $1', `dnl') 2627132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 262890792SgshapiroR$* $: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <> 262990792SgshapiroR<?>$* $: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <> 263090792SgshapiroR<?>$* $: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)> 263164562SgshapiroR<?>$* $@ OK 263290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 263390792SgshapiroR<$* _ATMPF_>$* $#temp', `dnl') 2634132943SgshapiroR<$+>$* $# $1') 263564562Sgshapiro 263690792Sgshapiro###################################################################### 263790792Sgshapiro### try_tls: try to use STARTTLS? 263890792Sgshapiro### (done in client) 263990792Sgshapiro###################################################################### 264064562SgshapiroStry_tls 264190792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl 264290792SgshapiroR$* $: $1 $| $>"Local_try_tls" $1 264390792SgshapiroR$* $| $#$* $#$2 264490792SgshapiroR$* $| $* $: $1', `dnl') 2645132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 264690792SgshapiroR$* $: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <> 264790792SgshapiroR<?>$* $: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <> 264890792SgshapiroR<?>$* $: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)> 264964562SgshapiroR<?>$* $@ OK 265090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 265190792SgshapiroR<$* _ATMPF_>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2652132943SgshapiroR<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"') 2653132943Sgshapiro 265490792Sgshapiro###################################################################### 265590792Sgshapiro### tls_rcpt: is connection with server "good" enough? 265690792Sgshapiro### (done in client, per recipient) 265790792Sgshapirodnl called from deliver() before RCPT command 265890792Sgshapiro### 265990792Sgshapiro### Parameters: 266090792Sgshapiro### $1: recipient 266190792Sgshapiro###################################################################### 266290792SgshapiroStls_rcpt 266390792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl 266490792SgshapiroR$* $: $1 $| $>"Local_tls_rcpt" $1 266590792SgshapiroR$* $| $#$* $#$2 266690792SgshapiroR$* $| $* $: $1', `dnl') 2667132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 266890792Sgshapirodnl store name of other side 266990792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 267090792Sgshapirodnl canonify recipient address 267190792SgshapiroR$+ $: <?> $>CanonAddr $1 267290792Sgshapirodnl strip trailing dots 267390792SgshapiroR<?> $+ < @ $+ . > <?> $1 <@ $2 > 267490792Sgshapirodnl full address? 267590792SgshapiroR<?> $+ < @ $+ > $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:> 267690792Sgshapirodnl only localpart? 267790792SgshapiroR<?> $+ $: $1 $| <U:$1@> <E:> 267890792Sgshapirodnl look it up 267990792Sgshapirodnl also look up a default value via E: 268090792SgshapiroR$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <> 268190792Sgshapirodnl found nothing: stop here 268290792SgshapiroR$* $| <?> $@ OK 268390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 268490792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 268590792Sgshapirodnl use the generic routine (for now) 268690792SgshapiroR$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>') 268764562Sgshapiro 268890792Sgshapiro###################################################################### 268990792Sgshapiro### tls_client: is connection with client "good" enough? 269090792Sgshapiro### (done in server) 269190792Sgshapiro### 269290792Sgshapiro### Parameters: 269390792Sgshapiro### ${verify} $| (MAIL|STARTTLS) 269490792Sgshapiro###################################################################### 269564562Sgshapirodnl MAIL: called from check_mail 269664562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted 269764562SgshapiroStls_client 269890792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl 2699182352SgshapiroR$* $: $1 <?> $>"Local_tls_client" $1 2700182352SgshapiroR$* <?> $#$* $#$2 2701182352SgshapiroR$* <?> $* $: $1', `dnl') 270264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 270390792Sgshapirodnl store name of other side 2704203004SgshapiroR$* $: $(macro {TLS_Name} $@ $&{client_name} $) $1 270564562Sgshapirodnl ignore second arg for now 270664562Sgshapirodnl maybe use it to distinguish permanent/temporary error? 270764562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered) 270864562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed) 270990792SgshapiroR$* $| $* $: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <> 271090792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <> 271164562Sgshapirodnl do a default lookup: just TLS_CLT_TAG 271264562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 271390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 271490792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 271590792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 271690792SgshapiroR$* $| $* $@ $>"TLS_connection" $1') 271764562Sgshapiro 271890792Sgshapiro###################################################################### 271990792Sgshapiro### tls_server: is connection with server "good" enough? 272090792Sgshapiro### (done in client) 272190792Sgshapiro### 272290792Sgshapiro### Parameter: 272390792Sgshapiro### ${verify} 272490792Sgshapiro###################################################################### 272564562Sgshapirodnl i.e. has the server been authenticated and is encryption active? 272664562Sgshapirodnl called from deliver() after STARTTLS command 272764562SgshapiroStls_server 272890792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl 272990792SgshapiroR$* $: $1 $| $>"Local_tls_server" $1 273090792SgshapiroR$* $| $#$* $#$2 273190792SgshapiroR$* $| $* $: $1', `dnl') 273264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 273390792Sgshapirodnl store name of other side 273490792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 273590792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <> 273690792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <> 273764562Sgshapirodnl do a default lookup: just TLS_SRV_TAG 273864562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 273990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 274090792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 274190792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 274290792SgshapiroR$* $@ $>"TLS_connection" $1') 274364562Sgshapiro 274490792Sgshapiro###################################################################### 274590792Sgshapiro### TLS_connection: is TLS connection "good" enough? 274690792Sgshapiro### 274790792Sgshapiro### Parameters: 274864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 274990792Sgshapiro### ${verify} $| <Requirement> [<>]', `dnl 275090792Sgshapiro### ${verify}') 275190792Sgshapiro### Requirement: RHS from access map, may be ? for none. 275290792Sgshapirodnl syntax for Requirement: 275390792Sgshapirodnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions] 275490792Sgshapirodnl extensions: could be a list of further requirements 275590792Sgshapirodnl for now: CN:string {cn_subject} == string 275690792Sgshapiro###################################################################### 275790792SgshapiroSTLS_connection 275890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error 275990792Sgshapirodnl deal with TLS handshake failures: abort 276090792SgshapiroRSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake." 276190792Sgshapirodivert(-1)') 276264562Sgshapirodnl common ruleset for tls_{client|server} 276390792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>] 276464562Sgshapirodnl remove optional <> 276564562SgshapiroR$* $| <$*>$* $: $1 $| <$2> 276690792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup> 276790792Sgshapiro# create the appropriate error codes 276864562Sgshapirodnl permanent or temporary error? 2769132943SgshapiroR$* $| <PERM + $={Tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 2770132943SgshapiroR$* $| <TEMP + $={Tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 277164562Sgshapirodnl default case depends on TLS_PERM_ERR 2772132943SgshapiroR$* $| <$={Tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 277390792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup> 277490792Sgshapiro# deal with TLS handshake failures: abort 277564562SgshapiroRSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 277664562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 277764562Sgshapirodnl use default error 277864562SgshapiroRSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 2779157001Sgshapiro# deal with TLS protocol errors: abort 2780157001SgshapiroRPROTOCOL $| <$-:$+> $* $#error $@ $2 $: $1 " STARTTLS failed." 2781157001Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 2782157001Sgshapirodnl use default error 2783157001SgshapiroRPROTOCOL $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') STARTTLS failed." 278490792SgshapiroR$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1 278590792Sgshapirodnl separate optional requirements 278690792SgshapiroR$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1 2787132943SgshapiroR$* $| <$*> <$={Tls}:$->$* $: <$2> <$3:$4> <> $1 278890792Sgshapirodnl separate optional requirements 2789132943SgshapiroR$* $| <$*> <$={Tls}:$- + $+>$* $: <$2> <$3:$4> <$5> $1 279064562Sgshapirodnl some other value in access map: accept 279164562Sgshapirodnl this also allows to override the default case (if used) 279264562SgshapiroR$* $| $* $@ OK 279364562Sgshapiro# authentication required: give appropriate error 279464562Sgshapiro# other side did authenticate (via STARTTLS) 279590792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify} 279664562Sgshapirodnl only verification required and it succeeded 279790792SgshapiroR<$*><VERIFY> <> OK $@ OK 279890792Sgshapirodnl verification required and it succeeded but extensions are given 279990792Sgshapirodnl change it to <SMTP:ESC> <REQ:0> <extensions> 280090792SgshapiroR<$*><VERIFY> <$+> OK $: <$1> <REQ:0> <$2> 280164562Sgshapirodnl verification required + some level of encryption 280290792SgshapiroR<$*><VERIFY:$-> <$*> OK $: <$1> <REQ:$2> <$3> 280364562Sgshapirodnl just some level of encryption required 280490792SgshapiroR<$*><ENCR:$-> <$*> $* $: <$1> <REQ:$2> <$3> 280590792Sgshapirodnl workspace: 280690792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]> <[extensions]> {verify} (!= OK) 280790792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits> <[extensions]> 280890792Sgshapirodnl verification required but ${verify} is not set (case 1.) 280990792SgshapiroR<$-:$+><VERIFY $*> <$*> $#error $@ $2 $: $1 " authentication required" 281090792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL $#error $@ $2 $: $1 " authentication failed" 281190792SgshapiroR<$-:$+><VERIFY $*> <$*> NO $#error $@ $2 $: $1 " not authenticated" 281290792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT $#error $@ $2 $: $1 " no authentication requested" 281390792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 281464562Sgshapirodnl some other value for ${verify} 281590792SgshapiroR<$-:$+><VERIFY $*> <$*> $+ $#error $@ $2 $: $1 " authentication failure " $4 281690792Sgshapirodnl some level of encryption required: get the maximum level (case 2.) 281790792SgshapiroR<$*><REQ:$-> <$*> $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf} 281864562Sgshapirodnl compare required bits with actual bits 281990792SgshapiroR<$*><REQ:$-> <$*> $- $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $) 282090792SgshapiroR<$-:$+><$-:$-> <$*> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 282190792Sgshapirodnl strength requirements fulfilled 282290792Sgshapirodnl TLS Additional Requirements Separator 282390792Sgshapirodnl this should be something which does not appear in the extensions itself 282490792Sgshapirodnl @ could be part of a CN, DN, etc... 282590792Sgshapirodnl use < > ? those are encoded in CN, DN, ... 282690792Sgshapirodefine(`_TLS_ARS_', `++')dnl 282790792Sgshapirodnl workspace: 282890792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare 282990792SgshapiroR<$-:$+><$-:$-> <$*> $* $: <$1:$2 _TLS_ARS_ $5> 283090792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions> 283190792Sgshapirodnl continue: check extensions 283290792SgshapiroR<$-:$+ _TLS_ARS_ > $@ OK 283390792Sgshapirodnl split extensions into own list 283490792SgshapiroR<$-:$+ _TLS_ARS_ $+ > $: <$1:$2> <$3> 283590792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ > <$1:$2> <$3> <$4> 283690792SgshapiroR<$-:$+> $+ $@ $>"TLS_req" $3 $| <$1:$2> 283764562Sgshapiro 283890792Sgshapiro###################################################################### 283990792Sgshapiro### TLS_req: check additional TLS requirements 284090792Sgshapiro### 284190792Sgshapiro### Parameters: [<list> <of> <req>] $| <$-:$+> 284290792Sgshapiro### $-: SMTP reply code 284390792Sgshapiro### $+: Enhanced Status Code 284490792Sgshapirodnl further requirements for this ruleset: 284590792Sgshapirodnl name of "other side" is stored is {TLS_name} (client/server_name) 284690792Sgshapirodnl 284790792Sgshapirodnl currently only CN[:common_name] is implemented 284890792Sgshapirodnl right now this is only a logical AND 284990792Sgshapirodnl i.e. all requirements must be true 285090792Sgshapirodnl how about an OR? CN must be X or CN must be Y or .. 285190792Sgshapirodnl use a macro to compute this as a trivial sequential 285290792Sgshapirodnl operations (no precedences etc)? 285390792Sgshapiro###################################################################### 285490792SgshapiroSTLS_req 285590792Sgshapirodnl no additional requirements: ok 285690792SgshapiroR $| $+ $@ OK 285790792Sgshapirodnl require CN: but no CN specified: use name of other side 285890792SgshapiroR<CN> $* $| <$+> $: <CN:$&{TLS_Name}> $1 $| <$2> 285990792Sgshapirodnl match, check rest 286090792SgshapiroR<CN:$&{cn_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 286190792Sgshapirodnl CN does not match 286290792Sgshapirodnl 1 2 3 4 286390792SgshapiroR<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1 286490792Sgshapirodnl cert subject 286590792SgshapiroR<CS:$&{cert_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 286690792Sgshapirodnl CS does not match 286790792Sgshapirodnl 1 2 3 4 2868110560SgshapiroR<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1 286990792Sgshapirodnl match, check rest 287090792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 287190792Sgshapirodnl CI does not match 287290792Sgshapirodnl 1 2 3 4 2873110560SgshapiroR<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1 287490792Sgshapirodnl return from recursive call 287590792SgshapiroROK $@ OK 287690792Sgshapiro 287790792Sgshapiro###################################################################### 287890792Sgshapiro### max: return the maximum of two values separated by : 287990792Sgshapiro### 288090792Sgshapiro### Parameters: [$-]:[$-] 288190792Sgshapiro###################################################################### 288264562SgshapiroSmax 288364562SgshapiroR: $: 0 288464562SgshapiroR:$- $: $1 288564562SgshapiroR$-: $: $1 288664562SgshapiroR$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 288764562SgshapiroRTRUE:$-:$- $: $2 288890792SgshapiroR$-:$-:$- $: $2 288990792Sgshapirodnl endif _ACCESS_TABLE_ 289090792Sgshapirodivert(0) 289164562Sgshapiro 289290792Sgshapiro###################################################################### 289390792Sgshapiro### RelayTLS: allow relaying based on TLS authentication 289490792Sgshapiro### 289590792Sgshapiro### Parameters: 289690792Sgshapiro### none 289790792Sgshapiro###################################################################### 289890792SgshapiroSRelayTLS 289964562Sgshapiro# authenticated? 290064562Sgshapirodnl we do not allow relaying for anyone who can present a cert 290164562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns 2902110560Sgshapirodnl CA in CertPath so we can authenticate users, we do not allow 290364562Sgshapirodnl them to abuse our server (they might be easier to get hold of, 290464562Sgshapirodnl but anyway). 290564562Sgshapirodnl so here is the trick: if the verification succeeded 290664562Sgshapirodnl we look up the cert issuer in the access map 290764562Sgshapirodnl (maybe after extracting a part with a regular expression) 290864562Sgshapirodnl if this returns RELAY we relay without further questions 290964562Sgshapirodnl if it returns SUBJECT we perform a similar check on the 291064562Sgshapirodnl cert subject. 291164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 291290792SgshapiroR$* $: <?> $&{verify} 291390792SgshapiroR<?> OK $: OK authenticated: continue 291490792SgshapiroR<?> $* $@ NO not authenticated 291564562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 291690792SgshapiroR$* $: $(CERTIssuer $&{cert_issuer} $)', 291790792Sgshapiro`R$* $: $&{cert_issuer}') 291890792SgshapiroR$+ $: $(access CERTISSUER`'_TAG_DELIM_`'$1 $) 291964562Sgshapirodnl use $# to stop further checks (delay_check) 292090792SgshapiroRRELAY $# RELAY 292164562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 292290792SgshapiroRSUBJECT $: <@> $(CERTSubject $&{cert_subject} $)', 292390792Sgshapiro`RSUBJECT $: <@> $&{cert_subject}') 292490792SgshapiroR<@> $+ $: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $) 292590792SgshapiroR<@> RELAY $# RELAY 292690792SgshapiroR$* $: NO', `dnl') 292764562Sgshapiro 292890792Sgshapiro###################################################################### 292990792Sgshapiro### authinfo: lookup authinfo in the access map 293090792Sgshapiro### 293190792Sgshapiro### Parameters: 293290792Sgshapiro### $1: {server_name} 293390792Sgshapiro### $2: {server_addr} 293490792Sgshapirodnl both are currently ignored 293590792Sgshapirodnl if it should be done via another map, we either need to restrict 293690792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another 293790792Sgshapirodnl parameter which I want to avoid, it's quite complex already) 293890792Sgshapiro###################################################################### 293990792Sgshapirodnl omit this ruleset if neither is defined? 294090792Sgshapirodnl it causes DefaultAuthInfo to be ignored 294190792Sgshapirodnl (which may be considered a good thing). 294290792SgshapiroSauthinfo 294390792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl 294490792SgshapiroR$* $: <$(authinfo AuthInfo:$&{server_name} $: ? $)> 294590792SgshapiroR<?> $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)> 294690792SgshapiroR<?> $: <$(authinfo AuthInfo: $: ? $)> 294790792SgshapiroR<?> $@ no no authinfo available 294890792SgshapiroR<$*> $# $1 294990792Sgshapirodnl', `dnl 295090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 295190792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <> 295290792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <> 295390792SgshapiroR$* $| <?>$* $: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <> 295490792SgshapiroR$* $| <?>$* $@ no no authinfo available 295590792SgshapiroR$* $| <$*> <> $# $2 295690792Sgshapirodnl', `dnl')') 295790792Sgshapiro 2958132943Sgshapiroifdef(`_RATE_CONTROL_',`dnl 2959132943Sgshapiro###################################################################### 2960132943Sgshapiro### RateControl: 2961132943Sgshapiro### Parameters: ignored 2962132943Sgshapiro### return: $#error or OK 2963132943Sgshapiro###################################################################### 2964132943SgshapiroSRateControl 2965132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 2966132943SgshapiroR$* $: <A:$&{client_addr}> <E:> 2967132943Sgshapirodnl also look up a default value via E: 2968132943SgshapiroR$+ $: $>SearchList <! ClientRate> $| $1 <> 2969132943Sgshapirodnl found nothing: stop here 2970132943SgshapiroR<?> $@ OK 2971132943Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 2972132943SgshapiroR<$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2973132943Sgshapirodnl use the generic routine (for now) 2974132943SgshapiroR<0> $@ OK no limit 2975173340SgshapiroR<$+> $: <$1> $| $(arith l $@ $1 $@ $&{client_rate} $) 2976132943Sgshapirodnl log this? Connection rate $&{client_rate} exceeds limit $1. 2977173340SgshapiroR<$+> $| TRUE $#error $@ 4.3.2 $: _RATE_CONTROL_REPLY Connection rate limit exceeded. 2978132943Sgshapiro')') 2979132943Sgshapiro 2980132943Sgshapiroifdef(`_CONN_CONTROL_',`dnl 2981132943Sgshapiro###################################################################### 2982132943Sgshapiro### ConnControl: 2983132943Sgshapiro### Parameters: ignored 2984132943Sgshapiro### return: $#error or OK 2985132943Sgshapiro###################################################################### 2986132943SgshapiroSConnControl 2987132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 2988132943SgshapiroR$* $: <A:$&{client_addr}> <E:> 2989132943Sgshapirodnl also look up a default value via E: 2990132943SgshapiroR$+ $: $>SearchList <! ClientConn> $| $1 <> 2991132943Sgshapirodnl found nothing: stop here 2992132943SgshapiroR<?> $@ OK 2993132943Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 2994132943SgshapiroR<$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2995132943Sgshapirodnl use the generic routine (for now) 2996132943SgshapiroR<0> $@ OK no limit 2997173340SgshapiroR<$+> $: <$1> $| $(arith l $@ $1 $@ $&{client_connections} $) 2998132943Sgshapirodnl log this: Open connections $&{client_connections} exceeds limit $1. 2999173340SgshapiroR<$+> $| TRUE $#error $@ 4.3.2 $: _CONN_CONTROL_REPLY Too many open connections. 3000132943Sgshapiro')') 3001132943Sgshapiro 300264562Sgshapiroundivert(9)dnl LOCAL_RULESETS 300338032Speter# 300438032Speter###################################################################### 300538032Speter###################################################################### 300638032Speter##### 300764562Sgshapiro`##### MAIL FILTER DEFINITIONS' 300864562Sgshapiro##### 300964562Sgshapiro###################################################################### 301064562Sgshapiro###################################################################### 301190792Sgshapiro_MAIL_FILTERS_ 301264562Sgshapiro# 301364562Sgshapiro###################################################################### 301464562Sgshapiro###################################################################### 301564562Sgshapiro##### 301638032Speter`##### MAILER DEFINITIONS' 301738032Speter##### 301838032Speter###################################################################### 301938032Speter###################################################################### 302064562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS 302166494Sgshapiro 3022