proto.m4 revision 182352
138032Speterdivert(-1) 238032Speter# 3168515Sgshapiro# Copyright (c) 1998-2007 Sendmail, Inc. and its suppliers. 464562Sgshapiro# All rights reserved. 538032Speter# Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. 638032Speter# Copyright (c) 1988, 1993 738032Speter# The Regents of the University of California. All rights reserved. 838032Speter# 938032Speter# By using this file, you agree to the terms and conditions set 1038032Speter# forth in the LICENSE file which can be found at the top level of 1138032Speter# the sendmail distribution. 1238032Speter# 1338032Speter# 1438032Speterdivert(0) 1538032Speter 16182352SgshapiroVERSIONID(`$Id: proto.m4,v 8.734 2008/01/24 23:42:01 ca Exp $') 1738032Speter 1864562Sgshapiro# level CF_LEVEL config file format 1964562SgshapiroV`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley') 2038032Speterdivert(-1) 2138032Speter 2290792Sgshapirodnl if MAILER(`local') not defined: do it ourself; be nice 2390792Sgshapirodnl maybe we should issue a warning? 2490792Sgshapiroifdef(`_MAILER_local_',`', `MAILER(local)') 2590792Sgshapiro 2638032Speter# do some sanity checking 2738032Speterifdef(`__OSTYPE__',, 2864562Sgshapiro `errprint(`*** ERROR: No system type defined (use OSTYPE macro) 2964562Sgshapiro')') 3038032Speter 3138032Speter# pick our default mailers 3238032Speterifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')') 3338032Speterifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')') 3438032Speterifdef(`confRELAY_MAILER',, 3538032Speter `define(`confRELAY_MAILER', 3638032Speter `ifdef(`_MAILER_smtp_', `relay', 3738032Speter `ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')') 3838032Speterifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')') 3938032Speterdefine(`_SMTP_', `confSMTP_MAILER')dnl for readability only 4038032Speterdefine(`_LOCAL_', `confLOCAL_MAILER')dnl for readability only 4138032Speterdefine(`_RELAY_', `confRELAY_MAILER')dnl for readability only 4238032Speterdefine(`_UUCP_', `confUUCP_MAILER')dnl for readability only 4338032Speter 4438032Speter# back compatibility with old config files 4538032Speterifdef(`confDEF_GROUP_ID', 4664562Sgshapiro`errprint(`*** confDEF_GROUP_ID is obsolete. 4764562Sgshapiro Use confDEF_USER_ID with a colon in the value instead. 4864562Sgshapiro')') 4938032Speterifdef(`confREAD_TIMEOUT', 5064562Sgshapiro`errprint(`*** confREAD_TIMEOUT is obsolete. 5164562Sgshapiro Use individual confTO_<timeout> parameters instead. 5264562Sgshapiro')') 5338032Speterifdef(`confMESSAGE_TIMEOUT', 5438032Speter `define(`_ARG_', index(confMESSAGE_TIMEOUT, /)) 5538032Speter ifelse(_ARG_, -1, 5638032Speter `define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)', 5738032Speter `define(`confTO_QUEUERETURN', 5838032Speter substr(confMESSAGE_TIMEOUT, 0, _ARG_)) 5938032Speter define(`confTO_QUEUEWARN', 6038032Speter substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')') 6138032Speterifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,, 6264562Sgshapiro`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete. 6364562Sgshapiro Use confMAX_MESSAGE_SIZE for the second part of the value. 6464562Sgshapiro')')') 6538032Speter 6664562Sgshapiro 6764562Sgshapiro# Sanity check on ldap_routing feature 6864562Sgshapiro# If the user doesn't specify a new map, they better have given as a 6964562Sgshapiro# default LDAP specification which has the LDAP base (and most likely the host) 7064562Sgshapiroifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(` 7164562SgshapiroWARNING: Using default FEATURE(ldap_routing) map definition(s) 7264562Sgshapirowithout setting confLDAP_DEFAULT_SPEC option. 7364562Sgshapiro')')')dnl 7464562Sgshapiro 7538032Speter# clean option definitions below.... 7664562Sgshapirodefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl 7738032Speter 7864562Sgshapirodnl required to "rename" the check_* rulesets... 7964562Sgshapirodefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_')) 8064562Sgshapirodnl default relaying denied message 8190792Sgshapiroifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG', 8290792Sgshapiroifdef(`_USE_AUTH_', `"550 Relaying denied. Proper authentication required."', `"550 Relaying denied"'))') 8390792Sgshapiroifdef(`confRCPTREJ_MSG', `', `define(`confRCPTREJ_MSG', `"550 Mailbox disabled for this recipient"')') 8490792Sgshapirodefine(`_CODE553', `553') 8538032Speterdivert(0)dnl 8638032Speter 8764562Sgshapiro# override file safeties - setting this option compromises system security, 8864562Sgshapiro# addressing the actual file configuration problem is preferred 8964562Sgshapiro# need to set this before any file actions are encountered in the cf file 9064562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe') 9138032Speter 9264562Sgshapiro# default LDAP map specification 9364562Sgshapiro# need to set this now before any LDAP maps are defined 9464562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost') 9564562Sgshapiro 9638032Speter################## 9738032Speter# local info # 9838032Speter################## 9938032Speter 10090792Sgshapiro# my LDAP cluster 10190792Sgshapiro# need to set this before any LDAP lookups are done (including classes) 10290792Sgshapiroifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m') 10390792Sgshapiro 10438032SpeterCwlocalhost 10538032Speterifdef(`USE_CW_FILE', 10638032Speter`# file containing names of hosts for which we receive email 10738032SpeterFw`'confCW_FILE', 10838032Speter `dnl') 10938032Speter 11038032Speter# my official domain name 11138032Speter# ... `define' this only if sendmail cannot automatically determine your domain 11238032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM') 11338032Speter 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 58338032Speter# shall we get local names from our installed interfaces? 58464562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 58538032Speter 58664562Sgshapiro# Return-Receipt-To: header implies DSN request 58764562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 58864562Sgshapiro 58964562Sgshapiro# override connection address (for testing) 59064562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 59164562Sgshapiro 59264562Sgshapiro# Trusted user for file ownership and starting the daemon 59364562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root') 59464562Sgshapiro 59564562Sgshapiro# Control socket for daemon management 59664562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 59764562Sgshapiro 59864562Sgshapiro# Maximum MIME header length to protect MUAs 599132943Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0') 60064562Sgshapiro 60164562Sgshapiro# Maximum length of the sum of all headers 60264562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768') 60364562Sgshapiro 60464562Sgshapiro# Maximum depth of alias recursion 60564562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10') 60664562Sgshapiro 60764562Sgshapiro# location of pid file 60864562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid') 60964562Sgshapiro 61064562Sgshapiro# Prefix string for the process title shown on 'ps' listings 61164562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix') 61264562Sgshapiro 61364562Sgshapiro# Data file (df) memory-buffer file maximum size 61464562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096') 61564562Sgshapiro 61664562Sgshapiro# Transcript file (xf) memory-buffer file maximum size 61764562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096') 61864562Sgshapiro 61990792Sgshapiro# lookup type to find information about local mailboxes 62090792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw') 62190792Sgshapiro 622132943Sgshapiro# override compile time flag REQUIRES_DIR_FSYNC 623132943Sgshapiro_OPTION(RequiresDirfsync, `confREQUIRES_DIR_FSYNC', `true') 624132943Sgshapiro 62564562Sgshapiro# list of authentication mechanisms 62690792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5') 62764562Sgshapiro 628132943Sgshapiro# Authentication realm 629132943Sgshapiro_OPTION(AuthRealm, `confAUTH_REALM', `') 630132943Sgshapiro 63164562Sgshapiro# default authentication information for outgoing connections 63264562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info') 63364562Sgshapiro 63464562Sgshapiro# SMTP AUTH flags 63564562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `') 63664562Sgshapiro 63790792Sgshapiro# SMTP AUTH maximum encryption strength 63890792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `') 63990792Sgshapiro 64090792Sgshapiro# SMTP STARTTLS server options 64190792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `') 64290792Sgshapiro 64364562Sgshapiro# Input mail filters 64464562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 64564562Sgshapiro 64698841Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl 64764562Sgshapiro# Milter options 64890792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `') 64964562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 65064562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') 65164562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') 652125820Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `') 653168515Sgshapiro_OPTION(Milter.macros.eom, `confMILTER_MACROS_EOM', `') 654168515Sgshapiro_OPTION(Milter.macros.eoh, `confMILTER_MACROS_EOH', `') 655168515Sgshapiro_OPTION(Milter.macros.data, `confMILTER_MACROS_DATA', `')') 65664562Sgshapiro 65764562Sgshapiro# CA directory 658110560Sgshapiro_OPTION(CACertPath, `confCACERT_PATH', `') 65964562Sgshapiro# CA file 660110560Sgshapiro_OPTION(CACertFile, `confCACERT', `') 66164562Sgshapiro# Server Cert 66264562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `') 66364562Sgshapiro# Server private key 66464562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `') 66564562Sgshapiro# Client Cert 66664562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `') 66764562Sgshapiro# Client private key 66864562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 669132943Sgshapiro# File containing certificate revocation lists 670132943Sgshapiro_OPTION(CRLFile, `confCRL', `') 67164562Sgshapiro# DHParameters (only required if DSA/DH is used) 67264562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `') 67364562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL) 67464562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `') 67564562Sgshapiro 676168515Sgshapiro# Maximum number of "useless" commands before slowing down 677168515Sgshapiro_OPTION(MaxNOOPCommands, `confMAX_NOOP_COMMANDS', `20') 678168515Sgshapiro 679168515Sgshapiro# Name to use for EHLO (defaults to $j) 680168515Sgshapiro_OPTION(HeloName, `confHELO_NAME') 681168515Sgshapiro 68290792Sgshapiro############################ 68390792Sgshapiro`# QUEUE GROUP DEFINITIONS #' 68490792Sgshapiro############################ 68590792Sgshapiro_QUEUE_GROUP_ 68642575Speter 68738032Speter########################### 68838032Speter# Message precedences # 68938032Speter########################### 69038032Speter 69138032SpeterPfirst-class=0 69238032SpeterPspecial-delivery=100 69338032SpeterPlist=-30 69438032SpeterPbulk=-60 69538032SpeterPjunk=-100 69638032Speter 69738032Speter##################### 69838032Speter# Trusted users # 69938032Speter##################### 70038032Speter 70138032Speter# this is equivalent to setting class "t" 70264562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 70338032SpeterTroot 70438032SpeterTdaemon 70538032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp') 70638032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 70738032Speter 70838032Speter######################### 70938032Speter# Format of headers # 71038032Speter######################### 71138032Speter 71238032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl 713132943Sgshapiroifdef(`confMESSAGEID_HEADER',, `define(`confMESSAGEID_HEADER', `<$t.$i@$j>')')dnl 71438032SpeterH?P?Return-Path: <$g> 71538032SpeterHReceived: confRECEIVED_HEADER 71638032SpeterH?D?Resent-Date: $a 71738032SpeterH?D?Date: $a 71838032SpeterH?F?Resent-From: confFROM_HEADER 71938032SpeterH?F?From: confFROM_HEADER 72038032SpeterH?x?Full-Name: $x 72138032Speter# HPosted-Date: $a 72238032Speter# H?l?Received-Date: $b 723132943SgshapiroH?M?Resent-Message-Id: confMESSAGEID_HEADER 724132943SgshapiroH?M?Message-Id: confMESSAGEID_HEADER 72564562Sgshapiro 72638032Speter# 72738032Speter###################################################################### 72838032Speter###################################################################### 72938032Speter##### 73038032Speter##### REWRITING RULES 73138032Speter##### 73238032Speter###################################################################### 73338032Speter###################################################################### 73438032Speter 73538032Speter############################################ 73638032Speter### Ruleset 3 -- Name Canonicalization ### 73738032Speter############################################ 73864562SgshapiroScanonify=3 73938032Speter 74038032Speter# handle null input (translate to <@> special case) 74138032SpeterR$@ $@ <@> 74238032Speter 74338032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon 74438032SpeterR$* $: $1 <@> mark addresses 74538032SpeterR$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> 74638032SpeterR@ $* <@> $: @ $1 unmark @host:... 74790792SgshapiroR$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr 74838032SpeterR$* :: $* <@> $: $1 :: $2 unmark node::addr 74938032SpeterR:`include': $* <@> $: :`include': $1 unmark :`include':... 75038032SpeterR$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon 75138032SpeterR$* : $* <@> $: $2 strip colon if marked 75238032SpeterR$* <@> $: $1 unmark 75338032SpeterR$* ; $1 strip trailing semi 75471345SgshapiroR$* < $+ :; > $* $@ $2 :; <@> catch <list:;> 75538032SpeterR$* < $* ; > $1 < $2 > bogus bracketed semi 75638032Speter 75738032Speter# null input now results from list:; syntax 75838032SpeterR$@ $@ :; <@> 75938032Speter 76038032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item 76138032SpeterR$* $: < $1 > housekeeping <> 76238032SpeterR$+ < $* > < $2 > strip excess on left 76338032SpeterR< $* > $+ < $1 > strip excess on right 76438032SpeterR<> $@ < @ > MAIL FROM:<> case 76538032SpeterR< $+ > $: $1 remove housekeeping <> 76638032Speter 76764562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 76838032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 76938032SpeterR@ $+ , $+ @ $1 : $2 change all "," to ":" 77038032Speter 77138032Speter# localize and dispose of route-based addresses 77290792Sgshapirodnl XXX: IPv6 colon conflict 77390792Sgshapiroifdef(`NO_NETINET6', `dnl', 77490792Sgshapiro`R@ [$+] : $+ $@ $>Canonify2 < @ [$1] > : $2 handle <route-addr>') 77564562SgshapiroR@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 77664562Sgshapirodnl',`dnl 77764562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d> 77864562SgshapiroR@ $+ , $+ $2 77990792Sgshapiroifdef(`NO_NETINET6', `dnl', 78090792Sgshapiro`R@ [ $* ] : $+ $2') 78164562SgshapiroR@ $+ : $+ $2 78264562Sgshapirodnl') 78338032Speter 78438032Speter# find focus for list syntax 78564562SgshapiroR $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 78638032SpeterR $+ : $* ; $@ $1 : $2; list syntax 78738032Speter 78838032Speter# find focus for @ syntax addresses 78938032SpeterR$+ @ $+ $: $1 < @ $2 > focus on domain 79038032SpeterR$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 79164562SgshapiroR$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 79238032Speter 79390792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here. 79490792Sgshapirodnl # do some sanity checking 79590792Sgshapirodnl R$* < @ $~[ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 79638032Speter 79738032Speterifdef(`_NO_UUCP_', `dnl', 79838032Speter`# convert old-style addresses to a domain-based address 79964562SgshapiroR$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 80064562SgshapiroR$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 80164562SgshapiroR$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 80238032Speter') 80338032Speterifdef(`_USE_DECNET_SYNTAX_', 80438032Speter`# convert node::user addresses into a domain-based address 80564562SgshapiroR$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 80664562SgshapiroR$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 80738032Speter', 80838032Speter `dnl') 80938032Speter# if we have % signs, take the rightmost one 81038032SpeterR$* % $* $1 @ $2 First make them all @s. 81138032SpeterR$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 81264562SgshapiroR$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 81338032Speter 81438032Speter# else we must be a local name 81564562SgshapiroR$* $@ $>Canonify2 $1 81638032Speter 81738032Speter 81838032Speter################################################ 81938032Speter### Ruleset 96 -- bottom half of ruleset 3 ### 82038032Speter################################################ 82138032Speter 82264562SgshapiroSCanonify2=96 82338032Speter 82438032Speter# handle special cases for local names 82538032SpeterR$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 82638032SpeterR$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 82738032Speterifdef(`_NO_UUCP_', `dnl', 82838032Speter`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 82964562Sgshapiro 83090792Sgshapiro# check for IPv4/IPv6 domain literal 83190792SgshapiroR$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr] 83238032SpeterR$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 83338032SpeterR$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 83438032Speter 83564562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl 83638032Speter# look up domains in the domain table 83738032SpeterR$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 83838032Speter 83964562Sgshapiroundivert(2)dnl LOCAL_RULE_3 84038032Speter 84164562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl 84238032Speter# handle BITNET mapping 84338032SpeterR$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 84438032Speter 84564562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl 84638032Speter# handle UUCP mapping 84738032SpeterR$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 84838032Speter 84938032Speterifdef(`_NO_UUCP_', `dnl', 85038032Speter`ifdef(`UUCP_RELAY', 85138032Speter`# pass UUCP addresses straight through 85238032SpeterR$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 85338032Speter`# if really UUCP, handle it immediately 85438032Speterifdef(`_CLASS_U_', 85538032Speter`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 85638032Speterifdef(`_CLASS_V_', 85738032Speter`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 85838032Speterifdef(`_CLASS_W_', 85938032Speter`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 86038032Speterifdef(`_CLASS_X_', 86138032Speter`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 86238032Speterifdef(`_CLASS_Y_', 86338032Speter`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 86438032Speter 86538032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl 86638032Speter# try UUCP traffic as a local address 86738032SpeterR$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 86838032SpeterR$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 86938032Speter')') 87064562Sgshapiro# hostnames ending in class P are always canonical 87164562SgshapiroR$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 87264562Sgshapirodnl apply the next rule only for hostnames not in class P 87364562Sgshapirodnl this even works for phrases in class P since . is in class P 87464562Sgshapirodnl which daemon flags are set? 87564562SgshapiroR$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 87664562Sgshapirodnl the other rules in this section only apply if the hostname 87764562Sgshapirodnl does not end in class P hence no further checks are done here 87864562Sgshapirodnl if this ever changes make sure the lookups are "protected" again! 87964562Sgshapiroifdef(`_NO_CANONIFY_', `dnl 88064562Sgshapirodnl do not canonify unless: 88164562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection 88264562Sgshapirodnl with class P is non-empty) 88364562Sgshapirodnl or {daemon_flags} has c set 88464562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify} 88564562SgshapiroR$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 88664562Sgshapiro# pass to name server to make hostname canonical if requested 88764562SgshapiroR$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 88864562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 88964562SgshapiroR$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 89064562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work 89164562SgshapiroR$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 89264562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl 89364562Sgshapirodnl this should only apply to unqualified hostnames 89464562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar 89564562Sgshapirodnl then $- does not work. 89664562Sgshapiro# lookup unqualified hostnames 89790792SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 89864562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless: 89964562Sgshapirodnl {daemon_flags} contains CC (do not canonify) 90071345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work 90171345Sgshapirodnl should we do this for every hostname: even unqualified? 90271345SgshapiroR$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 90364562SgshapiroR$* CC $* $| $* $: $3 90490792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl 90590792Sgshapiro# do not canonify header addresses 90690792SgshapiroR$* $| $* < @ $* $~P > $* $: $&{addr_type} $| $2 < @ $3 $4 > $5 90790792SgshapiroR$* h $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 90890792SgshapiroR$* h $* $| $* $: $3', `dnl') 90938032Speter# pass to name server to make hostname canonical 91064562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 91164562Sgshapirodnl remove {daemon_flags} for other cases 91264562SgshapiroR$* $| $* $: $2 91338032Speter 91438032Speter# local host aliases and pseudo-domains are always canonical 91538032SpeterR$* < @ $=w > $* $: $1 < @ $2 . > $3 91638032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 91738032Speter`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 91838032Speter`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 91964562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 92064562Sgshapirodnl virtual hosts are also canonical 92164562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 92264562Sgshapiro`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 92364562Sgshapiro`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 92464562Sgshapiro`dnl') 92590792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 92690792Sgshapirodnl hosts for genericstable are also canonical 92790792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_', 92890792Sgshapiro`R$* < @ $* $=G > $* $: $1 < @ $2 $3 . > $4', 92990792Sgshapiro`R$* < @ $=G > $* $: $1 < @ $2 . > $3')', 93090792Sgshapiro`dnl') 93164562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added 93264562Sgshapirodnl by one of the rules before 93338032SpeterR$* < @ $* . . > $* $1 < @ $2 . > $3 93438032Speter 93538032Speter 93638032Speter################################################## 93738032Speter### Ruleset 4 -- Final Output Post-rewriting ### 93838032Speter################################################## 93964562SgshapiroSfinal=4 94038032Speter 94171345SgshapiroR$+ :; <@> $@ $1 : handle <list:;> 94238032SpeterR$* <@> $@ handle <> and list:; 94338032Speter 94438032Speter# strip trailing dot off possibly canonical name 94538032SpeterR$* < @ $+ . > $* $1 < @ $2 > $3 94638032Speter 94764562Sgshapiro# eliminate internal code 94838032SpeterR$* < @ *LOCAL* > $* $1 < @ $j > $2 94938032Speter 95038032Speter# externalize local domain info 95138032SpeterR$* < $+ > $* $1 $2 $3 defocus 95238032SpeterR@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 95338032SpeterR@ $* $@ @ $1 ... and exit 95438032Speter 95538032Speterifdef(`_NO_UUCP_', `dnl', 95638032Speter`# UUCP must always be presented in old form 95738032SpeterR$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 95838032Speter 95938032Speterifdef(`_USE_DECNET_SYNTAX_', 96038032Speter`# put DECnet back in :: form 96138032SpeterR$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 96238032Speter `dnl') 96338032Speter# delete duplicate local names 96438032SpeterR$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 96538032Speter 96638032Speter 96738032Speter 96838032Speter############################################################## 96938032Speter### Ruleset 97 -- recanonicalize and call ruleset zero ### 97038032Speter### (used for recursive calls) ### 97138032Speter############################################################## 97238032Speter 97364562SgshapiroSRecurse=97 97464562SgshapiroR$* $: $>canonify $1 97564562SgshapiroR$* $@ $>parse $1 97638032Speter 97738032Speter 97838032Speter###################################### 97938032Speter### Ruleset 0 -- Parse Address ### 98038032Speter###################################### 98138032Speter 98264562SgshapiroSparse=0 98338032Speter 98438032SpeterR$* $: $>Parse0 $1 initial parsing 98538032SpeterR<@> $#_LOCAL_ $: <@> special case error msgs 98664562SgshapiroR$* $: $>ParseLocal $1 handle local hacks 98738032SpeterR$* $: $>Parse1 $1 final parsing 98838032Speter 98938032Speter# 99038032Speter# Parse0 -- do initial syntax checking and eliminate local addresses. 99138032Speter# This should either return with the (possibly modified) input 99238032Speter# or return with a #error mailer. It should not return with a 99338032Speter# #mailer other than the #error mailer. 99438032Speter# 99538032Speter 99638032SpeterSParse0 99738032SpeterR<@> $@ <@> special case error msgs 99890792SgshapiroR$* : $* ; <@> $#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses" 99964562SgshapiroR@ <@ $* > < @ $1 > catch "@@host" bogosity 100090792SgshapiroR<@ $+> $#error $@ 5.1.3 $: "_CODE553 User address required" 100190792SgshapiroR$+ <@> $#error $@ 5.1.3 $: "_CODE553 Hostname required" 100238032SpeterR$* $: <> $1 100390792Sgshapirodnl allow tricks like [host1]:[host2] 100490792SgshapiroR<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4 100590792SgshapiroR<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4 100690792Sgshapirodnl but no a@[b]c 100790792SgshapiroR<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid address" 100890792SgshapiroR<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 100990792SgshapiroR<> $* <$* : $* > $* $#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part" 101038032SpeterR<> $* $1 101190792SgshapiroR$* < @ . $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 101290792SgshapiroR$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 101390792Sgshapirodnl no a@b@ 101490792SgshapiroR$* < @ $* @ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid route address" 101590792Sgshapirodnl no a@b@c 101690792SgshapiroR$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 101764562Sgshapirodnl comma only allowed before @; this check is not complete 101890792SgshapiroR$* , $~O $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 101938032Speter 102090792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks 102190792SgshapiroR$* . < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot" 102290792SgshapiroR. $* < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot" 102390792Sgshapirodnl', `dnl') 102490792Sgshapiro 102538032Speter# now delete the local info -- note $=O to find characters that cause forwarding 102664562SgshapiroR$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 102764562SgshapiroR< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 102838032SpeterR$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 102990792SgshapiroR< @ $+ > $#error $@ 5.1.3 $: "_CODE553 User address required" 103064562SgshapiroR$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 103138032SpeterR$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 103290792SgshapiroR< @ *LOCAL* > $#error $@ 5.1.3 $: "_CODE553 User address required" 103338032SpeterR$* $=O $* < @ *LOCAL* > 103464562Sgshapiro $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 103538032SpeterR$* < @ *LOCAL* > $: $1 103638032Speter 103738032Speter# 103838032Speter# Parse1 -- the bottom half of ruleset 0. 103938032Speter# 104038032Speter 104138032SpeterSParse1 104264562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 104364562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute} 104490792SgshapiroR$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <> 104590792SgshapiroR$+ < @ $={LDAPRouteEquiv} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>', 104664562Sgshapiro`dnl') 104764562Sgshapiro 104838032Speterifdef(`_MAILER_smtp_', 104938032Speter`# handle numeric address spec 105064562Sgshapirodnl there is no check whether this is really an IP number 105164562SgshapiroR$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 1052112810SgshapiroR$* < @ [ $+ ] > $* $: $1 < @ [ $2 ] : $S > $3 Add smart host to path 105390792SgshapiroR$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 105464562SgshapiroR$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 105564562SgshapiroR$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 105638032Speter `dnl') 105738032Speter 105864562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 105938032Speter# handle virtual users 106090792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 106190792Sgshapirodnl this is not a documented option 106290792Sgshapirodnl it stops looping in virtusertable mapping if input and output 106390792Sgshapirodnl are identical, i.e., if address A is mapped to A. 106490792Sgshapirodnl it does not deal with multi-level recursion 106590792Sgshapiro# handle full domains in RHS of virtusertable 106690792SgshapiroR$+ < @ $+ > $: $(macro {RecipientAddress} $) $1 < @ $2 > 106790792SgshapiroR$+ < @ $+ > $: <?> $1 < @ $2 > $| $>final $1 < @ $2 > 106890792SgshapiroR<?> $+ $| $+ $: $1 $(macro {RecipientAddress} $@ $2 $) 106990792SgshapiroR<?> $+ $| $* $: $1', 107090792Sgshapiro`dnl') 107164562SgshapiroR$+ $: <!> $1 Mark for lookup 107290792Sgshapirodnl input: <!> local<@domain> 107364562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 107464562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 107564562Sgshapiro`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 107690792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain> 107764562SgshapiroR<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 107890792Sgshapirodnl if <@> local<@domain>: no match but try lookup 107990792Sgshapirodnl user+detail: try user++@domain if detail not empty 108090792SgshapiroR<@> $+ + $+ < @ $* . > 108190792Sgshapiro $: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 108290792Sgshapirodnl user+detail: try user+*@domain 108338032SpeterR<@> $+ + $* < @ $* . > 108490792Sgshapiro $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 108590792Sgshapirodnl user+detail: try user@domain 108638032SpeterR<@> $+ + $* < @ $* . > 108790792Sgshapiro $: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 108864562Sgshapirodnl try default entry: @domain 108990792Sgshapirodnl ++@domain 109090792SgshapiroR<@> $+ + $+ < @ $+ . > $: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 109164562Sgshapirodnl +*@domain 109290792SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 109364562Sgshapirodnl @domain if +detail exists 109498121Sgshapirodnl if no match, change marker to prevent a second @domain lookup 109598121SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . > 109698121Sgshapirodnl without +detail 109738032SpeterR<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 109890792Sgshapirodnl no match 109938032SpeterR<@> $+ $: $1 110090792Sgshapirodnl remove mark 110164562SgshapiroR<!> $+ $: $1 110264562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 110338032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 110490792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 110590792Sgshapiro# check virtuser input address against output address, if same, skip recursion 110690792SgshapiroR< $+ > $+ < @ $+ > $: < $1 > $2 < @ $3 > $| $1 110790792Sgshapiro# it is the same: stop now 110890792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress} $: $>ParseLocal $>Parse0 $>canonify $1 110990792SgshapiroR< $+ > $+ < @ $+ > $| $* $: < $1 > $2 < @ $3 > 111090792Sgshapirodnl', `dnl') 111180785Sgshapirodnl this is not a documented option 111280785Sgshapirodnl it performs no looping at all for virtusertable 111377349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_', 111477349Sgshapiro`R< $+ > $+ < @ $+ > $: $>ParseLocal $>Parse0 $>canonify $1', 111577349Sgshapiro`R< $+ > $+ < @ $+ > $: $>Recurse $1') 111677349Sgshapirodnl', `dnl') 111738032Speter 111838032Speter# short circuit local delivery so forwarded email works 111938032Speterifdef(`_MAILER_usenet_', `dnl 112064562SgshapiroR$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 112166494Sgshapiro 112266494Sgshapiro 112338032Speterifdef(`_STICKY_LOCAL_DOMAIN_', 112438032Speter`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 112564562SgshapiroR< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 112664562Sgshapirodnl $H empty (but @$=w.) 112738032SpeterR< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 112838032SpeterR< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 112964562Sgshapiro`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 113038032SpeterR$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 113138032Speter 113264562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 113338032Speter# not local -- try mailer table lookup 113438032SpeterR$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 113538032SpeterR< $+ . > $* $: < $1 > $2 strip trailing dot 113638032SpeterR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 113764562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 113864562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 113964562SgshapiroR< $+ > $* $: $>Mailertable <$1> $2 try domain', 114038032Speter`dnl') 114164562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)' 114238032Speter 114338032Speterifdef(`_NO_UUCP_', `dnl', 114438032Speter`# resolve remotely connected UUCP links (if any) 114538032Speterifdef(`_CLASS_V_', 114664562Sgshapiro`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 114738032Speter `dnl') 114838032Speterifdef(`_CLASS_W_', 114964562Sgshapiro`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 115038032Speter `dnl') 115138032Speterifdef(`_CLASS_X_', 115264562Sgshapiro`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 115338032Speter `dnl')') 115438032Speter 115538032Speter# resolve fake top level domains by forwarding to other hosts 115638032Speterifdef(`BITNET_RELAY', 115764562Sgshapiro`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 115838032Speter `dnl') 115938032Speterifdef(`DECNET_RELAY', 116064562Sgshapiro`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 116138032Speter `dnl') 116238032Speterifdef(`_MAILER_pop_', 116338032Speter`R$+ < @ POP. > $#pop $: $1 user@POP', 116438032Speter `dnl') 116538032Speterifdef(`_MAILER_fax_', 116638032Speter`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 116738032Speter`ifdef(`FAX_RELAY', 116864562Sgshapiro`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 116938032Speter `dnl')') 117038032Speter 117138032Speterifdef(`UUCP_RELAY', 117238032Speter`# forward non-local UUCP traffic to our UUCP relay 117364562SgshapiroR$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 117438032Speter`ifdef(`_MAILER_uucp_', 117538032Speter`# forward other UUCP traffic straight to UUCP 117638032SpeterR$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 117738032Speter `dnl')') 117838032Speterifdef(`_MAILER_usenet_', ` 117938032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup 118064562SgshapiroR$+ . USENET $#usenet $@ usenet $: $1', 118138032Speter `dnl') 118238032Speter 118338032Speterifdef(`_LOCAL_RULES_', 118438032Speter`# figure out what should stay in our local mail system 118538032Speterundivert(1)', `dnl') 118638032Speter 118738032Speter# pass names that still have a host to a smarthost (if defined) 118864562SgshapiroR$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 118938032Speter 119038032Speter# deal with other remote names 119138032Speterifdef(`_MAILER_smtp_', 119264562Sgshapiro`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 119390792Sgshapiro`R$* < @$* > $* $#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2') 119438032Speter 119538032Speter# handle locally delivered names 119664562SgshapiroR$=L $#_LOCAL_ $: @ $1 special local names 119738032SpeterR$+ $#_LOCAL_ $: $1 regular local names 119838032Speter 119938032Speter########################################################################### 120038032Speter### Ruleset 5 -- special rewriting after aliases have been expanded ### 120138032Speter########################################################################### 120238032Speter 120364562SgshapiroSLocal_localaddr 120464562SgshapiroSlocaladdr=5 120564562SgshapiroR$+ $: $1 $| $>"Local_localaddr" $1 120690792SgshapiroR$+ $| $#ok $@ $1 no change 120764562SgshapiroR$+ $| $#$* $#$2 120864562SgshapiroR$+ $| $* $: $1 120938032Speter 121090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 121190792Sgshapiro# Preserve rcpt_host in {Host} 121290792SgshapiroR$+ $: $1 $| $&h $| $&{Host} check h and {Host} 121390792SgshapiroR$+ $| $| $: $(macro {Host} $@ $) $1 no h or {Host} 121490792SgshapiroR$+ $| $| $+ $: $1 h not set, {Host} set 121590792SgshapiroR$+ $| +$* $| $* $: $1 h is +detail, {Host} set 121695154SgshapiroR$+ $| $* @ $+ $| $* $: $(macro {Host} $@ @$3 $) $1 set {Host} to host in h 121790792SgshapiroR$+ $| $+ $| $* $: $(macro {Host} $@ @$2 $) $1 set {Host} to h 121890792Sgshapiro')dnl 121990792Sgshapiro 122090792Sgshapiroifdef(`_FFR_5_', `dnl 122166494Sgshapiro# Preserve host in a macro 122266494SgshapiroR$+ $: $(macro {LocalAddrHost} $) $1 122366494SgshapiroR$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 122466494Sgshapiro 122590792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl 122638032Speter# deal with plussed users so aliases work nicely 122766494SgshapiroR$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 122866494SgshapiroR$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 122966494Sgshapiro') 123038032Speter# prepend an empty "forward host" on the front 123138032SpeterR$+ $: <> $1 123238032Speter 123338032Speterifdef(`LUSER_RELAY', `dnl 123438032Speter# send unrecognized local users to a relay host 123590792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 123666494SgshapiroR< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 123766494SgshapiroR< > $+ $: < ? $L > < > $(user $1 $) look up user 123866494SgshapiroR< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 123966494SgshapiroR< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 124064562SgshapiroR< > $+ $: < $L > $(user $1 $) look up user 124190792SgshapiroR< $* > $+ <> $: < > $2 found; strip $L') 124290792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 124390792SgshapiroR< $+ > $+ $: < $1 > $2 $&{Host}') 124490792Sgshapirodnl') 124538032Speter 124690792Sgshapiroifdef(`MAIL_HUB', `dnl 124790792SgshapiroR< > $+ $: < $H > $1 try hub', `dnl') 124890792Sgshapiroifdef(`LOCAL_RELAY', `dnl 124990792SgshapiroR< > $+ $: < $R > $1 try relay', `dnl') 125090792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 125190792SgshapiroR< > $+ $@ $1', `dnl 125264562SgshapiroR< > $+ $: < > < $1 <> $&h > nope, restore +detail 125390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 125490792SgshapiroR< > < $+ @ $+ <> + $* > $: < > < $1 + $3 @ $2 > check whether +detail') 125564562SgshapiroR< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 125664562SgshapiroR< > < $+ <> $* > $: < > < $1 > else discard 125738032SpeterR< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 125866494SgshapiroR< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 125938032SpeterR< > < $+ > $@ $1 no +detail 126043730SpeterR$+ $: $1 <> $&h add +detail back in 126190792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 126290792SgshapiroR$+ @ $+ <> + $* $: $1 + $3 @ $2 check whether +detail') 126343730SpeterR$+ <> + $* $: $1 + $2 check whether +detail 126466494SgshapiroR$+ <> $* $: $1 else discard') 126564562SgshapiroR< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 126664562SgshapiroR< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 126790792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 126890792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 126990792SgshapiroR< $~[ : $+ > $+ @ $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $4 >') 127090792SgshapiroR< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 127190792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 127290792SgshapiroR< $+ > $+ @ $+ $@ $>MailerToTriple < $1 > $2 < @ $3 >') 127364562SgshapiroR< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 127438032Speter 127564562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 127690792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 127738032Speter################################################################### 127890792Sgshapiro### Ruleset LDAPMailertable -- mailertable lookup for LDAP ### 127990792Sgshapirodnl input: <Domain> FullAddress 128090792Sgshapiro################################################################### 128190792Sgshapiro 128290792SgshapiroSLDAPMailertable 128390792SgshapiroR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 128490792SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check resolved? 128590792SgshapiroR< $+ > $* $: < $1 > $>Mailertable <$1> $2 try domain 128690792SgshapiroR< $+ > $#$* $#$2 found 128790792SgshapiroR< $+ > $* $#_RELAY_ $@ $1 $: $2 not found, direct relay', 128890792Sgshapiro`dnl') 128990792Sgshapiro 129090792Sgshapiro################################################################### 129138032Speter### Ruleset 90 -- try domain part of mailertable entry ### 129264562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 129338032Speter################################################################### 129438032Speter 129564562SgshapiroSMailertable=90 129664562Sgshapirodnl shift and check 129764562Sgshapirodnl %2 is not documented in cf/README 129838032SpeterR$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 129964562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 130064562SgshapiroR$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 130164562SgshapiroR$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 130264562Sgshapirodnl is $2 always empty? 130338032SpeterR$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 130464562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 130564562Sgshapirodnl return full address 130638032SpeterR< $* > $* $@ $2 no mailertable match', 130738032Speter`dnl') 130838032Speter 130938032Speter################################################################### 131038032Speter### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 131164562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest 131264562Sgshapirodnl <> address -> address 131364562Sgshapirodnl <error:d.s.n:text> -> error 1314120256Sgshapirodnl <error:keyword:text> -> error 131564562Sgshapirodnl <error:text> -> error 131664562Sgshapirodnl <mailer:user@host> lp<@domain>rest -> mailer host user 131764562Sgshapirodnl <mailer:host> address -> mailer host address 131864562Sgshapirodnl <localdomain> address -> address 131964562Sgshapirodnl <host> address -> relay host address 132038032Speter################################################################### 132138032Speter 132264562SgshapiroSMailerToTriple=95 132338032SpeterR< > $* $@ $1 strip off null relay 132464562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 1325120256SgshapiroR< error : $- : $+ > $* $#error $@ $(dequote $1 $) $: $2 1326120256SgshapiroR< error : $+ > $* $#error $: $1 132738032SpeterR< local : $* > $* $>CanonLocal < $1 > $2 132890792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 132990792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 133090792SgshapiroR< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 133138032SpeterR< $=w > $* $@ $2 delete local host 133238032SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 133338032Speter 133438032Speter################################################################### 133538032Speter### Ruleset CanonLocal -- canonify local: syntax ### 133664562Sgshapirodnl input: <user> address 133764562Sgshapirodnl <x> <@host> : rest -> Recurse rest 133864562Sgshapirodnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 133964562Sgshapirodnl <> user <@host> rest -> local user@host user 134064562Sgshapirodnl <> user -> local user user 134164562Sgshapirodnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 134264562Sgshapirodnl <user> lp <@host> rest -> local lp@host user 134364562Sgshapirodnl <user> lp -> local lp user 134438032Speter################################################################### 134538032Speter 134638032SpeterSCanonLocal 134743730Speter# strip local host from routed addresses 134864562SgshapiroR< $* > < @ $+ > : $+ $@ $>Recurse $3 134964562SgshapiroR< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 135043730Speter 135138032Speter# strip trailing dot from any host name that may appear 135238032SpeterR< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 135338032Speter 135438032Speter# handle local: syntax -- use old user, either with or without host 135538032SpeterR< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 135638032SpeterR< > $+ $#_LOCAL_ $@ $1 $: $1 135738032Speter 135838032Speter# handle local:user@host syntax -- ignore host part 135938032SpeterR< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 136038032Speter 136138032Speter# handle local:user syntax 136238032SpeterR< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 136338032SpeterR< $+ > $* $#_LOCAL_ $@ $2 $: $1 136438032Speter 136538032Speter################################################################### 136638032Speter### Ruleset 93 -- convert header names to masqueraded form ### 136738032Speter################################################################### 136838032Speter 136964562SgshapiroSMasqHdr=93 137038032Speter 137164562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 137238032Speter# handle generics database 137338032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_', 137464562Sgshapirodnl if generics should be applied add a @ as mark 137538032Speter`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 137638032Speter`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 137738032SpeterR$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 137864562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @ 137964562Sgshapirodnl ignore the first case for now 138064562Sgshapirodnl if it has the mark lookup full address 138190792Sgshapirodnl broken: %1 is full address not just detail 138264562SgshapiroR< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 138364562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain> 138464562Sgshapirodnl no match, try user+detail@domain 138564562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 138664562Sgshapiro $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 138764562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 138864562Sgshapiro $: < $(generics $1@$3 $: $) > $4 < @ $5 > 138964562Sgshapirodnl no match, remove mark 139064562SgshapiroR<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 139164562Sgshapirodnl no match, try @domain for exceptions 139264562SgshapiroR< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 139364562Sgshapirodnl workspace: ... or <match> user <@domain> 139464562Sgshapirodnl no match, try local part 139538032SpeterR< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 139664562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 139764562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 139864562SgshapiroR< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 139964562SgshapiroR< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 140038032SpeterR< > $* $: $1 not found', 140138032Speter`dnl') 140238032Speter 140364562Sgshapiro# do not masquerade anything in class N 140464562SgshapiroR$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 140564562Sgshapiro 140690792Sgshapiroifdef(`MASQUERADE_NAME', `dnl 140738032Speter# special case the users that should be exposed 140838032SpeterR$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 140938032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 141038032Speter`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 141138032Speter`R$=E < @ $=M . > $@ $1 < @ $2 . >') 141238032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 141338032Speter`R$=E < @ $=w . > $@ $1 < @ $2 . >') 141438032Speter 141538032Speter# handle domain-specific masquerading 141638032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 141738032Speter`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 141838032Speter`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 141938032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 142038032Speter`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 142138032SpeterR$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 142238032SpeterR$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 142338032SpeterR$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 142490792Sgshapirodnl', `dnl no masquerading 142590792Sgshapirodnl just fix *LOCAL* leftovers 142690792SgshapiroR$* < @ *LOCAL* > $@ $1 < @ $j . >') 142738032Speter 142838032Speter################################################################### 142938032Speter### Ruleset 94 -- convert envelope names to masqueraded form ### 143038032Speter################################################################### 143138032Speter 143264562SgshapiroSMasqEnv=94 143338032Speterifdef(`_MASQUERADE_ENVELOPE_', 143464562Sgshapiro`R$+ $@ $>MasqHdr $1', 143538032Speter`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 143638032Speter 143738032Speter################################################################### 143838032Speter### Ruleset 98 -- local part of ruleset zero (can be null) ### 143938032Speter################################################################### 144038032Speter 144164562SgshapiroSParseLocal=98 144264562Sgshapiroundivert(3)dnl LOCAL_RULE_0 144338032Speter 144464562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 144590792Sgshapiro###################################################################### 144690792Sgshapiro### LDAPExpand: Expand address using LDAP routing 144790792Sgshapiro### 144890792Sgshapiro### Parameters: 144990792Sgshapiro### <$1> -- parsed address (user < @ domain . >) (pass through) 145090792Sgshapiro### <$2> -- RFC822 address (user @ domain) (used for lookup) 145190792Sgshapiro### <$3> -- +detail information 145290792Sgshapiro### 145390792Sgshapiro### Returns: 145490792Sgshapiro### Mailer triplet ($#mailer $@ host $: address) 145590792Sgshapiro### Parsed address (user < @ domain . >) 145690792Sgshapiro###################################################################### 145790792Sgshapiro 1458132943Sgshapiro# SMTP operation modes 1459132943SgshapiroC{SMTPOpModes} s d D 1460132943Sgshapiro 146164562SgshapiroSLDAPExpand 146264562Sgshapiro# do the LDAP lookups 146390792SgshapiroR<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3> 146464562Sgshapiro 1465132943Sgshapiro# look for temporary failures and... 1466132943SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*> $: $&{opMode} $| TMPF <$&{addr_type}> $| $3 1467132943SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*> $: $&{opMode} $| TMPF <$&{addr_type}> $| $3 1468132943Sgshapiroifelse(_LDAP_ROUTE_MAPTEMP_, `_TEMPFAIL_', `dnl 1469132943Sgshapiro# ... temp fail RCPT SMTP commands 1470132943SgshapiroR$={SMTPOpModes} $| TMPF <e r> $| $+ $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."') 1471132943Sgshapiro# ... return original address for MTA to queue up 1472132943SgshapiroR$* $| TMPF <$*> $| $+ $@ $3 147394334Sgshapiro 147464562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost, 147564562Sgshapiro# return the new mailRoutingAddress 147690792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 147790792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2 147890792SgshapiroR<$+@$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $5 @ $2') 147990792SgshapiroR<$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 148090792SgshapiroR<$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 148164562Sgshapiro 148298121Sgshapiro 148364562Sgshapiro# if mailRoutingAddress and non-local mailHost, 148464562Sgshapiro# relay to mailHost with new mailRoutingAddress 148590792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 148690792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 148790792Sgshapiro# check mailertable for host, relay from there 148890792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$3> $>canonify $1 $6 @ $2', 148990792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')') 149090792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 149190792Sgshapiro# check mailertable for host, relay from there 149290792SgshapiroR<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1', 149390792Sgshapiro`R<$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $2 $: $>canonify $1') 149464562Sgshapiro 149564562Sgshapiro# if no mailRoutingAddress and local mailHost, 149664562Sgshapiro# return original address 149790792SgshapiroR<> <$=w> <$+> <$+> <$*> $@ $2 149864562Sgshapiro 149998121Sgshapiro 150064562Sgshapiro# if no mailRoutingAddress and non-local mailHost, 150164562Sgshapiro# relay to mailHost with original address 150290792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 150390792Sgshapiro# check mailertable for host, relay from there 150490792SgshapiroR<> <$+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2', 150590792Sgshapiro`R<> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $1 $: $2') 150664562Sgshapiro 150790792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_', 150890792Sgshapiro`# if no mailRoutingAddress and no mailHost, 150990792Sgshapiro# try without +detail 151090792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl 151190792Sgshapiro 1512132943Sgshapiroifdef(`_LDAP_ROUTE_NODOMAIN_', `dnl', ` 151390792Sgshapiro# if still no mailRoutingAddress and no mailHost, 151464562Sgshapiro# try @domain 151590792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 151690792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <@ $4> <+$3>') 1517132943SgshapiroR<> <> <$+> <$+ @ $+> <$*> $@ $>LDAPExpand <$1> <@ $3> <$4>') 151864562Sgshapiro 151964562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt, 152064562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 152164562Sgshapiro# user does not exist 152290792SgshapiroR<> <> <$+> <@ $+> <$*> $: <?> < $&{addr_type} > < $1 > 152390792Sgshapiro# only give error for envelope recipient 152490792SgshapiroR<?> <e r> <$+> $#error $@ nouser $: "550 User unknown" 1525132943Sgshapiroifdef(`_LDAP_SENDER_MUST_EXIST_', `dnl 1526132943Sgshapiro# and the sender too 1527132943SgshapiroR<?> <e s> <$+> $#error $@ nouser $: "550 User unknown"') 152890792SgshapiroR<?> <$*> <$+> $@ $2', 152964562Sgshapiro`dnl 153064562Sgshapiro# return the original address 153190792SgshapiroR<> <> <$+> <@ $+> <$*> $@ $1')', 153264562Sgshapiro`dnl') 153364562Sgshapiro 153464562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 153564562Sgshapiro')') 153690792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 153738032Speter###################################################################### 153890792Sgshapiro### D: LookUpDomain -- search for domain in access database 153938032Speter### 154038032Speter### Parameters: 154138032Speter### <$1> -- key (domain name) 154238032Speter### <$2> -- default (what to return if not found in db) 154364562Sgshapirodnl must not be empty 154490792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 154564562Sgshapiro### ! does lookup only with tag 154664562Sgshapiro### + does lookup with and without tag 154790792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 154864562Sgshapirodnl returns: <default> <passthru> 154964562Sgshapirodnl <result> <passthru> 155038032Speter###################################################################### 155138032Speter 155290792SgshapiroSD 155364562Sgshapirodnl workspace <key> <default> <passthru> <mark> 155464562Sgshapirodnl lookup with tag (in front, no delimiter here) 155590792Sgshapirodnl 2 3 4 5 155690792SgshapiroR<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 155764562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 155864562Sgshapirodnl lookup without tag? 155990792Sgshapirodnl 1 2 3 4 156090792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 156190792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest 156290792Sgshapirodnl XXX apply this also to IP addresses? 156390792Sgshapirodnl currently it works the wrong way round for [1.2.3.4] 156490792Sgshapirodnl 1 2 3 4 5 6 156590792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6> 156690792Sgshapirodnl 1 2 3 4 5 156790792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl') 156890792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 156990792Sgshapirodnl found SKIP: return <default> and <passthru> 157090792Sgshapirodnl 1 2 3 4 5 157190792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 157290792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!) 157390792Sgshapirodnl 1 2 3 4 5 6 157490792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*> $@ $>D <[$1]> <$3> <$4 $5> <$6> 157590792Sgshapiroifdef(`NO_NETINET6', `dnl', 157690792Sgshapiro`dnl not found: IPv6 net 157790792Sgshapirodnl (could be merged with previous rule if we have a class containing .:) 157890792Sgshapirodnl 1 2 3 4 5 6 157990792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6> 158090792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>') 158164562Sgshapirodnl not found, but subdomain: try again 158290792Sgshapirodnl 1 2 3 4 5 6 158390792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6> 158490792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag: 158590792Sgshapirodnl 1 2 3 4 158690792SgshapiroR<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl') 158790792Sgshapirodnl not found, no subdomain: return <default> and <passthru> 158890792Sgshapirodnl 1 2 3 4 5 158990792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 159090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 159190792Sgshapirodnl 2 3 4 5 6 159290792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 159390792Sgshapirodnl return <result of lookup> and <passthru> 159490792Sgshapirodnl 2 3 4 5 6 159590792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 159638032Speter 159738032Speter###################################################################### 159890792Sgshapiro### A: LookUpAddress -- search for host address in access database 159938032Speter### 160038032Speter### Parameters: 160138032Speter### <$1> -- key (dot quadded host address) 160238032Speter### <$2> -- default (what to return if not found in db) 160364562Sgshapirodnl must not be empty 160490792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 160564562Sgshapiro### ! does lookup only with tag 160664562Sgshapiro### + does lookup with and without tag 160790792Sgshapiro### <$4> -- passthru (additional data passed through) 160864562Sgshapirodnl returns: <default> <passthru> 160964562Sgshapirodnl <result> <passthru> 161038032Speter###################################################################### 161138032Speter 161290792SgshapiroSA 161364562Sgshapirodnl lookup with tag 161490792Sgshapirodnl 2 3 4 5 161590792SgshapiroR<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 161664562Sgshapirodnl lookup without tag 161790792Sgshapirodnl 1 2 3 4 161890792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 161990792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru> 162090792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 162190792Sgshapirodnl found SKIP: return <default> and <passthru> 162290792Sgshapirodnl 1 2 3 4 5 162390792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 162490792Sgshapiroifdef(`NO_NETINET6', `dnl', 162590792Sgshapiro`dnl no match; IPv6: remove last part 162690792Sgshapirodnl 1 2 3 4 5 6 162790792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 162890792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>') 162964562Sgshapirodnl no match; IPv4: remove last part 163090792Sgshapirodnl 1 2 3 4 5 6 163190792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 163264562Sgshapirodnl no match: return default 163390792Sgshapirodnl 1 2 3 4 5 163490792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 163590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 163690792Sgshapirodnl 2 3 4 5 6 163790792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 163864562Sgshapirodnl match: return result 163990792Sgshapirodnl 2 3 4 5 6 164090792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 164190792Sgshapirodnl endif _ACCESS_TABLE_ 164290792Sgshapirodivert(0) 164338032Speter###################################################################### 164442575Speter### CanonAddr -- Convert an address into a standard form for 164542575Speter### relay checking. Route address syntax is 164642575Speter### crudely converted into a %-hack address. 164742575Speter### 164842575Speter### Parameters: 164942575Speter### $1 -- full recipient address 165042575Speter### 165142575Speter### Returns: 165242575Speter### parsed address, not in source route form 165364562Sgshapirodnl user%host%host<@domain> 165464562Sgshapirodnl host!user<@domain> 165542575Speter###################################################################### 165642575Speter 165742575SpeterSCanonAddr 165864562SgshapiroR$* $: $>Parse0 $>canonify $1 make domain canonical 165964562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 166042575SpeterR< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 166142575SpeterR$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 166242575SpeterR$* < @ $+ > : $* $3 $1 < @ $2 > 166364562Sgshapirodnl') 166442575Speter 166542575Speter###################################################################### 166638032Speter### ParseRecipient -- Strip off hosts in $=R as well as possibly 166738032Speter### $* $=m or the access database. 166838032Speter### Check user portion for host separators. 166938032Speter### 167038032Speter### Parameters: 167138032Speter### $1 -- full recipient address 167238032Speter### 167338032Speter### Returns: 167438032Speter### parsed, non-local-relaying address 167538032Speter###################################################################### 167638032Speter 167738032SpeterSParseRecipient 167864562Sgshapirodnl mark and canonify address 167942575SpeterR$* $: <?> $>CanonAddr $1 168064562Sgshapirodnl workspace: <?> localpart<@domain[.]> 168142575SpeterR<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 168264562Sgshapirodnl workspace: <?> localpart<@domain> 168342575SpeterR<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 168438032Speter 168538032Speter# if no $=O character, no host in the user portion, we are done 168642575SpeterR<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 168764562Sgshapirodnl no $=O in localpart: return 168842575SpeterR<?> $* $@ $1 168938032Speter 169090792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O 169164562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY> 169238032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 169338032Speter# if we relay, check username portion for user%host so host can be checked also 169442575SpeterR<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 169564562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 169664562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 169790792Sgshapiro 169890792Sgshapirodnl what if access map returns something else than RELAY? 169990792Sgshapirodnl we are only interested in RELAY entries... 170090792Sgshapirodnl other To: entries: blacklist recipient; generic entries? 170190792Sgshapirodnl if it is an error we probably do not want to relay anyway 170238032Speterifdef(`_RELAY_HOSTS_ONLY_', 170342575Speter`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 170464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 170564562SgshapiroR<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 170642575SpeterR<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 170742575Speter`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 170864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 170990792SgshapiroR<NO> $* < @ $+ > $: $>D <$2> <NO> <+ To> <$1 < @ $2 >> 171042575SpeterR<$+> <$+> $: <$1> $2',`dnl')') 171138032Speter 171264562Sgshapiro 171390792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl 171490792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain? 171590792SgshapiroR<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 1716132943SgshapiroR<MX> < : $* <TEMP> : > $* $#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1 171790792Sgshapirodnl yes: mark it as <RELAY> 171890792SgshapiroR<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 171990792Sgshapirodnl no: put old <NO> mark back 172090792SgshapiroR<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 172190792Sgshapiro 172290792Sgshapirodnl do we relay to this recipient domain? 172342575SpeterR<RELAY> $* < @ $* > $@ $>ParseRecipient $1 172490792Sgshapirodnl something else 172590792SgshapiroR<$+> $* $@ $2 172642575Speter 172764562Sgshapiro 172838032Speter###################################################################### 172938032Speter### check_relay -- check hostname/address on SMTP startup 173038032Speter###################################################################### 173138032Speter 1732132943Sgshapiroifdef(`_CONTROL_IMMEDIATE_',`dnl 1733132943SgshapiroScheck_relay 1734132943Sgshapiroifdef(`_RATE_CONTROL_IMMEDIATE_',`dnl 1735132943Sgshapirodnl workspace: ignored... 1736132943SgshapiroR$* $: $>"RateControl" dummy', `dnl') 1737132943Sgshapiroifdef(`_CONN_CONTROL_IMMEDIATE_',`dnl 1738132943Sgshapirodnl workspace: ignored... 1739132943SgshapiroR$* $: $>"ConnControl" dummy', `dnl') 1740132943Sgshapirodnl') 1741132943Sgshapiro 174238032SpeterSLocal_check_relay 174364562SgshapiroScheck`'_U_`'relay 1744132943Sgshapiroifdef(`_USE_CLIENT_PTR_',`dnl 1745132943SgshapiroR$* $| $* $: $&{client_ptr} $| $2', `dnl') 174638032SpeterR$* $: $1 $| $>"Local_check_relay" $1 174738032SpeterR$* $| $* $| $#$* $#$3 174838032SpeterR$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 174938032Speter 175038032SpeterSBasic_check_relay 175138032Speter# check for deferred delivery mode 175298121SgshapiroR$* $: < $&{deliveryMode} > $1 175338032SpeterR< d > $* $@ deferred 175438032SpeterR< $* > $* $: $2 175538032Speter 175664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 175766494Sgshapirodnl workspace: {client_name} $| {client_addr} 175890792SgshapiroR$+ $| $+ $: $>D < $1 > <?> <+ Connect> < $2 > 175966494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 1760110560Sgshapirodnl OR $| $+ if client_name is empty 1761110560SgshapiroR $| $+ $: $>A < $1 > <?> <+ Connect> <> empty client_name 1762110560Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 176390792SgshapiroR<?> <$+> $: $>A < $1 > <?> <+ Connect> <> no: another lookup 176490792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) 176590792SgshapiroR<?> <$*> $: OK found nothing 176690792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK 176790792SgshapiroR<$={Accept}> <$*> $@ $1 return value of lookup 1768132943SgshapiroR<REJECT> <$*> $#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"') 176990792SgshapiroR<DISCARD> <$*> $#discard $: discard 1770132943SgshapiroR<QUARANTINE:$+> <$*> $#error $@ quarantine $: $1 177164562Sgshapirodnl error tag 177266494SgshapiroR<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 177366494SgshapiroR<ERROR:$+> <$*> $#error $: $1 177490792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 177564562Sgshapirodnl generic error from access map 177666494SgshapiroR<$+> <$*> $#error $: $1', `dnl') 177738032Speter 177864562Sgshapiroifdef(`_RBL_',`dnl 177964562Sgshapiro# DNS based IP address spam list 178090792Sgshapirodnl workspace: ignored... 178138032SpeterR$* $: $&{client_addr} 178264562SgshapiroR$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 178364562SgshapiroR<?>OK $: OKSOFAR 178498121SgshapiroR<?>$+ $#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"', 178538032Speter`dnl') 1786132943Sgshapiroifdef(`_RATE_CONTROL_',`dnl 1787132943Sgshapiroifdef(`_RATE_CONTROL_IMMEDIATE_',`', `dnl 1788132943Sgshapirodnl workspace: ignored... 1789132943SgshapiroR$* $: $>"RateControl" dummy')', `dnl') 1790132943Sgshapiroifdef(`_CONN_CONTROL_',`dnl 1791132943Sgshapiroifdef(`_CONN_CONTROL_IMMEDIATE_',`',`dnl 1792132943Sgshapirodnl workspace: ignored... 1793132943SgshapiroR$* $: $>"ConnControl" dummy')', `dnl') 179464562Sgshapiroundivert(8) 1795168515Sgshapiroifdef(`_REQUIRE_RDNS_', `dnl 1796168515SgshapiroR$* $: $&{client_addr} $| $&{client_resolve} 1797168515SgshapiroR$=R $* $@ RELAY We relay for these 1798168515SgshapiroR$* $| OK $@ OK Resolves. 1799168515SgshapiroR$* $| FAIL $#error $@ 5.7.1 $: 550 Fix reverse DNS for $1 1800168515SgshapiroR$* $| TEMP $#error $@ 4.1.8 $: 451 Client IP address $1 does not resolve 1801168515SgshapiroR$* $| FORGED $#error $@ 4.1.8 $: 451 Possibly forged hostname for $1 1802168515Sgshapiro', `dnl') 180338032Speter 180438032Speter###################################################################### 180538032Speter### check_mail -- check SMTP ``MAIL FROM:'' command argument 180638032Speter###################################################################### 180738032Speter 180838032SpeterSLocal_check_mail 180964562SgshapiroScheck`'_U_`'mail 181038032SpeterR$* $: $1 $| $>"Local_check_mail" $1 181138032SpeterR$* $| $#$* $#$2 181238032SpeterR$* $| $* $@ $>"Basic_check_mail" $1 181338032Speter 181438032SpeterSBasic_check_mail 181538032Speter# check for deferred delivery mode 181698121SgshapiroR$* $: < $&{deliveryMode} > $1 181738032SpeterR< d > $* $@ deferred 181838032SpeterR< $* > $* $: $2 181938032Speter 182064562Sgshapiro# authenticated? 182164562Sgshapirodnl done first: we can require authentication for every mail transaction 182264562Sgshapirodnl workspace: address as given by MAIL FROM: (sender) 182364562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 182464562SgshapiroR$* $| $#$+ $#$2 182564562Sgshapirodnl undo damage: remove result of tls_client call 182664562SgshapiroR$* $| $* $: $1 182738032Speter 182864562Sgshapirodnl workspace: address as given by MAIL FROM: 182964562SgshapiroR<> $@ <OK> we MUST accept <> (RFC 1123) 183038032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 183164562Sgshapirodnl do some additional checks 183264562Sgshapirodnl no user@host 183364562Sgshapirodnl no user@localhost (if nonlocal sender) 183464562Sgshapirodnl this is a pretty simple canonification, it will not catch every case 183564562Sgshapirodnl just make sure the address has <> around it (which is required by 183664562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...) 183764562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will 183864562Sgshapirodnl not be modified by host lookups. 183964562SgshapiroR$+ $: <?> $1 184064562SgshapiroR<?><$+> $: <@> <$1> 184164562SgshapiroR<?>$+ $: <@> <$1> 184264562Sgshapirodnl workspace: <@> <address> 184364562Sgshapirodnl prepend daemon_flags 184464562SgshapiroR$* $: $&{daemon_flags} $| $1 184564562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 184664562Sgshapirodnl do not allow these at all or only from local systems? 184764562SgshapiroR$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 184864562Sgshapirodnl accept unqualified sender: change mark to avoid test 184964562SgshapiroR$* u $* $| <@> < $* > $: <?> < $3 > 185064562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 185164562Sgshapirodnl or: <? ${client_name} > <address> 185264562Sgshapirodnl or: <?> <address> 185364562Sgshapirodnl remove daemon_flags 185464562SgshapiroR$* $| $* $: $2 185538032Speter# handle case of @localhost on address 185664562SgshapiroR<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 185764562SgshapiroR<@> < $* @ [127.0.0.1] > 185864562Sgshapiro $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 185964562SgshapiroR<@> < $* @ localhost.$m > 186064562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.$m > 186138032Speterifdef(`_NO_UUCP_', `dnl', 186264562Sgshapiro`R<@> < $* @ localhost.UUCP > 186364562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 186464562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 186564562Sgshapirodnl or: <@> <address> 186664562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 186764562SgshapiroR<@> $* $: $1 no localhost as domain 186864562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 186964562Sgshapirodnl or: <address> 187064562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 187164562SgshapiroR<? $=w> $* $: $2 local client: ok 187290792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address" 187364562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 187464562SgshapiroR<?> $* $: $1') 187564562Sgshapirodnl workspace: address (or <address>) 187664562SgshapiroR$* $: <?> $>CanonAddr $1 canonify sender address and mark it 187764562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 187864562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed 187964562SgshapiroR<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 188064562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 1881102528SgshapiroR<?> $* < @ $* $=P > $: <_RES_OK_> $1 < @ $2 $3 > 188264562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ? or OK 188398121Sgshapirodnl A sender address with my local host name ($j) is safe 1884102528SgshapiroR<?> $* < @ $j > $: <_RES_OK_> $1 < @ $j > 188564562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 188690792Sgshapiro`R<?> $* < @ $+ > $: <_RES_OK_> $1 < @ $2 > ... unresolvable OK', 188764562Sgshapiro`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 188864562SgshapiroR<? $* <$->> $* < @ $+ > 188964562Sgshapiro $: <$2> $3 < @ $4 >') 189090792Sgshapirodnl workspace <mark> CanonicalAddress where mark is ?, _RES_OK_, PERM, TEMP 189164562Sgshapirodnl mark is ? iff the address is user (wo @domain) 189238032Speter 189364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 189464562Sgshapiro# check sender address: user@address, user@, address 189564562Sgshapirodnl should we remove +ext from user? 189690792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP 189790792SgshapiroR<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3> 189864562SgshapiroR<$+> $+ $: @<$1> <$2> $| <U:$2@> 189964562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 190064562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 190164562Sgshapirodnl will only return user<@domain when "reversing" the args 190290792SgshapiroR@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <> 190364562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result> 190464562SgshapiroR<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 190564562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress> 190638032Speter# retransform for further use 190764562Sgshapirodnl required form: 190864562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress 190964562SgshapiroR<?> <$+> <$*> $: <$1> $2 no match 191064562SgshapiroR<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 191164562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress 191264562Sgshapirodnl mark is ? iff the address is user (wo @domain) 191338032Speter 191438032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 191538032Speter# handle case of no @domain on address 191664562Sgshapirodnl prepend daemon_flags 191764562SgshapiroR<?> $* $: $&{daemon_flags} $| <?> $1 191864562Sgshapirodnl accept unqualified sender: change mark to avoid test 191990792SgshapiroR$* u $* $| <?> $* $: <_RES_OK_> $3 192064562Sgshapirodnl remove daemon_flags 192164562SgshapiroR$* $| $* $: $2 1922110560SgshapiroR<?> $* $: < ? $&{client_addr} > $1 1923102528SgshapiroR<?> $* $@ <_RES_OK_> ...local unqualed ok 192490792SgshapiroR<? $+> $* $#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f 192538032Speter ...remote is not') 192638032Speter# check results 192764562SgshapiroR<?> $* $: @ $1 mark address: nothing known about it 1928168515SgshapiroR<$={ResOk}> $* $: @ $2 domain ok 192964562SgshapiroR<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 193090792SgshapiroR<PERM> $* $#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist" 193164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 193290792SgshapiroR<$={Accept}> $* $# $1 accept from access map 193338032SpeterR<DISCARD> $* $#discard $: discard 1934132943SgshapiroR<QUARANTINE:$+> $* $#error $@ quarantine $: $1 1935132943SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"') 193664562Sgshapirodnl error tag 193764562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 193864562SgshapiroR<ERROR:$+> $* $#error $: $1 193990792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 194064562Sgshapirodnl generic error from access map 194164562SgshapiroR<$+> $* $#error $: $1 error from access db', 194238032Speter`dnl') 1943168515Sgshapirodnl workspace: @ CanonicalAddress (i.e. address in canonical form localpart<@host>) 194438032Speter 1945168515Sgshapiroifdef(`_BADMX_CHK_', `dnl 1946168515SgshapiroR@ $*<@$+>$* $: $1<@$2>$3 $| $>BadMX $2 1947168515SgshapiroR$* $| $#$* $#$2 1948168515Sgshapiro 1949168515SgshapiroSBadMX 1950168515Sgshapiro# Look up MX records and ferret away a copy of the original address. 1951168515Sgshapiro# input: domain part of address to check 1952168515SgshapiroR$+ $:<MX><$1><:$(mxlist $1$):><:> 1953168515Sgshapiro# workspace: <MX><domain><: mxlist-result $><:> 1954168515SgshapiroR<MX><$+><:$*<TEMP>:><$*> $#error $@ 4.1.2 $: "450 MX lookup failure for "$1 1955168515Sgshapiro# workspace: <MX> <original destination> <unchecked mxlist> <checked mxlist> 1956168515Sgshapiro# Recursively run badmx check on each mx. 1957168515SgshapiroR<MX><$*><:$+:$*><:$*> <MX><$1><:$3><: $4 $(badmx $2 $):> 1958168515Sgshapiro# See if any of them fail. 1959182352SgshapiroR<MX><$*><$*><$*<BADMX>:$*> $#error $@ 5.1.2 $:"550 Illegal MX record for host "$1 1960168515Sgshapiro# Reverse the mxlists so we can use the same argument order again. 1961168515SgshapiroR<MX><$*><$*><$*> $:<MX><$1><$3><$2> 1962168515SgshapiroR<MX><$*><:$+:$*><:$*> <MX><$1><:$3><:$4 $(dnsA $2 $) :> 1963168515Sgshapiro 1964168515Sgshapiro# Reverse the lists so we can use the same argument order again. 1965168515SgshapiroR<MX><$*><$*><$*> $:<MX><$1><$3><$2> 1966168515SgshapiroR<MX><$*><:$+:$*><:$*> <MX><$1><:$3><:$4 $(BadMXIP $2 $) :> 1967168515Sgshapiro 1968182352SgshapiroR<MX><$*><$*><$*<BADMXIP>:$*> $#error $@ 5.1.2 $:"550 Invalid MX record for host "$1', 1969168515Sgshapiro`dnl') 1970168515Sgshapiro 1971168515Sgshapiro 197238032Speter###################################################################### 197338032Speter### check_rcpt -- check SMTP ``RCPT TO:'' command argument 197438032Speter###################################################################### 197538032Speter 197638032SpeterSLocal_check_rcpt 197764562SgshapiroScheck`'_U_`'rcpt 197838032SpeterR$* $: $1 $| $>"Local_check_rcpt" $1 197938032SpeterR$* $| $#$* $#$2 198038032SpeterR$* $| $* $@ $>"Basic_check_rcpt" $1 198138032Speter 198238032SpeterSBasic_check_rcpt 198390792Sgshapiro# empty address? 198490792SgshapiroR<> $#error $@ nouser $: "553 User address required" 198590792SgshapiroR$@ $#error $@ nouser $: "553 User address required" 198638032Speter# check for deferred delivery mode 198798121SgshapiroR$* $: < $&{deliveryMode} > $1 198838032SpeterR< d > $* $@ deferred 198938032SpeterR< $* > $* $: $2 199038032Speter 199164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 199290792Sgshapirodnl this code checks for user@host where host is not a FQHN. 199390792Sgshapirodnl it is not activated. 199490792Sgshapirodnl notice: code to check for a recipient without a domain name is 199590792Sgshapirodnl available down below; look for the same macro. 199690792Sgshapirodnl this check is done here because the name might be qualified by the 199790792Sgshapirodnl canonicalization. 199890792Sgshapiro# require fully qualified domain part? 199990792Sgshapirodnl very simple canonification: make sure the address is in < > 200064562SgshapiroR$+ $: <?> $1 200190792SgshapiroR<?> <$+> $: <@> <$1> 200290792SgshapiroR<?> $+ $: <@> <$1> 200390792SgshapiroR<@> < postmaster > $: postmaster 2004110560SgshapiroR<@> < $* @ $+ . $+ > $: < $1 @ $2 . $3 > 200564562Sgshapirodnl prepend daemon_flags 200690792SgshapiroR<@> $* $: $&{daemon_flags} $| <@> $1 200764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 2008159609Sgshapirodnl _r_equire qual.rcpt: ok 2009120256SgshapiroR$* r $* $| <@> < $+ @ $+ > $: < $3 @ $4 > 201064562Sgshapirodnl do not allow these at all or only from local systems? 2011120256SgshapiroR$* r $* $| <@> < $* > $: < ? $&{client_name} > < $3 > 201264562SgshapiroR<?> < $* > $: <$1> 201364562SgshapiroR<? $=w> < $* > $: <$1> 201490792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "553 Fully qualified domain name required" 201564562Sgshapirodnl remove daemon_flags for other cases 201664562SgshapiroR$* $| <@> $* $: $2', `dnl') 201764562Sgshapiro 201890792Sgshapirodnl ################################################################## 201990792Sgshapirodnl call subroutines for recipient and relay 202090792Sgshapirodnl possible returns from subroutines: 202190792Sgshapirodnl $#TEMP temporary failure 202290792Sgshapirodnl $#error permanent failure (or temporary if from access map) 202390792Sgshapirodnl $#other stop processing 202490792Sgshapirodnl RELAY RELAYing allowed 202590792Sgshapirodnl other otherwise 202690792Sgshapiro###################################################################### 202790792SgshapiroR$* $: $1 $| @ $>"Rcpt_ok" $1 202890792Sgshapirodnl temporary failure? remove mark @ and remember 202990792SgshapiroR$* $| @ $#TEMP $+ $: $1 $| T $2 203090792Sgshapirodnl error or ok (stop) 203190792SgshapiroR$* $| @ $#$* $#$2 203290792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 203390792SgshapiroR$* $| @ RELAY $@ RELAY 203490792Sgshapirodnl something else: call check sender (relay) 203590792SgshapiroR$* $| @ $* $: O $| $>"Relay_ok" $1 203690792Sgshapirodnl temporary failure: call check sender (relay) 203790792SgshapiroR$* $| T $+ $: T $2 $| $>"Relay_ok" $1 203890792Sgshapirodnl temporary failure? return that 203990792SgshapiroR$* $| $#TEMP $+ $#error $2 204090792Sgshapirodnl error or ok (stop) 204190792SgshapiroR$* $| $#$* $#$2 204290792SgshapiroR$* $| RELAY $@ RELAY 204390792Sgshapirodnl something else: return previous temp failure 204490792SgshapiroR T $+ $| $* $#error $1 204590792Sgshapiro# anything else is bogus 204690792SgshapiroR$* $#error $@ 5.7.1 $: confRELAY_MSG 204790792Sgshapirodivert(0) 204890792Sgshapiro 204990792Sgshapiro###################################################################### 205090792Sgshapiro### Rcpt_ok: is the recipient ok? 205190792Sgshapirodnl input: recipient address (RCPT TO) 205290792Sgshapirodnl output: see explanation at call 205390792Sgshapiro###################################################################### 205490792SgshapiroSRcpt_ok 205538032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl 205642575SpeterR$* $: $>CanonAddr $1 205738032SpeterR$* < @ $* . > $1 < @ $2 > strip trailing dots', 205838032Speter`R$* $: $>ParseRecipient $1 strip relayable hosts') 205938032Speter 206042575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl 206142575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl 206242575Speter# unlimited bestmx 206342575SpeterR$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 206442575Speter`dnl 206542575Speter# limit bestmx to $=B 206643730SpeterR$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 206790792SgshapiroR$* $=O $* < @ $* @@ $=w . > $* $@ $>"Rcpt_ok" $1 $2 $3 206842575SpeterR$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 206942575SpeterR$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 207042575Speter 207138032Speterifdef(`_BLACKLIST_RCPT_',`dnl 207264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 207338032Speter# blacklist local users or any host from receiving mail 207438032SpeterR$* $: <?> $1 207564562Sgshapirodnl user is now tagged with @ to be consistent with check_mail 207664562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user) 207790792SgshapiroR<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2> 207890792SgshapiroR<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2> 207964562SgshapiroR<?> $+ $: <> <$1> $| <U:$1@> 208064562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 208164562Sgshapirodnl will only return user<@domain when "reversing" the args 208290792SgshapiroR<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+ To> $| <$2> <> 208364562SgshapiroR<@> <$*> $| <$*> $: <$2> <$1> reverse result 208464562SgshapiroR<?> <$*> $: @ $1 mark address as no match 208590792Sgshapirodnl we may have to filter here because otherwise some RHSs 208690792Sgshapirodnl would be interpreted as generic error messages... 208790792Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 208890792Sgshapirodnl that would make a lot of things easier. 208964562SgshapiroR<$={Accept}> <$*> $: @ $2 mark address as no match 209090792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 209190792SgshapiroR<SKIP> <$*> $: @ $1 mark address as no match', `dnl') 209290792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl 209390792Sgshapirodnl compatility with 8.11/8.10: 209464562Sgshapirodnl we have to filter these because otherwise they would be interpreted 209564562Sgshapirodnl as generic error message... 209664562Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 209764562Sgshapirodnl that would make a lot of things easier. 209864562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)? 209964562SgshapiroR<$={SpamTag}> <$*> $: @ $2 mark address as no match') 210090792SgshapiroR<REJECT> $* $#error $@ 5.2.1 $: confRCPTREJ_MSG 210164562SgshapiroR<DISCARD> $* $#discard $: discard 2102132943SgshapiroR<QUARANTINE:$+> $* $#error $@ quarantine $: $1 210364562Sgshapirodnl error tag 210464562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 210564562SgshapiroR<ERROR:$+> $* $#error $: $1 210690792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 210764562Sgshapirodnl generic error from access map 210864562SgshapiroR<$+> $* $#error $: $1 error from access db 210964562SgshapiroR@ $* $1 remove mark', `dnl')', `dnl') 211038032Speter 211190792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 211290792Sgshapiro# authenticated via TLS? 211390792SgshapiroR$* $: $1 $| $>RelayTLS client authenticated? 211490792SgshapiroR$* $| $# $+ $# $2 error/ok? 211590792SgshapiroR$* $| $* $: $1 no 211664562Sgshapiro 211790792SgshapiroR$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type} 211890792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth 211990792SgshapiroR$* $| $# $* $# $2 212090792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech} 212190792SgshapiroR$* $| NO $: $1 212290792SgshapiroR$* $| $* $: $1 $| $&{auth_type} 212390792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ] 212464562Sgshapirodnl empty ${auth_type}? 212564562SgshapiroR$* $| $: $1 212664562Sgshapirodnl mechanism ${auth_type} accepted? 212764562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below 212890792SgshapiroR$* $| $={TrustAuthMech} $# RELAY 212990792Sgshapirodnl remove ${auth_type} 213064562SgshapiroR$* $| $* $: $1 213171345Sgshapirodnl workspace: localpart<@domain> | localpart 213264562Sgshapiroifelse(defn(`_NO_UUCP_'), `r', 213371345Sgshapiro`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 213471345SgshapiroR$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 213538032Speter# anything terminating locally is ok 213638032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 213790792SgshapiroR$+ < @ $* $=m > $@ RELAY', `dnl') 213890792SgshapiroR$+ < @ $=w > $@ RELAY 213938032Speterifdef(`_RELAY_HOSTS_ONLY_', 214090792Sgshapiro`R$+ < @ $=R > $@ RELAY 214164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 214264562SgshapiroR$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 214364562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 214464562SgshapiroR<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 214590792Sgshapiro`R$+ < @ $* $=R > $@ RELAY 214664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 2147132943Sgshapiroifdef(`_RELAY_FULL_ADDR_', `dnl 2148132943SgshapiroR$+ < @ $+ > $: $1 < @ $2 > $| $>SearchList <+ To> $| <F:$1@$2> <D:$2> <F:$1@> <> 2149132943SgshapiroR$+ < @ $+ > $| <$*> $: <$3> <$1 <@ $2>> 2150132943SgshapiroR$+ < @ $+ > $| $* $: <$3> <$1 <@ $2>>', 2151132943Sgshapiro`R$+ < @ $+ > $: $>D <$2> <?> <+ To> <$1 < @ $2 >>')')') 215264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 215364562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 215490792SgshapiroR<RELAY> $* $@ RELAY 215590792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 215638032SpeterR<$*> <$*> $: $2',`dnl') 215738032Speter 215864562Sgshapiro 215938032Speterifdef(`_RELAY_MX_SERVED_', `dnl 216038032Speter# allow relaying for hosts which we MX serve 216164562SgshapiroR$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 216264562Sgshapirodnl this must not necessarily happen if the client is checked first... 2163132943SgshapiroR< : $* <TEMP> : > $* $#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1 216490792SgshapiroR<$* : $=w . : $*> $* $@ RELAY 216542575SpeterR< : $* : > $* $: $2', 216638032Speter`dnl') 216738032Speter 216838032Speter# check for local user (i.e. unqualified address) 216938032SpeterR$* $: <?> $1 217042575SpeterR<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 217138032Speter# local user is ok 217264562Sgshapirodnl is it really? the standard requires user@domain, not just user 217364562Sgshapirodnl but we should accept it anyway (maybe making it an option: 217464562Sgshapirodnl RequireFQDN ?) 217564562Sgshapirodnl postmaster must be accepted without domain (DRUMS) 217664562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 217790792SgshapiroR<?> postmaster $@ OK 217864562Sgshapiro# require qualified recipient? 217964562Sgshapirodnl prepend daemon_flags 218064562SgshapiroR<?> $+ $: $&{daemon_flags} $| <?> $1 218164562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart 218264562Sgshapirodnl do not allow these at all or only from local systems? 218364562Sgshapirodnl r flag? add client_name 218464562SgshapiroR$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 218564562Sgshapirodnl no r flag: relay to local user (only local part) 218664562Sgshapiro# no qualified recipient required 218790792SgshapiroR$* $| <?> $+ $@ RELAY 218864562Sgshapirodnl client_name is empty 218990792SgshapiroR<?> <?> $+ $@ RELAY 219064562Sgshapirodnl client_name is local 219190792SgshapiroR<? $=w> <?> $+ $@ RELAY 219264562Sgshapirodnl client_name is not local 219364562SgshapiroR<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 219464562Sgshapirodnl no qualified recipient required 219590792SgshapiroR<?> $+ $@ RELAY') 219664562Sgshapirodnl it is a remote user: remove mark and then check client 219738032SpeterR<$+> $* $: $2 219864562Sgshapirodnl currently the recipient address is not used below 219938032Speter 220090792Sgshapiro###################################################################### 220190792Sgshapiro### Relay_ok: is the relay/sender ok? 220290792Sgshapirodnl input: ignored 220390792Sgshapirodnl output: see explanation at call 220490792Sgshapiro###################################################################### 220590792SgshapiroSRelay_ok 220638032Speter# anything originating locally is ok 220764562Sgshapiro# check IP address 220864562SgshapiroR$* $: $&{client_addr} 220990792SgshapiroR$@ $@ RELAY originated locally 221090792SgshapiroR0 $@ RELAY originated locally 2211110560SgshapiroR127.0.0.1 $@ RELAY originated locally 2212110560SgshapiroRIPv6:::1 $@ RELAY originated locally 221390792SgshapiroR$=R $* $@ RELAY relayable IP address 221464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 221590792SgshapiroR$* $: $>A <$1> <?> <+ Connect> <$1> 221690792SgshapiroR<RELAY> $* $@ RELAY relayable IP address 2217102528Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl 2218102528Sgshapirodnl this will cause rejections in cases like: 2219102528Sgshapirodnl Connect:My.Host.Domain RELAY 2220102528Sgshapirodnl Connect:My.Net REJECT 2221102528Sgshapirodnl since in check_relay client_name is checked before client_addr 2222102528SgshapiroR<REJECT> $* $@ REJECT rejected IP address') 222390792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 222464562SgshapiroR<$*> <$*> $: $2', `dnl') 222564562SgshapiroR$* $: [ $1 ] put brackets around it... 222690792SgshapiroR$=w $@ RELAY ... and see if it is local 222764562Sgshapiro 222864562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 222964562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 223064562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl 223164562Sgshapirodnl input: {client_addr} or something "broken" 223264562Sgshapirodnl just throw the input away; we do not need it. 223364562Sgshapiro# check whether FROM is allowed to use system as relay 223464562SgshapiroR$* $: <?> $>CanonAddr $&f 223590792SgshapiroR<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 223664562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl 223764562Sgshapiro# check whether local FROM is ok 223890792SgshapiroR<?> $+ < @ $=w > $@ RELAY FROM local', `dnl') 223964562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl 224094334SgshapiroR<?> $+ < @ $+ > $: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <> 224190792SgshapiroR<@> <RELAY> $@ RELAY RELAY FROM sender ok 224290792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 224390792Sgshapiro', `dnl 224490792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', 224590792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 224664562Sgshapiro')', 224764562Sgshapiro`dnl') 224864562Sgshapirodnl')', `dnl') 224990792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind. 225090792Sgshapirodnl it does not matter in this case because the following rule ignores 225190792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace. 225264562Sgshapiro 225364562Sgshapiro# check client name: first: did it resolve? 225464562Sgshapirodnl input: ignored 225564562SgshapiroR$* $: < $&{client_resolve} > 2256132943SgshapiroR<TEMP> $#TEMP $@ 4.4.0 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 225764562SgshapiroR<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 225864562SgshapiroR<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 225964562Sgshapirodnl ${client_resolve} should be OK, so go ahead 226090792SgshapiroR$* $: <@> $&{client_name} 226190792Sgshapirodnl should not be necessary since it has been done for client_addr already 2262110560Sgshapirodnl this rule actually may cause a problem if {client_name} resolves to "" 2263110560Sgshapirodnl however, this should not happen since the forward lookup should fail 2264110560Sgshapirodnl and {client_resolve} should be TEMP or FAIL. 2265110560Sgshapirodnl nevertheless, removing the rule doesn't hurt. 2266110560Sgshapirodnl R<@> $@ RELAY 226790792Sgshapirodnl workspace: <@> ${client_name} (not empty) 226838032Speter# pass to name server to make hostname canonical 226990792SgshapiroR<@> $* $=P $:<?> $1 $2 227090792SgshapiroR<@> $+ $:<?> $[ $1 $] 227190792Sgshapirodnl workspace: <?> ${client_name} (canonified) 227264562SgshapiroR$* . $1 strip trailing dots 227338032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 227490792SgshapiroR<?> $* $=m $@ RELAY', `dnl') 227590792SgshapiroR<?> $=w $@ RELAY 227638032Speterifdef(`_RELAY_HOSTS_ONLY_', 227790792Sgshapiro`R<?> $=R $@ RELAY 227864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 227964562SgshapiroR<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 228064562SgshapiroR<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 228190792Sgshapiro`R<?> $* $=R $@ RELAY 228264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 228390792SgshapiroR<?> $* $: $>D <$1> <?> <+ Connect> <$1>',`dnl')') 228464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 228590792SgshapiroR<RELAY> $* $@ RELAY 228690792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 228738032SpeterR<$*> <$*> $: $2',`dnl') 228890792Sgshapirodnl end of _PROMISCUOUS_RELAY_ 228964562Sgshapirodivert(0) 229064562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 229164562Sgshapiro# turn a canonical address in the form user<@domain> 229264562Sgshapiro# qualify unqual. addresses with $j 229364562Sgshapirodnl it might have been only user (without <@domain>) 229464562SgshapiroSFullAddr 229564562SgshapiroR$* <@ $+ . > $1 <@ $2 > 229664562SgshapiroR$* <@ $* > $@ $1 <@ $2 > 229764562SgshapiroR$+ $@ $1 <@ $j > 229838032Speter 2299120256SgshapiroSDelay_TLS_Clt 2300110560Sgshapiro# authenticated? 2301110560Sgshapirodnl code repeated here from Basic_check_mail 2302110560Sgshapirodnl only called from check_rcpt in delay mode if checkrcpt returns $# 2303110560SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 2304110560SgshapiroR$* $| $#$+ $#$2 2305110560Sgshapirodnl return result from checkrcpt 2306120256SgshapiroR$* $| $* $# $1 2307110560SgshapiroR$* $# $1 2308110560Sgshapiro 2309120256SgshapiroSDelay_TLS_Clt2 2310110560Sgshapiro# authenticated? 2311110560Sgshapirodnl code repeated here from Basic_check_mail 2312110560Sgshapirodnl only called from check_rcpt in delay mode if stopping due to Friend/Hater 2313110560SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 2314110560SgshapiroR$* $| $#$+ $#$2 2315110560Sgshapirodnl return result from friend/hater check 2316120256SgshapiroR$* $| $* $@ $1 2317110560SgshapiroR$* $@ $1 2318110560Sgshapiro 231964562Sgshapiro# call all necessary rulesets 232064562SgshapiroScheck_rcpt 232164562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset 232264562Sgshapirodnl which is the correct DSN code? 232364562Sgshapiro# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 2324110560Sgshapiro 232564562SgshapiroR$+ $: $1 $| $>checkrcpt $1 232664562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 2327110560Sgshapirodnl on error (or discard) stop now 2328110560SgshapiroR$+ $| $#error $* $#error $2 2329110560SgshapiroR$+ $| $#discard $* $#discard $2 2330110560Sgshapirodnl otherwise call tls_client; see above 2331120256SgshapiroR$+ $| $#$* $@ $>"Delay_TLS_Clt" $2 233264562SgshapiroR$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 233364562Sgshapiroifdef(`_SPAM_FH_', 233464562Sgshapiro`dnl lookup user@ and user@address 233564562Sgshapiroifdef(`_ACCESS_TABLE_', `', 233664562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 233764562Sgshapiro')')dnl 233864562Sgshapirodnl one of the next two rules is supposed to match 233964562Sgshapirodnl this code has been copied from BLACKLIST... etc 234064562Sgshapirodnl and simplified by omitting some < >. 234190792SgshapiroR<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@> 234290792SgshapiroR<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > 234364562Sgshapirodnl R<?> $@ something_is_very_wrong_here 234490792Sgshapiro# lookup the addresses only with Spam tag 234590792SgshapiroR<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <> 234664562SgshapiroR<@> $* $| $* $: $2 $1 reverse result 234764562Sgshapirodnl', `dnl') 234864562Sgshapiroifdef(`_SPAM_FRIEND_', 234964562Sgshapiro`# is the recipient a spam friend? 235064562Sgshapiroifdef(`_SPAM_HATER_', 2351110560Sgshapiro `errprint(`*** ERROR: define either Hater or Friend -- not both. 235264562Sgshapiro')', `dnl') 2353120256SgshapiroR<FRIEND> $+ $@ $>"Delay_TLS_Clt2" SPAMFRIEND 235464562SgshapiroR<$*> $+ $: $2', 235564562Sgshapiro`dnl') 235664562Sgshapiroifdef(`_SPAM_HATER_', 235764562Sgshapiro`# is the recipient no spam hater? 235890792SgshapiroR<HATER> $+ $: $1 spam hater: continue checks 2359120256SgshapiroR<$*> $+ $@ $>"Delay_TLS_Clt2" NOSPAMHATER everyone else: stop 236064562Sgshapirodnl',`dnl') 2361168515Sgshapiro 236264562Sgshapirodnl run further checks: check_mail 236364562Sgshapirodnl should we "clean up" $&f? 236490792Sgshapiroifdef(`_FFR_MAIL_MACRO', 236590792Sgshapiro`R$* $: $1 $| $>checkmail $&{mail_from}', 236690792Sgshapiro`R$* $: $1 $| $>checkmail <$&f>') 236794334Sgshapirodnl recipient (canonical format) $| result of checkmail 236864562SgshapiroR$* $| $#$* $#$2 236964562Sgshapirodnl run further checks: check_relay 237094334SgshapiroR$* $| $* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 237164562SgshapiroR$* $| $#$* $#$2 237238032SpeterR$* $| $* $: $1 237338032Speter', `dnl') 237490792Sgshapiro 2375168515Sgshapiroifdef(`_BLOCK_BAD_HELO_', `dnl 2376168515SgshapiroR$* $: $1 $| <$&{auth_authen}> Get auth info 2377168515Sgshapirodnl Bypass the test for users who have authenticated. 2378168515SgshapiroR$* $| <$+> $: $1 skip if auth 2379168515SgshapiroR$* $| <$*> $: $1 $| <$&{client_addr}> [$&s] Get connection info 2380168515Sgshapirodnl Bypass for local clients -- IP address starts with $=R 2381168515SgshapiroR$* $| <$=R $*> [$*] $: $1 skip if local client 2382168515Sgshapirodnl Bypass a "sendmail -bs" session, which use 0 for client ip address 2383168515SgshapiroR$* $| <0> [$*] $: $1 skip if sendmail -bs 2384168515Sgshapirodnl Reject our IP - assumes "[ip]" is in class $=w 2385168515SgshapiroR$* $| <$*> $=w $#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s 2386168515Sgshapirodnl Reject our hostname 2387168515SgshapiroR$* $| <$*> [$=w] $#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s 2388168515Sgshapirodnl Pass anything else with a "." in the domain parameter 2389168515SgshapiroR$* $| <$*> [$+.$+] $: $1 qualified domain ok 2390168515Sgshapirodnl Reject if there was no "." or only an initial or final "." 2391168515SgshapiroR$* $| <$*> [$*] $#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s 2392168515Sgshapirodnl Clean up the workspace 2393168515SgshapiroR$* $| $* $: $1 2394168515Sgshapiro', `dnl') 2395168515Sgshapiro 239690792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 239764562Sgshapiro###################################################################### 239890792Sgshapiro### F: LookUpFull -- search for an entry in access database 239990792Sgshapiro### 240090792Sgshapiro### lookup of full key (which should be an address) and 240190792Sgshapiro### variations if +detail exists: +* and without +detail 240290792Sgshapiro### 240390792Sgshapiro### Parameters: 240490792Sgshapiro### <$1> -- key 240590792Sgshapiro### <$2> -- default (what to return if not found in db) 240690792Sgshapirodnl must not be empty 240790792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 240890792Sgshapiro### ! does lookup only with tag 240990792Sgshapiro### + does lookup with and without tag 241090792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 241190792Sgshapirodnl returns: <default> <passthru> 241290792Sgshapirodnl <result> <passthru> 241390792Sgshapiro###################################################################### 241490792Sgshapiro 241590792SgshapiroSF 241690792Sgshapirodnl workspace: <key> <def> <o tag> <thru> 241790792Sgshapirodnl full lookup 241890792Sgshapirodnl 2 3 4 5 241990792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 242090792Sgshapirodnl no match, try without tag 242190792Sgshapirodnl 1 2 3 4 242290792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 242390792Sgshapirodnl no match, +detail: try +* 242490792Sgshapirodnl 1 2 3 4 5 6 7 242590792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 242690792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 242790792Sgshapirodnl no match, +detail: try +* without tag 242890792Sgshapirodnl 1 2 3 4 5 6 242990792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 243090792Sgshapiro $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 243190792Sgshapirodnl no match, +detail: try without +detail 243290792Sgshapirodnl 1 2 3 4 5 6 7 243390792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 243490792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 243590792Sgshapirodnl no match, +detail: try without +detail and without tag 243690792Sgshapirodnl 1 2 3 4 5 6 243790792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 243890792Sgshapiro $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 243990792Sgshapirodnl no match, return <default> <passthru> 244090792Sgshapirodnl 1 2 3 4 5 244190792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 244290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 244390792Sgshapirodnl 2 3 4 5 244490792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 244590792Sgshapirodnl match, return <match> <passthru> 244690792Sgshapirodnl 2 3 4 5 244790792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 244890792Sgshapiro 244990792Sgshapiro###################################################################### 245090792Sgshapiro### E: LookUpExact -- search for an entry in access database 245190792Sgshapiro### 245290792Sgshapiro### Parameters: 245390792Sgshapiro### <$1> -- key 245490792Sgshapiro### <$2> -- default (what to return if not found in db) 245590792Sgshapirodnl must not be empty 245690792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 245790792Sgshapiro### ! does lookup only with tag 245890792Sgshapiro### + does lookup with and without tag 245990792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 246090792Sgshapirodnl returns: <default> <passthru> 246190792Sgshapirodnl <result> <passthru> 246290792Sgshapiro###################################################################### 246390792Sgshapiro 246490792SgshapiroSE 246590792Sgshapirodnl 2 3 4 5 246690792SgshapiroR<$*> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 246790792Sgshapirodnl no match, try without tag 246890792Sgshapirodnl 1 2 3 4 246990792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 247090792Sgshapirodnl no match, return default passthru 247190792Sgshapirodnl 1 2 3 4 5 247290792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 247390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 247490792Sgshapirodnl 2 3 4 5 247590792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 247690792Sgshapirodnl match, return <match> <passthru> 247790792Sgshapirodnl 2 3 4 5 247890792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 247990792Sgshapiro 248090792Sgshapiro###################################################################### 248190792Sgshapiro### U: LookUpUser -- search for an entry in access database 248290792Sgshapiro### 248390792Sgshapiro### lookup of key (which should be a local part) and 248490792Sgshapiro### variations if +detail exists: +* and without +detail 248590792Sgshapiro### 248690792Sgshapiro### Parameters: 248790792Sgshapiro### <$1> -- key (user@) 248890792Sgshapiro### <$2> -- default (what to return if not found in db) 248990792Sgshapirodnl must not be empty 249090792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 249190792Sgshapiro### ! does lookup only with tag 249290792Sgshapiro### + does lookup with and without tag 249390792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 249490792Sgshapirodnl returns: <default> <passthru> 249590792Sgshapirodnl <result> <passthru> 249690792Sgshapiro###################################################################### 249790792Sgshapiro 249890792SgshapiroSU 249990792Sgshapirodnl user lookups are always with trailing @ 250090792Sgshapirodnl 2 3 4 5 250190792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 250290792Sgshapirodnl no match, try without tag 250390792Sgshapirodnl 1 2 3 4 250490792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 250590792Sgshapirodnl do not remove the @ from the lookup: 250690792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup 250790792Sgshapirodnl no match, +detail: try +* 250890792Sgshapirodnl 1 2 3 4 5 6 250990792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 251090792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 251190792Sgshapirodnl no match, +detail: try +* without tag 251290792Sgshapirodnl 1 2 3 4 5 251390792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 251490792Sgshapiro $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 251590792Sgshapirodnl no match, +detail: try without +detail 251690792Sgshapirodnl 1 2 3 4 5 6 251790792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 251890792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 251990792Sgshapirodnl no match, +detail: try without +detail and without tag 252090792Sgshapirodnl 1 2 3 4 5 252190792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 252290792Sgshapiro $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 252390792Sgshapirodnl no match, return <default> <passthru> 252490792Sgshapirodnl 1 2 3 4 5 252590792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 252690792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 252790792Sgshapirodnl 2 3 4 5 252890792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 252990792Sgshapirodnl match, return <match> <passthru> 253090792Sgshapirodnl 2 3 4 5 253190792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 253290792Sgshapiro 253390792Sgshapiro###################################################################### 253464562Sgshapiro### SearchList: search a list of items in the access map 253564562Sgshapiro### Parameters: 253664562Sgshapiro### <exact tag> $| <mark:address> <mark:address> ... <> 253764562Sgshapirodnl maybe we should have a @ (again) in front of the mark to 253864562Sgshapirodnl avoid errorneous matches (with error messages?) 253964562Sgshapirodnl if we can make sure that tag is always a single token 254064562Sgshapirodnl then we can omit the delimiter $|, otherwise we need it 254190792Sgshapirodnl to avoid errorneous matchs (first rule: D: if there 254264562Sgshapirodnl is that mark somewhere in the list, it will be taken). 254364562Sgshapirodnl moreover, we can do some tricks to enforce lookup with 254464562Sgshapirodnl the tag only, e.g.: 254564562Sgshapiro### where "exact" is either "+" or "!": 254664562Sgshapiro### <+ TAG> lookup with and w/o tag 254764562Sgshapiro### <! TAG> lookup with tag 254864562Sgshapirodnl Warning: + and ! should be in OperatorChars (otherwise there must be 254964562Sgshapirodnl a blank between them and the tag. 255064562Sgshapiro### possible values for "mark" are: 255190792Sgshapiro### D: recursive host lookup (LookUpDomain) 255264562Sgshapirodnl A: recursive address lookup (LookUpAddress) [not yet required] 255364562Sgshapiro### E: exact lookup, no modifications 255464562Sgshapiro### F: full lookup, try user+ext@domain and user@domain 255564562Sgshapiro### U: user lookup, try user+ext and user (input must have trailing @) 255664562Sgshapiro### return: <RHS of lookup> or <?> (not found) 255764562Sgshapiro###################################################################### 255838032Speter 255964562Sgshapiro# class with valid marks for SearchList 256064562Sgshapirodnl if A is activated: add it 2561132943SgshapiroC{Src}E F D U ifdef(`_FFR_SRCHLIST_A', `A') 256264562SgshapiroSSearchList 256390792Sgshapiro# just call the ruleset with the name of the tag... nice trick... 256490792Sgshapirodnl 2 3 4 2565132943SgshapiroR<$+> $| <$={Src}:$*> <$*> $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <> 256690792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <> 256790792Sgshapirodnl no match and nothing left: return 256890792SgshapiroR<$+> $| <> $| <?> <> $@ <?> 256990792Sgshapirodnl no match but something left: continue 257090792SgshapiroR<$+> $| <$+> $| <?> <> $@ $>SearchList <$1> $| <$2> 257190792Sgshapirodnl match: return 257290792SgshapiroR<$+> $| <$*> $| <$+> <> $@ <$3> 257364562Sgshapirodnl return result from recursive invocation 257490792SgshapiroR<$+> $| <$+> $@ <$2> 257590792Sgshapirodnl endif _ACCESS_TABLE_ 257690792Sgshapirodivert(0) 257738032Speter 257890792Sgshapiro###################################################################### 257990792Sgshapiro### trust_auth: is user trusted to authenticate as someone else? 258090792Sgshapiro### 258190792Sgshapiro### Parameters: 258290792Sgshapiro### $1: AUTH= parameter from MAIL command 258390792Sgshapiro###################################################################### 258490792Sgshapiro 258590792Sgshapirodnl empty ruleset definition so it can be called 258690792SgshapiroSLocal_trust_auth 258764562SgshapiroStrust_auth 258864562SgshapiroR$* $: $&{auth_type} $| $1 258964562Sgshapiro# required by RFC 2554 section 4. 259064562SgshapiroR$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 259164562Sgshapirodnl seems to be useful... 259264562SgshapiroR$* $| $&{auth_authen} $@ identical 259364562SgshapiroR$* $| <$&{auth_authen}> $@ identical 259464562Sgshapirodnl call user supplied code 2595120256SgshapiroR$* $| $* $: $1 $| $>"Local_trust_auth" $2 259664562SgshapiroR$* $| $#$* $#$2 259764562Sgshapirodnl default: error 259864562SgshapiroR$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 259964562Sgshapiro 260090792Sgshapiro###################################################################### 260190792Sgshapiro### Relay_Auth: allow relaying based on authentication? 260290792Sgshapiro### 260390792Sgshapiro### Parameters: 260490792Sgshapiro### $1: ${auth_type} 260590792Sgshapiro###################################################################### 260690792SgshapiroSLocal_Relay_Auth 260764562Sgshapiro 260890792Sgshapiro###################################################################### 260990792Sgshapiro### srv_features: which features to offer to a client? 261090792Sgshapiro### (done in server) 261190792Sgshapiro###################################################################### 261290792SgshapiroSsrv_features 261390792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl 261490792SgshapiroR$* $: $1 $| $>"Local_srv_features" $1 261590792SgshapiroR$* $| $#$* $#$2 261690792SgshapiroR$* $| $* $: $1', `dnl') 2617132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 261890792SgshapiroR$* $: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <> 261990792SgshapiroR<?>$* $: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <> 262090792SgshapiroR<?>$* $: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)> 262164562SgshapiroR<?>$* $@ OK 262290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 262390792SgshapiroR<$* _ATMPF_>$* $#temp', `dnl') 2624132943SgshapiroR<$+>$* $# $1') 262564562Sgshapiro 262690792Sgshapiro###################################################################### 262790792Sgshapiro### try_tls: try to use STARTTLS? 262890792Sgshapiro### (done in client) 262990792Sgshapiro###################################################################### 263064562SgshapiroStry_tls 263190792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl 263290792SgshapiroR$* $: $1 $| $>"Local_try_tls" $1 263390792SgshapiroR$* $| $#$* $#$2 263490792SgshapiroR$* $| $* $: $1', `dnl') 2635132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 263690792SgshapiroR$* $: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <> 263790792SgshapiroR<?>$* $: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <> 263890792SgshapiroR<?>$* $: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)> 263964562SgshapiroR<?>$* $@ OK 264090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 264190792SgshapiroR<$* _ATMPF_>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2642132943SgshapiroR<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"') 2643132943Sgshapiro 264490792Sgshapiro###################################################################### 264590792Sgshapiro### tls_rcpt: is connection with server "good" enough? 264690792Sgshapiro### (done in client, per recipient) 264790792Sgshapirodnl called from deliver() before RCPT command 264890792Sgshapiro### 264990792Sgshapiro### Parameters: 265090792Sgshapiro### $1: recipient 265190792Sgshapiro###################################################################### 265290792SgshapiroStls_rcpt 265390792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl 265490792SgshapiroR$* $: $1 $| $>"Local_tls_rcpt" $1 265590792SgshapiroR$* $| $#$* $#$2 265690792SgshapiroR$* $| $* $: $1', `dnl') 2657132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 265890792Sgshapirodnl store name of other side 265990792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 266090792Sgshapirodnl canonify recipient address 266190792SgshapiroR$+ $: <?> $>CanonAddr $1 266290792Sgshapirodnl strip trailing dots 266390792SgshapiroR<?> $+ < @ $+ . > <?> $1 <@ $2 > 266490792Sgshapirodnl full address? 266590792SgshapiroR<?> $+ < @ $+ > $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:> 266690792Sgshapirodnl only localpart? 266790792SgshapiroR<?> $+ $: $1 $| <U:$1@> <E:> 266890792Sgshapirodnl look it up 266990792Sgshapirodnl also look up a default value via E: 267090792SgshapiroR$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <> 267190792Sgshapirodnl found nothing: stop here 267290792SgshapiroR$* $| <?> $@ OK 267390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 267490792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 267590792Sgshapirodnl use the generic routine (for now) 267690792SgshapiroR$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>') 267764562Sgshapiro 267890792Sgshapiro###################################################################### 267990792Sgshapiro### tls_client: is connection with client "good" enough? 268090792Sgshapiro### (done in server) 268190792Sgshapiro### 268290792Sgshapiro### Parameters: 268390792Sgshapiro### ${verify} $| (MAIL|STARTTLS) 268490792Sgshapiro###################################################################### 268564562Sgshapirodnl MAIL: called from check_mail 268664562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted 268764562SgshapiroStls_client 268890792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl 2689182352SgshapiroR$* $: $1 <?> $>"Local_tls_client" $1 2690182352SgshapiroR$* <?> $#$* $#$2 2691182352SgshapiroR$* <?> $* $: $1', `dnl') 269264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 269390792Sgshapirodnl store name of other side 269490792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 269564562Sgshapirodnl ignore second arg for now 269664562Sgshapirodnl maybe use it to distinguish permanent/temporary error? 269764562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered) 269864562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed) 269990792SgshapiroR$* $| $* $: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <> 270090792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <> 270164562Sgshapirodnl do a default lookup: just TLS_CLT_TAG 270264562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 270390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 270490792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 270590792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 270690792SgshapiroR$* $| $* $@ $>"TLS_connection" $1') 270764562Sgshapiro 270890792Sgshapiro###################################################################### 270990792Sgshapiro### tls_server: is connection with server "good" enough? 271090792Sgshapiro### (done in client) 271190792Sgshapiro### 271290792Sgshapiro### Parameter: 271390792Sgshapiro### ${verify} 271490792Sgshapiro###################################################################### 271564562Sgshapirodnl i.e. has the server been authenticated and is encryption active? 271664562Sgshapirodnl called from deliver() after STARTTLS command 271764562SgshapiroStls_server 271890792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl 271990792SgshapiroR$* $: $1 $| $>"Local_tls_server" $1 272090792SgshapiroR$* $| $#$* $#$2 272190792SgshapiroR$* $| $* $: $1', `dnl') 272264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 272390792Sgshapirodnl store name of other side 272490792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 272590792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <> 272690792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <> 272764562Sgshapirodnl do a default lookup: just TLS_SRV_TAG 272864562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 272990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 273090792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 273190792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 273290792SgshapiroR$* $@ $>"TLS_connection" $1') 273364562Sgshapiro 273490792Sgshapiro###################################################################### 273590792Sgshapiro### TLS_connection: is TLS connection "good" enough? 273690792Sgshapiro### 273790792Sgshapiro### Parameters: 273864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 273990792Sgshapiro### ${verify} $| <Requirement> [<>]', `dnl 274090792Sgshapiro### ${verify}') 274190792Sgshapiro### Requirement: RHS from access map, may be ? for none. 274290792Sgshapirodnl syntax for Requirement: 274390792Sgshapirodnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions] 274490792Sgshapirodnl extensions: could be a list of further requirements 274590792Sgshapirodnl for now: CN:string {cn_subject} == string 274690792Sgshapiro###################################################################### 274790792SgshapiroSTLS_connection 274890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error 274990792Sgshapirodnl deal with TLS handshake failures: abort 275090792SgshapiroRSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake." 275190792Sgshapirodivert(-1)') 275264562Sgshapirodnl common ruleset for tls_{client|server} 275390792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>] 275464562Sgshapirodnl remove optional <> 275564562SgshapiroR$* $| <$*>$* $: $1 $| <$2> 275690792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup> 275790792Sgshapiro# create the appropriate error codes 275864562Sgshapirodnl permanent or temporary error? 2759132943SgshapiroR$* $| <PERM + $={Tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 2760132943SgshapiroR$* $| <TEMP + $={Tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 276164562Sgshapirodnl default case depends on TLS_PERM_ERR 2762132943SgshapiroR$* $| <$={Tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 276390792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup> 276490792Sgshapiro# deal with TLS handshake failures: abort 276564562SgshapiroRSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 276664562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 276764562Sgshapirodnl use default error 276864562SgshapiroRSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 2769157001Sgshapiro# deal with TLS protocol errors: abort 2770157001SgshapiroRPROTOCOL $| <$-:$+> $* $#error $@ $2 $: $1 " STARTTLS failed." 2771157001Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 2772157001Sgshapirodnl use default error 2773157001SgshapiroRPROTOCOL $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') STARTTLS failed." 277490792SgshapiroR$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1 277590792Sgshapirodnl separate optional requirements 277690792SgshapiroR$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1 2777132943SgshapiroR$* $| <$*> <$={Tls}:$->$* $: <$2> <$3:$4> <> $1 277890792Sgshapirodnl separate optional requirements 2779132943SgshapiroR$* $| <$*> <$={Tls}:$- + $+>$* $: <$2> <$3:$4> <$5> $1 278064562Sgshapirodnl some other value in access map: accept 278164562Sgshapirodnl this also allows to override the default case (if used) 278264562SgshapiroR$* $| $* $@ OK 278364562Sgshapiro# authentication required: give appropriate error 278464562Sgshapiro# other side did authenticate (via STARTTLS) 278590792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify} 278664562Sgshapirodnl only verification required and it succeeded 278790792SgshapiroR<$*><VERIFY> <> OK $@ OK 278890792Sgshapirodnl verification required and it succeeded but extensions are given 278990792Sgshapirodnl change it to <SMTP:ESC> <REQ:0> <extensions> 279090792SgshapiroR<$*><VERIFY> <$+> OK $: <$1> <REQ:0> <$2> 279164562Sgshapirodnl verification required + some level of encryption 279290792SgshapiroR<$*><VERIFY:$-> <$*> OK $: <$1> <REQ:$2> <$3> 279364562Sgshapirodnl just some level of encryption required 279490792SgshapiroR<$*><ENCR:$-> <$*> $* $: <$1> <REQ:$2> <$3> 279590792Sgshapirodnl workspace: 279690792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]> <[extensions]> {verify} (!= OK) 279790792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits> <[extensions]> 279890792Sgshapirodnl verification required but ${verify} is not set (case 1.) 279990792SgshapiroR<$-:$+><VERIFY $*> <$*> $#error $@ $2 $: $1 " authentication required" 280090792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL $#error $@ $2 $: $1 " authentication failed" 280190792SgshapiroR<$-:$+><VERIFY $*> <$*> NO $#error $@ $2 $: $1 " not authenticated" 280290792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT $#error $@ $2 $: $1 " no authentication requested" 280390792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 280464562Sgshapirodnl some other value for ${verify} 280590792SgshapiroR<$-:$+><VERIFY $*> <$*> $+ $#error $@ $2 $: $1 " authentication failure " $4 280690792Sgshapirodnl some level of encryption required: get the maximum level (case 2.) 280790792SgshapiroR<$*><REQ:$-> <$*> $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf} 280864562Sgshapirodnl compare required bits with actual bits 280990792SgshapiroR<$*><REQ:$-> <$*> $- $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $) 281090792SgshapiroR<$-:$+><$-:$-> <$*> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 281190792Sgshapirodnl strength requirements fulfilled 281290792Sgshapirodnl TLS Additional Requirements Separator 281390792Sgshapirodnl this should be something which does not appear in the extensions itself 281490792Sgshapirodnl @ could be part of a CN, DN, etc... 281590792Sgshapirodnl use < > ? those are encoded in CN, DN, ... 281690792Sgshapirodefine(`_TLS_ARS_', `++')dnl 281790792Sgshapirodnl workspace: 281890792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare 281990792SgshapiroR<$-:$+><$-:$-> <$*> $* $: <$1:$2 _TLS_ARS_ $5> 282090792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions> 282190792Sgshapirodnl continue: check extensions 282290792SgshapiroR<$-:$+ _TLS_ARS_ > $@ OK 282390792Sgshapirodnl split extensions into own list 282490792SgshapiroR<$-:$+ _TLS_ARS_ $+ > $: <$1:$2> <$3> 282590792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ > <$1:$2> <$3> <$4> 282690792SgshapiroR<$-:$+> $+ $@ $>"TLS_req" $3 $| <$1:$2> 282764562Sgshapiro 282890792Sgshapiro###################################################################### 282990792Sgshapiro### TLS_req: check additional TLS requirements 283090792Sgshapiro### 283190792Sgshapiro### Parameters: [<list> <of> <req>] $| <$-:$+> 283290792Sgshapiro### $-: SMTP reply code 283390792Sgshapiro### $+: Enhanced Status Code 283490792Sgshapirodnl further requirements for this ruleset: 283590792Sgshapirodnl name of "other side" is stored is {TLS_name} (client/server_name) 283690792Sgshapirodnl 283790792Sgshapirodnl currently only CN[:common_name] is implemented 283890792Sgshapirodnl right now this is only a logical AND 283990792Sgshapirodnl i.e. all requirements must be true 284090792Sgshapirodnl how about an OR? CN must be X or CN must be Y or .. 284190792Sgshapirodnl use a macro to compute this as a trivial sequential 284290792Sgshapirodnl operations (no precedences etc)? 284390792Sgshapiro###################################################################### 284490792SgshapiroSTLS_req 284590792Sgshapirodnl no additional requirements: ok 284690792SgshapiroR $| $+ $@ OK 284790792Sgshapirodnl require CN: but no CN specified: use name of other side 284890792SgshapiroR<CN> $* $| <$+> $: <CN:$&{TLS_Name}> $1 $| <$2> 284990792Sgshapirodnl match, check rest 285090792SgshapiroR<CN:$&{cn_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 285190792Sgshapirodnl CN does not match 285290792Sgshapirodnl 1 2 3 4 285390792SgshapiroR<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1 285490792Sgshapirodnl cert subject 285590792SgshapiroR<CS:$&{cert_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 285690792Sgshapirodnl CS does not match 285790792Sgshapirodnl 1 2 3 4 2858110560SgshapiroR<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1 285990792Sgshapirodnl match, check rest 286090792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 286190792Sgshapirodnl CI does not match 286290792Sgshapirodnl 1 2 3 4 2863110560SgshapiroR<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1 286490792Sgshapirodnl return from recursive call 286590792SgshapiroROK $@ OK 286690792Sgshapiro 286790792Sgshapiro###################################################################### 286890792Sgshapiro### max: return the maximum of two values separated by : 286990792Sgshapiro### 287090792Sgshapiro### Parameters: [$-]:[$-] 287190792Sgshapiro###################################################################### 287264562SgshapiroSmax 287364562SgshapiroR: $: 0 287464562SgshapiroR:$- $: $1 287564562SgshapiroR$-: $: $1 287664562SgshapiroR$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 287764562SgshapiroRTRUE:$-:$- $: $2 287890792SgshapiroR$-:$-:$- $: $2 287990792Sgshapirodnl endif _ACCESS_TABLE_ 288090792Sgshapirodivert(0) 288164562Sgshapiro 288290792Sgshapiro###################################################################### 288390792Sgshapiro### RelayTLS: allow relaying based on TLS authentication 288490792Sgshapiro### 288590792Sgshapiro### Parameters: 288690792Sgshapiro### none 288790792Sgshapiro###################################################################### 288890792SgshapiroSRelayTLS 288964562Sgshapiro# authenticated? 289064562Sgshapirodnl we do not allow relaying for anyone who can present a cert 289164562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns 2892110560Sgshapirodnl CA in CertPath so we can authenticate users, we do not allow 289364562Sgshapirodnl them to abuse our server (they might be easier to get hold of, 289464562Sgshapirodnl but anyway). 289564562Sgshapirodnl so here is the trick: if the verification succeeded 289664562Sgshapirodnl we look up the cert issuer in the access map 289764562Sgshapirodnl (maybe after extracting a part with a regular expression) 289864562Sgshapirodnl if this returns RELAY we relay without further questions 289964562Sgshapirodnl if it returns SUBJECT we perform a similar check on the 290064562Sgshapirodnl cert subject. 290164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 290290792SgshapiroR$* $: <?> $&{verify} 290390792SgshapiroR<?> OK $: OK authenticated: continue 290490792SgshapiroR<?> $* $@ NO not authenticated 290564562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 290690792SgshapiroR$* $: $(CERTIssuer $&{cert_issuer} $)', 290790792Sgshapiro`R$* $: $&{cert_issuer}') 290890792SgshapiroR$+ $: $(access CERTISSUER`'_TAG_DELIM_`'$1 $) 290964562Sgshapirodnl use $# to stop further checks (delay_check) 291090792SgshapiroRRELAY $# RELAY 291164562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 291290792SgshapiroRSUBJECT $: <@> $(CERTSubject $&{cert_subject} $)', 291390792Sgshapiro`RSUBJECT $: <@> $&{cert_subject}') 291490792SgshapiroR<@> $+ $: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $) 291590792SgshapiroR<@> RELAY $# RELAY 291690792SgshapiroR$* $: NO', `dnl') 291764562Sgshapiro 291890792Sgshapiro###################################################################### 291990792Sgshapiro### authinfo: lookup authinfo in the access map 292090792Sgshapiro### 292190792Sgshapiro### Parameters: 292290792Sgshapiro### $1: {server_name} 292390792Sgshapiro### $2: {server_addr} 292490792Sgshapirodnl both are currently ignored 292590792Sgshapirodnl if it should be done via another map, we either need to restrict 292690792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another 292790792Sgshapirodnl parameter which I want to avoid, it's quite complex already) 292890792Sgshapiro###################################################################### 292990792Sgshapirodnl omit this ruleset if neither is defined? 293090792Sgshapirodnl it causes DefaultAuthInfo to be ignored 293190792Sgshapirodnl (which may be considered a good thing). 293290792SgshapiroSauthinfo 293390792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl 293490792SgshapiroR$* $: <$(authinfo AuthInfo:$&{server_name} $: ? $)> 293590792SgshapiroR<?> $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)> 293690792SgshapiroR<?> $: <$(authinfo AuthInfo: $: ? $)> 293790792SgshapiroR<?> $@ no no authinfo available 293890792SgshapiroR<$*> $# $1 293990792Sgshapirodnl', `dnl 294090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 294190792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <> 294290792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <> 294390792SgshapiroR$* $| <?>$* $: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <> 294490792SgshapiroR$* $| <?>$* $@ no no authinfo available 294590792SgshapiroR$* $| <$*> <> $# $2 294690792Sgshapirodnl', `dnl')') 294790792Sgshapiro 2948132943Sgshapiroifdef(`_RATE_CONTROL_',`dnl 2949132943Sgshapiro###################################################################### 2950132943Sgshapiro### RateControl: 2951132943Sgshapiro### Parameters: ignored 2952132943Sgshapiro### return: $#error or OK 2953132943Sgshapiro###################################################################### 2954132943SgshapiroSRateControl 2955132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 2956132943SgshapiroR$* $: <A:$&{client_addr}> <E:> 2957132943Sgshapirodnl also look up a default value via E: 2958132943SgshapiroR$+ $: $>SearchList <! ClientRate> $| $1 <> 2959132943Sgshapirodnl found nothing: stop here 2960132943SgshapiroR<?> $@ OK 2961132943Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 2962132943SgshapiroR<$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2963132943Sgshapirodnl use the generic routine (for now) 2964132943SgshapiroR<0> $@ OK no limit 2965173340SgshapiroR<$+> $: <$1> $| $(arith l $@ $1 $@ $&{client_rate} $) 2966132943Sgshapirodnl log this? Connection rate $&{client_rate} exceeds limit $1. 2967173340SgshapiroR<$+> $| TRUE $#error $@ 4.3.2 $: _RATE_CONTROL_REPLY Connection rate limit exceeded. 2968132943Sgshapiro')') 2969132943Sgshapiro 2970132943Sgshapiroifdef(`_CONN_CONTROL_',`dnl 2971132943Sgshapiro###################################################################### 2972132943Sgshapiro### ConnControl: 2973132943Sgshapiro### Parameters: ignored 2974132943Sgshapiro### return: $#error or OK 2975132943Sgshapiro###################################################################### 2976132943SgshapiroSConnControl 2977132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 2978132943SgshapiroR$* $: <A:$&{client_addr}> <E:> 2979132943Sgshapirodnl also look up a default value via E: 2980132943SgshapiroR$+ $: $>SearchList <! ClientConn> $| $1 <> 2981132943Sgshapirodnl found nothing: stop here 2982132943SgshapiroR<?> $@ OK 2983132943Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 2984132943SgshapiroR<$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2985132943Sgshapirodnl use the generic routine (for now) 2986132943SgshapiroR<0> $@ OK no limit 2987173340SgshapiroR<$+> $: <$1> $| $(arith l $@ $1 $@ $&{client_connections} $) 2988132943Sgshapirodnl log this: Open connections $&{client_connections} exceeds limit $1. 2989173340SgshapiroR<$+> $| TRUE $#error $@ 4.3.2 $: _CONN_CONTROL_REPLY Too many open connections. 2990132943Sgshapiro')') 2991132943Sgshapiro 299264562Sgshapiroundivert(9)dnl LOCAL_RULESETS 299338032Speter# 299438032Speter###################################################################### 299538032Speter###################################################################### 299638032Speter##### 299764562Sgshapiro`##### MAIL FILTER DEFINITIONS' 299864562Sgshapiro##### 299964562Sgshapiro###################################################################### 300064562Sgshapiro###################################################################### 300190792Sgshapiro_MAIL_FILTERS_ 300264562Sgshapiro# 300364562Sgshapiro###################################################################### 300464562Sgshapiro###################################################################### 300564562Sgshapiro##### 300638032Speter`##### MAILER DEFINITIONS' 300738032Speter##### 300838032Speter###################################################################### 300938032Speter###################################################################### 301064562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS 301166494Sgshapiro 3012