proto.m4 revision 90792
138032Speterdivert(-1) 238032Speter# 390792Sgshapiro# Copyright (c) 1998-2001 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 1690792SgshapiroVERSIONID(`$Id: proto.m4,v 8.628 2001/12/28 19:02:40 ca Exp $') 1738032Speter 1864562Sgshapiro# level CF_LEVEL config file format 1964562SgshapiroV`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley') 2038032Speterdivert(-1) 2138032Speter 2290792Sgshapirodnl if MAILER(`local') not defined: do it ourself; be nice 2390792Sgshapirodnl maybe we should issue a warning? 2490792Sgshapiroifdef(`_MAILER_local_',`', `MAILER(local)') 2590792Sgshapiro 2638032Speter# do some sanity checking 2738032Speterifdef(`__OSTYPE__',, 2864562Sgshapiro `errprint(`*** ERROR: No system type defined (use OSTYPE macro) 2964562Sgshapiro')') 3038032Speter 3138032Speter# pick our default mailers 3238032Speterifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')') 3338032Speterifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')') 3438032Speterifdef(`confRELAY_MAILER',, 3538032Speter `define(`confRELAY_MAILER', 3638032Speter `ifdef(`_MAILER_smtp_', `relay', 3738032Speter `ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')') 3838032Speterifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')') 3938032Speterdefine(`_SMTP_', `confSMTP_MAILER')dnl for readability only 4038032Speterdefine(`_LOCAL_', `confLOCAL_MAILER')dnl for readability only 4138032Speterdefine(`_RELAY_', `confRELAY_MAILER')dnl for readability only 4238032Speterdefine(`_UUCP_', `confUUCP_MAILER')dnl for readability only 4338032Speter 4438032Speter# back compatibility with old config files 4538032Speterifdef(`confDEF_GROUP_ID', 4664562Sgshapiro`errprint(`*** confDEF_GROUP_ID is obsolete. 4764562Sgshapiro Use confDEF_USER_ID with a colon in the value instead. 4864562Sgshapiro')') 4938032Speterifdef(`confREAD_TIMEOUT', 5064562Sgshapiro`errprint(`*** confREAD_TIMEOUT is obsolete. 5164562Sgshapiro Use individual confTO_<timeout> parameters instead. 5264562Sgshapiro')') 5338032Speterifdef(`confMESSAGE_TIMEOUT', 5438032Speter `define(`_ARG_', index(confMESSAGE_TIMEOUT, /)) 5538032Speter ifelse(_ARG_, -1, 5638032Speter `define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)', 5738032Speter `define(`confTO_QUEUERETURN', 5838032Speter substr(confMESSAGE_TIMEOUT, 0, _ARG_)) 5938032Speter define(`confTO_QUEUEWARN', 6038032Speter substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')') 6138032Speterifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,, 6264562Sgshapiro`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete. 6364562Sgshapiro Use confMAX_MESSAGE_SIZE for the second part of the value. 6464562Sgshapiro')')') 6538032Speter 6664562Sgshapiro 6764562Sgshapiro# Sanity check on ldap_routing feature 6864562Sgshapiro# If the user doesn't specify a new map, they better have given as a 6964562Sgshapiro# default LDAP specification which has the LDAP base (and most likely the host) 7064562Sgshapiroifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(` 7164562SgshapiroWARNING: Using default FEATURE(ldap_routing) map definition(s) 7264562Sgshapirowithout setting confLDAP_DEFAULT_SPEC option. 7364562Sgshapiro')')')dnl 7464562Sgshapiro 7538032Speter# clean option definitions below.... 7664562Sgshapirodefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl 7738032Speter 7864562Sgshapirodnl required to "rename" the check_* rulesets... 7964562Sgshapirodefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_')) 8064562Sgshapirodnl default relaying denied message 8190792Sgshapiroifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG', 8290792Sgshapiroifdef(`_USE_AUTH_', `"550 Relaying denied. Proper authentication required."', `"550 Relaying denied"'))') 8390792Sgshapiroifdef(`confRCPTREJ_MSG', `', `define(`confRCPTREJ_MSG', `"550 Mailbox disabled for this recipient"')') 8490792Sgshapirodefine(`_CODE553', `553') 8538032Speterdivert(0)dnl 8638032Speter 8764562Sgshapiro# override file safeties - setting this option compromises system security, 8864562Sgshapiro# addressing the actual file configuration problem is preferred 8964562Sgshapiro# need to set this before any file actions are encountered in the cf file 9064562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe') 9138032Speter 9264562Sgshapiro# default LDAP map specification 9364562Sgshapiro# need to set this now before any LDAP maps are defined 9464562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost') 9564562Sgshapiro 9638032Speter################## 9738032Speter# local info # 9838032Speter################## 9938032Speter 10090792Sgshapiro# my LDAP cluster 10190792Sgshapiro# need to set this before any LDAP lookups are done (including classes) 10290792Sgshapiroifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m') 10390792Sgshapiro 10438032SpeterCwlocalhost 10538032Speterifdef(`USE_CW_FILE', 10638032Speter`# file containing names of hosts for which we receive email 10738032SpeterFw`'confCW_FILE', 10838032Speter `dnl') 10938032Speter 11038032Speter# my official domain name 11138032Speter# ... `define' this only if sendmail cannot automatically determine your domain 11238032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM') 11338032Speter 11438032SpeterCP. 11538032Speter 11638032Speterifdef(`UUCP_RELAY', 11738032Speter`# UUCP relay host 11838032SpeterDY`'UUCP_RELAY 11938032SpeterCPUUCP 12038032Speter 12138032Speter')dnl 12238032Speterifdef(`BITNET_RELAY', 12338032Speter`# BITNET relay host 12438032SpeterDB`'BITNET_RELAY 12538032SpeterCPBITNET 12638032Speter 12738032Speter')dnl 12838032Speterifdef(`DECNET_RELAY', 12938032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl 13038032Speter# DECnet relay host 13138032SpeterDC`'DECNET_RELAY 13238032SpeterCPDECNET 13338032Speter 13438032Speter')dnl 13538032Speterifdef(`FAX_RELAY', 13638032Speter`# FAX relay host 13738032SpeterDF`'FAX_RELAY 13838032SpeterCPFAX 13938032Speter 14038032Speter')dnl 14138032Speter# "Smart" relay host (may be null) 14290792SgshapiroDS`'ifdef(`SMART_HOST', `SMART_HOST') 14338032Speter 14438032Speterifdef(`LUSER_RELAY', `dnl 14538032Speter# place to which unknown users should be forwarded 14638032SpeterKuser user -m -a<> 14738032SpeterDL`'LUSER_RELAY', 14838032Speter`dnl') 14938032Speter 15038032Speter# operators that cannot be in local usernames (i.e., network indicators) 15138032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!') 15238032Speter 15338032Speter# a class with just dot (for identifying canonical names) 15438032SpeterC.. 15538032Speter 15638032Speter# a class with just a left bracket (for identifying domain literals) 15738032SpeterC[[ 15838032Speter 15964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 16064562Sgshapiro# access_db acceptance class 16164562SgshapiroC{Accept}OK RELAY 16290792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl 16364562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl 16464562Sgshapiro# possible access_db RHS for spam friends/haters 16564562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')', 16638032Speter`dnl') 16738032Speter 16890792Sgshapirodnl mark for "domain is ok" (resolved or accepted anyway) 16990792Sgshapirodefine(`_RES_OK_', `OKR')dnl 17038032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl 17138032Speter# Resolve map (to check if a host exists in check_mail) 17290792SgshapiroKresolve host -a<_RES_OK_> -T<TEMP>') 17390792SgshapiroC{ResOk}_RES_OK_ 17438032Speter 17580785Sgshapiroifdef(`_NEED_MACRO_MAP_', `dnl 17680785Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map 17780785Sgshapirodefine(`_MACRO_MAP_', `1')dnl 17880785SgshapiroKmacro macro')', `dnl') 17966494Sgshapiro 18038032Speterifdef(`confCR_FILE', `dnl 18166494Sgshapiro# Hosts for which relaying is permitted ($=R) 18238032SpeterFR`'confCR_FILE', 18338032Speter`dnl') 18438032Speter 18590792Sgshapirodefine(`TLS_SRV_TAG', `"TLS_Srv"')dnl 18690792Sgshapirodefine(`TLS_CLT_TAG', `"TLS_Clt"')dnl 18790792Sgshapirodefine(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl 18890792Sgshapirodefine(`TLS_TRY_TAG', `"Try_TLS"')dnl 18990792Sgshapirodefine(`SRV_FEAT_TAG', `"Srv_Features"')dnl 19064562Sgshapirodnl this may be useful in other contexts too 19164562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map 19264562Sgshapirodefine(`_ARITH_MAP_', `1')dnl 19364562SgshapiroKarith arith') 19464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 19590792Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map 19690792Sgshapirodefine(`_MACRO_MAP_', `1')dnl 19790792SgshapiroKmacro macro') 19890792Sgshapiro# possible values for TLS_connection in access map 19964562SgshapiroC{tls}VERIFY ENCR', `dnl') 20064562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 20164562Sgshapiro# extract relevant part from cert issuer 20264562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl') 20364562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 20464562Sgshapiro# extract relevant part from cert subject 20564562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl') 20664562Sgshapiro 20790792Sgshapiroifdef(`LOCAL_RELAY', `dnl 20838032Speter# who I send unqualified names to (null means deliver locally) 20990792SgshapiroDR`'LOCAL_RELAY') 21038032Speter 21190792Sgshapiroifdef(`MAIL_HUB', `dnl 21238032Speter# who gets all local email traffic ($R has precedence for unqualified names) 21390792SgshapiroDH`'MAIL_HUB') 21438032Speter 21538032Speter# dequoting map 21690792SgshapiroKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `') 21738032Speter 21838032Speterdivert(0)dnl # end of nullclient diversion 21938032Speter# class E: names that should be exposed as from this host, even if we masquerade 22064562Sgshapiro# class L: names that should be delivered locally, even if we have a relay 22138032Speter# class M: domains that should be converted to $M 22264562Sgshapiro# class N: domains that should not be converted to $M 22338032Speter#CL root 22438032Speterundivert(5)dnl 22564562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl') 22638032Speter 22790792Sgshapiroifdef(`MASQUERADE_NAME', `dnl 22838032Speter# who I masquerade as (null for no masquerading) (see also $=M) 22990792SgshapiroDM`'MASQUERADE_NAME') 23038032Speter 23138032Speter# my name for error messages 23238032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON') 23338032Speter 23464562Sgshapiroundivert(6)dnl LOCAL_CONFIG 23538032Speterinclude(_CF_DIR_`m4/version.m4') 23638032Speter 23738032Speter############### 23838032Speter# Options # 23938032Speter############### 24090792Sgshapiroifdef(`confAUTO_REBUILD', 24190792Sgshapiro`errprint(WARNING: `confAUTO_REBUILD' is no longer valid. 24290792Sgshapiro There was a potential for a denial of service attack if this is set. 24390792Sgshapiro)')dnl 24438032Speter 24538032Speter# strip message body to 7 bits on input? 24664562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False') 24738032Speter 24838032Speter# 8-bit data handling 24977349Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8') 25038032Speter 25138032Speter# wait for alias file rebuild (default units: minutes) 25264562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m') 25338032Speter 25438032Speter# location of alias file 25564562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases') 25664562Sgshapiro 25738032Speter# minimum number of free blocks on filesystem 25864562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100') 25938032Speter 26038032Speter# maximum message size 26164562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000') 26238032Speter 26338032Speter# substitution for space (blank) characters 26464562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_') 26538032Speter 26638032Speter# avoid connecting to "expensive" mailers on initial submission? 26764562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False') 26838032Speter 26938032Speter# checkpoint queue runs after every N successful deliveries 27064562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10') 27138032Speter 27238032Speter# default delivery mode 27364562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background') 27438032Speter 27538032Speter# error message header/file 27664562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header') 27738032Speter 27838032Speter# error mode 27964562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print') 28038032Speter 28138032Speter# save Unix-style "From_" lines at top of header? 28264562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False') 28338032Speter 28490792Sgshapiro# queue file mode (qf files) 28590792Sgshapiro_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600') 28690792Sgshapiro 28738032Speter# temporary file mode 28864562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600') 28938032Speter 29038032Speter# match recipients against GECOS field? 29164562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False') 29238032Speter 29338032Speter# maximum hop count 29490792Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `25') 29538032Speter 29638032Speter# location of help file 29764562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile') 29838032Speter 29938032Speter# ignore dots as terminators in incoming messages? 30064562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False') 30138032Speter 30238032Speter# name resolver options 30364562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY') 30438032Speter 30538032Speter# deliver MIME-encapsulated error messages? 30664562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True') 30738032Speter 30838032Speter# Forward file search path 30964562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward') 31038032Speter 31138032Speter# open connection cache size 31264562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2') 31338032Speter 31438032Speter# open connection cache timeout 31564562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m') 31638032Speter 31738032Speter# persistent host status directory 31864562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat') 31938032Speter 32038032Speter# single thread deliveries (requires HostStatusDirectory)? 32164562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False') 32238032Speter 32338032Speter# use Errors-To: header? 32464562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False') 32538032Speter 32638032Speter# log level 32764562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10') 32838032Speter 32938032Speter# send to me too, even in an alias expansion? 33064562Sgshapiro_OPTION(MeToo, `confME_TOO', `True') 33138032Speter 33238032Speter# verify RHS in newaliases? 33364562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False') 33438032Speter 33538032Speter# default messages to old style headers if no special punctuation? 33664562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False') 33738032Speter 33838032Speter# SMTP daemon options 33964562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl', 34064562Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. See cf/README for more information. 34164562Sgshapiro)'dnl 34264562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')') 34366494Sgshapiroifelse(defn(`_DPO_'), `', 34490792Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet 34590792SgshapiroO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_') 34664562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E') 34738032Speter 34864562Sgshapiro# SMTP client options 34990792Sgshapiroifelse(defn(`confCLIENT_OPTIONS'), `', `dnl', 35090792Sgshapiro`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid. See cf/README for more information. 35190792Sgshapiro)'dnl 35290792Sgshapiro`CLIENT_OPTIONS(`confCLIENT_OPTIONS')') 35390792Sgshapiroifelse(defn(`_CPO_'), `', 35490792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_') 35564562Sgshapiro 35690792Sgshapiro# Modifiers to `define' {daemon_flags} for direct submissions 35790792Sgshapiro_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `') 35890792Sgshapiro 35990792Sgshapiro# Use as mail submission program? See sendmail/SECURITY 36090792Sgshapiro_OPTION(UseMSP, `confUSE_MSP', `') 36190792Sgshapiro 36238032Speter# privacy flags 36364562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings') 36438032Speter 36538032Speter# who (if anyone) should get extra copies of error messages 36664562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster') 36738032Speter 36838032Speter# slope of queue-only function 36964562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000') 37038032Speter 37190792Sgshapiro# limit on number of concurrent queue runners 37290792Sgshapiro_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `') 37390792Sgshapiro 37490792Sgshapiro# maximum number of queue-runners per queue-grouping with multiple queues 37590792Sgshapiro_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1') 37690792Sgshapiro 37790792Sgshapiro# priority of queue runners (nice(3)) 37890792Sgshapiro_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `') 37990792Sgshapiro 38090792Sgshapiro# shall we sort the queue by hostname first? 38190792Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority') 38290792Sgshapiro 38390792Sgshapiro# minimum time in queue before retry 38490792Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m') 38590792Sgshapiro 38690792Sgshapiro# how many jobs can you process in the queue? 38790792Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000') 38890792Sgshapiro 38990792Sgshapiro# perform initial split of envelope without checking MX records 39090792Sgshapiro_OPTION(FastSplit, `confFAST_SPLIT', `1') 39190792Sgshapiro 39238032Speter# queue directory 39364562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue') 39438032Speter 39590792Sgshapiro# key for shared memory; 0 to turn off 39690792Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0') 39790792Sgshapiro 39838032Speter# timeouts (many of these) 39964562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m') 40064562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m') 40190792Sgshapiro_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s') 40264562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m') 40364562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m') 40464562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m') 40564562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h') 40664562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m') 40764562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h') 40864562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h') 40964562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m') 41064562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m') 41164562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m') 41264562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h') 41364562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s') 41464562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s') 41564562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m') 41664562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d') 41764562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d') 41864562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d') 41964562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d') 42064562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h') 42164562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h') 42264562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h') 42364562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h') 42464562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m') 42564562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s') 42664562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s') 42764562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s') 42864562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4') 42964562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4') 43064562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4') 43190792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m') 43290792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m') 43390792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h') 43438032Speter 43590792Sgshapiro# time for DeliverBy; extension disabled if less than 0 43690792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0') 43790792Sgshapiro 43838032Speter# should we not prune routes in route-addr syntax addresses? 43964562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False') 44038032Speter 44138032Speter# queue up everything before forking? 44264562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True') 44338032Speter 44438032Speter# status file 44564562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics') 44638032Speter 44738032Speter# time zone handling: 44838032Speter# if undefined, use system default 44938032Speter# if defined but null, use TZ envariable passed in 45038032Speter# if defined and non-null, use that info 45138032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=', 45238032Speter confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=', 45338032Speter `O TimeZoneSpec=confTIME_ZONE') 45438032Speter 45538032Speter# default UID (can be username or userid:groupid) 45664562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull') 45738032Speter 45838032Speter# list of locations of user database file (null means no lookup) 45964562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb') 46038032Speter 46138032Speter# fallback MX host 46264562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net') 46338032Speter 46438032Speter# if we are the best MX host for a site, try it directly instead of config err 46564562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False') 46638032Speter 46738032Speter# load average at which we just queue messages 46864562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8') 46938032Speter 47038032Speter# load average at which we refuse connections 47164562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12') 47238032Speter 47390792Sgshapiro# load average at which we delay connections; 0 means no limit 47490792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0') 47590792Sgshapiro 47638032Speter# maximum number of children we allow at one time 47764562Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12') 47838032Speter 47938032Speter# maximum number of new connections per second 48071345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0') 48138032Speter 48238032Speter# work recipient factor 48364562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') 48438032Speter 48538032Speter# deliver each queued job in a separate process? 48664562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False') 48738032Speter 48838032Speter# work class factor 48964562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800') 49038032Speter 49138032Speter# work time factor 49264562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000') 49338032Speter 49438032Speter# default character set 49564562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1') 49638032Speter 49790792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others) 49864562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch') 49938032Speter 50038032Speter# hosts file (normally /etc/hosts) 50164562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts') 50238032Speter 50338032Speter# dialup line delay on connection failure 50464562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s') 50538032Speter 50638032Speter# action to take if there are no recipients in the message 50764562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed') 50838032Speter 50938032Speter# chrooted environment for writing to files 51064562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch') 51138032Speter 51238032Speter# are colons OK in addresses? 51364562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True') 51438032Speter 51538032Speter# shall I avoid expanding CNAMEs (violates protocols)? 51664562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False') 51738032Speter 51838032Speter# SMTP initial login message (old $e macro) 51964562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b') 52038032Speter 52138032Speter# UNIX initial From header format (old $l macro) 52264562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d') 52338032Speter 52438032Speter# From: lines that have embedded newlines are unwrapped onto one line 52564562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False') 52638032Speter 52738032Speter# Allow HELO SMTP command that does not `include' a host name 52864562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False') 52938032Speter 53038032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic) 53164562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.') 53238032Speter 53338032Speter# delimiter (operator) characters (old $o macro) 53464562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]') 53538032Speter 53638032Speter# shall I avoid calling initgroups(3) because of high NIS costs? 53764562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False') 53838032Speter 53938032Speter# are group-writable `:include:' and .forward files (un)trustworthy? 54090792Sgshapiro# True (the default) means they are not trustworthy. 54164562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True') 54290792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES', 54390792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL. 54490792Sgshapiro')') 54538032Speter 54638032Speter# where do errors that occur when sending errors get sent? 54764562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster') 54838032Speter 54964562Sgshapiro# where to save bounces if all else fails 55064562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter') 55164562Sgshapiro 55238032Speter# what user id do we assume for the majority of the processing? 55364562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail') 55438032Speter 55538032Speter# maximum number of recipients per SMTP envelope 55664562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100') 55738032Speter 55890792Sgshapiro# limit the rate recipients per SMTP envelope are accepted 55990792Sgshapiro# once the threshold number of recipients have been rejected 56090792Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20') 56190792Sgshapiro 56238032Speter# shall we get local names from our installed interfaces? 56364562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 56438032Speter 56564562Sgshapiro# Return-Receipt-To: header implies DSN request 56664562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 56764562Sgshapiro 56864562Sgshapiro# override connection address (for testing) 56964562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 57064562Sgshapiro 57164562Sgshapiro# Trusted user for file ownership and starting the daemon 57264562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root') 57364562Sgshapiro 57464562Sgshapiro# Control socket for daemon management 57564562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 57664562Sgshapiro 57764562Sgshapiro# Maximum MIME header length to protect MUAs 57864562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0') 57964562Sgshapiro 58064562Sgshapiro# Maximum length of the sum of all headers 58164562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768') 58264562Sgshapiro 58364562Sgshapiro# Maximum depth of alias recursion 58464562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10') 58564562Sgshapiro 58664562Sgshapiro# location of pid file 58764562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid') 58864562Sgshapiro 58964562Sgshapiro# Prefix string for the process title shown on 'ps' listings 59064562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix') 59164562Sgshapiro 59264562Sgshapiro# Data file (df) memory-buffer file maximum size 59364562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096') 59464562Sgshapiro 59564562Sgshapiro# Transcript file (xf) memory-buffer file maximum size 59664562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096') 59764562Sgshapiro 59890792Sgshapiro# lookup type to find information about local mailboxes 59990792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw') 60090792Sgshapiro 60164562Sgshapiro# list of authentication mechanisms 60290792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5') 60364562Sgshapiro 60464562Sgshapiro# default authentication information for outgoing connections 60564562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info') 60664562Sgshapiro 60764562Sgshapiro# SMTP AUTH flags 60864562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `') 60964562Sgshapiro 61090792Sgshapiro# SMTP AUTH maximum encryption strength 61190792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `') 61290792Sgshapiro 61390792Sgshapiro# SMTP STARTTLS server options 61490792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `') 61590792Sgshapiro 61664562Sgshapiro# Input mail filters 61764562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 61864562Sgshapiro 61990792Sgshapiroifdef(`confINPUT_MAIL_FILTERS', `dnl 62064562Sgshapiro# Milter options 62190792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `') 62264562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 62364562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') 62464562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') 62564562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')') 62664562Sgshapiro 62764562Sgshapiro# CA directory 62864562Sgshapiro_OPTION(CACERTPath, `confCACERT_PATH', `') 62964562Sgshapiro# CA file 63064562Sgshapiro_OPTION(CACERTFile, `confCACERT', `') 63164562Sgshapiro# Server Cert 63264562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `') 63364562Sgshapiro# Server private key 63464562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `') 63564562Sgshapiro# Client Cert 63664562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `') 63764562Sgshapiro# Client private key 63864562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 63964562Sgshapiro# DHParameters (only required if DSA/DH is used) 64064562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `') 64164562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL) 64264562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `') 64364562Sgshapiro 64490792Sgshapiro############################ 64590792Sgshapiro`# QUEUE GROUP DEFINITIONS #' 64690792Sgshapiro############################ 64790792Sgshapiro_QUEUE_GROUP_ 64842575Speter 64938032Speter########################### 65038032Speter# Message precedences # 65138032Speter########################### 65238032Speter 65338032SpeterPfirst-class=0 65438032SpeterPspecial-delivery=100 65538032SpeterPlist=-30 65638032SpeterPbulk=-60 65738032SpeterPjunk=-100 65838032Speter 65938032Speter##################### 66038032Speter# Trusted users # 66138032Speter##################### 66238032Speter 66338032Speter# this is equivalent to setting class "t" 66464562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 66538032SpeterTroot 66638032SpeterTdaemon 66738032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp') 66838032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 66938032Speter 67038032Speter######################### 67138032Speter# Format of headers # 67238032Speter######################### 67338032Speter 67438032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl 67538032SpeterH?P?Return-Path: <$g> 67638032SpeterHReceived: confRECEIVED_HEADER 67738032SpeterH?D?Resent-Date: $a 67838032SpeterH?D?Date: $a 67938032SpeterH?F?Resent-From: confFROM_HEADER 68038032SpeterH?F?From: confFROM_HEADER 68138032SpeterH?x?Full-Name: $x 68238032Speter# HPosted-Date: $a 68338032Speter# H?l?Received-Date: $b 68438032SpeterH?M?Resent-Message-Id: <$t.$i@$j> 68538032SpeterH?M?Message-Id: <$t.$i@$j> 68664562Sgshapiro 68738032Speter# 68838032Speter###################################################################### 68938032Speter###################################################################### 69038032Speter##### 69138032Speter##### REWRITING RULES 69238032Speter##### 69338032Speter###################################################################### 69438032Speter###################################################################### 69538032Speter 69638032Speter############################################ 69738032Speter### Ruleset 3 -- Name Canonicalization ### 69838032Speter############################################ 69964562SgshapiroScanonify=3 70038032Speter 70138032Speter# handle null input (translate to <@> special case) 70238032SpeterR$@ $@ <@> 70338032Speter 70438032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon 70538032SpeterR$* $: $1 <@> mark addresses 70638032SpeterR$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> 70738032SpeterR@ $* <@> $: @ $1 unmark @host:... 70890792SgshapiroR$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr 70938032SpeterR$* :: $* <@> $: $1 :: $2 unmark node::addr 71038032SpeterR:`include': $* <@> $: :`include': $1 unmark :`include':... 71138032SpeterR$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon 71238032SpeterR$* : $* <@> $: $2 strip colon if marked 71338032SpeterR$* <@> $: $1 unmark 71438032SpeterR$* ; $1 strip trailing semi 71571345SgshapiroR$* < $+ :; > $* $@ $2 :; <@> catch <list:;> 71638032SpeterR$* < $* ; > $1 < $2 > bogus bracketed semi 71738032Speter 71838032Speter# null input now results from list:; syntax 71938032SpeterR$@ $@ :; <@> 72038032Speter 72138032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item 72238032SpeterR$* $: < $1 > housekeeping <> 72338032SpeterR$+ < $* > < $2 > strip excess on left 72438032SpeterR< $* > $+ < $1 > strip excess on right 72538032SpeterR<> $@ < @ > MAIL FROM:<> case 72638032SpeterR< $+ > $: $1 remove housekeeping <> 72738032Speter 72864562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 72938032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 73038032SpeterR@ $+ , $+ @ $1 : $2 change all "," to ":" 73138032Speter 73238032Speter# localize and dispose of route-based addresses 73390792Sgshapirodnl XXX: IPv6 colon conflict 73490792Sgshapiroifdef(`NO_NETINET6', `dnl', 73590792Sgshapiro`R@ [$+] : $+ $@ $>Canonify2 < @ [$1] > : $2 handle <route-addr>') 73664562SgshapiroR@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 73764562Sgshapirodnl',`dnl 73864562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d> 73964562SgshapiroR@ $+ , $+ $2 74090792Sgshapiroifdef(`NO_NETINET6', `dnl', 74190792Sgshapiro`R@ [ $* ] : $+ $2') 74264562SgshapiroR@ $+ : $+ $2 74364562Sgshapirodnl') 74438032Speter 74538032Speter# find focus for list syntax 74664562SgshapiroR $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 74738032SpeterR $+ : $* ; $@ $1 : $2; list syntax 74838032Speter 74938032Speter# find focus for @ syntax addresses 75038032SpeterR$+ @ $+ $: $1 < @ $2 > focus on domain 75138032SpeterR$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 75264562SgshapiroR$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 75338032Speter 75490792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here. 75590792Sgshapirodnl # do some sanity checking 75690792Sgshapirodnl R$* < @ $~[ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 75738032Speter 75838032Speterifdef(`_NO_UUCP_', `dnl', 75938032Speter`# convert old-style addresses to a domain-based address 76064562SgshapiroR$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 76164562SgshapiroR$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 76264562SgshapiroR$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 76338032Speter') 76438032Speterifdef(`_USE_DECNET_SYNTAX_', 76538032Speter`# convert node::user addresses into a domain-based address 76664562SgshapiroR$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 76764562SgshapiroR$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 76838032Speter', 76938032Speter `dnl') 77038032Speter# if we have % signs, take the rightmost one 77138032SpeterR$* % $* $1 @ $2 First make them all @s. 77238032SpeterR$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 77364562SgshapiroR$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 77438032Speter 77538032Speter# else we must be a local name 77664562SgshapiroR$* $@ $>Canonify2 $1 77738032Speter 77838032Speter 77938032Speter################################################ 78038032Speter### Ruleset 96 -- bottom half of ruleset 3 ### 78138032Speter################################################ 78238032Speter 78364562SgshapiroSCanonify2=96 78438032Speter 78538032Speter# handle special cases for local names 78638032SpeterR$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 78738032SpeterR$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 78838032Speterifdef(`_NO_UUCP_', `dnl', 78938032Speter`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 79064562Sgshapiro 79190792Sgshapiro# check for IPv4/IPv6 domain literal 79290792SgshapiroR$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr] 79338032SpeterR$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 79438032SpeterR$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 79538032Speter 79664562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl 79738032Speter# look up domains in the domain table 79838032SpeterR$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 79938032Speter 80064562Sgshapiroundivert(2)dnl LOCAL_RULE_3 80138032Speter 80264562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl 80338032Speter# handle BITNET mapping 80438032SpeterR$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 80538032Speter 80664562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl 80738032Speter# handle UUCP mapping 80838032SpeterR$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 80938032Speter 81038032Speterifdef(`_NO_UUCP_', `dnl', 81138032Speter`ifdef(`UUCP_RELAY', 81238032Speter`# pass UUCP addresses straight through 81338032SpeterR$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 81438032Speter`# if really UUCP, handle it immediately 81538032Speterifdef(`_CLASS_U_', 81638032Speter`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 81738032Speterifdef(`_CLASS_V_', 81838032Speter`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 81938032Speterifdef(`_CLASS_W_', 82038032Speter`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82138032Speterifdef(`_CLASS_X_', 82238032Speter`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82338032Speterifdef(`_CLASS_Y_', 82438032Speter`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82538032Speter 82638032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl 82738032Speter# try UUCP traffic as a local address 82838032SpeterR$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 82938032SpeterR$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 83038032Speter')') 83164562Sgshapiro# hostnames ending in class P are always canonical 83264562SgshapiroR$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 83364562Sgshapirodnl apply the next rule only for hostnames not in class P 83464562Sgshapirodnl this even works for phrases in class P since . is in class P 83564562Sgshapirodnl which daemon flags are set? 83664562SgshapiroR$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 83764562Sgshapirodnl the other rules in this section only apply if the hostname 83864562Sgshapirodnl does not end in class P hence no further checks are done here 83964562Sgshapirodnl if this ever changes make sure the lookups are "protected" again! 84064562Sgshapiroifdef(`_NO_CANONIFY_', `dnl 84164562Sgshapirodnl do not canonify unless: 84264562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection 84364562Sgshapirodnl with class P is non-empty) 84464562Sgshapirodnl or {daemon_flags} has c set 84564562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify} 84664562SgshapiroR$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 84764562Sgshapiro# pass to name server to make hostname canonical if requested 84864562SgshapiroR$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 84964562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 85064562SgshapiroR$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 85164562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work 85264562SgshapiroR$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 85364562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl 85464562Sgshapirodnl this should only apply to unqualified hostnames 85564562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar 85664562Sgshapirodnl then $- does not work. 85764562Sgshapiro# lookup unqualified hostnames 85890792SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 85964562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless: 86064562Sgshapirodnl {daemon_flags} contains CC (do not canonify) 86171345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work 86271345Sgshapirodnl should we do this for every hostname: even unqualified? 86371345SgshapiroR$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 86464562SgshapiroR$* CC $* $| $* $: $3 86590792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl 86690792Sgshapiro# do not canonify header addresses 86790792SgshapiroR$* $| $* < @ $* $~P > $* $: $&{addr_type} $| $2 < @ $3 $4 > $5 86890792SgshapiroR$* h $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 86990792SgshapiroR$* h $* $| $* $: $3', `dnl') 87038032Speter# pass to name server to make hostname canonical 87164562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 87264562Sgshapirodnl remove {daemon_flags} for other cases 87364562SgshapiroR$* $| $* $: $2 87438032Speter 87538032Speter# local host aliases and pseudo-domains are always canonical 87638032SpeterR$* < @ $=w > $* $: $1 < @ $2 . > $3 87738032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 87838032Speter`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 87938032Speter`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 88064562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 88164562Sgshapirodnl virtual hosts are also canonical 88264562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 88364562Sgshapiro`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 88464562Sgshapiro`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 88564562Sgshapiro`dnl') 88690792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 88790792Sgshapirodnl hosts for genericstable are also canonical 88890792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_', 88990792Sgshapiro`R$* < @ $* $=G > $* $: $1 < @ $2 $3 . > $4', 89090792Sgshapiro`R$* < @ $=G > $* $: $1 < @ $2 . > $3')', 89190792Sgshapiro`dnl') 89264562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added 89364562Sgshapirodnl by one of the rules before 89438032SpeterR$* < @ $* . . > $* $1 < @ $2 . > $3 89538032Speter 89638032Speter 89738032Speter################################################## 89838032Speter### Ruleset 4 -- Final Output Post-rewriting ### 89938032Speter################################################## 90064562SgshapiroSfinal=4 90138032Speter 90271345SgshapiroR$+ :; <@> $@ $1 : handle <list:;> 90338032SpeterR$* <@> $@ handle <> and list:; 90438032Speter 90538032Speter# strip trailing dot off possibly canonical name 90638032SpeterR$* < @ $+ . > $* $1 < @ $2 > $3 90738032Speter 90864562Sgshapiro# eliminate internal code 90938032SpeterR$* < @ *LOCAL* > $* $1 < @ $j > $2 91038032Speter 91138032Speter# externalize local domain info 91238032SpeterR$* < $+ > $* $1 $2 $3 defocus 91338032SpeterR@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 91438032SpeterR@ $* $@ @ $1 ... and exit 91538032Speter 91638032Speterifdef(`_NO_UUCP_', `dnl', 91738032Speter`# UUCP must always be presented in old form 91838032SpeterR$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 91938032Speter 92038032Speterifdef(`_USE_DECNET_SYNTAX_', 92138032Speter`# put DECnet back in :: form 92238032SpeterR$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 92338032Speter `dnl') 92438032Speter# delete duplicate local names 92538032SpeterR$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 92638032Speter 92738032Speter 92838032Speter 92938032Speter############################################################## 93038032Speter### Ruleset 97 -- recanonicalize and call ruleset zero ### 93138032Speter### (used for recursive calls) ### 93238032Speter############################################################## 93338032Speter 93464562SgshapiroSRecurse=97 93564562SgshapiroR$* $: $>canonify $1 93664562SgshapiroR$* $@ $>parse $1 93738032Speter 93838032Speter 93938032Speter###################################### 94038032Speter### Ruleset 0 -- Parse Address ### 94138032Speter###################################### 94238032Speter 94364562SgshapiroSparse=0 94438032Speter 94538032SpeterR$* $: $>Parse0 $1 initial parsing 94638032SpeterR<@> $#_LOCAL_ $: <@> special case error msgs 94764562SgshapiroR$* $: $>ParseLocal $1 handle local hacks 94838032SpeterR$* $: $>Parse1 $1 final parsing 94938032Speter 95038032Speter# 95138032Speter# Parse0 -- do initial syntax checking and eliminate local addresses. 95238032Speter# This should either return with the (possibly modified) input 95338032Speter# or return with a #error mailer. It should not return with a 95438032Speter# #mailer other than the #error mailer. 95538032Speter# 95638032Speter 95738032SpeterSParse0 95838032SpeterR<@> $@ <@> special case error msgs 95990792SgshapiroR$* : $* ; <@> $#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses" 96064562SgshapiroR@ <@ $* > < @ $1 > catch "@@host" bogosity 96190792SgshapiroR<@ $+> $#error $@ 5.1.3 $: "_CODE553 User address required" 96290792SgshapiroR$+ <@> $#error $@ 5.1.3 $: "_CODE553 Hostname required" 96338032SpeterR$* $: <> $1 96490792Sgshapirodnl allow tricks like [host1]:[host2] 96590792SgshapiroR<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4 96690792SgshapiroR<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4 96790792Sgshapirodnl but no a@[b]c 96890792SgshapiroR<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid address" 96990792SgshapiroR<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 97090792SgshapiroR<> $* <$* : $* > $* $#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part" 97138032SpeterR<> $* $1 97290792SgshapiroR$* < @ . $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 97390792SgshapiroR$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 97490792Sgshapirodnl no a@b@ 97590792SgshapiroR$* < @ $* @ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid route address" 97690792Sgshapirodnl no a@b@c 97790792SgshapiroR$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 97864562Sgshapirodnl comma only allowed before @; this check is not complete 97990792SgshapiroR$* , $~O $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 98038032Speter 98190792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks 98290792SgshapiroR$* . < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot" 98390792SgshapiroR. $* < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot" 98490792Sgshapirodnl', `dnl') 98590792Sgshapiro 98638032Speter# now delete the local info -- note $=O to find characters that cause forwarding 98764562SgshapiroR$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 98864562SgshapiroR< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 98938032SpeterR$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 99090792SgshapiroR< @ $+ > $#error $@ 5.1.3 $: "_CODE553 User address required" 99164562SgshapiroR$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 99238032SpeterR$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 99390792SgshapiroR< @ *LOCAL* > $#error $@ 5.1.3 $: "_CODE553 User address required" 99438032SpeterR$* $=O $* < @ *LOCAL* > 99564562Sgshapiro $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 99638032SpeterR$* < @ *LOCAL* > $: $1 99738032Speter 99838032Speter# 99938032Speter# Parse1 -- the bottom half of ruleset 0. 100038032Speter# 100138032Speter 100238032SpeterSParse1 100364562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 100464562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute} 100590792SgshapiroR$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <> 100690792SgshapiroR$+ < @ $={LDAPRouteEquiv} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>', 100764562Sgshapiro`dnl') 100864562Sgshapiro 100938032Speterifdef(`_MAILER_smtp_', 101038032Speter`# handle numeric address spec 101164562Sgshapirodnl there is no check whether this is really an IP number 101264562SgshapiroR$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 101364562SgshapiroR$* < @ [ $+ ] > $* $1 < @ [ $2 ] : $S > $3 Add smart host to path 101490792SgshapiroR$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 101564562SgshapiroR$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 101664562SgshapiroR$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 101738032Speter `dnl') 101838032Speter 101964562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 102038032Speter# handle virtual users 102190792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 102290792Sgshapirodnl this is not a documented option 102390792Sgshapirodnl it stops looping in virtusertable mapping if input and output 102490792Sgshapirodnl are identical, i.e., if address A is mapped to A. 102590792Sgshapirodnl it does not deal with multi-level recursion 102690792Sgshapiro# handle full domains in RHS of virtusertable 102790792SgshapiroR$+ < @ $+ > $: $(macro {RecipientAddress} $) $1 < @ $2 > 102890792SgshapiroR$+ < @ $+ > $: <?> $1 < @ $2 > $| $>final $1 < @ $2 > 102990792SgshapiroR<?> $+ $| $+ $: $1 $(macro {RecipientAddress} $@ $2 $) 103090792SgshapiroR<?> $+ $| $* $: $1', 103190792Sgshapiro`dnl') 103264562SgshapiroR$+ $: <!> $1 Mark for lookup 103390792Sgshapirodnl input: <!> local<@domain> 103464562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 103564562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 103664562Sgshapiro`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 103790792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain> 103864562SgshapiroR<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 103990792Sgshapirodnl if <@> local<@domain>: no match but try lookup 104090792Sgshapirodnl user+detail: try user++@domain if detail not empty 104190792SgshapiroR<@> $+ + $+ < @ $* . > 104290792Sgshapiro $: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 104390792Sgshapirodnl user+detail: try user+*@domain 104438032SpeterR<@> $+ + $* < @ $* . > 104590792Sgshapiro $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 104690792Sgshapirodnl user+detail: try user@domain 104738032SpeterR<@> $+ + $* < @ $* . > 104890792Sgshapiro $: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 104964562Sgshapirodnl try default entry: @domain 105090792Sgshapirodnl ++@domain 105190792SgshapiroR<@> $+ + $+ < @ $+ . > $: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105264562Sgshapirodnl +*@domain 105390792SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105464562Sgshapirodnl @domain if +detail exists 105590792SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105664562Sgshapirodnl without +detail (or no match) 105738032SpeterR<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 105890792Sgshapirodnl no match 105938032SpeterR<@> $+ $: $1 106090792Sgshapirodnl remove mark 106164562SgshapiroR<!> $+ $: $1 106264562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 106338032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 106490792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 106590792Sgshapiro# check virtuser input address against output address, if same, skip recursion 106690792SgshapiroR< $+ > $+ < @ $+ > $: < $1 > $2 < @ $3 > $| $1 106790792Sgshapiro# it is the same: stop now 106890792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress} $: $>ParseLocal $>Parse0 $>canonify $1 106990792SgshapiroR< $+ > $+ < @ $+ > $| $* $: < $1 > $2 < @ $3 > 107090792Sgshapirodnl', `dnl') 107180785Sgshapirodnl this is not a documented option 107280785Sgshapirodnl it performs no looping at all for virtusertable 107377349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_', 107477349Sgshapiro`R< $+ > $+ < @ $+ > $: $>ParseLocal $>Parse0 $>canonify $1', 107577349Sgshapiro`R< $+ > $+ < @ $+ > $: $>Recurse $1') 107677349Sgshapirodnl', `dnl') 107738032Speter 107838032Speter# short circuit local delivery so forwarded email works 107938032Speterifdef(`_MAILER_usenet_', `dnl 108064562SgshapiroR$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 108166494Sgshapiro 108266494Sgshapiro 108338032Speterifdef(`_STICKY_LOCAL_DOMAIN_', 108438032Speter`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 108564562SgshapiroR< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 108664562Sgshapirodnl $H empty (but @$=w.) 108738032SpeterR< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 108838032SpeterR< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 108964562Sgshapiro`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 109038032SpeterR$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 109138032Speter 109264562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 109338032Speter# not local -- try mailer table lookup 109438032SpeterR$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 109538032SpeterR< $+ . > $* $: < $1 > $2 strip trailing dot 109638032SpeterR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 109764562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 109864562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 109964562SgshapiroR< $+ > $* $: $>Mailertable <$1> $2 try domain', 110038032Speter`dnl') 110164562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)' 110238032Speter 110338032Speterifdef(`_NO_UUCP_', `dnl', 110438032Speter`# resolve remotely connected UUCP links (if any) 110538032Speterifdef(`_CLASS_V_', 110664562Sgshapiro`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 110738032Speter `dnl') 110838032Speterifdef(`_CLASS_W_', 110964562Sgshapiro`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 111038032Speter `dnl') 111138032Speterifdef(`_CLASS_X_', 111264562Sgshapiro`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 111338032Speter `dnl')') 111438032Speter 111538032Speter# resolve fake top level domains by forwarding to other hosts 111638032Speterifdef(`BITNET_RELAY', 111764562Sgshapiro`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 111838032Speter `dnl') 111938032Speterifdef(`DECNET_RELAY', 112064562Sgshapiro`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 112138032Speter `dnl') 112238032Speterifdef(`_MAILER_pop_', 112338032Speter`R$+ < @ POP. > $#pop $: $1 user@POP', 112438032Speter `dnl') 112538032Speterifdef(`_MAILER_fax_', 112638032Speter`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 112738032Speter`ifdef(`FAX_RELAY', 112864562Sgshapiro`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 112938032Speter `dnl')') 113038032Speter 113138032Speterifdef(`UUCP_RELAY', 113238032Speter`# forward non-local UUCP traffic to our UUCP relay 113364562SgshapiroR$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 113438032Speter`ifdef(`_MAILER_uucp_', 113538032Speter`# forward other UUCP traffic straight to UUCP 113638032SpeterR$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 113738032Speter `dnl')') 113838032Speterifdef(`_MAILER_usenet_', ` 113938032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup 114064562SgshapiroR$+ . USENET $#usenet $@ usenet $: $1', 114138032Speter `dnl') 114238032Speter 114338032Speterifdef(`_LOCAL_RULES_', 114438032Speter`# figure out what should stay in our local mail system 114538032Speterundivert(1)', `dnl') 114638032Speter 114738032Speter# pass names that still have a host to a smarthost (if defined) 114864562SgshapiroR$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 114938032Speter 115038032Speter# deal with other remote names 115138032Speterifdef(`_MAILER_smtp_', 115264562Sgshapiro`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 115390792Sgshapiro`R$* < @$* > $* $#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2') 115438032Speter 115538032Speter# handle locally delivered names 115664562SgshapiroR$=L $#_LOCAL_ $: @ $1 special local names 115738032SpeterR$+ $#_LOCAL_ $: $1 regular local names 115838032Speter 115938032Speter########################################################################### 116038032Speter### Ruleset 5 -- special rewriting after aliases have been expanded ### 116138032Speter########################################################################### 116238032Speter 116364562SgshapiroSLocal_localaddr 116464562SgshapiroSlocaladdr=5 116564562SgshapiroR$+ $: $1 $| $>"Local_localaddr" $1 116690792SgshapiroR$+ $| $#ok $@ $1 no change 116764562SgshapiroR$+ $| $#$* $#$2 116864562SgshapiroR$+ $| $* $: $1 116938032Speter 117090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 117190792Sgshapiro# Preserve rcpt_host in {Host} 117290792SgshapiroR$+ $: $1 $| $&h $| $&{Host} check h and {Host} 117390792SgshapiroR$+ $| $| $: $(macro {Host} $@ $) $1 no h or {Host} 117490792SgshapiroR$+ $| $| $+ $: $1 h not set, {Host} set 117590792SgshapiroR$+ $| +$* $| $* $: $1 h is +detail, {Host} set 117690792SgshapiroR$+ $| $+ $| $* $: $(macro {Host} $@ @$2 $) $1 set {Host} to h 117790792Sgshapiro')dnl 117890792Sgshapiro 117990792Sgshapiroifdef(`_FFR_5_', `dnl 118066494Sgshapiro# Preserve host in a macro 118166494SgshapiroR$+ $: $(macro {LocalAddrHost} $) $1 118266494SgshapiroR$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 118366494Sgshapiro 118490792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl 118538032Speter# deal with plussed users so aliases work nicely 118666494SgshapiroR$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 118766494SgshapiroR$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 118866494Sgshapiro') 118938032Speter# prepend an empty "forward host" on the front 119038032SpeterR$+ $: <> $1 119138032Speter 119238032Speterifdef(`LUSER_RELAY', `dnl 119338032Speter# send unrecognized local users to a relay host 119490792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 119566494SgshapiroR< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 119666494SgshapiroR< > $+ $: < ? $L > < > $(user $1 $) look up user 119766494SgshapiroR< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 119866494SgshapiroR< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 119964562SgshapiroR< > $+ $: < $L > $(user $1 $) look up user 120090792SgshapiroR< $* > $+ <> $: < > $2 found; strip $L') 120190792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 120290792SgshapiroR< $+ > $+ $: < $1 > $2 $&{Host}') 120390792Sgshapirodnl') 120438032Speter 120590792Sgshapiroifdef(`MAIL_HUB', `dnl 120690792SgshapiroR< > $+ $: < $H > $1 try hub', `dnl') 120790792Sgshapiroifdef(`LOCAL_RELAY', `dnl 120890792SgshapiroR< > $+ $: < $R > $1 try relay', `dnl') 120990792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 121090792SgshapiroR< > $+ $@ $1', `dnl 121164562SgshapiroR< > $+ $: < > < $1 <> $&h > nope, restore +detail 121290792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 121390792SgshapiroR< > < $+ @ $+ <> + $* > $: < > < $1 + $3 @ $2 > check whether +detail') 121464562SgshapiroR< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 121564562SgshapiroR< > < $+ <> $* > $: < > < $1 > else discard 121638032SpeterR< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 121766494SgshapiroR< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 121838032SpeterR< > < $+ > $@ $1 no +detail 121943730SpeterR$+ $: $1 <> $&h add +detail back in 122090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 122190792SgshapiroR$+ @ $+ <> + $* $: $1 + $3 @ $2 check whether +detail') 122243730SpeterR$+ <> + $* $: $1 + $2 check whether +detail 122366494SgshapiroR$+ <> $* $: $1 else discard') 122464562SgshapiroR< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 122564562SgshapiroR< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 122690792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 122790792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 122890792SgshapiroR< $~[ : $+ > $+ @ $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $4 >') 122990792SgshapiroR< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 123090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 123190792SgshapiroR< $+ > $+ @ $+ $@ $>MailerToTriple < $1 > $2 < @ $3 >') 123264562SgshapiroR< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 123338032Speter 123464562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 123590792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 123638032Speter################################################################### 123790792Sgshapiro### Ruleset LDAPMailertable -- mailertable lookup for LDAP ### 123890792Sgshapirodnl input: <Domain> FullAddress 123990792Sgshapiro################################################################### 124090792Sgshapiro 124190792SgshapiroSLDAPMailertable 124290792SgshapiroR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 124390792SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check resolved? 124490792SgshapiroR< $+ > $* $: < $1 > $>Mailertable <$1> $2 try domain 124590792SgshapiroR< $+ > $#$* $#$2 found 124690792SgshapiroR< $+ > $* $#_RELAY_ $@ $1 $: $2 not found, direct relay', 124790792Sgshapiro`dnl') 124890792Sgshapiro 124990792Sgshapiro################################################################### 125038032Speter### Ruleset 90 -- try domain part of mailertable entry ### 125164562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 125238032Speter################################################################### 125338032Speter 125464562SgshapiroSMailertable=90 125564562Sgshapirodnl shift and check 125664562Sgshapirodnl %2 is not documented in cf/README 125738032SpeterR$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 125864562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 125964562SgshapiroR$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 126064562SgshapiroR$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 126164562Sgshapirodnl is $2 always empty? 126238032SpeterR$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 126364562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 126464562Sgshapirodnl return full address 126538032SpeterR< $* > $* $@ $2 no mailertable match', 126638032Speter`dnl') 126738032Speter 126838032Speter################################################################### 126938032Speter### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 127064562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest 127164562Sgshapirodnl <> address -> address 127264562Sgshapirodnl <error:d.s.n:text> -> error 127364562Sgshapirodnl <error:text> -> error 127464562Sgshapirodnl <mailer:user@host> lp<@domain>rest -> mailer host user 127564562Sgshapirodnl <mailer:host> address -> mailer host address 127664562Sgshapirodnl <localdomain> address -> address 127764562Sgshapirodnl <host> address -> relay host address 127838032Speter################################################################### 127938032Speter 128064562SgshapiroSMailerToTriple=95 128138032SpeterR< > $* $@ $1 strip off null relay 128264562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 128338032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 128438032SpeterR< local : $* > $* $>CanonLocal < $1 > $2 128590792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 128690792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 128790792SgshapiroR< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 128838032SpeterR< $=w > $* $@ $2 delete local host 128938032SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 129038032Speter 129138032Speter################################################################### 129238032Speter### Ruleset CanonLocal -- canonify local: syntax ### 129364562Sgshapirodnl input: <user> address 129464562Sgshapirodnl <x> <@host> : rest -> Recurse rest 129564562Sgshapirodnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 129664562Sgshapirodnl <> user <@host> rest -> local user@host user 129764562Sgshapirodnl <> user -> local user user 129864562Sgshapirodnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 129964562Sgshapirodnl <user> lp <@host> rest -> local lp@host user 130064562Sgshapirodnl <user> lp -> local lp user 130138032Speter################################################################### 130238032Speter 130338032SpeterSCanonLocal 130443730Speter# strip local host from routed addresses 130564562SgshapiroR< $* > < @ $+ > : $+ $@ $>Recurse $3 130664562SgshapiroR< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 130743730Speter 130838032Speter# strip trailing dot from any host name that may appear 130938032SpeterR< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 131038032Speter 131138032Speter# handle local: syntax -- use old user, either with or without host 131238032SpeterR< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 131338032SpeterR< > $+ $#_LOCAL_ $@ $1 $: $1 131438032Speter 131538032Speter# handle local:user@host syntax -- ignore host part 131638032SpeterR< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 131738032Speter 131838032Speter# handle local:user syntax 131938032SpeterR< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 132038032SpeterR< $+ > $* $#_LOCAL_ $@ $2 $: $1 132138032Speter 132238032Speter################################################################### 132338032Speter### Ruleset 93 -- convert header names to masqueraded form ### 132438032Speter################################################################### 132538032Speter 132664562SgshapiroSMasqHdr=93 132738032Speter 132864562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 132938032Speter# handle generics database 133038032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_', 133164562Sgshapirodnl if generics should be applied add a @ as mark 133238032Speter`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 133338032Speter`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 133438032SpeterR$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 133564562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @ 133664562Sgshapirodnl ignore the first case for now 133764562Sgshapirodnl if it has the mark lookup full address 133890792Sgshapirodnl broken: %1 is full address not just detail 133964562SgshapiroR< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 134064562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain> 134164562Sgshapirodnl no match, try user+detail@domain 134264562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 134364562Sgshapiro $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 134464562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 134564562Sgshapiro $: < $(generics $1@$3 $: $) > $4 < @ $5 > 134664562Sgshapirodnl no match, remove mark 134764562SgshapiroR<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 134864562Sgshapirodnl no match, try @domain for exceptions 134964562SgshapiroR< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 135064562Sgshapirodnl workspace: ... or <match> user <@domain> 135164562Sgshapirodnl no match, try local part 135238032SpeterR< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 135364562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 135464562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 135564562SgshapiroR< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 135664562SgshapiroR< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 135738032SpeterR< > $* $: $1 not found', 135838032Speter`dnl') 135938032Speter 136064562Sgshapiro# do not masquerade anything in class N 136164562SgshapiroR$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 136264562Sgshapiro 136390792Sgshapiroifdef(`MASQUERADE_NAME', `dnl 136438032Speter# special case the users that should be exposed 136538032SpeterR$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 136638032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 136738032Speter`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 136838032Speter`R$=E < @ $=M . > $@ $1 < @ $2 . >') 136938032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 137038032Speter`R$=E < @ $=w . > $@ $1 < @ $2 . >') 137138032Speter 137238032Speter# handle domain-specific masquerading 137338032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 137438032Speter`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 137538032Speter`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 137638032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 137738032Speter`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 137838032SpeterR$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 137938032SpeterR$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 138038032SpeterR$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 138190792Sgshapirodnl', `dnl no masquerading 138290792Sgshapirodnl just fix *LOCAL* leftovers 138390792SgshapiroR$* < @ *LOCAL* > $@ $1 < @ $j . >') 138438032Speter 138538032Speter################################################################### 138638032Speter### Ruleset 94 -- convert envelope names to masqueraded form ### 138738032Speter################################################################### 138838032Speter 138964562SgshapiroSMasqEnv=94 139038032Speterifdef(`_MASQUERADE_ENVELOPE_', 139164562Sgshapiro`R$+ $@ $>MasqHdr $1', 139238032Speter`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 139338032Speter 139438032Speter################################################################### 139538032Speter### Ruleset 98 -- local part of ruleset zero (can be null) ### 139638032Speter################################################################### 139738032Speter 139864562SgshapiroSParseLocal=98 139964562Sgshapiroundivert(3)dnl LOCAL_RULE_0 140038032Speter 140164562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 140290792Sgshapiro###################################################################### 140390792Sgshapiro### LDAPExpand: Expand address using LDAP routing 140490792Sgshapiro### 140590792Sgshapiro### Parameters: 140690792Sgshapiro### <$1> -- parsed address (user < @ domain . >) (pass through) 140790792Sgshapiro### <$2> -- RFC822 address (user @ domain) (used for lookup) 140890792Sgshapiro### <$3> -- +detail information 140990792Sgshapiro### 141090792Sgshapiro### Returns: 141190792Sgshapiro### Mailer triplet ($#mailer $@ host $: address) 141290792Sgshapiro### Parsed address (user < @ domain . >) 141390792Sgshapiro###################################################################### 141490792Sgshapiro 141564562SgshapiroSLDAPExpand 141664562Sgshapiro# do the LDAP lookups 141790792SgshapiroR<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3> 141864562Sgshapiro 141964562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost, 142064562Sgshapiro# return the new mailRoutingAddress 142190792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 142290792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2 142390792SgshapiroR<$+@$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $5 @ $2') 142490792SgshapiroR<$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 142590792SgshapiroR<$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 142664562Sgshapiro 142764562Sgshapiro# if mailRoutingAddress and non-local mailHost, 142864562Sgshapiro# relay to mailHost with new mailRoutingAddress 142990792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 143090792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 143190792Sgshapiro# check mailertable for host, relay from there 143290792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$3> $>canonify $1 $6 @ $2', 143390792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')') 143490792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 143590792Sgshapiro# check mailertable for host, relay from there 143690792SgshapiroR<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1', 143790792Sgshapiro`R<$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $2 $: $>canonify $1') 143864562Sgshapiro 143964562Sgshapiro# if no mailRoutingAddress and local mailHost, 144064562Sgshapiro# return original address 144190792SgshapiroR<> <$=w> <$+> <$+> <$*> $@ $2 144264562Sgshapiro 144364562Sgshapiro# if no mailRoutingAddress and non-local mailHost, 144464562Sgshapiro# relay to mailHost with original address 144590792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 144690792Sgshapiro# check mailertable for host, relay from there 144790792SgshapiroR<> <$+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2', 144890792Sgshapiro`R<> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $1 $: $2') 144964562Sgshapiro 145090792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_', 145190792Sgshapiro`# if no mailRoutingAddress and no mailHost, 145290792Sgshapiro# try without +detail 145390792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl 145490792Sgshapiro 145590792Sgshapiro# if still no mailRoutingAddress and no mailHost, 145664562Sgshapiro# try @domain 145790792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 145890792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <@ $4> <+$3>') 145990792SgshapiroR<> <> <$+> <$+ @ $+> <$*> $@ $>LDAPExpand <$1> <@ $3> <$4> 146064562Sgshapiro 146164562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt, 146264562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 146364562Sgshapiro# user does not exist 146490792SgshapiroR<> <> <$+> <@ $+> <$*> $: <?> < $&{addr_type} > < $1 > 146590792Sgshapiro# only give error for envelope recipient 146690792SgshapiroR<?> <e r> <$+> $#error $@ nouser $: "550 User unknown" 146790792SgshapiroR<?> <$*> <$+> $@ $2', 146864562Sgshapiro`dnl 146964562Sgshapiro# return the original address 147090792SgshapiroR<> <> <$+> <@ $+> <$*> $@ $1')', 147164562Sgshapiro`dnl') 147264562Sgshapiro 147364562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 147464562Sgshapiro')') 147590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 147638032Speter###################################################################### 147790792Sgshapiro### D: LookUpDomain -- search for domain in access database 147838032Speter### 147938032Speter### Parameters: 148038032Speter### <$1> -- key (domain name) 148138032Speter### <$2> -- default (what to return if not found in db) 148264562Sgshapirodnl must not be empty 148390792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 148464562Sgshapiro### ! does lookup only with tag 148564562Sgshapiro### + does lookup with and without tag 148690792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 148764562Sgshapirodnl returns: <default> <passthru> 148864562Sgshapirodnl <result> <passthru> 148938032Speter###################################################################### 149038032Speter 149190792SgshapiroSD 149264562Sgshapirodnl workspace <key> <default> <passthru> <mark> 149364562Sgshapirodnl lookup with tag (in front, no delimiter here) 149490792Sgshapirodnl 2 3 4 5 149590792SgshapiroR<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 149664562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 149764562Sgshapirodnl lookup without tag? 149890792Sgshapirodnl 1 2 3 4 149990792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 150090792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest 150190792Sgshapirodnl XXX apply this also to IP addresses? 150290792Sgshapirodnl currently it works the wrong way round for [1.2.3.4] 150390792Sgshapirodnl 1 2 3 4 5 6 150490792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6> 150590792Sgshapirodnl 1 2 3 4 5 150690792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl') 150790792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 150890792Sgshapirodnl found SKIP: return <default> and <passthru> 150990792Sgshapirodnl 1 2 3 4 5 151090792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 151190792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!) 151290792Sgshapirodnl 1 2 3 4 5 6 151390792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*> $@ $>D <[$1]> <$3> <$4 $5> <$6> 151490792Sgshapiroifdef(`NO_NETINET6', `dnl', 151590792Sgshapiro`dnl not found: IPv6 net 151690792Sgshapirodnl (could be merged with previous rule if we have a class containing .:) 151790792Sgshapirodnl 1 2 3 4 5 6 151890792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6> 151990792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>') 152064562Sgshapirodnl not found, but subdomain: try again 152190792Sgshapirodnl 1 2 3 4 5 6 152290792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6> 152390792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag: 152490792Sgshapirodnl 1 2 3 4 152590792SgshapiroR<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl') 152690792Sgshapirodnl not found, no subdomain: return <default> and <passthru> 152790792Sgshapirodnl 1 2 3 4 5 152890792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 152990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 153090792Sgshapirodnl 2 3 4 5 6 153190792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 153290792Sgshapirodnl return <result of lookup> and <passthru> 153390792Sgshapirodnl 2 3 4 5 6 153490792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 153538032Speter 153638032Speter###################################################################### 153790792Sgshapiro### A: LookUpAddress -- search for host address in access database 153838032Speter### 153938032Speter### Parameters: 154038032Speter### <$1> -- key (dot quadded host address) 154138032Speter### <$2> -- default (what to return if not found in db) 154264562Sgshapirodnl must not be empty 154390792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 154464562Sgshapiro### ! does lookup only with tag 154564562Sgshapiro### + does lookup with and without tag 154690792Sgshapiro### <$4> -- passthru (additional data passed through) 154764562Sgshapirodnl returns: <default> <passthru> 154864562Sgshapirodnl <result> <passthru> 154938032Speter###################################################################### 155038032Speter 155190792SgshapiroSA 155264562Sgshapirodnl lookup with tag 155390792Sgshapirodnl 2 3 4 5 155490792SgshapiroR<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 155564562Sgshapirodnl lookup without tag 155690792Sgshapirodnl 1 2 3 4 155790792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 155890792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru> 155990792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 156090792Sgshapirodnl found SKIP: return <default> and <passthru> 156190792Sgshapirodnl 1 2 3 4 5 156290792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 156390792Sgshapiroifdef(`NO_NETINET6', `dnl', 156490792Sgshapiro`dnl no match; IPv6: remove last part 156590792Sgshapirodnl 1 2 3 4 5 6 156690792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 156790792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>') 156864562Sgshapirodnl no match; IPv4: remove last part 156990792Sgshapirodnl 1 2 3 4 5 6 157090792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 157164562Sgshapirodnl no match: return default 157290792Sgshapirodnl 1 2 3 4 5 157390792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 157490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 157590792Sgshapirodnl 2 3 4 5 6 157690792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 157764562Sgshapirodnl match: return result 157890792Sgshapirodnl 2 3 4 5 6 157990792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 158090792Sgshapirodnl endif _ACCESS_TABLE_ 158190792Sgshapirodivert(0) 158238032Speter###################################################################### 158342575Speter### CanonAddr -- Convert an address into a standard form for 158442575Speter### relay checking. Route address syntax is 158542575Speter### crudely converted into a %-hack address. 158642575Speter### 158742575Speter### Parameters: 158842575Speter### $1 -- full recipient address 158942575Speter### 159042575Speter### Returns: 159142575Speter### parsed address, not in source route form 159264562Sgshapirodnl user%host%host<@domain> 159364562Sgshapirodnl host!user<@domain> 159442575Speter###################################################################### 159542575Speter 159642575SpeterSCanonAddr 159764562SgshapiroR$* $: $>Parse0 $>canonify $1 make domain canonical 159864562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 159942575SpeterR< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 160042575SpeterR$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 160142575SpeterR$* < @ $+ > : $* $3 $1 < @ $2 > 160264562Sgshapirodnl') 160342575Speter 160442575Speter###################################################################### 160538032Speter### ParseRecipient -- Strip off hosts in $=R as well as possibly 160638032Speter### $* $=m or the access database. 160738032Speter### Check user portion for host separators. 160838032Speter### 160938032Speter### Parameters: 161038032Speter### $1 -- full recipient address 161138032Speter### 161238032Speter### Returns: 161338032Speter### parsed, non-local-relaying address 161438032Speter###################################################################### 161538032Speter 161638032SpeterSParseRecipient 161764562Sgshapirodnl mark and canonify address 161842575SpeterR$* $: <?> $>CanonAddr $1 161964562Sgshapirodnl workspace: <?> localpart<@domain[.]> 162042575SpeterR<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 162164562Sgshapirodnl workspace: <?> localpart<@domain> 162242575SpeterR<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 162338032Speter 162438032Speter# if no $=O character, no host in the user portion, we are done 162542575SpeterR<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 162664562Sgshapirodnl no $=O in localpart: return 162742575SpeterR<?> $* $@ $1 162838032Speter 162990792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O 163064562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY> 163138032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 163238032Speter# if we relay, check username portion for user%host so host can be checked also 163342575SpeterR<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 163464562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 163564562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 163690792Sgshapiro 163790792Sgshapirodnl what if access map returns something else than RELAY? 163890792Sgshapirodnl we are only interested in RELAY entries... 163990792Sgshapirodnl other To: entries: blacklist recipient; generic entries? 164090792Sgshapirodnl if it is an error we probably do not want to relay anyway 164138032Speterifdef(`_RELAY_HOSTS_ONLY_', 164242575Speter`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 164364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 164464562SgshapiroR<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 164542575SpeterR<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 164642575Speter`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 164764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 164890792SgshapiroR<NO> $* < @ $+ > $: $>D <$2> <NO> <+ To> <$1 < @ $2 >> 164942575SpeterR<$+> <$+> $: <$1> $2',`dnl')') 165038032Speter 165164562Sgshapiro 165290792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl 165390792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain? 165490792SgshapiroR<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 165590792SgshapiroR<MX> < : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 165690792Sgshapirodnl yes: mark it as <RELAY> 165790792SgshapiroR<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 165890792Sgshapirodnl no: put old <NO> mark back 165990792SgshapiroR<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 166090792Sgshapiro 166190792Sgshapirodnl do we relay to this recipient domain? 166242575SpeterR<RELAY> $* < @ $* > $@ $>ParseRecipient $1 166390792Sgshapirodnl something else 166490792SgshapiroR<$+> $* $@ $2 166542575Speter 166664562Sgshapiro 166738032Speter###################################################################### 166838032Speter### check_relay -- check hostname/address on SMTP startup 166938032Speter###################################################################### 167038032Speter 167138032SpeterSLocal_check_relay 167264562SgshapiroScheck`'_U_`'relay 167338032SpeterR$* $: $1 $| $>"Local_check_relay" $1 167438032SpeterR$* $| $* $| $#$* $#$3 167538032SpeterR$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 167638032Speter 167738032SpeterSBasic_check_relay 167838032Speter# check for deferred delivery mode 167938032SpeterR$* $: < ${deliveryMode} > $1 168038032SpeterR< d > $* $@ deferred 168138032SpeterR< $* > $* $: $2 168238032Speter 168364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 168466494Sgshapirodnl workspace: {client_name} $| {client_addr} 168590792SgshapiroR$+ $| $+ $: $>D < $1 > <?> <+ Connect> < $2 > 168666494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 168790792SgshapiroR<?> <$+> $: $>A < $1 > <?> <+ Connect> <> no: another lookup 168890792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) 168990792SgshapiroR<?> <$*> $: OK found nothing 169090792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK 169190792SgshapiroR<$={Accept}> <$*> $@ $1 return value of lookup 169290792SgshapiroR<REJECT> <$*> $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 169390792SgshapiroR<DISCARD> <$*> $#discard $: discard 169490792Sgshapiroifdef(`_FFR_QUARANTINE', 169590792Sgshapiro`R<QUARANTINE:$+> <$*> $#error $@ quarantine $: $1', `dnl') 169664562Sgshapirodnl error tag 169766494SgshapiroR<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 169866494SgshapiroR<ERROR:$+> <$*> $#error $: $1 169990792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 170064562Sgshapirodnl generic error from access map 170166494SgshapiroR<$+> <$*> $#error $: $1', `dnl') 170238032Speter 170364562Sgshapiroifdef(`_RBL_',`dnl 170464562Sgshapiro# DNS based IP address spam list 170590792Sgshapirodnl workspace: ignored... 170638032SpeterR$* $: $&{client_addr} 170764562SgshapiroR$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 170864562SgshapiroR<?>OK $: OKSOFAR 170964562SgshapiroR<?>$+ $#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"', 171038032Speter`dnl') 171164562Sgshapiroundivert(8) 171238032Speter 171338032Speter###################################################################### 171438032Speter### check_mail -- check SMTP ``MAIL FROM:'' command argument 171538032Speter###################################################################### 171638032Speter 171738032SpeterSLocal_check_mail 171864562SgshapiroScheck`'_U_`'mail 171938032SpeterR$* $: $1 $| $>"Local_check_mail" $1 172038032SpeterR$* $| $#$* $#$2 172138032SpeterR$* $| $* $@ $>"Basic_check_mail" $1 172238032Speter 172338032SpeterSBasic_check_mail 172438032Speter# check for deferred delivery mode 172538032SpeterR$* $: < ${deliveryMode} > $1 172638032SpeterR< d > $* $@ deferred 172738032SpeterR< $* > $* $: $2 172838032Speter 172964562Sgshapiro# authenticated? 173064562Sgshapirodnl done first: we can require authentication for every mail transaction 173164562Sgshapirodnl workspace: address as given by MAIL FROM: (sender) 173264562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 173364562SgshapiroR$* $| $#$+ $#$2 173464562Sgshapirodnl undo damage: remove result of tls_client call 173564562SgshapiroR$* $| $* $: $1 173638032Speter 173764562Sgshapirodnl workspace: address as given by MAIL FROM: 173864562SgshapiroR<> $@ <OK> we MUST accept <> (RFC 1123) 173938032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 174064562Sgshapirodnl do some additional checks 174164562Sgshapirodnl no user@host 174264562Sgshapirodnl no user@localhost (if nonlocal sender) 174364562Sgshapirodnl this is a pretty simple canonification, it will not catch every case 174464562Sgshapirodnl just make sure the address has <> around it (which is required by 174564562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...) 174664562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will 174764562Sgshapirodnl not be modified by host lookups. 174864562SgshapiroR$+ $: <?> $1 174964562SgshapiroR<?><$+> $: <@> <$1> 175064562SgshapiroR<?>$+ $: <@> <$1> 175164562Sgshapirodnl workspace: <@> <address> 175264562Sgshapirodnl prepend daemon_flags 175364562SgshapiroR$* $: $&{daemon_flags} $| $1 175464562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 175564562Sgshapirodnl do not allow these at all or only from local systems? 175664562SgshapiroR$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 175764562Sgshapirodnl accept unqualified sender: change mark to avoid test 175864562SgshapiroR$* u $* $| <@> < $* > $: <?> < $3 > 175964562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 176064562Sgshapirodnl or: <? ${client_name} > <address> 176164562Sgshapirodnl or: <?> <address> 176264562Sgshapirodnl remove daemon_flags 176364562SgshapiroR$* $| $* $: $2 176438032Speter# handle case of @localhost on address 176564562SgshapiroR<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 176664562SgshapiroR<@> < $* @ [127.0.0.1] > 176764562Sgshapiro $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 176864562SgshapiroR<@> < $* @ localhost.$m > 176964562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.$m > 177038032Speterifdef(`_NO_UUCP_', `dnl', 177164562Sgshapiro`R<@> < $* @ localhost.UUCP > 177264562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 177364562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 177464562Sgshapirodnl or: <@> <address> 177564562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 177664562SgshapiroR<@> $* $: $1 no localhost as domain 177764562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 177864562Sgshapirodnl or: <address> 177964562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 178064562SgshapiroR<? $=w> $* $: $2 local client: ok 178190792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address" 178264562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 178364562SgshapiroR<?> $* $: $1') 178464562Sgshapirodnl workspace: address (or <address>) 178564562SgshapiroR$* $: <?> $>CanonAddr $1 canonify sender address and mark it 178664562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 178764562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed 178864562SgshapiroR<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 178964562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 179064562SgshapiroR<?> $* < @ $* $=P > $: <OK> $1 < @ $2 $3 > 179164562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ? or OK 179264562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 179390792Sgshapiro`R<?> $* < @ $+ > $: <_RES_OK_> $1 < @ $2 > ... unresolvable OK', 179464562Sgshapiro`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 179564562SgshapiroR<? $* <$->> $* < @ $+ > 179664562Sgshapiro $: <$2> $3 < @ $4 >') 179790792Sgshapirodnl workspace <mark> CanonicalAddress where mark is ?, _RES_OK_, PERM, TEMP 179864562Sgshapirodnl mark is ? iff the address is user (wo @domain) 179938032Speter 180064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 180164562Sgshapiro# check sender address: user@address, user@, address 180264562Sgshapirodnl should we remove +ext from user? 180390792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP 180490792SgshapiroR<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3> 180564562SgshapiroR<$+> $+ $: @<$1> <$2> $| <U:$2@> 180664562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 180764562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 180864562Sgshapirodnl will only return user<@domain when "reversing" the args 180990792SgshapiroR@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <> 181064562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result> 181164562SgshapiroR<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 181264562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress> 181338032Speter# retransform for further use 181464562Sgshapirodnl required form: 181564562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress 181664562SgshapiroR<?> <$+> <$*> $: <$1> $2 no match 181764562SgshapiroR<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 181864562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress 181964562Sgshapirodnl mark is ? iff the address is user (wo @domain) 182038032Speter 182138032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 182238032Speter# handle case of no @domain on address 182364562Sgshapirodnl prepend daemon_flags 182464562SgshapiroR<?> $* $: $&{daemon_flags} $| <?> $1 182564562Sgshapirodnl accept unqualified sender: change mark to avoid test 182690792SgshapiroR$* u $* $| <?> $* $: <_RES_OK_> $3 182764562Sgshapirodnl remove daemon_flags 182864562SgshapiroR$* $| $* $: $2 182938032SpeterR<?> $* $: < ? $&{client_name} > $1 183038032SpeterR<?> $* $@ <OK> ...local unqualed ok 183190792SgshapiroR<? $+> $* $#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f 183238032Speter ...remote is not') 183338032Speter# check results 183464562SgshapiroR<?> $* $: @ $1 mark address: nothing known about it 183590792SgshapiroR<$={ResOk}> $* $@ <_RES_OK_> domain ok: stop 183664562SgshapiroR<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 183790792SgshapiroR<PERM> $* $#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist" 183864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 183990792SgshapiroR<$={Accept}> $* $# $1 accept from access map 184038032SpeterR<DISCARD> $* $#discard $: discard 184190792Sgshapiroifdef(`_FFR_QUARANTINE', 184290792Sgshapiro`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 184364562SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 184464562Sgshapirodnl error tag 184564562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 184664562SgshapiroR<ERROR:$+> $* $#error $: $1 184790792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 184864562Sgshapirodnl generic error from access map 184964562SgshapiroR<$+> $* $#error $: $1 error from access db', 185038032Speter`dnl') 185138032Speter 185238032Speter###################################################################### 185338032Speter### check_rcpt -- check SMTP ``RCPT TO:'' command argument 185438032Speter###################################################################### 185538032Speter 185638032SpeterSLocal_check_rcpt 185764562SgshapiroScheck`'_U_`'rcpt 185838032SpeterR$* $: $1 $| $>"Local_check_rcpt" $1 185938032SpeterR$* $| $#$* $#$2 186038032SpeterR$* $| $* $@ $>"Basic_check_rcpt" $1 186138032Speter 186238032SpeterSBasic_check_rcpt 186390792Sgshapiro# empty address? 186490792SgshapiroR<> $#error $@ nouser $: "553 User address required" 186590792SgshapiroR$@ $#error $@ nouser $: "553 User address required" 186638032Speter# check for deferred delivery mode 186738032SpeterR$* $: < ${deliveryMode} > $1 186838032SpeterR< d > $* $@ deferred 186938032SpeterR< $* > $* $: $2 187038032Speter 187164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 187290792Sgshapirodnl this code checks for user@host where host is not a FQHN. 187390792Sgshapirodnl it is not activated. 187490792Sgshapirodnl notice: code to check for a recipient without a domain name is 187590792Sgshapirodnl available down below; look for the same macro. 187690792Sgshapirodnl this check is done here because the name might be qualified by the 187790792Sgshapirodnl canonicalization. 187890792Sgshapiro# require fully qualified domain part? 187990792Sgshapirodnl very simple canonification: make sure the address is in < > 188064562SgshapiroR$+ $: <?> $1 188190792SgshapiroR<?> <$+> $: <@> <$1> 188290792SgshapiroR<?> $+ $: <@> <$1> 188390792SgshapiroR<@> < postmaster > $: postmaster 188490792SgshapiroR<@> < $* @ $+ . $+ > $: < $3 @ $4 . $5 > 188564562Sgshapirodnl prepend daemon_flags 188690792SgshapiroR<@> $* $: $&{daemon_flags} $| <@> $1 188764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 188864562Sgshapirodnl do not allow these at all or only from local systems? 188990792SgshapiroR$* r $* $| <@> < $* @ $* > $: < ? $&{client_name} > < $3 @ $4 > 189064562SgshapiroR<?> < $* > $: <$1> 189164562SgshapiroR<? $=w> < $* > $: <$1> 189290792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "553 Fully qualified domain name required" 189364562Sgshapirodnl remove daemon_flags for other cases 189464562SgshapiroR$* $| <@> $* $: $2', `dnl') 189564562Sgshapiro 189690792Sgshapirodnl ################################################################## 189790792Sgshapirodnl call subroutines for recipient and relay 189890792Sgshapirodnl possible returns from subroutines: 189990792Sgshapirodnl $#TEMP temporary failure 190090792Sgshapirodnl $#error permanent failure (or temporary if from access map) 190190792Sgshapirodnl $#other stop processing 190290792Sgshapirodnl RELAY RELAYing allowed 190390792Sgshapirodnl other otherwise 190490792Sgshapiro###################################################################### 190590792SgshapiroR$* $: $1 $| @ $>"Rcpt_ok" $1 190690792Sgshapirodnl temporary failure? remove mark @ and remember 190790792SgshapiroR$* $| @ $#TEMP $+ $: $1 $| T $2 190890792Sgshapirodnl error or ok (stop) 190990792SgshapiroR$* $| @ $#$* $#$2 191090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 191190792SgshapiroR$* $| @ RELAY $@ RELAY 191290792Sgshapirodnl something else: call check sender (relay) 191390792SgshapiroR$* $| @ $* $: O $| $>"Relay_ok" $1 191490792Sgshapirodnl temporary failure: call check sender (relay) 191590792SgshapiroR$* $| T $+ $: T $2 $| $>"Relay_ok" $1 191690792Sgshapirodnl temporary failure? return that 191790792SgshapiroR$* $| $#TEMP $+ $#error $2 191890792Sgshapirodnl error or ok (stop) 191990792SgshapiroR$* $| $#$* $#$2 192090792SgshapiroR$* $| RELAY $@ RELAY 192190792Sgshapirodnl something else: return previous temp failure 192290792SgshapiroR T $+ $| $* $#error $1 192390792Sgshapiro# anything else is bogus 192490792SgshapiroR$* $#error $@ 5.7.1 $: confRELAY_MSG 192590792Sgshapirodivert(0) 192690792Sgshapiro 192790792Sgshapiro###################################################################### 192890792Sgshapiro### Rcpt_ok: is the recipient ok? 192990792Sgshapirodnl input: recipient address (RCPT TO) 193090792Sgshapirodnl output: see explanation at call 193190792Sgshapiro###################################################################### 193290792SgshapiroSRcpt_ok 193338032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl 193442575SpeterR$* $: $>CanonAddr $1 193538032SpeterR$* < @ $* . > $1 < @ $2 > strip trailing dots', 193638032Speter`R$* $: $>ParseRecipient $1 strip relayable hosts') 193738032Speter 193842575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl 193942575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl 194042575Speter# unlimited bestmx 194142575SpeterR$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 194242575Speter`dnl 194342575Speter# limit bestmx to $=B 194443730SpeterR$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 194590792SgshapiroR$* $=O $* < @ $* @@ $=w . > $* $@ $>"Rcpt_ok" $1 $2 $3 194642575SpeterR$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 194742575SpeterR$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 194842575Speter 194938032Speterifdef(`_BLACKLIST_RCPT_',`dnl 195064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 195138032Speter# blacklist local users or any host from receiving mail 195238032SpeterR$* $: <?> $1 195364562Sgshapirodnl user is now tagged with @ to be consistent with check_mail 195464562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user) 195590792SgshapiroR<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2> 195690792SgshapiroR<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2> 195764562SgshapiroR<?> $+ $: <> <$1> $| <U:$1@> 195864562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 195964562Sgshapirodnl will only return user<@domain when "reversing" the args 196090792SgshapiroR<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+ To> $| <$2> <> 196164562SgshapiroR<@> <$*> $| <$*> $: <$2> <$1> reverse result 196264562SgshapiroR<?> <$*> $: @ $1 mark address as no match 196390792Sgshapirodnl we may have to filter here because otherwise some RHSs 196490792Sgshapirodnl would be interpreted as generic error messages... 196590792Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 196690792Sgshapirodnl that would make a lot of things easier. 196764562SgshapiroR<$={Accept}> <$*> $: @ $2 mark address as no match 196890792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 196990792SgshapiroR<SKIP> <$*> $: @ $1 mark address as no match', `dnl') 197090792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl 197190792Sgshapirodnl compatility with 8.11/8.10: 197264562Sgshapirodnl we have to filter these because otherwise they would be interpreted 197364562Sgshapirodnl as generic error message... 197464562Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 197564562Sgshapirodnl that would make a lot of things easier. 197664562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)? 197764562SgshapiroR<$={SpamTag}> <$*> $: @ $2 mark address as no match') 197890792SgshapiroR<REJECT> $* $#error $@ 5.2.1 $: confRCPTREJ_MSG 197964562SgshapiroR<DISCARD> $* $#discard $: discard 198090792Sgshapiroifdef(`_FFR_QUARANTINE', 198190792Sgshapiro`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 198264562Sgshapirodnl error tag 198364562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 198464562SgshapiroR<ERROR:$+> $* $#error $: $1 198590792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 198664562Sgshapirodnl generic error from access map 198764562SgshapiroR<$+> $* $#error $: $1 error from access db 198864562SgshapiroR@ $* $1 remove mark', `dnl')', `dnl') 198938032Speter 199090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 199190792Sgshapiro# authenticated via TLS? 199290792SgshapiroR$* $: $1 $| $>RelayTLS client authenticated? 199390792SgshapiroR$* $| $# $+ $# $2 error/ok? 199490792SgshapiroR$* $| $* $: $1 no 199564562Sgshapiro 199690792SgshapiroR$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type} 199790792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth 199890792SgshapiroR$* $| $# $* $# $2 199990792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech} 200090792SgshapiroR$* $| NO $: $1 200190792SgshapiroR$* $| $* $: $1 $| $&{auth_type} 200290792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ] 200364562Sgshapirodnl empty ${auth_type}? 200464562SgshapiroR$* $| $: $1 200564562Sgshapirodnl mechanism ${auth_type} accepted? 200664562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below 200790792SgshapiroR$* $| $={TrustAuthMech} $# RELAY 200890792Sgshapirodnl remove ${auth_type} 200964562SgshapiroR$* $| $* $: $1 201071345Sgshapirodnl workspace: localpart<@domain> | localpart 201164562Sgshapiroifelse(defn(`_NO_UUCP_'), `r', 201271345Sgshapiro`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 201371345SgshapiroR$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 201438032Speter# anything terminating locally is ok 201538032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 201690792SgshapiroR$+ < @ $* $=m > $@ RELAY', `dnl') 201790792SgshapiroR$+ < @ $=w > $@ RELAY 201838032Speterifdef(`_RELAY_HOSTS_ONLY_', 201990792Sgshapiro`R$+ < @ $=R > $@ RELAY 202064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 202164562SgshapiroR$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 202264562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 202364562SgshapiroR<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 202490792Sgshapiro`R$+ < @ $* $=R > $@ RELAY 202564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 202690792SgshapiroR$+ < @ $+ > $: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')') 202764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 202864562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 202990792SgshapiroR<RELAY> $* $@ RELAY 203090792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 203138032SpeterR<$*> <$*> $: $2',`dnl') 203238032Speter 203364562Sgshapiro 203438032Speterifdef(`_RELAY_MX_SERVED_', `dnl 203538032Speter# allow relaying for hosts which we MX serve 203664562SgshapiroR$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 203764562Sgshapirodnl this must not necessarily happen if the client is checked first... 203890792SgshapiroR< : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 203990792SgshapiroR<$* : $=w . : $*> $* $@ RELAY 204042575SpeterR< : $* : > $* $: $2', 204138032Speter`dnl') 204238032Speter 204338032Speter# check for local user (i.e. unqualified address) 204438032SpeterR$* $: <?> $1 204542575SpeterR<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 204638032Speter# local user is ok 204764562Sgshapirodnl is it really? the standard requires user@domain, not just user 204864562Sgshapirodnl but we should accept it anyway (maybe making it an option: 204964562Sgshapirodnl RequireFQDN ?) 205064562Sgshapirodnl postmaster must be accepted without domain (DRUMS) 205164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 205290792SgshapiroR<?> postmaster $@ OK 205364562Sgshapiro# require qualified recipient? 205464562Sgshapirodnl prepend daemon_flags 205564562SgshapiroR<?> $+ $: $&{daemon_flags} $| <?> $1 205664562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart 205764562Sgshapirodnl do not allow these at all or only from local systems? 205864562Sgshapirodnl r flag? add client_name 205964562SgshapiroR$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 206064562Sgshapirodnl no r flag: relay to local user (only local part) 206164562Sgshapiro# no qualified recipient required 206290792SgshapiroR$* $| <?> $+ $@ RELAY 206364562Sgshapirodnl client_name is empty 206490792SgshapiroR<?> <?> $+ $@ RELAY 206564562Sgshapirodnl client_name is local 206690792SgshapiroR<? $=w> <?> $+ $@ RELAY 206764562Sgshapirodnl client_name is not local 206864562SgshapiroR<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 206964562Sgshapirodnl no qualified recipient required 207090792SgshapiroR<?> $+ $@ RELAY') 207164562Sgshapirodnl it is a remote user: remove mark and then check client 207238032SpeterR<$+> $* $: $2 207364562Sgshapirodnl currently the recipient address is not used below 207438032Speter 207590792Sgshapiro###################################################################### 207690792Sgshapiro### Relay_ok: is the relay/sender ok? 207790792Sgshapirodnl input: ignored 207890792Sgshapirodnl output: see explanation at call 207990792Sgshapiro###################################################################### 208090792SgshapiroSRelay_ok 208138032Speter# anything originating locally is ok 208264562Sgshapiro# check IP address 208364562SgshapiroR$* $: $&{client_addr} 208490792SgshapiroR$@ $@ RELAY originated locally 208590792SgshapiroR0 $@ RELAY originated locally 208690792SgshapiroR$=R $* $@ RELAY relayable IP address 208764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 208890792SgshapiroR$* $: $>A <$1> <?> <+ Connect> <$1> 208990792SgshapiroR<RELAY> $* $@ RELAY relayable IP address 209090792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 209164562SgshapiroR<$*> <$*> $: $2', `dnl') 209264562SgshapiroR$* $: [ $1 ] put brackets around it... 209390792SgshapiroR$=w $@ RELAY ... and see if it is local 209464562Sgshapiro 209564562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 209664562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 209764562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl 209864562Sgshapirodnl input: {client_addr} or something "broken" 209964562Sgshapirodnl just throw the input away; we do not need it. 210064562Sgshapiro# check whether FROM is allowed to use system as relay 210164562SgshapiroR$* $: <?> $>CanonAddr $&f 210290792SgshapiroR<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 210364562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl 210464562Sgshapiro# check whether local FROM is ok 210590792SgshapiroR<?> $+ < @ $=w > $@ RELAY FROM local', `dnl') 210664562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl 210790792SgshapiroR<?> $+ < @ $+ > $: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<D:$2>') <> 210890792SgshapiroR<@> <RELAY> $@ RELAY RELAY FROM sender ok 210990792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 211090792Sgshapiro', `dnl 211190792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', 211290792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 211364562Sgshapiro')', 211464562Sgshapiro`dnl') 211564562Sgshapirodnl')', `dnl') 211690792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind. 211790792Sgshapirodnl it does not matter in this case because the following rule ignores 211890792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace. 211964562Sgshapiro 212064562Sgshapiro# check client name: first: did it resolve? 212164562Sgshapirodnl input: ignored 212264562SgshapiroR$* $: < $&{client_resolve} > 212390792SgshapiroR<TEMP> $#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 212464562SgshapiroR<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 212564562SgshapiroR<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 212664562Sgshapirodnl ${client_resolve} should be OK, so go ahead 212790792SgshapiroR$* $: <@> $&{client_name} 212890792Sgshapirodnl should not be necessary since it has been done for client_addr already 212990792SgshapiroR<@> $@ RELAY 213090792Sgshapirodnl workspace: <@> ${client_name} (not empty) 213138032Speter# pass to name server to make hostname canonical 213290792SgshapiroR<@> $* $=P $:<?> $1 $2 213390792SgshapiroR<@> $+ $:<?> $[ $1 $] 213490792Sgshapirodnl workspace: <?> ${client_name} (canonified) 213564562SgshapiroR$* . $1 strip trailing dots 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 Connect:$1 $: ? $)> <$1> 214364562SgshapiroR<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 214490792Sgshapiro`R<?> $* $=R $@ RELAY 214564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 214690792SgshapiroR<?> $* $: $>D <$1> <?> <+ Connect> <$1>',`dnl')') 214764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 214890792SgshapiroR<RELAY> $* $@ RELAY 214990792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 215038032SpeterR<$*> <$*> $: $2',`dnl') 215190792Sgshapirodnl end of _PROMISCUOUS_RELAY_ 215264562Sgshapirodivert(0) 215364562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 215464562Sgshapiro# turn a canonical address in the form user<@domain> 215564562Sgshapiro# qualify unqual. addresses with $j 215664562Sgshapirodnl it might have been only user (without <@domain>) 215764562SgshapiroSFullAddr 215864562SgshapiroR$* <@ $+ . > $1 <@ $2 > 215964562SgshapiroR$* <@ $* > $@ $1 <@ $2 > 216064562SgshapiroR$+ $@ $1 <@ $j > 216138032Speter 216264562Sgshapiro# call all necessary rulesets 216364562SgshapiroScheck_rcpt 216464562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset 216564562Sgshapirodnl which is the correct DSN code? 216664562Sgshapiro# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 216764562SgshapiroR$+ $: $1 $| $>checkrcpt $1 216864562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 216964562SgshapiroR$+ $| $#$* $#$2 217064562SgshapiroR$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 217164562Sgshapiroifdef(`_SPAM_FH_', 217264562Sgshapiro`dnl lookup user@ and user@address 217364562Sgshapiroifdef(`_ACCESS_TABLE_', `', 217464562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 217564562Sgshapiro')')dnl 217664562Sgshapirodnl one of the next two rules is supposed to match 217764562Sgshapirodnl this code has been copied from BLACKLIST... etc 217864562Sgshapirodnl and simplified by omitting some < >. 217990792SgshapiroR<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@> 218090792SgshapiroR<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > 218164562Sgshapirodnl R<?> $@ something_is_very_wrong_here 218290792Sgshapiro# lookup the addresses only with Spam tag 218390792SgshapiroR<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <> 218464562SgshapiroR<@> $* $| $* $: $2 $1 reverse result 218564562Sgshapirodnl', `dnl') 218664562Sgshapiroifdef(`_SPAM_FRIEND_', 218764562Sgshapiro`# is the recipient a spam friend? 218864562Sgshapiroifdef(`_SPAM_HATER_', 218964562Sgshapiro `errprint(`*** ERROR: define either SpamHater or SpamFriend 219064562Sgshapiro')', `dnl') 219190792SgshapiroR<FRIEND> $+ $@ SPAMFRIEND 219264562SgshapiroR<$*> $+ $: $2', 219364562Sgshapiro`dnl') 219464562Sgshapiroifdef(`_SPAM_HATER_', 219564562Sgshapiro`# is the recipient no spam hater? 219690792SgshapiroR<HATER> $+ $: $1 spam hater: continue checks 219764562SgshapiroR<$*> $+ $@ NOSPAMHATER everyone else: stop 219864562Sgshapirodnl',`dnl') 219964562Sgshapirodnl run further checks: check_mail 220064562Sgshapirodnl should we "clean up" $&f? 220190792Sgshapiroifdef(`_FFR_MAIL_MACRO', 220290792Sgshapiro`R$* $: $1 $| $>checkmail $&{mail_from}', 220390792Sgshapiro`R$* $: $1 $| $>checkmail <$&f>') 220464562SgshapiroR$* $| $#$* $#$2 220564562Sgshapirodnl run further checks: check_relay 220664562SgshapiroR$* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 220764562SgshapiroR$* $| $#$* $#$2 220838032SpeterR$* $| $* $: $1 220938032Speter', `dnl') 221090792Sgshapiro 221190792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 221264562Sgshapiro###################################################################### 221390792Sgshapiro### F: LookUpFull -- search for an entry in access database 221490792Sgshapiro### 221590792Sgshapiro### lookup of full key (which should be an address) and 221690792Sgshapiro### variations if +detail exists: +* and without +detail 221790792Sgshapiro### 221890792Sgshapiro### Parameters: 221990792Sgshapiro### <$1> -- key 222090792Sgshapiro### <$2> -- default (what to return if not found in db) 222190792Sgshapirodnl must not be empty 222290792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 222390792Sgshapiro### ! does lookup only with tag 222490792Sgshapiro### + does lookup with and without tag 222590792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 222690792Sgshapirodnl returns: <default> <passthru> 222790792Sgshapirodnl <result> <passthru> 222890792Sgshapiro###################################################################### 222990792Sgshapiro 223090792SgshapiroSF 223190792Sgshapirodnl workspace: <key> <def> <o tag> <thru> 223290792Sgshapirodnl full lookup 223390792Sgshapirodnl 2 3 4 5 223490792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 223590792Sgshapirodnl no match, try without tag 223690792Sgshapirodnl 1 2 3 4 223790792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 223890792Sgshapirodnl no match, +detail: try +* 223990792Sgshapirodnl 1 2 3 4 5 6 7 224090792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 224190792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 224290792Sgshapirodnl no match, +detail: try +* without tag 224390792Sgshapirodnl 1 2 3 4 5 6 224490792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 224590792Sgshapiro $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 224690792Sgshapirodnl no match, +detail: try without +detail 224790792Sgshapirodnl 1 2 3 4 5 6 7 224890792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 224990792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 225090792Sgshapirodnl no match, +detail: try without +detail and without tag 225190792Sgshapirodnl 1 2 3 4 5 6 225290792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 225390792Sgshapiro $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 225490792Sgshapirodnl no match, return <default> <passthru> 225590792Sgshapirodnl 1 2 3 4 5 225690792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 225790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 225890792Sgshapirodnl 2 3 4 5 225990792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 226090792Sgshapirodnl match, return <match> <passthru> 226190792Sgshapirodnl 2 3 4 5 226290792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 226390792Sgshapiro 226490792Sgshapiro###################################################################### 226590792Sgshapiro### E: LookUpExact -- search for an entry in access database 226690792Sgshapiro### 226790792Sgshapiro### Parameters: 226890792Sgshapiro### <$1> -- key 226990792Sgshapiro### <$2> -- default (what to return if not found in db) 227090792Sgshapirodnl must not be empty 227190792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 227290792Sgshapiro### ! does lookup only with tag 227390792Sgshapiro### + does lookup with and without tag 227490792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 227590792Sgshapirodnl returns: <default> <passthru> 227690792Sgshapirodnl <result> <passthru> 227790792Sgshapiro###################################################################### 227890792Sgshapiro 227990792SgshapiroSE 228090792Sgshapirodnl 2 3 4 5 228190792SgshapiroR<$*> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 228290792Sgshapirodnl no match, try without tag 228390792Sgshapirodnl 1 2 3 4 228490792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 228590792Sgshapirodnl no match, return default passthru 228690792Sgshapirodnl 1 2 3 4 5 228790792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 228890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 228990792Sgshapirodnl 2 3 4 5 229090792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 229190792Sgshapirodnl match, return <match> <passthru> 229290792Sgshapirodnl 2 3 4 5 229390792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 229490792Sgshapiro 229590792Sgshapiro###################################################################### 229690792Sgshapiro### U: LookUpUser -- search for an entry in access database 229790792Sgshapiro### 229890792Sgshapiro### lookup of key (which should be a local part) and 229990792Sgshapiro### variations if +detail exists: +* and without +detail 230090792Sgshapiro### 230190792Sgshapiro### Parameters: 230290792Sgshapiro### <$1> -- key (user@) 230390792Sgshapiro### <$2> -- default (what to return if not found in db) 230490792Sgshapirodnl must not be empty 230590792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 230690792Sgshapiro### ! does lookup only with tag 230790792Sgshapiro### + does lookup with and without tag 230890792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 230990792Sgshapirodnl returns: <default> <passthru> 231090792Sgshapirodnl <result> <passthru> 231190792Sgshapiro###################################################################### 231290792Sgshapiro 231390792SgshapiroSU 231490792Sgshapirodnl user lookups are always with trailing @ 231590792Sgshapirodnl 2 3 4 5 231690792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 231790792Sgshapirodnl no match, try without tag 231890792Sgshapirodnl 1 2 3 4 231990792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 232090792Sgshapirodnl do not remove the @ from the lookup: 232190792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup 232290792Sgshapirodnl no match, +detail: try +* 232390792Sgshapirodnl 1 2 3 4 5 6 232490792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 232590792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 232690792Sgshapirodnl no match, +detail: try +* without tag 232790792Sgshapirodnl 1 2 3 4 5 232890792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 232990792Sgshapiro $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 233090792Sgshapirodnl no match, +detail: try without +detail 233190792Sgshapirodnl 1 2 3 4 5 6 233290792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 233390792Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 233490792Sgshapirodnl no match, +detail: try without +detail and without tag 233590792Sgshapirodnl 1 2 3 4 5 233690792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 233790792Sgshapiro $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 233890792Sgshapirodnl no match, return <default> <passthru> 233990792Sgshapirodnl 1 2 3 4 5 234090792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 234190792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 234290792Sgshapirodnl 2 3 4 5 234390792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 234490792Sgshapirodnl match, return <match> <passthru> 234590792Sgshapirodnl 2 3 4 5 234690792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 234790792Sgshapiro 234890792Sgshapiro###################################################################### 234964562Sgshapiro### SearchList: search a list of items in the access map 235064562Sgshapiro### Parameters: 235164562Sgshapiro### <exact tag> $| <mark:address> <mark:address> ... <> 235264562Sgshapirodnl maybe we should have a @ (again) in front of the mark to 235364562Sgshapirodnl avoid errorneous matches (with error messages?) 235464562Sgshapirodnl if we can make sure that tag is always a single token 235564562Sgshapirodnl then we can omit the delimiter $|, otherwise we need it 235690792Sgshapirodnl to avoid errorneous matchs (first rule: D: if there 235764562Sgshapirodnl is that mark somewhere in the list, it will be taken). 235864562Sgshapirodnl moreover, we can do some tricks to enforce lookup with 235964562Sgshapirodnl the tag only, e.g.: 236064562Sgshapiro### where "exact" is either "+" or "!": 236164562Sgshapiro### <+ TAG> lookup with and w/o tag 236264562Sgshapiro### <! TAG> lookup with tag 236364562Sgshapirodnl Warning: + and ! should be in OperatorChars (otherwise there must be 236464562Sgshapirodnl a blank between them and the tag. 236564562Sgshapiro### possible values for "mark" are: 236690792Sgshapiro### D: recursive host lookup (LookUpDomain) 236764562Sgshapirodnl A: recursive address lookup (LookUpAddress) [not yet required] 236864562Sgshapiro### E: exact lookup, no modifications 236964562Sgshapiro### F: full lookup, try user+ext@domain and user@domain 237064562Sgshapiro### U: user lookup, try user+ext and user (input must have trailing @) 237164562Sgshapiro### return: <RHS of lookup> or <?> (not found) 237264562Sgshapiro###################################################################### 237338032Speter 237464562Sgshapiro# class with valid marks for SearchList 237564562Sgshapirodnl if A is activated: add it 237690792SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A') 237764562SgshapiroSSearchList 237890792Sgshapiro# just call the ruleset with the name of the tag... nice trick... 237990792Sgshapirodnl 2 3 4 238090792SgshapiroR<$+> $| <$={src}:$*> <$*> $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <> 238190792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <> 238290792Sgshapirodnl no match and nothing left: return 238390792SgshapiroR<$+> $| <> $| <?> <> $@ <?> 238490792Sgshapirodnl no match but something left: continue 238590792SgshapiroR<$+> $| <$+> $| <?> <> $@ $>SearchList <$1> $| <$2> 238690792Sgshapirodnl match: return 238790792SgshapiroR<$+> $| <$*> $| <$+> <> $@ <$3> 238864562Sgshapirodnl return result from recursive invocation 238990792SgshapiroR<$+> $| <$+> $@ <$2> 239090792Sgshapirodnl endif _ACCESS_TABLE_ 239190792Sgshapirodivert(0) 239238032Speter 239390792Sgshapiro###################################################################### 239490792Sgshapiro### trust_auth: is user trusted to authenticate as someone else? 239590792Sgshapiro### 239690792Sgshapiro### Parameters: 239790792Sgshapiro### $1: AUTH= parameter from MAIL command 239890792Sgshapiro###################################################################### 239990792Sgshapiro 240090792Sgshapirodnl empty ruleset definition so it can be called 240190792SgshapiroSLocal_trust_auth 240264562SgshapiroStrust_auth 240364562SgshapiroR$* $: $&{auth_type} $| $1 240464562Sgshapiro# required by RFC 2554 section 4. 240564562SgshapiroR$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 240664562Sgshapirodnl seems to be useful... 240764562SgshapiroR$* $| $&{auth_authen} $@ identical 240864562SgshapiroR$* $| <$&{auth_authen}> $@ identical 240964562Sgshapirodnl call user supplied code 241064562SgshapiroR$* $| $* $: $1 $| $>"Local_trust_auth" $1 241164562SgshapiroR$* $| $#$* $#$2 241264562Sgshapirodnl default: error 241364562SgshapiroR$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 241464562Sgshapiro 241590792Sgshapiro###################################################################### 241690792Sgshapiro### Relay_Auth: allow relaying based on authentication? 241790792Sgshapiro### 241890792Sgshapiro### Parameters: 241990792Sgshapiro### $1: ${auth_type} 242090792Sgshapiro###################################################################### 242190792SgshapiroSLocal_Relay_Auth 242264562Sgshapiro 242390792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 242490792Sgshapiro###################################################################### 242590792Sgshapiro### srv_features: which features to offer to a client? 242690792Sgshapiro### (done in server) 242790792Sgshapiro###################################################################### 242890792SgshapiroSsrv_features 242990792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl 243090792SgshapiroR$* $: $1 $| $>"Local_srv_features" $1 243190792SgshapiroR$* $| $#$* $#$2 243290792SgshapiroR$* $| $* $: $1', `dnl') 243390792SgshapiroR$* $: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <> 243490792SgshapiroR<?>$* $: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <> 243590792SgshapiroR<?>$* $: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)> 243664562SgshapiroR<?>$* $@ OK 243790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 243890792SgshapiroR<$* _ATMPF_>$* $#temp', `dnl') 243990792SgshapiroR<$+>$* $# $1 244064562Sgshapiro 244190792Sgshapiro###################################################################### 244290792Sgshapiro### try_tls: try to use STARTTLS? 244390792Sgshapiro### (done in client) 244490792Sgshapiro###################################################################### 244564562SgshapiroStry_tls 244690792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl 244790792SgshapiroR$* $: $1 $| $>"Local_try_tls" $1 244890792SgshapiroR$* $| $#$* $#$2 244990792SgshapiroR$* $| $* $: $1', `dnl') 245090792SgshapiroR$* $: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <> 245190792SgshapiroR<?>$* $: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <> 245290792SgshapiroR<?>$* $: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)> 245364562SgshapiroR<?>$* $@ OK 245490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 245590792SgshapiroR<$* _ATMPF_>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 245671345SgshapiroR<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 245790792Sgshapiro 245890792Sgshapiro###################################################################### 245990792Sgshapiro### tls_rcpt: is connection with server "good" enough? 246090792Sgshapiro### (done in client, per recipient) 246190792Sgshapirodnl called from deliver() before RCPT command 246290792Sgshapiro### 246390792Sgshapiro### Parameters: 246490792Sgshapiro### $1: recipient 246590792Sgshapiro###################################################################### 246690792SgshapiroStls_rcpt 246790792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl 246890792SgshapiroR$* $: $1 $| $>"Local_tls_rcpt" $1 246990792SgshapiroR$* $| $#$* $#$2 247090792SgshapiroR$* $| $* $: $1', `dnl') 247190792Sgshapirodnl store name of other side 247290792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 247390792Sgshapirodnl canonify recipient address 247490792SgshapiroR$+ $: <?> $>CanonAddr $1 247590792Sgshapirodnl strip trailing dots 247690792SgshapiroR<?> $+ < @ $+ . > <?> $1 <@ $2 > 247790792Sgshapirodnl full address? 247890792SgshapiroR<?> $+ < @ $+ > $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:> 247990792Sgshapirodnl only localpart? 248090792SgshapiroR<?> $+ $: $1 $| <U:$1@> <E:> 248190792Sgshapirodnl look it up 248290792Sgshapirodnl also look up a default value via E: 248390792SgshapiroR$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <> 248490792Sgshapirodnl found nothing: stop here 248590792SgshapiroR$* $| <?> $@ OK 248690792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 248790792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 248890792Sgshapirodnl use the generic routine (for now) 248990792SgshapiroR$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>') 249064562Sgshapiro 249190792Sgshapiro###################################################################### 249290792Sgshapiro### tls_client: is connection with client "good" enough? 249390792Sgshapiro### (done in server) 249490792Sgshapiro### 249590792Sgshapiro### Parameters: 249690792Sgshapiro### ${verify} $| (MAIL|STARTTLS) 249790792Sgshapiro###################################################################### 249864562Sgshapirodnl MAIL: called from check_mail 249964562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted 250064562SgshapiroStls_client 250190792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl 250290792SgshapiroR$* $: $1 $| $>"Local_tls_client" $1 250390792SgshapiroR$* $| $#$* $#$2 250490792SgshapiroR$* $| $* $: $1', `dnl') 250564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 250690792Sgshapirodnl store name of other side 250790792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 250864562Sgshapirodnl ignore second arg for now 250964562Sgshapirodnl maybe use it to distinguish permanent/temporary error? 251064562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered) 251164562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed) 251290792SgshapiroR$* $| $* $: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <> 251390792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <> 251464562Sgshapirodnl do a default lookup: just TLS_CLT_TAG 251564562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 251690792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 251790792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 251890792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 251990792SgshapiroR$* $| $* $@ $>"TLS_connection" $1') 252064562Sgshapiro 252190792Sgshapiro###################################################################### 252290792Sgshapiro### tls_server: is connection with server "good" enough? 252390792Sgshapiro### (done in client) 252490792Sgshapiro### 252590792Sgshapiro### Parameter: 252690792Sgshapiro### ${verify} 252790792Sgshapiro###################################################################### 252864562Sgshapirodnl i.e. has the server been authenticated and is encryption active? 252964562Sgshapirodnl called from deliver() after STARTTLS command 253064562SgshapiroStls_server 253190792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl 253290792SgshapiroR$* $: $1 $| $>"Local_tls_server" $1 253390792SgshapiroR$* $| $#$* $#$2 253490792SgshapiroR$* $| $* $: $1', `dnl') 253564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 253690792Sgshapirodnl store name of other side 253790792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 253890792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <> 253990792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <> 254064562Sgshapirodnl do a default lookup: just TLS_SRV_TAG 254164562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 254290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 254390792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 254490792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 254590792SgshapiroR$* $@ $>"TLS_connection" $1') 254664562Sgshapiro 254790792Sgshapiro###################################################################### 254890792Sgshapiro### TLS_connection: is TLS connection "good" enough? 254990792Sgshapiro### 255090792Sgshapiro### Parameters: 255164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 255290792Sgshapiro### ${verify} $| <Requirement> [<>]', `dnl 255390792Sgshapiro### ${verify}') 255490792Sgshapiro### Requirement: RHS from access map, may be ? for none. 255590792Sgshapirodnl syntax for Requirement: 255690792Sgshapirodnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions] 255790792Sgshapirodnl extensions: could be a list of further requirements 255890792Sgshapirodnl for now: CN:string {cn_subject} == string 255990792Sgshapiro###################################################################### 256090792SgshapiroSTLS_connection 256190792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error 256290792Sgshapirodnl deal with TLS handshake failures: abort 256390792SgshapiroRSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake." 256490792Sgshapirodivert(-1)') 256564562Sgshapirodnl common ruleset for tls_{client|server} 256690792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>] 256764562Sgshapirodnl remove optional <> 256864562SgshapiroR$* $| <$*>$* $: $1 $| <$2> 256990792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup> 257090792Sgshapiro# create the appropriate error codes 257164562Sgshapirodnl permanent or temporary error? 257264562SgshapiroR$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 257364562SgshapiroR$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 257464562Sgshapirodnl default case depends on TLS_PERM_ERR 257564562SgshapiroR$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 257690792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup> 257790792Sgshapiro# deal with TLS handshake failures: abort 257864562SgshapiroRSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 257964562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 258064562Sgshapirodnl use default error 258164562SgshapiroRSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 258290792SgshapiroR$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1 258390792Sgshapirodnl separate optional requirements 258490792SgshapiroR$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1 258590792SgshapiroR$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> <> $1 258690792Sgshapirodnl separate optional requirements 258790792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$* $: <$2> <$3:$4> <$5> $1 258864562Sgshapirodnl some other value in access map: accept 258964562Sgshapirodnl this also allows to override the default case (if used) 259064562SgshapiroR$* $| $* $@ OK 259164562Sgshapiro# authentication required: give appropriate error 259264562Sgshapiro# other side did authenticate (via STARTTLS) 259390792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify} 259464562Sgshapirodnl only verification required and it succeeded 259590792SgshapiroR<$*><VERIFY> <> OK $@ OK 259690792Sgshapirodnl verification required and it succeeded but extensions are given 259790792Sgshapirodnl change it to <SMTP:ESC> <REQ:0> <extensions> 259890792SgshapiroR<$*><VERIFY> <$+> OK $: <$1> <REQ:0> <$2> 259964562Sgshapirodnl verification required + some level of encryption 260090792SgshapiroR<$*><VERIFY:$-> <$*> OK $: <$1> <REQ:$2> <$3> 260164562Sgshapirodnl just some level of encryption required 260290792SgshapiroR<$*><ENCR:$-> <$*> $* $: <$1> <REQ:$2> <$3> 260390792Sgshapirodnl workspace: 260490792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]> <[extensions]> {verify} (!= OK) 260590792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits> <[extensions]> 260690792Sgshapirodnl verification required but ${verify} is not set (case 1.) 260790792SgshapiroR<$-:$+><VERIFY $*> <$*> $#error $@ $2 $: $1 " authentication required" 260890792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL $#error $@ $2 $: $1 " authentication failed" 260990792SgshapiroR<$-:$+><VERIFY $*> <$*> NO $#error $@ $2 $: $1 " not authenticated" 261090792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT $#error $@ $2 $: $1 " no authentication requested" 261190792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 261264562Sgshapirodnl some other value for ${verify} 261390792SgshapiroR<$-:$+><VERIFY $*> <$*> $+ $#error $@ $2 $: $1 " authentication failure " $4 261490792Sgshapirodnl some level of encryption required: get the maximum level (case 2.) 261590792SgshapiroR<$*><REQ:$-> <$*> $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf} 261664562Sgshapirodnl compare required bits with actual bits 261790792SgshapiroR<$*><REQ:$-> <$*> $- $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $) 261890792SgshapiroR<$-:$+><$-:$-> <$*> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 261990792Sgshapirodnl strength requirements fulfilled 262090792Sgshapirodnl TLS Additional Requirements Separator 262190792Sgshapirodnl this should be something which does not appear in the extensions itself 262290792Sgshapirodnl @ could be part of a CN, DN, etc... 262390792Sgshapirodnl use < > ? those are encoded in CN, DN, ... 262490792Sgshapirodefine(`_TLS_ARS_', `++')dnl 262590792Sgshapirodnl workspace: 262690792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare 262790792SgshapiroR<$-:$+><$-:$-> <$*> $* $: <$1:$2 _TLS_ARS_ $5> 262890792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions> 262990792Sgshapirodnl continue: check extensions 263090792SgshapiroR<$-:$+ _TLS_ARS_ > $@ OK 263190792Sgshapirodnl split extensions into own list 263290792SgshapiroR<$-:$+ _TLS_ARS_ $+ > $: <$1:$2> <$3> 263390792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ > <$1:$2> <$3> <$4> 263490792SgshapiroR<$-:$+> $+ $@ $>"TLS_req" $3 $| <$1:$2> 263564562Sgshapiro 263690792Sgshapiro###################################################################### 263790792Sgshapiro### TLS_req: check additional TLS requirements 263890792Sgshapiro### 263990792Sgshapiro### Parameters: [<list> <of> <req>] $| <$-:$+> 264090792Sgshapiro### $-: SMTP reply code 264190792Sgshapiro### $+: Enhanced Status Code 264290792Sgshapirodnl further requirements for this ruleset: 264390792Sgshapirodnl name of "other side" is stored is {TLS_name} (client/server_name) 264490792Sgshapirodnl 264590792Sgshapirodnl currently only CN[:common_name] is implemented 264690792Sgshapirodnl right now this is only a logical AND 264790792Sgshapirodnl i.e. all requirements must be true 264890792Sgshapirodnl how about an OR? CN must be X or CN must be Y or .. 264990792Sgshapirodnl use a macro to compute this as a trivial sequential 265090792Sgshapirodnl operations (no precedences etc)? 265190792Sgshapiro###################################################################### 265290792SgshapiroSTLS_req 265390792Sgshapirodnl no additional requirements: ok 265490792SgshapiroR $| $+ $@ OK 265590792Sgshapirodnl require CN: but no CN specified: use name of other side 265690792SgshapiroR<CN> $* $| <$+> $: <CN:$&{TLS_Name}> $1 $| <$2> 265790792Sgshapirodnl match, check rest 265890792SgshapiroR<CN:$&{cn_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 265990792Sgshapirodnl CN does not match 266090792Sgshapirodnl 1 2 3 4 266190792SgshapiroR<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1 266290792Sgshapirodnl cert subject 266390792SgshapiroR<CS:$&{cert_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 266490792Sgshapirodnl CS does not match 266590792Sgshapirodnl 1 2 3 4 266690792SgshapiroR<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CERT Subject " $&{cert_subject} " does not match " $1 266790792Sgshapirodnl match, check rest 266890792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 266990792Sgshapirodnl CI does not match 267090792Sgshapirodnl 1 2 3 4 267190792SgshapiroR<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CERT Issuer " $&{cert_issuer} " does not match " $1 267290792Sgshapirodnl return from recursive call 267390792SgshapiroROK $@ OK 267490792Sgshapiro 267590792Sgshapiro###################################################################### 267690792Sgshapiro### max: return the maximum of two values separated by : 267790792Sgshapiro### 267890792Sgshapiro### Parameters: [$-]:[$-] 267990792Sgshapiro###################################################################### 268064562SgshapiroSmax 268164562SgshapiroR: $: 0 268264562SgshapiroR:$- $: $1 268364562SgshapiroR$-: $: $1 268464562SgshapiroR$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 268564562SgshapiroRTRUE:$-:$- $: $2 268690792SgshapiroR$-:$-:$- $: $2 268790792Sgshapirodnl endif _ACCESS_TABLE_ 268890792Sgshapirodivert(0) 268964562Sgshapiro 269090792Sgshapiro###################################################################### 269190792Sgshapiro### RelayTLS: allow relaying based on TLS authentication 269290792Sgshapiro### 269390792Sgshapiro### Parameters: 269490792Sgshapiro### none 269590792Sgshapiro###################################################################### 269690792SgshapiroSRelayTLS 269764562Sgshapiro# authenticated? 269864562Sgshapirodnl we do not allow relaying for anyone who can present a cert 269964562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns 270064562Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow 270164562Sgshapirodnl them to abuse our server (they might be easier to get hold of, 270264562Sgshapirodnl but anyway). 270364562Sgshapirodnl so here is the trick: if the verification succeeded 270464562Sgshapirodnl we look up the cert issuer in the access map 270564562Sgshapirodnl (maybe after extracting a part with a regular expression) 270664562Sgshapirodnl if this returns RELAY we relay without further questions 270764562Sgshapirodnl if it returns SUBJECT we perform a similar check on the 270864562Sgshapirodnl cert subject. 270964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 271090792SgshapiroR$* $: <?> $&{verify} 271190792SgshapiroR<?> OK $: OK authenticated: continue 271290792SgshapiroR<?> $* $@ NO not authenticated 271364562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 271490792SgshapiroR$* $: $(CERTIssuer $&{cert_issuer} $)', 271590792Sgshapiro`R$* $: $&{cert_issuer}') 271690792SgshapiroR$+ $: $(access CERTISSUER`'_TAG_DELIM_`'$1 $) 271764562Sgshapirodnl use $# to stop further checks (delay_check) 271890792SgshapiroRRELAY $# RELAY 271964562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 272090792SgshapiroRSUBJECT $: <@> $(CERTSubject $&{cert_subject} $)', 272190792Sgshapiro`RSUBJECT $: <@> $&{cert_subject}') 272290792SgshapiroR<@> $+ $: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $) 272390792SgshapiroR<@> RELAY $# RELAY 272490792SgshapiroR$* $: NO', `dnl') 272564562Sgshapiro 272690792Sgshapiro###################################################################### 272790792Sgshapiro### authinfo: lookup authinfo in the access map 272890792Sgshapiro### 272990792Sgshapiro### Parameters: 273090792Sgshapiro### $1: {server_name} 273190792Sgshapiro### $2: {server_addr} 273290792Sgshapirodnl both are currently ignored 273390792Sgshapirodnl if it should be done via another map, we either need to restrict 273490792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another 273590792Sgshapirodnl parameter which I want to avoid, it's quite complex already) 273690792Sgshapiro###################################################################### 273790792Sgshapirodnl omit this ruleset if neither is defined? 273890792Sgshapirodnl it causes DefaultAuthInfo to be ignored 273990792Sgshapirodnl (which may be considered a good thing). 274090792SgshapiroSauthinfo 274190792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl 274290792SgshapiroR$* $: <$(authinfo AuthInfo:$&{server_name} $: ? $)> 274390792SgshapiroR<?> $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)> 274490792SgshapiroR<?> $: <$(authinfo AuthInfo: $: ? $)> 274590792SgshapiroR<?> $@ no no authinfo available 274690792SgshapiroR<$*> $# $1 274790792Sgshapirodnl', `dnl 274890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 274990792SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <> 275090792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <> 275190792SgshapiroR$* $| <?>$* $: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <> 275290792SgshapiroR$* $| <?>$* $@ no no authinfo available 275390792SgshapiroR$* $| <$*> <> $# $2 275490792Sgshapirodnl', `dnl')') 275590792Sgshapiro 275664562Sgshapiroundivert(9)dnl LOCAL_RULESETS 275738032Speter# 275838032Speter###################################################################### 275938032Speter###################################################################### 276038032Speter##### 276164562Sgshapiro`##### MAIL FILTER DEFINITIONS' 276264562Sgshapiro##### 276364562Sgshapiro###################################################################### 276464562Sgshapiro###################################################################### 276590792Sgshapiro_MAIL_FILTERS_ 276664562Sgshapiro# 276764562Sgshapiro###################################################################### 276864562Sgshapiro###################################################################### 276964562Sgshapiro##### 277038032Speter`##### MAILER DEFINITIONS' 277138032Speter##### 277238032Speter###################################################################### 277338032Speter###################################################################### 277464562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS 277566494Sgshapiro 2776