proto.m4 revision 110560
138032Speterdivert(-1) 238032Speter# 394334Sgshapiro# Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. 464562Sgshapiro# All rights reserved. 538032Speter# Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. 638032Speter# Copyright (c) 1988, 1993 738032Speter# The Regents of the University of California. All rights reserved. 838032Speter# 938032Speter# By using this file, you agree to the terms and conditions set 1038032Speter# forth in the LICENSE file which can be found at the top level of 1138032Speter# the sendmail distribution. 1238032Speter# 1338032Speter# 1438032Speterdivert(0) 1538032Speter 16102528SgshapiroVERSIONID(`$Id: proto.m4,v 8.649.2.13 2002/12/04 00:12:18 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 if FEATURE(stickyhost) is used 20990792Sgshapiro# (null means deliver locally) 21038032SpeterDR`'LOCAL_RELAY') 21190792Sgshapiro 21238032Speterifdef(`MAIL_HUB', `dnl 21390792Sgshapiro# who gets all local email traffic 21438032Speter# ($R has precedence for unqualified names if FEATURE(stickyhost) is used) 21538032SpeterDH`'MAIL_HUB') 21690792Sgshapiro 21738032Speter# dequoting map 21838032SpeterKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `') 21938032Speter 22064562Sgshapirodivert(0)dnl # end of nullclient diversion 22138032Speter# class E: names that should be exposed as from this host, even if we masquerade 22264562Sgshapiro# class L: names that should be delivered locally, even if we have a relay 22338032Speter# class M: domains that should be converted to $M 22438032Speter# class N: domains that should not be converted to $M 22564562Sgshapiro#CL root 22638032Speterundivert(5)dnl 22790792Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl') 22838032Speter 22990792Sgshapiroifdef(`MASQUERADE_NAME', `dnl 23038032Speter# who I masquerade as (null for no masquerading) (see also $=M) 23138032SpeterDM`'MASQUERADE_NAME') 23238032Speter 23338032Speter# my name for error messages 23464562Sgshapiroifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON') 23538032Speter 23638032Speterundivert(6)dnl LOCAL_CONFIG 23738032Speterinclude(_CF_DIR_`m4/version.m4') 23838032Speter 23938032Speter############### 24090792Sgshapiro# Options # 24190792Sgshapiro############### 24290792Sgshapiroifdef(`confAUTO_REBUILD', 24390792Sgshapiro`errprint(WARNING: `confAUTO_REBUILD' is no longer valid. 24438032Speter There was a potential for a denial of service attack if this is set. 24538032Speter)')dnl 24664562Sgshapiro 24738032Speter# strip message body to 7 bits on input? 24838032Speter_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False') 24977349Sgshapiro 25038032Speter# 8-bit data handling 25138032Speter_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8') 25264562Sgshapiro 25338032Speter# wait for alias file rebuild (default units: minutes) 25438032Speter_OPTION(AliasWait, `confALIAS_WAIT', `5m') 25564562Sgshapiro 25664562Sgshapiro# location of alias file 25738032Speter_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases') 25864562Sgshapiro 25938032Speter# minimum number of free blocks on filesystem 26038032Speter_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100') 26164562Sgshapiro 26238032Speter# maximum message size 26338032Speter_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000') 26464562Sgshapiro 26538032Speter# substitution for space (blank) characters 26638032Speter_OPTION(BlankSub, `confBLANK_SUB', `_') 26764562Sgshapiro 26838032Speter# avoid connecting to "expensive" mailers on initial submission? 26938032Speter_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False') 27064562Sgshapiro 27138032Speter# checkpoint queue runs after every N successful deliveries 27238032Speter_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10') 27364562Sgshapiro 27438032Speter# default delivery mode 27538032Speter_OPTION(DeliveryMode, `confDELIVERY_MODE', `background') 27664562Sgshapiro 27738032Speter# error message header/file 27838032Speter_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header') 27964562Sgshapiro 28038032Speter# error mode 28138032Speter_OPTION(ErrorMode, `confERROR_MODE', `print') 28264562Sgshapiro 28338032Speter# save Unix-style "From_" lines at top of header? 28490792Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False') 28590792Sgshapiro 28690792Sgshapiro# queue file mode (qf files) 28738032Speter_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600') 28864562Sgshapiro 28938032Speter# temporary file mode 29038032Speter_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600') 29164562Sgshapiro 29238032Speter# match recipients against GECOS field? 29338032Speter_OPTION(MatchGECOS, `confMATCH_GECOS', `False') 29490792Sgshapiro 29538032Speter# maximum hop count 29638032Speter_OPTION(MaxHopCount, `confMAX_HOP', `25') 29764562Sgshapiro 29838032Speter# location of help file 29938032SpeterO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile') 30064562Sgshapiro 30138032Speter# ignore dots as terminators in incoming messages? 30238032Speter_OPTION(IgnoreDots, `confIGNORE_DOTS', `False') 30364562Sgshapiro 30438032Speter# name resolver options 30538032Speter_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY') 30664562Sgshapiro 30738032Speter# deliver MIME-encapsulated error messages? 30838032Speter_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True') 30964562Sgshapiro 31038032Speter# Forward file search path 31138032Speter_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward') 31264562Sgshapiro 31338032Speter# open connection cache size 31438032Speter_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2') 31564562Sgshapiro 31638032Speter# open connection cache timeout 31738032Speter_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m') 31864562Sgshapiro 31938032Speter# persistent host status directory 32038032Speter_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat') 32164562Sgshapiro 32238032Speter# single thread deliveries (requires HostStatusDirectory)? 32338032Speter_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False') 32464562Sgshapiro 32538032Speter# use Errors-To: header? 32638032Speter_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False') 32764562Sgshapiro 32838032Speter# log level 32938032Speter_OPTION(LogLevel, `confLOG_LEVEL', `10') 33064562Sgshapiro 33138032Speter# send to me too, even in an alias expansion? 33238032Speter_OPTION(MeToo, `confME_TOO', `True') 33364562Sgshapiro 33438032Speter# verify RHS in newaliases? 33538032Speter_OPTION(CheckAliases, `confCHECK_ALIASES', `False') 33664562Sgshapiro 33738032Speter# default messages to old style headers if no special punctuation? 33838032Speter_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False') 33964562Sgshapiro 34094334Sgshapiro# SMTP daemon options 34194334Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl', 34264562Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. 34364562Sgshapiro Use `DAEMON_OPTIONS()'; see cf/README. 34466494Sgshapiro)'dnl 34590792Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')') 34690792Sgshapiroifelse(defn(`_DPO_'), `', 34764562Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet 34838032SpeterO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_') 34964562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E') 35090792Sgshapiro 35190792Sgshapiro# SMTP client options 35290792Sgshapiroifelse(defn(`confCLIENT_OPTIONS'), `', `dnl', 35390792Sgshapiro`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid. See cf/README for more information. 35490792Sgshapiro)'dnl 35590792Sgshapiro`CLIENT_OPTIONS(`confCLIENT_OPTIONS')') 35664562Sgshapiroifelse(defn(`_CPO_'), `', 35790792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_') 35890792Sgshapiro 35990792Sgshapiro# Modifiers to `define' {daemon_flags} for direct submissions 36090792Sgshapiro_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `') 36190792Sgshapiro 36290792Sgshapiro# Use as mail submission program? See sendmail/SECURITY 36338032Speter_OPTION(UseMSP, `confUSE_MSP', `') 36464562Sgshapiro 36538032Speter# privacy flags 36638032Speter_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings') 36764562Sgshapiro 36838032Speter# who (if anyone) should get extra copies of error messages 36938032Speter_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster') 37064562Sgshapiro 37138032Speter# slope of queue-only function 37290792Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000') 37390792Sgshapiro 37490792Sgshapiro# limit on number of concurrent queue runners 37590792Sgshapiro_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `') 37690792Sgshapiro 37790792Sgshapiro# maximum number of queue-runners per queue-grouping with multiple queues 37890792Sgshapiro_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1') 37990792Sgshapiro 38090792Sgshapiro# priority of queue runners (nice(3)) 38190792Sgshapiro_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `') 38290792Sgshapiro 38390792Sgshapiro# shall we sort the queue by hostname first? 38490792Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority') 38590792Sgshapiro 38690792Sgshapiro# minimum time in queue before retry 38790792Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m') 38890792Sgshapiro 38990792Sgshapiro# how many jobs can you process in the queue? 39090792Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000') 39190792Sgshapiro 39290792Sgshapiro# perform initial split of envelope without checking MX records 39338032Speter_OPTION(FastSplit, `confFAST_SPLIT', `1') 39464562Sgshapiro 39538032Speter# queue directory 39690792SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue') 39790792Sgshapiro 39890792Sgshapiro# key for shared memory; 0 to turn off 39994334Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0') 40094334Sgshapiro 40194334Sgshapiroifdef(`confSHARED_MEMORY_KEY_FILE', `dnl 40294334Sgshapiro# file to store key for shared memory (if SharedMemoryKey = -1) 40338032SpeterO SharedMemoryKeyFile=confSHARED_MEMORY_KEY_FILE') 40464562Sgshapiro 40564562Sgshapiro# timeouts (many of these) 40690792Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m') 40764562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m') 40864562Sgshapiro_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s') 40964562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m') 41064562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m') 41164562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m') 41264562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h') 41364562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m') 41464562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h') 41564562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h') 41664562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m') 41764562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m') 41864562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m') 41964562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h') 42064562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s') 42164562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s') 42264562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m') 42364562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d') 42464562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d') 42564562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d') 42664562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d') 42764562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h') 42864562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h') 42964562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h') 43064562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h') 43164562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m') 43264562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s') 43364562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s') 43464562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s') 43564562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4') 43690792Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4') 43790792Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4') 43890792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m') 43938032Speter_OPTION(Timeout.auth, `confTO_AUTH', `10m') 44090792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h') 44190792Sgshapiro 44290792Sgshapiro# time for DeliverBy; extension disabled if less than 0 44338032Speter_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0') 44464562Sgshapiro 44538032Speter# should we not prune routes in route-addr syntax addresses? 44638032Speter_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False') 44764562Sgshapiro 44838032Speter# queue up everything before forking? 44938032Speter_OPTION(SuperSafe, `confSAFE_QUEUE', `True') 45064562Sgshapiro 45138032Speter# status file 45238032SpeterO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics') 45338032Speter 45438032Speter# time zone handling: 45538032Speter# if undefined, use system default 45638032Speter# if defined but null, use TZ envariable passed in 45738032Speter# if defined and non-null, use that info 45838032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=', 45938032Speter confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=', 46038032Speter `O TimeZoneSpec=confTIME_ZONE') 46164562Sgshapiro 46238032Speter# default UID (can be username or userid:groupid) 46338032Speter_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull') 46464562Sgshapiro 46538032Speter# list of locations of user database file (null means no lookup) 46638032Speter_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb') 46764562Sgshapiro 46838032Speter# fallback MX host 46938032Speter_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net') 47064562Sgshapiro 47138032Speter# if we are the best MX host for a site, try it directly instead of config err 47238032Speter_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False') 47364562Sgshapiro 47438032Speter# load average at which we just queue messages 47538032Speter_OPTION(QueueLA, `confQUEUE_LA', `8') 47664562Sgshapiro 47738032Speter# load average at which we refuse connections 47890792Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12') 47990792Sgshapiro 48090792Sgshapiro# load average at which we delay connections; 0 means no limit 48138032Speter_OPTION(DelayLA, `confDELAY_LA', `0') 48298841Sgshapiro 48338032Speter# maximum number of children we allow at one time 48438032Speter_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0') 48571345Sgshapiro 48638032Speter# maximum number of new connections per second 48738032Speter_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0') 48864562Sgshapiro 48938032Speter# work recipient factor 49038032Speter_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') 49164562Sgshapiro 49238032Speter# deliver each queued job in a separate process? 49338032Speter_OPTION(ForkEachJob, `confSEPARATE_PROC', `False') 49464562Sgshapiro 49538032Speter# work class factor 49638032Speter_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800') 49764562Sgshapiro 49838032Speter# work time factor 49938032Speter_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000') 50064562Sgshapiro 50138032Speter# default character set 50290792Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1') 50364562Sgshapiro 50438032Speter# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others) 50538032Speter_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch') 50664562Sgshapiro 50738032Speter# hosts file (normally /etc/hosts) 50838032Speter_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts') 50964562Sgshapiro 51038032Speter# dialup line delay on connection failure 51138032Speter_OPTION(DialDelay, `confDIAL_DELAY', `10s') 51264562Sgshapiro 51338032Speter# action to take if there are no recipients in the message 51438032Speter_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed') 51564562Sgshapiro 51638032Speter# chrooted environment for writing to files 51738032Speter_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch') 51864562Sgshapiro 51938032Speter# are colons OK in addresses? 52038032Speter_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True') 52164562Sgshapiro 52238032Speter# shall I avoid expanding CNAMEs (violates protocols)? 52338032Speter_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False') 52464562Sgshapiro 52538032Speter# SMTP initial login message (old $e macro) 52638032Speter_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b') 52764562Sgshapiro 52838032Speter# UNIX initial From header format (old $l macro) 52938032Speter_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d') 53064562Sgshapiro 53138032Speter# From: lines that have embedded newlines are unwrapped onto one line 53238032Speter_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False') 53364562Sgshapiro 53438032Speter# Allow HELO SMTP command that does not `include' a host name 53538032Speter_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False') 53664562Sgshapiro 53738032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic) 53838032Speter_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.') 53964562Sgshapiro 54038032Speter# delimiter (operator) characters (old $o macro) 54138032Speter_OPTION(OperatorChars, `confOPERATORS', `.:@[]') 54264562Sgshapiro 54338032Speter# shall I avoid calling initgroups(3) because of high NIS costs? 54438032Speter_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False') 54590792Sgshapiro 54664562Sgshapiro# are group-writable `:include:' and .forward files (un)trustworthy? 54790792Sgshapiro# True (the default) means they are not trustworthy. 54890792Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True') 54990792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES', 55038032Speter`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL. 55138032Speter')') 55264562Sgshapiro 55338032Speter# where do errors that occur when sending errors get sent? 55464562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster') 55564562Sgshapiro 55664562Sgshapiro# where to save bounces if all else fails 55738032Speter_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter') 55864562Sgshapiro 55938032Speter# what user id do we assume for the majority of the processing? 56038032Speter_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail') 56164562Sgshapiro 56238032Speter# maximum number of recipients per SMTP envelope 56390792Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100') 56490792Sgshapiro 56590792Sgshapiro# limit the rate recipients per SMTP envelope are accepted 56690792Sgshapiro# once the threshold number of recipients have been rejected 56738032Speter_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20') 56864562Sgshapiro 56938032Speter# shall we get local names from our installed interfaces? 57064562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 57164562Sgshapiro 57264562Sgshapiro# Return-Receipt-To: header implies DSN request 57364562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 57464562Sgshapiro 57564562Sgshapiro# override connection address (for testing) 57664562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 57764562Sgshapiro 57864562Sgshapiro# Trusted user for file ownership and starting the daemon 57964562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root') 58064562Sgshapiro 58164562Sgshapiro# Control socket for daemon management 58264562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 58364562Sgshapiro 58464562Sgshapiro# Maximum MIME header length to protect MUAs 58564562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0') 58664562Sgshapiro 58764562Sgshapiro# Maximum length of the sum of all headers 58864562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768') 58964562Sgshapiro 59064562Sgshapiro# Maximum depth of alias recursion 59164562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10') 59264562Sgshapiro 59364562Sgshapiro# location of pid file 59464562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid') 59564562Sgshapiro 59664562Sgshapiro# Prefix string for the process title shown on 'ps' listings 59764562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix') 59864562Sgshapiro 59964562Sgshapiro# Data file (df) memory-buffer file maximum size 60064562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096') 60164562Sgshapiro 60264562Sgshapiro# Transcript file (xf) memory-buffer file maximum size 60390792Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096') 60490792Sgshapiro 60590792Sgshapiro# lookup type to find information about local mailboxes 60664562Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw') 60790792Sgshapiro 60864562Sgshapiro# list of authentication mechanisms 60964562Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5') 61064562Sgshapiro 61164562Sgshapiro# default authentication information for outgoing connections 61264562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info') 61364562Sgshapiro 61464562Sgshapiro# SMTP AUTH flags 61590792Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `') 61690792Sgshapiro 61790792Sgshapiro# SMTP AUTH maximum encryption strength 61890792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `') 61990792Sgshapiro 62090792Sgshapiro# SMTP STARTTLS server options 62164562Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `') 62264562Sgshapiro 62364562Sgshapiro# Input mail filters 62498841Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 62564562Sgshapiro 62690792Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl 62764562Sgshapiro# Milter options 62864562Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `') 62964562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 63064562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') 63164562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') 63264562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')') 63364562Sgshapiro 63464562Sgshapiro# CA directory 63564562Sgshapiro_OPTION(CACertPath, `confCACERT_PATH', `') 63664562Sgshapiro# CA file 63764562Sgshapiro_OPTION(CACertFile, `confCACERT', `') 63864562Sgshapiro# Server Cert 63964562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `') 64064562Sgshapiro# Server private key 64164562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `') 64264562Sgshapiro# Client Cert 64364562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `') 64464562Sgshapiro# Client private key 64564562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 64664562Sgshapiro# DHParameters (only required if DSA/DH is used) 64764562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `') 64864562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL) 64990792Sgshapiro_OPTION(RandFile, `confRAND_FILE', `') 65090792Sgshapiro 65190792Sgshapiro############################ 65290792Sgshapiro`# QUEUE GROUP DEFINITIONS #' 65342575Speter############################ 65438032Speter_QUEUE_GROUP_ 65538032Speter 65638032Speter########################### 65738032Speter# Message precedences # 65838032Speter########################### 65938032Speter 66038032SpeterPfirst-class=0 66138032SpeterPspecial-delivery=100 66238032SpeterPlist=-30 66338032SpeterPbulk=-60 66438032SpeterPjunk=-100 66538032Speter 66638032Speter##################### 66738032Speter# Trusted users # 66838032Speter##################### 66964562Sgshapiro 67038032Speter# this is equivalent to setting class "t" 67138032Speterifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 67238032SpeterTroot 67338032SpeterTdaemon 67438032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp') 67538032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 67638032Speter 67738032Speter######################### 67838032Speter# Format of headers # 67938032Speter######################### 68038032Speter 68138032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl 68238032SpeterH?P?Return-Path: <$g> 68338032SpeterHReceived: confRECEIVED_HEADER 68438032SpeterH?D?Resent-Date: $a 68538032SpeterH?D?Date: $a 68638032SpeterH?F?Resent-From: confFROM_HEADER 68738032SpeterH?F?From: confFROM_HEADER 68838032SpeterH?x?Full-Name: $x 68938032Speter# HPosted-Date: $a 69038032Speter# H?l?Received-Date: $b 69164562SgshapiroH?M?Resent-Message-Id: <$t.$i@$j> 69238032SpeterH?M?Message-Id: <$t.$i@$j> 69338032Speter 69438032Speter# 69538032Speter###################################################################### 69638032Speter###################################################################### 69738032Speter##### 69838032Speter##### REWRITING RULES 69938032Speter##### 70038032Speter###################################################################### 70138032Speter###################################################################### 70238032Speter 70338032Speter############################################ 70464562Sgshapiro### Ruleset 3 -- Name Canonicalization ### 70538032Speter############################################ 70638032SpeterScanonify=3 70738032Speter 70838032Speter# handle null input (translate to <@> special case) 70938032SpeterR$@ $@ <@> 71038032Speter 71138032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon 71238032SpeterR$* $: $1 <@> mark addresses 71390792SgshapiroR$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> 71438032SpeterR@ $* <@> $: @ $1 unmark @host:... 71538032SpeterR$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr 71638032SpeterR$* :: $* <@> $: $1 :: $2 unmark node::addr 71738032SpeterR:`include': $* <@> $: :`include': $1 unmark :`include':... 71838032SpeterR$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon 71938032SpeterR$* : $* <@> $: $2 strip colon if marked 72071345SgshapiroR$* <@> $: $1 unmark 72138032SpeterR$* ; $1 strip trailing semi 72238032SpeterR$* < $+ :; > $* $@ $2 :; <@> catch <list:;> 72338032SpeterR$* < $* ; > $1 < $2 > bogus bracketed semi 72438032Speter 72538032Speter# null input now results from list:; syntax 72638032SpeterR$@ $@ :; <@> 72738032Speter 72838032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item 72938032SpeterR$* $: < $1 > housekeeping <> 73038032SpeterR$+ < $* > < $2 > strip excess on left 73138032SpeterR< $* > $+ < $1 > strip excess on right 73238032SpeterR<> $@ < @ > MAIL FROM:<> case 73364562SgshapiroR< $+ > $: $1 remove housekeeping <> 73438032Speter 73538032Speterifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 73638032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 73738032SpeterR@ $+ , $+ @ $1 : $2 change all "," to ":" 73890792Sgshapiro 73990792Sgshapiro# localize and dispose of route-based addresses 74090792Sgshapirodnl XXX: IPv6 colon conflict 74164562Sgshapiroifdef(`NO_NETINET6', `dnl', 74264562Sgshapiro`R@ [$+] : $+ $@ $>Canonify2 < @ [$1] > : $2 handle <route-addr>') 74364562SgshapiroR@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 74464562Sgshapirodnl',`dnl 74590792Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d> 74690792SgshapiroR@ $+ , $+ $2 74764562Sgshapiroifdef(`NO_NETINET6', `dnl', 74864562Sgshapiro`R@ [ $* ] : $+ $2') 74938032SpeterR@ $+ : $+ $2 75038032Speterdnl') 75164562Sgshapiro 75238032Speter# find focus for list syntax 75338032SpeterR $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 75438032SpeterR $+ : $* ; $@ $1 : $2; list syntax 75538032Speter 75638032Speter# find focus for @ syntax addresses 75764562SgshapiroR$+ @ $+ $: $1 < @ $2 > focus on domain 75838032SpeterR$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 75990792SgshapiroR$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 76090792Sgshapiro 76190792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here. 76238032Speterdnl # do some sanity checking 76338032Speterdnl R$* < @ $~[ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 76438032Speter 76564562Sgshapiroifdef(`_NO_UUCP_', `dnl', 76664562Sgshapiro`# convert old-style addresses to a domain-based address 76764562SgshapiroR$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 76838032SpeterR$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 76938032SpeterR$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 77038032Speter') 77164562Sgshapiroifdef(`_USE_DECNET_SYNTAX_', 77264562Sgshapiro`# convert node::user addresses into a domain-based address 77338032SpeterR$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 77438032SpeterR$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 77538032Speter', 77638032Speter `dnl') 77738032Speter# if we have % signs, take the rightmost one 77864562SgshapiroR$* % $* $1 @ $2 First make them all @s. 77938032SpeterR$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 78038032SpeterR$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 78164562Sgshapiro 78238032Speter# else we must be a local name 78338032SpeterR$* $@ $>Canonify2 $1 78438032Speter 78538032Speter 78638032Speter################################################ 78738032Speter### Ruleset 96 -- bottom half of ruleset 3 ### 78864562Sgshapiro################################################ 78938032Speter 79038032SpeterSCanonify2=96 79138032Speter 79238032Speter# handle special cases for local names 79338032SpeterR$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 79438032SpeterR$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 79564562Sgshapiroifdef(`_NO_UUCP_', `dnl', 79690792Sgshapiro`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 79790792Sgshapiro 79838032Speter# check for IPv4/IPv6 domain literal 79938032SpeterR$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr] 80038032SpeterR$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 80164562SgshapiroR$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 80238032Speter 80338032Speterifdef(`_DOMAIN_TABLE_', `dnl 80438032Speter# look up domains in the domain table 80564562SgshapiroR$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 80638032Speter 80764562Sgshapiroundivert(2)dnl LOCAL_RULE_3 80838032Speter 80938032Speterifdef(`_BITDOMAIN_TABLE_', `dnl 81038032Speter# handle BITNET mapping 81164562SgshapiroR$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 81238032Speter 81338032Speterifdef(`_UUDOMAIN_TABLE_', `dnl 81438032Speter# handle UUCP mapping 81538032SpeterR$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 81638032Speter 81738032Speterifdef(`_NO_UUCP_', `dnl', 81838032Speter`ifdef(`UUCP_RELAY', 81938032Speter`# pass UUCP addresses straight through 82038032SpeterR$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 82138032Speter`# if really UUCP, handle it immediately 82238032Speterifdef(`_CLASS_U_', 82338032Speter`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82438032Speterifdef(`_CLASS_V_', 82538032Speter`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82638032Speterifdef(`_CLASS_W_', 82738032Speter`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 82838032Speterifdef(`_CLASS_X_', 82938032Speter`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 83038032Speterifdef(`_CLASS_Y_', 83138032Speter`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 83238032Speter 83338032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl 83438032Speter# try UUCP traffic as a local address 83538032SpeterR$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 83664562SgshapiroR$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 83764562Sgshapiro')') 83864562Sgshapiro# hostnames ending in class P are always canonical 83964562SgshapiroR$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 84064562Sgshapirodnl apply the next rule only for hostnames not in class P 84164562Sgshapirodnl this even works for phrases in class P since . is in class P 84264562Sgshapirodnl which daemon flags are set? 84364562SgshapiroR$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 84464562Sgshapirodnl the other rules in this section only apply if the hostname 84564562Sgshapirodnl does not end in class P hence no further checks are done here 84664562Sgshapirodnl if this ever changes make sure the lookups are "protected" again! 84764562Sgshapiroifdef(`_NO_CANONIFY_', `dnl 84864562Sgshapirodnl do not canonify unless: 84964562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection 85064562Sgshapirodnl with class P is non-empty) 85164562Sgshapirodnl or {daemon_flags} has c set 85264562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify} 85364562SgshapiroR$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 85464562Sgshapiro# pass to name server to make hostname canonical if requested 85564562SgshapiroR$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 85664562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 85764562SgshapiroR$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 85864562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work 85964562SgshapiroR$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 86064562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl 86164562Sgshapirodnl this should only apply to unqualified hostnames 86264562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar 86390792Sgshapirodnl then $- does not work. 86464562Sgshapiro# lookup unqualified hostnames 86564562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 86671345Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless: 86771345Sgshapirodnl {daemon_flags} contains CC (do not canonify) 86871345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work 86964562Sgshapirodnl should we do this for every hostname: even unqualified? 87090792SgshapiroR$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 87190792SgshapiroR$* CC $* $| $* $: $3 87290792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl 87390792Sgshapiro# do not canonify header addresses 87490792SgshapiroR$* $| $* < @ $* $~P > $* $: $&{addr_type} $| $2 < @ $3 $4 > $5 87538032SpeterR$* h $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 87664562SgshapiroR$* h $* $| $* $: $3', `dnl') 87764562Sgshapiro# pass to name server to make hostname canonical 87864562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 87938032Speterdnl remove {daemon_flags} for other cases 88038032SpeterR$* $| $* $: $2 88138032Speter 88238032Speter# local host aliases and pseudo-domains are always canonical 88338032SpeterR$* < @ $=w > $* $: $1 < @ $2 . > $3 88438032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 88564562Sgshapiro`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 88664562Sgshapiro`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 88764562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 88864562Sgshapirodnl virtual hosts are also canonical 88964562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 89064562Sgshapiro`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 89190792Sgshapiro`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 89290792Sgshapiro`dnl') 89390792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 89490792Sgshapirodnl hosts for genericstable are also canonical 89590792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_', 89690792Sgshapiro`R$* < @ $* $=G > $* $: $1 < @ $2 $3 . > $4', 89764562Sgshapiro`R$* < @ $=G > $* $: $1 < @ $2 . > $3')', 89864562Sgshapiro`dnl') 89938032Speterdnl remove superfluous dots (maybe repeatedly) which may have been added 90038032Speterdnl by one of the rules before 90138032SpeterR$* < @ $* . . > $* $1 < @ $2 . > $3 90238032Speter 90338032Speter 90438032Speter################################################## 90564562Sgshapiro### Ruleset 4 -- Final Output Post-rewriting ### 90638032Speter################################################## 90771345SgshapiroSfinal=4 90838032Speter 90938032SpeterR$+ :; <@> $@ $1 : handle <list:;> 91038032SpeterR$* <@> $@ handle <> and list:; 91138032Speter 91238032Speter# strip trailing dot off possibly canonical name 91364562SgshapiroR$* < @ $+ . > $* $1 < @ $2 > $3 91438032Speter 91538032Speter# eliminate internal code 91638032SpeterR$* < @ *LOCAL* > $* $1 < @ $j > $2 91738032Speter 91838032Speter# externalize local domain info 91938032SpeterR$* < $+ > $* $1 $2 $3 defocus 92038032SpeterR@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 92138032SpeterR@ $* $@ @ $1 ... and exit 92238032Speter 92338032Speterifdef(`_NO_UUCP_', `dnl', 92438032Speter`# UUCP must always be presented in old form 92538032SpeterR$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 92638032Speter 92738032Speterifdef(`_USE_DECNET_SYNTAX_', 92838032Speter`# put DECnet back in :: form 92938032SpeterR$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 93038032Speter `dnl') 93138032Speter# delete duplicate local names 93238032SpeterR$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 93338032Speter 93438032Speter 93538032Speter 93638032Speter############################################################## 93738032Speter### Ruleset 97 -- recanonicalize and call ruleset zero ### 93838032Speter### (used for recursive calls) ### 93964562Sgshapiro############################################################## 94064562Sgshapiro 94164562SgshapiroSRecurse=97 94238032SpeterR$* $: $>canonify $1 94338032SpeterR$* $@ $>parse $1 94438032Speter 94538032Speter 94638032Speter###################################### 94738032Speter### Ruleset 0 -- Parse Address ### 94864562Sgshapiro###################################### 94938032Speter 95038032SpeterSparse=0 95138032Speter 95264562SgshapiroR$* $: $>Parse0 $1 initial parsing 95338032SpeterR<@> $#_LOCAL_ $: <@> special case error msgs 95438032SpeterR$* $: $>ParseLocal $1 handle local hacks 95538032SpeterR$* $: $>Parse1 $1 final parsing 95638032Speter 95738032Speter# 95838032Speter# Parse0 -- do initial syntax checking and eliminate local addresses. 95938032Speter# This should either return with the (possibly modified) input 96038032Speter# or return with a #error mailer. It should not return with a 96138032Speter# #mailer other than the #error mailer. 96238032Speter# 96338032Speter 96490792SgshapiroSParse0 96564562SgshapiroR<@> $@ <@> special case error msgs 96690792SgshapiroR$* : $* ; <@> $#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses" 96790792SgshapiroR@ <@ $* > < @ $1 > catch "@@host" bogosity 96838032SpeterR<@ $+> $#error $@ 5.1.3 $: "_CODE553 User address required" 96990792SgshapiroR$+ <@> $#error $@ 5.1.3 $: "_CODE553 Hostname required" 97090792SgshapiroR$* $: <> $1 97190792Sgshapirodnl allow tricks like [host1]:[host2] 97290792SgshapiroR<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4 97390792SgshapiroR<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4 97490792Sgshapirodnl but no a@[b]c 97590792SgshapiroR<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid address" 97638032SpeterR<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 97790792SgshapiroR<> $* <$* : $* > $* $#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part" 97890792SgshapiroR<> $* $1 97990792SgshapiroR$* < @ . $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 98090792SgshapiroR$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name" 98190792Sgshapirodnl no a@b@ 98290792SgshapiroR$* < @ $* @ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid route address" 98364562Sgshapirodnl no a@b@c 98490792SgshapiroR$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 98538032Speterdnl comma only allowed before @; this check is not complete 98690792SgshapiroR$* , $~O $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address" 98790792Sgshapiro 98890792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks 98990792SgshapiroR$* . < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot" 99090792SgshapiroR. $* < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot" 99138032Speterdnl', `dnl') 99264562Sgshapiro 99364562Sgshapiro# now delete the local info -- note $=O to find characters that cause forwarding 99438032SpeterR$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 99590792SgshapiroR< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 99664562SgshapiroR$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 99738032SpeterR< @ $+ > $#error $@ 5.1.3 $: "_CODE553 User address required" 99890792SgshapiroR$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 99938032SpeterR$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 100064562SgshapiroR< @ *LOCAL* > $#error $@ 5.1.3 $: "_CODE553 User address required" 100138032SpeterR$* $=O $* < @ *LOCAL* > 100238032Speter $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 100338032SpeterR$* < @ *LOCAL* > $: $1 100438032Speter 100538032Speter# 100638032Speter# Parse1 -- the bottom half of ruleset 0. 100738032Speter# 100864562Sgshapiro 100964562SgshapiroSParse1 101090792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 101190792Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute} 101264562SgshapiroR$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <> 101364562SgshapiroR$+ < @ $={LDAPRouteEquiv} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>', 101438032Speter`dnl') 101538032Speter 101664562Sgshapiroifdef(`_MAILER_smtp_', 101764562Sgshapiro`# handle numeric address spec 101864562Sgshapirodnl there is no check whether this is really an IP number 101990792SgshapiroR$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 102064562SgshapiroR$* < @ [ $+ ] > $* $1 < @ [ $2 ] : $S > $3 Add smart host to path 102164562SgshapiroR$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 102238032SpeterR$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 102338032SpeterR$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 102464562Sgshapiro `dnl') 102538032Speter 102690792Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 102790792Sgshapiro# handle virtual users 102890792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 102990792Sgshapirodnl this is not a documented option 103090792Sgshapirodnl it stops looping in virtusertable mapping if input and output 103190792Sgshapirodnl are identical, i.e., if address A is mapped to A. 103290792Sgshapirodnl it does not deal with multi-level recursion 103390792Sgshapiro# handle full domains in RHS of virtusertable 103490792SgshapiroR$+ < @ $+ > $: $(macro {RecipientAddress} $) $1 < @ $2 > 103590792SgshapiroR$+ < @ $+ > $: <?> $1 < @ $2 > $| $>final $1 < @ $2 > 103690792SgshapiroR<?> $+ $| $+ $: $1 $(macro {RecipientAddress} $@ $2 $) 103764562SgshapiroR<?> $+ $| $* $: $1', 103890792Sgshapiro`dnl') 103964562SgshapiroR$+ $: <!> $1 Mark for lookup 104064562Sgshapirodnl input: <!> local<@domain> 104164562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 104290792Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 104364562Sgshapiro`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 104490792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain> 104590792SgshapiroR<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 104690792Sgshapirodnl if <@> local<@domain>: no match but try lookup 104790792Sgshapirodnl user+detail: try user++@domain if detail not empty 104890792SgshapiroR<@> $+ + $+ < @ $* . > 104938032Speter $: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105090792Sgshapirodnl user+detail: try user+*@domain 105190792SgshapiroR<@> $+ + $* < @ $* . > 105238032Speter $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105390792Sgshapirodnl user+detail: try user@domain 105464562SgshapiroR<@> $+ + $* < @ $* . > 105590792Sgshapiro $: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105690792Sgshapirodnl try default entry: @domain 105764562Sgshapirodnl ++@domain 105890792SgshapiroR<@> $+ + $+ < @ $+ . > $: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 105964562Sgshapirodnl +*@domain 106098121SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . > 106198121Sgshapirodnl @domain if +detail exists 106298121Sgshapirodnl if no match, change marker to prevent a second @domain lookup 106338032SpeterR<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . > 106490792Sgshapirodnl without +detail 106538032SpeterR<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 106690792Sgshapirodnl no match 106764562SgshapiroR<@> $+ $: $1 106864562Sgshapirodnl remove mark 106938032SpeterR<!> $+ $: $1 107090792SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 107190792SgshapiroR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 107290792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl 107390792Sgshapiro# check virtuser input address against output address, if same, skip recursion 107490792SgshapiroR< $+ > $+ < @ $+ > $: < $1 > $2 < @ $3 > $| $1 107590792Sgshapiro# it is the same: stop now 107690792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress} $: $>ParseLocal $>Parse0 $>canonify $1 107780785SgshapiroR< $+ > $+ < @ $+ > $| $* $: < $1 > $2 < @ $3 > 107880785Sgshapirodnl', `dnl') 107977349Sgshapirodnl this is not a documented option 108077349Sgshapirodnl it performs no looping at all for virtusertable 108177349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_', 108277349Sgshapiro`R< $+ > $+ < @ $+ > $: $>ParseLocal $>Parse0 $>canonify $1', 108338032Speter`R< $+ > $+ < @ $+ > $: $>Recurse $1') 108438032Speterdnl', `dnl') 108538032Speter 108664562Sgshapiro# short circuit local delivery so forwarded email works 108766494Sgshapiroifdef(`_MAILER_usenet_', `dnl 108866494SgshapiroR$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 108938032Speter 109038032Speter 109164562Sgshapiroifdef(`_STICKY_LOCAL_DOMAIN_', 109264562Sgshapiro`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 109338032SpeterR< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 109438032Speterdnl $H empty (but @$=w.) 109564562SgshapiroR< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 109638032SpeterR< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 109738032Speter`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 109864562SgshapiroR$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 109938032Speter 110038032Speterifdef(`_MAILER_TABLE_', `dnl 110138032Speter# not local -- try mailer table lookup 110238032SpeterR$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 110364562SgshapiroR< $+ . > $* $: < $1 > $2 strip trailing dot 110464562SgshapiroR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 110564562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 110638032SpeterR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 110764562SgshapiroR< $+ > $* $: $>Mailertable <$1> $2 try domain', 110838032Speter`dnl') 110938032Speterundivert(4)dnl UUCP rules from `MAILER(uucp)' 111038032Speter 111138032Speterifdef(`_NO_UUCP_', `dnl', 111264562Sgshapiro`# resolve remotely connected UUCP links (if any) 111338032Speterifdef(`_CLASS_V_', 111438032Speter`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 111564562Sgshapiro `dnl') 111638032Speterifdef(`_CLASS_W_', 111738032Speter`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 111864562Sgshapiro `dnl') 111938032Speterifdef(`_CLASS_X_', 112038032Speter`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 112138032Speter `dnl')') 112238032Speter 112364562Sgshapiro# resolve fake top level domains by forwarding to other hosts 112438032Speterifdef(`BITNET_RELAY', 112538032Speter`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 112664562Sgshapiro `dnl') 112738032Speterifdef(`DECNET_RELAY', 112838032Speter`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 112938032Speter `dnl') 113038032Speterifdef(`_MAILER_pop_', 113138032Speter`R$+ < @ POP. > $#pop $: $1 user@POP', 113238032Speter `dnl') 113338032Speterifdef(`_MAILER_fax_', 113464562Sgshapiro`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 113538032Speter`ifdef(`FAX_RELAY', 113638032Speter`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 113738032Speter `dnl')') 113838032Speter 113964562Sgshapiroifdef(`UUCP_RELAY', 114038032Speter`# forward non-local UUCP traffic to our UUCP relay 114138032SpeterR$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 114238032Speter`ifdef(`_MAILER_uucp_', 114338032Speter`# forward other UUCP traffic straight to UUCP 114438032SpeterR$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 114538032Speter `dnl')') 114664562Sgshapiroifdef(`_MAILER_usenet_', ` 114738032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup 114838032SpeterR$+ . USENET $#usenet $@ usenet $: $1', 114938032Speter `dnl') 115038032Speter 115138032Speterifdef(`_LOCAL_RULES_', 115238032Speter`# figure out what should stay in our local mail system 115338032Speterundivert(1)', `dnl') 115464562Sgshapiro 115538032Speter# pass names that still have a host to a smarthost (if defined) 115638032SpeterR$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 115738032Speter 115864562Sgshapiro# deal with other remote names 115990792Sgshapiroifdef(`_MAILER_smtp_', 116038032Speter`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 116138032Speter`R$* < @$* > $* $#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2') 116264562Sgshapiro 116338032Speter# handle locally delivered names 116438032SpeterR$=L $#_LOCAL_ $: @ $1 special local names 116538032SpeterR$+ $#_LOCAL_ $: $1 regular local names 116638032Speter 116738032Speter########################################################################### 116838032Speter### Ruleset 5 -- special rewriting after aliases have been expanded ### 116964562Sgshapiro########################################################################### 117064562Sgshapiro 117164562SgshapiroSLocal_localaddr 117290792SgshapiroSlocaladdr=5 117364562SgshapiroR$+ $: $1 $| $>"Local_localaddr" $1 117464562SgshapiroR$+ $| $#ok $@ $1 no change 117538032SpeterR$+ $| $#$* $#$2 117690792SgshapiroR$+ $| $* $: $1 117790792Sgshapiro 117890792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 117990792Sgshapiro# Preserve rcpt_host in {Host} 118090792SgshapiroR$+ $: $1 $| $&h $| $&{Host} check h and {Host} 118190792SgshapiroR$+ $| $| $: $(macro {Host} $@ $) $1 no h or {Host} 118295154SgshapiroR$+ $| $| $+ $: $1 h not set, {Host} set 118390792SgshapiroR$+ $| +$* $| $* $: $1 h is +detail, {Host} set 118490792SgshapiroR$+ $| $* @ $+ $| $* $: $(macro {Host} $@ @$3 $) $1 set {Host} to host in h 118590792SgshapiroR$+ $| $+ $| $* $: $(macro {Host} $@ @$2 $) $1 set {Host} to h 118690792Sgshapiro')dnl 118766494Sgshapiro 118866494Sgshapiroifdef(`_FFR_5_', `dnl 118966494Sgshapiro# Preserve host in a macro 119066494SgshapiroR$+ $: $(macro {LocalAddrHost} $) $1 119190792SgshapiroR$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 119238032Speter 119366494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl 119466494Sgshapiro# deal with plussed users so aliases work nicely 119566494SgshapiroR$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 119638032SpeterR$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 119738032Speter') 119838032Speter# prepend an empty "forward host" on the front 119938032SpeterR$+ $: <> $1 120038032Speter 120190792Sgshapiroifdef(`LUSER_RELAY', `dnl 120266494Sgshapiro# send unrecognized local users to a relay host 120366494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 120466494SgshapiroR< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 120566494SgshapiroR< > $+ $: < ? $L > < > $(user $1 $) look up user 120664562SgshapiroR< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 120790792SgshapiroR< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 120890792SgshapiroR< > $+ $: < $L > $(user $1 $) look up user 120990792SgshapiroR< $* > $+ <> $: < > $2 found; strip $L') 121090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 121138032SpeterR< $+ > $+ $: < $1 > $2 $&{Host}') 121290792Sgshapirodnl') 121390792Sgshapiro 121490792Sgshapiroifdef(`MAIL_HUB', `dnl 121590792SgshapiroR< > $+ $: < $H > $1 try hub', `dnl') 121690792Sgshapiroifdef(`LOCAL_RELAY', `dnl 121790792SgshapiroR< > $+ $: < $R > $1 try relay', `dnl') 121864562Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl 121990792SgshapiroR< > $+ $@ $1', `dnl 122090792SgshapiroR< > $+ $: < > < $1 <> $&h > nope, restore +detail 122164562Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 122264562SgshapiroR< > < $+ @ $+ <> + $* > $: < > < $1 + $3 @ $2 > check whether +detail') 122338032SpeterR< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 122466494SgshapiroR< > < $+ <> $* > $: < > < $1 > else discard 122538032SpeterR< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 122643730SpeterR< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 122790792SgshapiroR< > < $+ > $@ $1 no +detail 122890792SgshapiroR$+ $: $1 <> $&h add +detail back in 122943730Speterifdef(`_PRESERVE_LUSER_HOST_', `dnl 123066494SgshapiroR$+ @ $+ <> + $* $: $1 + $3 @ $2 check whether +detail') 123164562SgshapiroR$+ <> + $* $: $1 + $2 check whether +detail 123264562SgshapiroR$+ <> $* $: $1 else discard') 123390792SgshapiroR< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 123490792SgshapiroR< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 123590792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 123690792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 123790792SgshapiroR< $~[ : $+ > $+ @ $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $4 >') 123890792SgshapiroR< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 123964562Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl 124038032SpeterR< $+ > $+ @ $+ $@ $>MailerToTriple < $1 > $2 < @ $3 >') 124164562SgshapiroR< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 124290792Sgshapiro 124338032Speterifdef(`_MAILER_TABLE_', `dnl 124490792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 124590792Sgshapiro################################################################### 124690792Sgshapiro### Ruleset LDAPMailertable -- mailertable lookup for LDAP ### 124790792Sgshapirodnl input: <Domain> FullAddress 124890792Sgshapiro################################################################### 124990792Sgshapiro 125090792SgshapiroSLDAPMailertable 125190792SgshapiroR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 125290792SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check resolved? 125390792SgshapiroR< $+ > $* $: < $1 > $>Mailertable <$1> $2 try domain 125490792SgshapiroR< $+ > $#$* $#$2 found 125590792SgshapiroR< $+ > $* $#_RELAY_ $@ $1 $: $2 not found, direct relay', 125690792Sgshapiro`dnl') 125738032Speter 125864562Sgshapiro################################################################### 125938032Speter### Ruleset 90 -- try domain part of mailertable entry ### 126038032Speterdnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 126164562Sgshapiro################################################################### 126264562Sgshapiro 126364562SgshapiroSMailertable=90 126438032Speterdnl shift and check 126564562Sgshapirodnl %2 is not documented in cf/README 126664562SgshapiroR$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 126764562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 126864562SgshapiroR$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 126938032SpeterR$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 127064562Sgshapirodnl is $2 always empty? 127164562SgshapiroR$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 127238032SpeterR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 127338032Speterdnl return full address 127438032SpeterR< $* > $* $@ $2 no mailertable match', 127538032Speter`dnl') 127638032Speter 127764562Sgshapiro################################################################### 127864562Sgshapiro### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 127964562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest 128064562Sgshapirodnl <> address -> address 128164562Sgshapirodnl <error:d.s.n:text> -> error 128264562Sgshapirodnl <error:text> -> error 128364562Sgshapirodnl <mailer:user@host> lp<@domain>rest -> mailer host user 128464562Sgshapirodnl <mailer:host> address -> mailer host address 128538032Speterdnl <localdomain> address -> address 128638032Speterdnl <host> address -> relay host address 128764562Sgshapiro################################################################### 128838032Speter 128964562SgshapiroSMailerToTriple=95 129038032SpeterR< > $* $@ $1 strip off null relay 129138032SpeterR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 129290792SgshapiroR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 129390792SgshapiroR< local : $* > $* $>CanonLocal < $1 > $2 129490792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 129538032SpeterR< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 129638032SpeterR< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 129738032SpeterR< $=w > $* $@ $2 delete local host 129838032SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 129938032Speter 130064562Sgshapiro################################################################### 130164562Sgshapiro### Ruleset CanonLocal -- canonify local: syntax ### 130264562Sgshapirodnl input: <user> address 130364562Sgshapirodnl <x> <@host> : rest -> Recurse rest 130464562Sgshapirodnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 130564562Sgshapirodnl <> user <@host> rest -> local user@host user 130664562Sgshapirodnl <> user -> local user user 130764562Sgshapirodnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 130838032Speterdnl <user> lp <@host> rest -> local lp@host user 130938032Speterdnl <user> lp -> local lp user 131038032Speter################################################################### 131143730Speter 131264562SgshapiroSCanonLocal 131364562Sgshapiro# strip local host from routed addresses 131443730SpeterR< $* > < @ $+ > : $+ $@ $>Recurse $3 131538032SpeterR< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 131638032Speter 131738032Speter# strip trailing dot from any host name that may appear 131838032SpeterR< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 131938032Speter 132038032Speter# handle local: syntax -- use old user, either with or without host 132138032SpeterR< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 132238032SpeterR< > $+ $#_LOCAL_ $@ $1 $: $1 132338032Speter 132438032Speter# handle local:user@host syntax -- ignore host part 132538032SpeterR< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 132638032Speter 132738032Speter# handle local:user syntax 132838032SpeterR< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 132938032SpeterR< $+ > $* $#_LOCAL_ $@ $2 $: $1 133038032Speter 133138032Speter################################################################### 133238032Speter### Ruleset 93 -- convert header names to masqueraded form ### 133364562Sgshapiro################################################################### 133438032Speter 133564562SgshapiroSMasqHdr=93 133638032Speter 133738032Speterifdef(`_GENERICS_TABLE_', `dnl 133864562Sgshapiro# handle generics database 133938032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_', 134038032Speterdnl if generics should be applied add a @ as mark 134138032Speter`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 134264562Sgshapiro`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 134364562SgshapiroR$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 134464562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @ 134590792Sgshapirodnl ignore the first case for now 134664562Sgshapirodnl if it has the mark lookup full address 134764562Sgshapirodnl broken: %1 is full address not just detail 134864562SgshapiroR< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 134964562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain> 135064562Sgshapirodnl no match, try user+detail@domain 135164562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 135264562Sgshapiro $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 135364562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 135464562Sgshapiro $: < $(generics $1@$3 $: $) > $4 < @ $5 > 135564562Sgshapirodnl no match, remove mark 135664562SgshapiroR<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 135764562Sgshapirodnl no match, try @domain for exceptions 135864562SgshapiroR< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 135938032Speterdnl workspace: ... or <match> user <@domain> 136064562Sgshapirodnl no match, try local part 136164562SgshapiroR< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 136264562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 136364562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 136438032SpeterR< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 136538032SpeterR< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 136638032SpeterR< > $* $: $1 not found', 136764562Sgshapiro`dnl') 136864562Sgshapiro 136964562Sgshapiro# do not masquerade anything in class N 137090792SgshapiroR$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 137138032Speter 137238032Speterifdef(`MASQUERADE_NAME', `dnl 137338032Speter# special case the users that should be exposed 137438032SpeterR$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 137538032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 137638032Speter`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 137738032Speter`R$=E < @ $=M . > $@ $1 < @ $2 . >') 137838032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 137938032Speter`R$=E < @ $=w . > $@ $1 < @ $2 . >') 138038032Speter 138138032Speter# handle domain-specific masquerading 138238032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 138338032Speter`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 138438032Speter`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 138538032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 138638032Speter`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 138738032SpeterR$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 138890792SgshapiroR$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 138990792SgshapiroR$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 139090792Sgshapirodnl', `dnl no masquerading 139138032Speterdnl just fix *LOCAL* leftovers 139238032SpeterR$* < @ *LOCAL* > $@ $1 < @ $j . >') 139338032Speter 139438032Speter################################################################### 139538032Speter### Ruleset 94 -- convert envelope names to masqueraded form ### 139664562Sgshapiro################################################################### 139738032Speter 139864562SgshapiroSMasqEnv=94 139938032Speterifdef(`_MASQUERADE_ENVELOPE_', 140038032Speter`R$+ $@ $>MasqHdr $1', 140138032Speter`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 140238032Speter 140338032Speter################################################################### 140438032Speter### Ruleset 98 -- local part of ruleset zero (can be null) ### 140564562Sgshapiro################################################################### 140664562Sgshapiro 140738032SpeterSParseLocal=98 140864562Sgshapiroundivert(3)dnl LOCAL_RULE_0 140990792Sgshapiro 141090792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 141190792Sgshapiro###################################################################### 141290792Sgshapiro### LDAPExpand: Expand address using LDAP routing 141390792Sgshapiro### 141490792Sgshapiro### Parameters: 141590792Sgshapiro### <$1> -- parsed address (user < @ domain . >) (pass through) 141690792Sgshapiro### <$2> -- RFC822 address (user @ domain) (used for lookup) 141790792Sgshapiro### <$3> -- +detail information 141890792Sgshapiro### 141990792Sgshapiro### Returns: 142090792Sgshapiro### Mailer triplet ($#mailer $@ host $: address) 142190792Sgshapiro### Parsed address (user < @ domain . >) 142264562Sgshapiro###################################################################### 142364562Sgshapiro 142490792SgshapiroSLDAPExpand 142564562Sgshapiro# do the LDAP lookups 142694334SgshapiroR<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3> 1427102528Sgshapiro 1428102528Sgshapiro# look for temporary failures (return original address, MTA will queue up) 142994334SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*> $@ $3 143064562SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*> $@ $3 143164562Sgshapiro 143290792Sgshapiro# if mailRoutingAddress and local or non-existant mailHost, 143390792Sgshapiro# return the new mailRoutingAddress 143490792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 143590792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2 143690792SgshapiroR<$+@$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $5 @ $2') 143764562SgshapiroR<$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 143898121SgshapiroR<$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 143964562Sgshapiro 144064562Sgshapiro 144190792Sgshapiro# if mailRoutingAddress and non-local mailHost, 144290792Sgshapiro# relay to mailHost with new mailRoutingAddress 144390792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 144490792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 144590792Sgshapiro# check mailertable for host, relay from there 144690792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$3> $>canonify $1 $6 @ $2', 144790792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')') 144890792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 144990792Sgshapiro# check mailertable for host, relay from there 145064562SgshapiroR<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1', 145164562Sgshapiro`R<$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $2 $: $>canonify $1') 145264562Sgshapiro 145390792Sgshapiro# if no mailRoutingAddress and local mailHost, 145464562Sgshapiro# return original address 145598121SgshapiroR<> <$=w> <$+> <$+> <$*> $@ $2 145664562Sgshapiro 145764562Sgshapiro 145890792Sgshapiro# if no mailRoutingAddress and non-local mailHost, 145990792Sgshapiro# relay to mailHost with original address 146090792Sgshapiroifdef(`_MAILER_TABLE_', `dnl 146190792Sgshapiro# check mailertable for host, relay from there 146264562SgshapiroR<> <$+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2', 146390792Sgshapiro`R<> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $1 $: $2') 146490792Sgshapiro 146590792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_', 146690792Sgshapiro`# if no mailRoutingAddress and no mailHost, 146790792Sgshapiro# try without +detail 146890792SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl 146964562Sgshapiro 147090792Sgshapiro# if still no mailRoutingAddress and no mailHost, 147190792Sgshapiro# try @domain 147290792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 147364562SgshapiroR<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <@ $4> <+$3>') 147464562SgshapiroR<> <> <$+> <$+ @ $+> <$*> $@ $>LDAPExpand <$1> <@ $3> <$4> 147564562Sgshapiro 147664562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt, 147790792Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 147890792Sgshapiro# user does not exist 147990792SgshapiroR<> <> <$+> <@ $+> <$*> $: <?> < $&{addr_type} > < $1 > 148090792Sgshapiro# only give error for envelope recipient 148164562SgshapiroR<?> <e r> <$+> $#error $@ nouser $: "550 User unknown" 148264562SgshapiroR<?> <$*> <$+> $@ $2', 148390792Sgshapiro`dnl 148464562Sgshapiro# return the original address 148564562SgshapiroR<> <> <$+> <@ $+> <$*> $@ $1')', 148664562Sgshapiro`dnl') 148764562Sgshapiro 148890792Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 148938032Speter')') 149090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 149138032Speter###################################################################### 149238032Speter### D: LookUpDomain -- search for domain in access database 149338032Speter### 149438032Speter### Parameters: 149564562Sgshapiro### <$1> -- key (domain name) 149690792Sgshapiro### <$2> -- default (what to return if not found in db) 149764562Sgshapirodnl must not be empty 149864562Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 149990792Sgshapiro### ! does lookup only with tag 150064562Sgshapiro### + does lookup with and without tag 150164562Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 150238032Speterdnl returns: <default> <passthru> 150338032Speterdnl <result> <passthru> 150490792Sgshapiro###################################################################### 150564562Sgshapiro 150664562SgshapiroSD 150790792Sgshapirodnl workspace <key> <default> <passthru> <mark> 150890792Sgshapirodnl lookup with tag (in front, no delimiter here) 150964562Sgshapirodnl 2 3 4 5 151064562SgshapiroR<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 151190792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 151290792Sgshapirodnl lookup without tag? 151390792Sgshapirodnl 1 2 3 4 151490792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 151590792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest 151690792Sgshapirodnl XXX apply this also to IP addresses? 151790792Sgshapirodnl currently it works the wrong way round for [1.2.3.4] 151890792Sgshapirodnl 1 2 3 4 5 6 151990792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6> 152090792Sgshapirodnl 1 2 3 4 5 152190792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl') 152290792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 152390792Sgshapirodnl found SKIP: return <default> and <passthru> 152490792Sgshapirodnl 1 2 3 4 5 152590792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 152690792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!) 152790792Sgshapirodnl 1 2 3 4 5 6 152890792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*> $@ $>D <[$1]> <$3> <$4 $5> <$6> 152990792Sgshapiroifdef(`NO_NETINET6', `dnl', 153090792Sgshapiro`dnl not found: IPv6 net 153190792Sgshapirodnl (could be merged with previous rule if we have a class containing .:) 153290792Sgshapirodnl 1 2 3 4 5 6 153364562SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6> 153490792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>') 153590792Sgshapirodnl not found, but subdomain: try again 153690792Sgshapirodnl 1 2 3 4 5 6 153790792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6> 153890792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag: 153990792Sgshapirodnl 1 2 3 4 154090792SgshapiroR<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl') 154190792Sgshapirodnl not found, no subdomain: return <default> and <passthru> 154290792Sgshapirodnl 1 2 3 4 5 154390792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 154490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 154590792Sgshapirodnl 2 3 4 5 6 154690792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 154790792Sgshapirodnl return <result of lookup> and <passthru> 154838032Speterdnl 2 3 4 5 6 154938032SpeterR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 155090792Sgshapiro 155138032Speter###################################################################### 155238032Speter### A: LookUpAddress -- search for host address in access database 155338032Speter### 155438032Speter### Parameters: 155564562Sgshapiro### <$1> -- key (dot quadded host address) 155690792Sgshapiro### <$2> -- default (what to return if not found in db) 155764562Sgshapirodnl must not be empty 155864562Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 155990792Sgshapiro### ! does lookup only with tag 156064562Sgshapiro### + does lookup with and without tag 156164562Sgshapiro### <$4> -- passthru (additional data passed through) 156238032Speterdnl returns: <default> <passthru> 156338032Speterdnl <result> <passthru> 156490792Sgshapiro###################################################################### 156564562Sgshapiro 156690792SgshapiroSA 156790792Sgshapirodnl lookup with tag 156864562Sgshapirodnl 2 3 4 5 156990792SgshapiroR<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 157090792Sgshapirodnl lookup without tag 157190792Sgshapirodnl 1 2 3 4 157290792SgshapiroR<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 157390792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru> 157490792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 157590792Sgshapirodnl found SKIP: return <default> and <passthru> 157690792Sgshapirodnl 1 2 3 4 5 157790792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 157890792Sgshapiroifdef(`NO_NETINET6', `dnl', 157990792Sgshapiro`dnl no match; IPv6: remove last part 158090792Sgshapirodnl 1 2 3 4 5 6 158164562SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 158290792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>') 158390792Sgshapirodnl no match; IPv4: remove last part 158464562Sgshapirodnl 1 2 3 4 5 6 158590792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 158690792Sgshapirodnl no match: return default 158790792Sgshapirodnl 1 2 3 4 5 158890792SgshapiroR<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 158990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 159064562Sgshapirodnl 2 3 4 5 6 159190792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 159290792Sgshapirodnl match: return result 159390792Sgshapirodnl 2 3 4 5 6 159490792SgshapiroR<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 159538032Speterdnl endif _ACCESS_TABLE_ 159642575Speterdivert(0) 159742575Speter###################################################################### 159842575Speter### CanonAddr -- Convert an address into a standard form for 159942575Speter### relay checking. Route address syntax is 160042575Speter### crudely converted into a %-hack address. 160142575Speter### 160242575Speter### Parameters: 160342575Speter### $1 -- full recipient address 160442575Speter### 160564562Sgshapiro### Returns: 160664562Sgshapiro### parsed address, not in source route form 160742575Speterdnl user%host%host<@domain> 160842575Speterdnl host!user<@domain> 160942575Speter###################################################################### 161064562Sgshapiro 161164562SgshapiroSCanonAddr 161242575SpeterR$* $: $>Parse0 $>canonify $1 make domain canonical 161342575Speterifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 161442575SpeterR< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 161564562SgshapiroR$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 161642575SpeterR$* < @ $+ > : $* $3 $1 < @ $2 > 161742575Speterdnl') 161838032Speter 161938032Speter###################################################################### 162038032Speter### ParseRecipient -- Strip off hosts in $=R as well as possibly 162138032Speter### $* $=m or the access database. 162238032Speter### Check user portion for host separators. 162338032Speter### 162438032Speter### Parameters: 162538032Speter### $1 -- full recipient address 162638032Speter### 162738032Speter### Returns: 162838032Speter### parsed, non-local-relaying address 162938032Speter###################################################################### 163064562Sgshapiro 163142575SpeterSParseRecipient 163264562Sgshapirodnl mark and canonify address 163342575SpeterR$* $: <?> $>CanonAddr $1 163464562Sgshapirodnl workspace: <?> localpart<@domain[.]> 163542575SpeterR<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 163638032Speterdnl workspace: <?> localpart<@domain> 163738032SpeterR<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 163842575Speter 163964562Sgshapiro# if no $=O character, no host in the user portion, we are done 164042575SpeterR<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 164138032Speterdnl no $=O in localpart: return 164290792SgshapiroR<?> $* $@ $1 164364562Sgshapiro 164438032Speterdnl workspace: <NO> localpart<@domain>, where localpart contains $=O 164538032Speterdnl mark everything which has an "authorized" domain with <RELAY> 164642575Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 164764562Sgshapiro# if we relay, check username portion for user%host so host can be checked also 164864562SgshapiroR<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 164990792Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 165090792Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 165190792Sgshapiro 165290792Sgshapirodnl what if access map returns something else than RELAY? 165390792Sgshapirodnl we are only interested in RELAY entries... 165438032Speterdnl other To: entries: blacklist recipient; generic entries? 165542575Speterdnl if it is an error we probably do not want to relay anyway 165664562Sgshapiroifdef(`_RELAY_HOSTS_ONLY_', 165764562Sgshapiro`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 165842575Speterifdef(`_ACCESS_TABLE_', `dnl 165942575SpeterR<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 166064562SgshapiroR<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 166190792Sgshapiro`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 166242575Speterifdef(`_ACCESS_TABLE_', `dnl 166338032SpeterR<NO> $* < @ $+ > $: $>D <$2> <NO> <+ To> <$1 < @ $2 >> 166464562SgshapiroR<$+> <$+> $: <$1> $2',`dnl')') 166590792Sgshapiro 166690792Sgshapiro 166790792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl 166890792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain? 166990792SgshapiroR<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 167090792SgshapiroR<MX> < : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 167190792Sgshapirodnl yes: mark it as <RELAY> 167290792SgshapiroR<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 167390792Sgshapirodnl no: put old <NO> mark back 167490792SgshapiroR<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 167542575Speter 167690792Sgshapirodnl do we relay to this recipient domain? 167790792SgshapiroR<RELAY> $* < @ $* > $@ $>ParseRecipient $1 167842575Speterdnl something else 167964562SgshapiroR<$+> $* $@ $2 168038032Speter 168138032Speter 168238032Speter###################################################################### 168338032Speter### check_relay -- check hostname/address on SMTP startup 168438032Speter###################################################################### 168564562Sgshapiro 168638032SpeterSLocal_check_relay 168738032SpeterScheck`'_U_`'relay 168838032SpeterR$* $: $1 $| $>"Local_check_relay" $1 168938032SpeterR$* $| $* $| $#$* $#$3 169038032SpeterR$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 169138032Speter 169298121SgshapiroSBasic_check_relay 169338032Speter# check for deferred delivery mode 169438032SpeterR$* $: < $&{deliveryMode} > $1 169538032SpeterR< d > $* $@ deferred 169664562SgshapiroR< $* > $* $: $2 169766494Sgshapiro 169890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 169966494Sgshapirodnl workspace: {client_name} $| {client_addr} 170090792SgshapiroR$+ $| $+ $: $>D < $1 > <?> <+ Connect> < $2 > 170190792Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 170290792Sgshapirodnl OR $| $+ if client_name is empty 170390792SgshapiroR $| $+ $: $>A < $1 > <?> <+ Connect> <> empty client_name 170490792Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 170590792SgshapiroR<?> <$+> $: $>A < $1 > <?> <+ Connect> <> no: another lookup 170690792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) 170790792SgshapiroR<?> <$*> $: OK found nothing 170890792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK 170964562SgshapiroR<$={Accept}> <$*> $@ $1 return value of lookup 171066494SgshapiroR<REJECT> <$*> $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 171166494SgshapiroR<DISCARD> <$*> $#discard $: discard 171290792Sgshapiroifdef(`_FFR_QUARANTINE', 171364562Sgshapiro`R<QUARANTINE:$+> <$*> $#error $@ quarantine $: $1', `dnl') 171466494Sgshapirodnl error tag 171538032SpeterR<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 171664562SgshapiroR<ERROR:$+> <$*> $#error $: $1 171764562Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 171890792Sgshapirodnl generic error from access map 171938032SpeterR<$+> <$*> $#error $: $1', `dnl') 172064562Sgshapiro 172164562Sgshapiroifdef(`_RBL_',`dnl 172298121Sgshapiro# DNS based IP address spam list 172338032Speterdnl workspace: ignored... 172464562SgshapiroR$* $: $&{client_addr} 172538032SpeterR$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 172638032SpeterR<?>OK $: OKSOFAR 172738032SpeterR<?>$+ $#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"', 172838032Speter`dnl') 172938032Speterundivert(8) 173038032Speter 173164562Sgshapiro###################################################################### 173238032Speter### check_mail -- check SMTP ``MAIL FROM:'' command argument 173338032Speter###################################################################### 173438032Speter 173538032SpeterSLocal_check_mail 173638032SpeterScheck`'_U_`'mail 173738032SpeterR$* $: $1 $| $>"Local_check_mail" $1 173898121SgshapiroR$* $| $#$* $#$2 173938032SpeterR$* $| $* $@ $>"Basic_check_mail" $1 174038032Speter 174138032SpeterSBasic_check_mail 174264562Sgshapiro# check for deferred delivery mode 174364562SgshapiroR$* $: < $&{deliveryMode} > $1 174464562SgshapiroR< d > $* $@ deferred 174564562SgshapiroR< $* > $* $: $2 174664562Sgshapiro 174764562Sgshapiro# authenticated? 174864562Sgshapirodnl done first: we can require authentication for every mail transaction 174938032Speterdnl workspace: address as given by MAIL FROM: (sender) 175064562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 175164562SgshapiroR$* $| $#$+ $#$2 175238032Speterdnl undo damage: remove result of tls_client call 175364562SgshapiroR$* $| $* $: $1 175464562Sgshapiro 175564562Sgshapirodnl workspace: address as given by MAIL FROM: 175664562SgshapiroR<> $@ <OK> we MUST accept <> (RFC 1123) 175764562Sgshapiroifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 175864562Sgshapirodnl do some additional checks 175964562Sgshapirodnl no user@host 176064562Sgshapirodnl no user@localhost (if nonlocal sender) 176164562Sgshapirodnl this is a pretty simple canonification, it will not catch every case 176264562Sgshapirodnl just make sure the address has <> around it (which is required by 176364562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...) 176464562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will 176564562Sgshapirodnl not be modified by host lookups. 176664562SgshapiroR$+ $: <?> $1 176764562SgshapiroR<?><$+> $: <@> <$1> 176864562SgshapiroR<?>$+ $: <@> <$1> 176964562Sgshapirodnl workspace: <@> <address> 177064562Sgshapirodnl prepend daemon_flags 177164562SgshapiroR$* $: $&{daemon_flags} $| $1 177264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 177364562Sgshapirodnl do not allow these at all or only from local systems? 177464562SgshapiroR$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 177564562Sgshapirodnl accept unqualified sender: change mark to avoid test 177664562SgshapiroR$* u $* $| <@> < $* > $: <?> < $3 > 177738032Speterdnl workspace: ${daemon_flags} $| <@> <address> 177864562Sgshapirodnl or: <? ${client_name} > <address> 177964562Sgshapirodnl or: <?> <address> 178064562Sgshapirodnl remove daemon_flags 178164562SgshapiroR$* $| $* $: $2 178264562Sgshapiro# handle case of @localhost on address 178338032SpeterR<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 178464562SgshapiroR<@> < $* @ [127.0.0.1] > 178564562Sgshapiro $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 178664562SgshapiroR<@> < $* @ localhost.$m > 178764562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.$m > 178864562Sgshapiroifdef(`_NO_UUCP_', `dnl', 178964562Sgshapiro`R<@> < $* @ localhost.UUCP > 179064562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 179164562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 179264562Sgshapirodnl or: <@> <address> 179364562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 179490792SgshapiroR<@> $* $: $1 no localhost as domain 179564562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 179664562Sgshapirodnl or: <address> 179764562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 179864562SgshapiroR<? $=w> $* $: $2 local client: ok 179964562SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address" 180064562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 180164562SgshapiroR<?> $* $: $1') 180264562Sgshapirodnl workspace: address (or <address>) 1803102528SgshapiroR$* $: <?> $>CanonAddr $1 canonify sender address and mark it 180464562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 180598121Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed 1806102528SgshapiroR<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 180764562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 180890792SgshapiroR<?> $* < @ $* $=P > $: <_RES_OK_> $1 < @ $2 $3 > 180964562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ? or OK 181064562Sgshapirodnl A sender address with my local host name ($j) is safe 181164562SgshapiroR<?> $* < @ $j > $: <_RES_OK_> $1 < @ $j > 181290792Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 181364562Sgshapiro`R<?> $* < @ $+ > $: <_RES_OK_> $1 < @ $2 > ... unresolvable OK', 181438032Speter`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 181564562SgshapiroR<? $* <$->> $* < @ $+ > 181664562Sgshapiro $: <$2> $3 < @ $4 >') 181764562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ?, _RES_OK_, PERM, TEMP 181890792Sgshapirodnl mark is ? iff the address is user (wo @domain) 181990792Sgshapiro 182064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 182164562Sgshapiro# check sender address: user@address, user@, address 182264562Sgshapirodnl should we remove +ext from user? 182364562Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP 182490792SgshapiroR<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3> 182564562SgshapiroR<$+> $+ $: @<$1> <$2> $| <U:$2@> 182664562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 182764562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 182838032Speterdnl will only return user<@domain when "reversing" the args 182964562SgshapiroR@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <> 183064562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result> 183164562SgshapiroR<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 183264562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress> 183364562Sgshapiro# retransform for further use 183464562Sgshapirodnl required form: 183538032Speterdnl <ResultOfLookup|mark> CanonicalAddress 183638032SpeterR<?> <$+> <$*> $: <$1> $2 no match 183738032SpeterR<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 183864562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress 183964562Sgshapirodnl mark is ? iff the address is user (wo @domain) 184064562Sgshapiro 184190792Sgshapiroifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 184264562Sgshapiro# handle case of no @domain on address 184364562Sgshapirodnl prepend daemon_flags 184438032SpeterR<?> $* $: $&{daemon_flags} $| <?> $1 1845102528Sgshapirodnl accept unqualified sender: change mark to avoid test 184690792SgshapiroR$* u $* $| <?> $* $: <_RES_OK_> $3 184738032Speterdnl remove daemon_flags 184838032SpeterR$* $| $* $: $2 184964562SgshapiroR<?> $* $: < ? $&{client_addr} > $1 185090792SgshapiroR<?> $* $@ <_RES_OK_> ...local unqualed ok 185164562SgshapiroR<? $+> $* $#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f 185290792Sgshapiro ...remote is not') 185364562Sgshapiro# check results 185490792SgshapiroR<?> $* $: @ $1 mark address: nothing known about it 185538032SpeterR<$={ResOk}> $* $@ <_RES_OK_> domain ok: stop 185690792SgshapiroR<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 185790792SgshapiroR<PERM> $* $#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist" 185864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 185964562SgshapiroR<$={Accept}> $* $# $1 accept from access map 186064562SgshapiroR<DISCARD> $* $#discard $: discard 186164562Sgshapiroifdef(`_FFR_QUARANTINE', 186290792Sgshapiro`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 186364562SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 186464562Sgshapirodnl error tag 186538032SpeterR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 186638032SpeterR<ERROR:$+> $* $#error $: $1 186738032Speterifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 186838032Speterdnl generic error from access map 186938032SpeterR<$+> $* $#error $: $1 error from access db', 187038032Speter`dnl') 187138032Speter 187264562Sgshapiro###################################################################### 187338032Speter### check_rcpt -- check SMTP ``RCPT TO:'' command argument 187438032Speter###################################################################### 187538032Speter 187638032SpeterSLocal_check_rcpt 187738032SpeterScheck`'_U_`'rcpt 187890792SgshapiroR$* $: $1 $| $>"Local_check_rcpt" $1 187990792SgshapiroR$* $| $#$* $#$2 188090792SgshapiroR$* $| $* $@ $>"Basic_check_rcpt" $1 188138032Speter 188298121SgshapiroSBasic_check_rcpt 188338032Speter# empty address? 188438032SpeterR<> $#error $@ nouser $: "553 User address required" 188538032SpeterR$@ $#error $@ nouser $: "553 User address required" 188664562Sgshapiro# check for deferred delivery mode 188790792SgshapiroR$* $: < $&{deliveryMode} > $1 188890792SgshapiroR< d > $* $@ deferred 188990792SgshapiroR< $* > $* $: $2 189090792Sgshapiro 189190792Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 189290792Sgshapirodnl this code checks for user@host where host is not a FQHN. 189390792Sgshapirodnl it is not activated. 189490792Sgshapirodnl notice: code to check for a recipient without a domain name is 189564562Sgshapirodnl available down below; look for the same macro. 189690792Sgshapirodnl this check is done here because the name might be qualified by the 189790792Sgshapirodnl canonicalization. 189890792Sgshapiro# require fully qualified domain part? 189990792Sgshapirodnl very simple canonification: make sure the address is in < > 190064562SgshapiroR$+ $: <?> $1 190190792SgshapiroR<?> <$+> $: <@> <$1> 190264562SgshapiroR<?> $+ $: <@> <$1> 190364562SgshapiroR<@> < postmaster > $: postmaster 190490792SgshapiroR<@> < $* @ $+ . $+ > $: < $1 @ $2 . $3 > 190564562Sgshapirodnl prepend daemon_flags 190664562SgshapiroR<@> $* $: $&{daemon_flags} $| <@> $1 190790792Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 190864562Sgshapirodnl do not allow these at all or only from local systems? 190964562SgshapiroR$* r $* $| <@> < $* @ $* > $: < ? $&{client_name} > < $3 @ $4 > 191064562SgshapiroR<?> < $* > $: <$1> 191190792SgshapiroR<? $=w> < $* > $: <$1> 191290792SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "553 Fully qualified domain name required" 191390792Sgshapirodnl remove daemon_flags for other cases 191490792SgshapiroR$* $| <@> $* $: $2', `dnl') 191590792Sgshapiro 191690792Sgshapirodnl ################################################################## 191790792Sgshapirodnl call subroutines for recipient and relay 191890792Sgshapirodnl possible returns from subroutines: 191990792Sgshapirodnl $#TEMP temporary failure 192090792Sgshapirodnl $#error permanent failure (or temporary if from access map) 192190792Sgshapirodnl $#other stop processing 192290792Sgshapirodnl RELAY RELAYing allowed 192390792Sgshapirodnl other otherwise 192490792Sgshapiro###################################################################### 192590792SgshapiroR$* $: $1 $| @ $>"Rcpt_ok" $1 192690792Sgshapirodnl temporary failure? remove mark @ and remember 192790792SgshapiroR$* $| @ $#TEMP $+ $: $1 $| T $2 192890792Sgshapirodnl error or ok (stop) 192990792SgshapiroR$* $| @ $#$* $#$2 193090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 193190792SgshapiroR$* $| @ RELAY $@ RELAY 193290792Sgshapirodnl something else: call check sender (relay) 193390792SgshapiroR$* $| @ $* $: O $| $>"Relay_ok" $1 193490792Sgshapirodnl temporary failure: call check sender (relay) 193590792SgshapiroR$* $| T $+ $: T $2 $| $>"Relay_ok" $1 193690792Sgshapirodnl temporary failure? return that 193790792SgshapiroR$* $| $#TEMP $+ $#error $2 193890792Sgshapirodnl error or ok (stop) 193990792SgshapiroR$* $| $#$* $#$2 194090792SgshapiroR$* $| RELAY $@ RELAY 194190792Sgshapirodnl something else: return previous temp failure 194290792SgshapiroR T $+ $| $* $#error $1 194390792Sgshapiro# anything else is bogus 194490792SgshapiroR$* $#error $@ 5.7.1 $: confRELAY_MSG 194590792Sgshapirodivert(0) 194690792Sgshapiro 194790792Sgshapiro###################################################################### 194838032Speter### Rcpt_ok: is the recipient ok? 194942575Speterdnl input: recipient address (RCPT TO) 195038032Speterdnl output: see explanation at call 195138032Speter###################################################################### 195238032SpeterSRcpt_ok 195342575Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl 195442575SpeterR$* $: $>CanonAddr $1 195542575SpeterR$* < @ $* . > $1 < @ $2 > strip trailing dots', 195642575Speter`R$* $: $>ParseRecipient $1 strip relayable hosts') 195742575Speter 195842575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl 195943730Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl 196090792Sgshapiro# unlimited bestmx 196142575SpeterR$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 196242575Speter`dnl 196342575Speter# limit bestmx to $=B 196438032SpeterR$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 196564562SgshapiroR$* $=O $* < @ $* @@ $=w . > $* $@ $>"Rcpt_ok" $1 $2 $3 196638032SpeterR$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 196738032SpeterR$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 196864562Sgshapiro 196964562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl 197090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 197190792Sgshapiro# blacklist local users or any host from receiving mail 197264562SgshapiroR$* $: <?> $1 197364562Sgshapirodnl user is now tagged with @ to be consistent with check_mail 197464562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user) 197590792SgshapiroR<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2> 197664562SgshapiroR<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2> 197764562SgshapiroR<?> $+ $: <> <$1> $| <U:$1@> 197890792Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 197990792Sgshapirodnl will only return user<@domain when "reversing" the args 198090792SgshapiroR<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+ To> $| <$2> <> 198190792SgshapiroR<@> <$*> $| <$*> $: <$2> <$1> reverse result 198264562SgshapiroR<?> <$*> $: @ $1 mark address as no match 198390792Sgshapirodnl we may have to filter here because otherwise some RHSs 198490792Sgshapirodnl would be interpreted as generic error messages... 198590792Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 198690792Sgshapirodnl that would make a lot of things easier. 198764562SgshapiroR<$={Accept}> <$*> $: @ $2 mark address as no match 198864562Sgshapiroifdef(`_ACCESS_SKIP_', `dnl 198964562SgshapiroR<SKIP> <$*> $: @ $1 mark address as no match', `dnl') 199064562Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl 199164562Sgshapirodnl compatility with 8.11/8.10: 199264562Sgshapirodnl we have to filter these because otherwise they would be interpreted 199390792Sgshapirodnl as generic error message... 199464562Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 199590792Sgshapirodnl that would make a lot of things easier. 199690792Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)? 199764562SgshapiroR<$={SpamTag}> <$*> $: @ $2 mark address as no match') 199864562SgshapiroR<REJECT> $* $#error $@ 5.2.1 $: confRCPTREJ_MSG 199964562SgshapiroR<DISCARD> $* $#discard $: discard 200090792Sgshapiroifdef(`_FFR_QUARANTINE', 200164562Sgshapiro`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 200264562Sgshapirodnl error tag 200364562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 200438032SpeterR<ERROR:$+> $* $#error $: $1 200590792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 200690792Sgshapirodnl generic error from access map 200790792SgshapiroR<$+> $* $#error $: $1 error from access db 200890792SgshapiroR@ $* $1 remove mark', `dnl')', `dnl') 200990792Sgshapiro 201064562Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 201190792Sgshapiro# authenticated via TLS? 201290792SgshapiroR$* $: $1 $| $>RelayTLS client authenticated? 201390792SgshapiroR$* $| $# $+ $# $2 error/ok? 201490792SgshapiroR$* $| $* $: $1 no 201590792Sgshapiro 201690792SgshapiroR$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type} 201790792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth 201864562SgshapiroR$* $| $# $* $# $2 201964562Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech} 202064562SgshapiroR$* $| NO $: $1 202164562SgshapiroR$* $| $* $: $1 $| $&{auth_type} 202290792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ] 202390792Sgshapirodnl empty ${auth_type}? 202464562SgshapiroR$* $| $: $1 202571345Sgshapirodnl mechanism ${auth_type} accepted? 202664562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below 202771345SgshapiroR$* $| $={TrustAuthMech} $# RELAY 202871345Sgshapirodnl remove ${auth_type} 202938032SpeterR$* $| $* $: $1 203038032Speterdnl workspace: localpart<@domain> | localpart 203190792Sgshapiroifelse(defn(`_NO_UUCP_'), `r', 203290792Sgshapiro`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 203338032SpeterR$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 203490792Sgshapiro# anything terminating locally is ok 203564562Sgshapiroifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 203664562SgshapiroR$+ < @ $* $=m > $@ RELAY', `dnl') 203764562SgshapiroR$+ < @ $=w > $@ RELAY 203864562Sgshapiroifdef(`_RELAY_HOSTS_ONLY_', 203990792Sgshapiro`R$+ < @ $=R > $@ RELAY 204064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 204190792SgshapiroR$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 204264562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 204364562SgshapiroR<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 204490792Sgshapiro`R$+ < @ $* $=R > $@ RELAY 204590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 204638032SpeterR$+ < @ $+ > $: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')') 204738032Speterifdef(`_ACCESS_TABLE_', `dnl 204864562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 204938032SpeterR<RELAY> $* $@ RELAY 205038032Speterifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 205164562SgshapiroR<$*> <$*> $: $2',`dnl') 205264562Sgshapiro 205390792Sgshapiro 205490792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl 205542575Speter# allow relaying for hosts which we MX serve 205638032SpeterR$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 205738032Speterdnl this must not necessarily happen if the client is checked first... 205838032SpeterR< : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 205938032SpeterR<$* : $=w . : $*> $* $@ RELAY 206042575SpeterR< : $* : > $* $: $2', 206138032Speter`dnl') 206264562Sgshapiro 206364562Sgshapiro# check for local user (i.e. unqualified address) 206464562SgshapiroR$* $: <?> $1 206564562SgshapiroR<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 206664562Sgshapiro# local user is ok 206790792Sgshapirodnl is it really? the standard requires user@domain, not just user 206864562Sgshapirodnl but we should accept it anyway (maybe making it an option: 206964562Sgshapirodnl RequireFQDN ?) 207064562Sgshapirodnl postmaster must be accepted without domain (DRUMS) 207164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 207264562SgshapiroR<?> postmaster $@ OK 207364562Sgshapiro# require qualified recipient? 207464562Sgshapirodnl prepend daemon_flags 207564562SgshapiroR<?> $+ $: $&{daemon_flags} $| <?> $1 207664562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart 207790792Sgshapirodnl do not allow these at all or only from local systems? 207864562Sgshapirodnl r flag? add client_name 207990792SgshapiroR$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 208064562Sgshapirodnl no r flag: relay to local user (only local part) 208190792Sgshapiro# no qualified recipient required 208264562SgshapiroR$* $| <?> $+ $@ RELAY 208364562Sgshapirodnl client_name is empty 208464562SgshapiroR<?> <?> $+ $@ RELAY 208590792Sgshapirodnl client_name is local 208664562SgshapiroR<? $=w> <?> $+ $@ RELAY 208738032Speterdnl client_name is not local 208864562SgshapiroR<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 208938032Speterdnl no qualified recipient required 209090792SgshapiroR<?> $+ $@ RELAY') 209190792Sgshapirodnl it is a remote user: remove mark and then check client 209290792SgshapiroR<$+> $* $: $2 209390792Sgshapirodnl currently the recipient address is not used below 209490792Sgshapiro 209590792Sgshapiro###################################################################### 209638032Speter### Relay_ok: is the relay/sender ok? 209764562Sgshapirodnl input: ignored 209864562Sgshapirodnl output: see explanation at call 209990792Sgshapiro###################################################################### 210090792SgshapiroSRelay_ok 210190792Sgshapiro# anything originating locally is ok 210264562Sgshapiro# check IP address 210390792SgshapiroR$* $: $&{client_addr} 210490792SgshapiroR$@ $@ RELAY originated locally 2105102528SgshapiroR0 $@ RELAY originated locally 2106102528SgshapiroR127.0.0.1 $@ RELAY originated locally 2107102528SgshapiroRIPv6:::1 $@ RELAY originated locally 2108102528SgshapiroR$=R $* $@ RELAY relayable IP address 2109102528Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 2110102528SgshapiroR$* $: $>A <$1> <?> <+ Connect> <$1> 211190792SgshapiroR<RELAY> $* $@ RELAY relayable IP address 211264562Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl 211364562Sgshapirodnl this will cause rejections in cases like: 211490792Sgshapirodnl Connect:My.Host.Domain RELAY 211564562Sgshapirodnl Connect:My.Net REJECT 211664562Sgshapirodnl since in check_relay client_name is checked before client_addr 211764562SgshapiroR<REJECT> $* $@ REJECT rejected IP address') 211864562Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 211964562SgshapiroR<$*> <$*> $: $2', `dnl') 212064562SgshapiroR$* $: [ $1 ] put brackets around it... 212164562SgshapiroR$=w $@ RELAY ... and see if it is local 212264562Sgshapiro 212390792Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 212464562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 212564562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl 212690792Sgshapirodnl input: {client_addr} or something "broken" 212764562Sgshapirodnl just throw the input away; we do not need it. 212894334Sgshapiro# check whether FROM is allowed to use system as relay 212990792SgshapiroR$* $: <?> $>CanonAddr $&f 213090792SgshapiroR<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 213190792Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl 213290792Sgshapiro# check whether local FROM is ok 213390792SgshapiroR<?> $+ < @ $=w > $@ RELAY FROM local', `dnl') 213464562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl 213564562SgshapiroR<?> $+ < @ $+ > $: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <> 213664562SgshapiroR<@> <RELAY> $@ RELAY RELAY FROM sender ok 213790792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 213890792Sgshapiro', `dnl 213990792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', 214064562Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 214164562Sgshapiro')', 214264562Sgshapiro`dnl') 214364562Sgshapirodnl')', `dnl') 214490792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind. 214564562Sgshapirodnl it does not matter in this case because the following rule ignores 214664562Sgshapirodnl the input. otherwise these rules must "clean up" the workspace. 214764562Sgshapiro 214890792Sgshapiro# check client name: first: did it resolve? 214990792Sgshapirodnl input: ignored 215090792SgshapiroR$* $: < $&{client_resolve} > 215190792SgshapiroR<TEMP> $#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 215238032SpeterR<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 215390792SgshapiroR<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 215490792Sgshapirodnl ${client_resolve} should be OK, so go ahead 215590792SgshapiroR$* $: <@> $&{client_name} 215664562Sgshapirodnl should not be necessary since it has been done for client_addr already 215738032Speterdnl this rule actually may cause a problem if {client_name} resolves to "" 215890792Sgshapirodnl however, this should not happen since the forward lookup should fail 215990792Sgshapirodnl and {client_resolve} should be TEMP or FAIL. 216038032Speterdnl nevertheless, removing the rule doesn't hurt. 216190792Sgshapirodnl R<@> $@ RELAY 216264562Sgshapirodnl workspace: <@> ${client_name} (not empty) 216364562Sgshapiro# pass to name server to make hostname canonical 216464562SgshapiroR<@> $* $=P $:<?> $1 $2 216590792SgshapiroR<@> $+ $:<?> $[ $1 $] 216664562Sgshapirodnl workspace: <?> ${client_name} (canonified) 216790792SgshapiroR$* . $1 strip trailing dots 216864562Sgshapiroifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 216990792SgshapiroR<?> $* $=m $@ RELAY', `dnl') 217090792SgshapiroR<?> $=w $@ RELAY 217138032Speterifdef(`_RELAY_HOSTS_ONLY_', 217290792Sgshapiro`R<?> $=R $@ RELAY 217364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 217464562SgshapiroR<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 217564562SgshapiroR<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 217664562Sgshapiro`R<?> $* $=R $@ RELAY 217764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 217864562SgshapiroR<?> $* $: $>D <$1> <?> <+ Connect> <$1>',`dnl')') 217964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 218064562SgshapiroR<RELAY> $* $@ RELAY 218164562Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 218238032SpeterR<$*> <$*> $: $2',`dnl') 218364562Sgshapirodnl end of _PROMISCUOUS_RELAY_ 218464562Sgshapirodivert(0) 218564562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 218664562Sgshapiro# turn a canonical address in the form user<@domain> 218764562Sgshapiro# qualify unqual. addresses with $j 218864562Sgshapirodnl it might have been only user (without <@domain>) 218964562SgshapiroSFullAddr 219064562SgshapiroR$* <@ $+ . > $1 <@ $2 > 219164562SgshapiroR$* <@ $* > $@ $1 <@ $2 > 219264562SgshapiroR$+ $@ $1 <@ $j > 219364562Sgshapiro 219464562SgshapiroSDelay_TLS_Client 219564562Sgshapiro# authenticated? 219664562Sgshapirodnl code repeated here from Basic_check_mail 219764562Sgshapirodnl only called from check_rcpt in delay mode if checkrcpt returns $# 219864562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 219964562SgshapiroR$* $| $#$+ $#$2 220090792Sgshapirodnl return result from checkrcpt 220190792SgshapiroR$* $# $1 220264562Sgshapiro 220390792SgshapiroSDelay_TLS_Client2 220490792Sgshapiro# authenticated? 220564562Sgshapirodnl code repeated here from Basic_check_mail 220664562Sgshapirodnl only called from check_rcpt in delay mode if stopping due to Friend/Hater 220764562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 220864562SgshapiroR$* $| $#$+ $#$2 220964562Sgshapirodnl return result from friend/hater check 221064562SgshapiroR$* $@ $1 221164562Sgshapiro 221290792Sgshapiro# call all necessary rulesets 221364562SgshapiroScheck_rcpt 221464562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset 221564562Sgshapirodnl which is the correct DSN code? 221664562Sgshapiro# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 221790792Sgshapiro 221864562SgshapiroR$+ $: $1 $| $>checkrcpt $1 221964562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 222064562Sgshapirodnl on error (or discard) stop now 222164562SgshapiroR$+ $| $#error $* $#error $2 222290792SgshapiroR$+ $| $#discard $* $#discard $2 222390792Sgshapirodnl otherwise call tls_client; see above 222490792SgshapiroR$+ $| $#$* $@ $>"Delay_TLS_Client" $2 222594334SgshapiroR$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 222664562Sgshapiroifdef(`_SPAM_FH_', 222764562Sgshapiro`dnl lookup user@ and user@address 222894334Sgshapiroifdef(`_ACCESS_TABLE_', `', 222964562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 223038032Speter')')dnl 223138032Speterdnl one of the next two rules is supposed to match 223290792Sgshapirodnl this code has been copied from BLACKLIST... etc 223390792Sgshapirodnl and simplified by omitting some < >. 223464562SgshapiroR<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@> 223590792SgshapiroR<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > 223690792Sgshapirodnl R<?> $@ something_is_very_wrong_here 223790792Sgshapiro# lookup the addresses only with Spam tag 223890792SgshapiroR<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <> 223990792SgshapiroR<@> $* $| $* $: $2 $1 reverse result 224090792Sgshapirodnl', `dnl') 224190792Sgshapiroifdef(`_SPAM_FRIEND_', 224290792Sgshapiro`# is the recipient a spam friend? 224390792Sgshapiroifdef(`_SPAM_HATER_', 224490792Sgshapiro `errprint(`*** ERROR: define either Hater or Friend -- not both. 224590792Sgshapiro')', `dnl') 224690792SgshapiroR<FRIEND> $+ $@ $>"Delay_TLS_Client2" SPAMFRIEND 224790792SgshapiroR<$*> $+ $: $2', 224890792Sgshapiro`dnl') 224990792Sgshapiroifdef(`_SPAM_HATER_', 225090792Sgshapiro`# is the recipient no spam hater? 225190792SgshapiroR<HATER> $+ $: $1 spam hater: continue checks 225290792SgshapiroR<$*> $+ $@ $>"Delay_TLS_Client2" NOSPAMHATER everyone else: stop 225390792Sgshapirodnl',`dnl') 225490792Sgshapirodnl run further checks: check_mail 225590792Sgshapirodnl should we "clean up" $&f? 225690792Sgshapiroifdef(`_FFR_MAIL_MACRO', 225790792Sgshapiro`R$* $: $1 $| $>checkmail $&{mail_from}', 225890792Sgshapiro`R$* $: $1 $| $>checkmail <$&f>') 225990792Sgshapirodnl recipient (canonical format) $| result of checkmail 226090792SgshapiroR$* $| $#$* $#$2 226190792Sgshapirodnl run further checks: check_relay 226290792SgshapiroR$* $| $* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 226390792SgshapiroR$* $| $#$* $#$2 226490792SgshapiroR$* $| $* $: $1 226590792Sgshapiro', `dnl') 226690792Sgshapiro 226790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 226890792Sgshapiro###################################################################### 226990792Sgshapiro### F: LookUpFull -- search for an entry in access database 227090792Sgshapiro### 227190792Sgshapiro### lookup of full key (which should be an address) and 227290792Sgshapiro### variations if +detail exists: +* and without +detail 227390792Sgshapiro### 227490792Sgshapiro### Parameters: 227590792Sgshapiro### <$1> -- key 227690792Sgshapiro### <$2> -- default (what to return if not found in db) 227790792Sgshapirodnl must not be empty 227890792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 227990792Sgshapiro### ! does lookup only with tag 228090792Sgshapiro### + does lookup with and without tag 228190792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 228290792Sgshapirodnl returns: <default> <passthru> 228390792Sgshapirodnl <result> <passthru> 228490792Sgshapiro###################################################################### 228590792Sgshapiro 228690792SgshapiroSF 228790792Sgshapirodnl workspace: <key> <def> <o tag> <thru> 228890792Sgshapirodnl full lookup 228990792Sgshapirodnl 2 3 4 5 229090792SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 229190792Sgshapirodnl no match, try without tag 229290792Sgshapirodnl 1 2 3 4 229390792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 229490792Sgshapirodnl no match, +detail: try +* 229590792Sgshapirodnl 1 2 3 4 5 6 7 229690792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 229790792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 229890792Sgshapirodnl no match, +detail: try +* without tag 229990792Sgshapirodnl 1 2 3 4 5 6 230090792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 230190792Sgshapiro $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 230290792Sgshapirodnl no match, +detail: try without +detail 230390792Sgshapirodnl 1 2 3 4 5 6 7 230490792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 230590792Sgshapiro $: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 230690792Sgshapirodnl no match, +detail: try without +detail and without tag 230790792Sgshapirodnl 1 2 3 4 5 6 230890792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 230990792Sgshapiro $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 231090792Sgshapirodnl no match, return <default> <passthru> 231190792Sgshapirodnl 1 2 3 4 5 231290792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 231390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 231490792Sgshapirodnl 2 3 4 5 231590792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 231690792Sgshapirodnl match, return <match> <passthru> 231790792Sgshapirodnl 2 3 4 5 231890792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 231990792Sgshapiro 232090792Sgshapiro###################################################################### 232190792Sgshapiro### E: LookUpExact -- search for an entry in access database 232290792Sgshapiro### 232390792Sgshapiro### Parameters: 232490792Sgshapiro### <$1> -- key 232590792Sgshapiro### <$2> -- default (what to return if not found in db) 232690792Sgshapirodnl must not be empty 232790792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 232890792Sgshapiro### ! does lookup only with tag 232990792Sgshapiro### + does lookup with and without tag 233090792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 233190792Sgshapirodnl returns: <default> <passthru> 233290792Sgshapirodnl <result> <passthru> 233390792Sgshapiro###################################################################### 233490792Sgshapiro 233590792SgshapiroSE 233690792Sgshapirodnl 2 3 4 5 233790792SgshapiroR<$*> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 233890792Sgshapirodnl no match, try without tag 233990792Sgshapirodnl 1 2 3 4 234090792SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 234190792Sgshapirodnl no match, return default passthru 234290792Sgshapirodnl 1 2 3 4 5 234390792SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 234490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 234590792Sgshapirodnl 2 3 4 5 234690792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 234790792Sgshapirodnl match, return <match> <passthru> 234890792Sgshapirodnl 2 3 4 5 234990792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 235090792Sgshapiro 235190792Sgshapiro###################################################################### 235290792Sgshapiro### U: LookUpUser -- search for an entry in access database 235390792Sgshapiro### 235490792Sgshapiro### lookup of key (which should be a local part) and 235590792Sgshapiro### variations if +detail exists: +* and without +detail 235690792Sgshapiro### 235790792Sgshapiro### Parameters: 235890792Sgshapiro### <$1> -- key (user@) 235990792Sgshapiro### <$2> -- default (what to return if not found in db) 236090792Sgshapirodnl must not be empty 236190792Sgshapiro### <$3> -- mark (must be <(!|+) single-token>) 236290792Sgshapiro### ! does lookup only with tag 236390792Sgshapiro### + does lookup with and without tag 236490792Sgshapiro### <$4> -- passthru (additional data passed unchanged through) 236590792Sgshapirodnl returns: <default> <passthru> 236690792Sgshapirodnl <result> <passthru> 236790792Sgshapiro###################################################################### 236890792Sgshapiro 236990792SgshapiroSU 237090792Sgshapirodnl user lookups are always with trailing @ 237164562Sgshapirodnl 2 3 4 5 237264562SgshapiroR<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 237364562Sgshapirodnl no match, try without tag 237464562Sgshapirodnl 1 2 3 4 237564562SgshapiroR<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 237664562Sgshapirodnl do not remove the @ from the lookup: 237764562Sgshapirodnl it is part of the +detail@ which is omitted for the lookup 237890792Sgshapirodnl no match, +detail: try +* 237964562Sgshapirodnl 1 2 3 4 5 6 238064562SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 238164562Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 238264562Sgshapirodnl no match, +detail: try +* without tag 238364562Sgshapirodnl 1 2 3 4 5 238464562SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 238564562Sgshapiro $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 238664562Sgshapirodnl no match, +detail: try without +detail 238764562Sgshapirodnl 1 2 3 4 5 6 238890792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*> 238964562Sgshapiro $: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 239064562Sgshapirodnl no match, +detail: try without +detail and without tag 239164562Sgshapirodnl 1 2 3 4 5 239264562SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*> 239364562Sgshapiro $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 239464562Sgshapirodnl no match, return <default> <passthru> 239538032Speterdnl 1 2 3 4 5 239664562SgshapiroR<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 239764562Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 239890792Sgshapirodnl 2 3 4 5 239964562SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 240090792Sgshapirodnl match, return <match> <passthru> 240190792Sgshapirodnl 2 3 4 5 240290792SgshapiroR<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 240390792Sgshapiro 240490792Sgshapiro###################################################################### 240590792Sgshapiro### SearchList: search a list of items in the access map 240690792Sgshapiro### Parameters: 240790792Sgshapiro### <exact tag> $| <mark:address> <mark:address> ... <> 240890792Sgshapirodnl maybe we should have a @ (again) in front of the mark to 240990792Sgshapirodnl avoid errorneous matches (with error messages?) 241064562Sgshapirodnl if we can make sure that tag is always a single token 241190792Sgshapirodnl then we can omit the delimiter $|, otherwise we need it 241290792Sgshapirodnl to avoid errorneous matchs (first rule: D: if there 241390792Sgshapirodnl is that mark somewhere in the list, it will be taken). 241438032Speterdnl moreover, we can do some tricks to enforce lookup with 241590792Sgshapirodnl the tag only, e.g.: 241690792Sgshapiro### where "exact" is either "+" or "!": 241790792Sgshapiro### <+ TAG> lookup with and w/o tag 241890792Sgshapiro### <! TAG> lookup with tag 241990792Sgshapirodnl Warning: + and ! should be in OperatorChars (otherwise there must be 242090792Sgshapirodnl a blank between them and the tag. 242190792Sgshapiro### possible values for "mark" are: 242290792Sgshapiro### D: recursive host lookup (LookUpDomain) 242390792Sgshapirodnl A: recursive address lookup (LookUpAddress) [not yet required] 242464562Sgshapiro### E: exact lookup, no modifications 242564562Sgshapiro### F: full lookup, try user+ext@domain and user@domain 242664562Sgshapiro### U: user lookup, try user+ext and user (input must have trailing @) 242764562Sgshapiro### return: <RHS of lookup> or <?> (not found) 242864562Sgshapiro###################################################################### 242964562Sgshapiro 243064562Sgshapiro# class with valid marks for SearchList 243164562Sgshapirodnl if A is activated: add it 243264562SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A') 243364562SgshapiroSSearchList 243464562Sgshapiro# just call the ruleset with the name of the tag... nice trick... 243564562Sgshapirodnl 2 3 4 243664562SgshapiroR<$+> $| <$={src}:$*> <$*> $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <> 243790792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <> 243890792Sgshapirodnl no match and nothing left: return 243990792SgshapiroR<$+> $| <> $| <?> <> $@ <?> 244090792Sgshapirodnl no match but something left: continue 244190792SgshapiroR<$+> $| <$+> $| <?> <> $@ $>SearchList <$1> $| <$2> 244290792Sgshapirodnl match: return 244390792SgshapiroR<$+> $| <$*> $| <$+> <> $@ <$3> 244464562Sgshapirodnl return result from recursive invocation 244590792SgshapiroR<$+> $| <$+> $@ <$2> 244690792Sgshapirodnl endif _ACCESS_TABLE_ 244790792Sgshapirodivert(0) 244890792Sgshapiro 244990792Sgshapiro###################################################################### 245090792Sgshapiro### trust_auth: is user trusted to authenticate as someone else? 245190792Sgshapiro### 245290792Sgshapiro### Parameters: 245390792Sgshapiro### $1: AUTH= parameter from MAIL command 245490792Sgshapiro###################################################################### 245590792Sgshapiro 245690792Sgshapirodnl empty ruleset definition so it can be called 245790792SgshapiroSLocal_trust_auth 245864562SgshapiroStrust_auth 245990792SgshapiroR$* $: $&{auth_type} $| $1 246090792Sgshapiro# required by RFC 2554 section 4. 246190792SgshapiroR$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 246264562Sgshapirodnl seems to be useful... 246390792SgshapiroR$* $| $&{auth_authen} $@ identical 246490792SgshapiroR$* $| <$&{auth_authen}> $@ identical 246590792Sgshapirodnl call user supplied code 246690792SgshapiroR$* $| $* $: $1 $| $>"Local_trust_auth" $1 246764562SgshapiroR$* $| $#$* $#$2 246890792Sgshapirodnl default: error 246990792SgshapiroR$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 247090792Sgshapiro 247190792Sgshapiro###################################################################### 247290792Sgshapiro### Relay_Auth: allow relaying based on authentication? 247390792Sgshapiro### 247490792Sgshapiro### Parameters: 247564562Sgshapiro### $1: ${auth_type} 247690792Sgshapiro###################################################################### 247790792SgshapiroSLocal_Relay_Auth 247871345Sgshapiro 2479102528Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 248090792Sgshapiro###################################################################### 248190792Sgshapiro### srv_features: which features to offer to a client? 248290792Sgshapiro### (done in server) 248390792Sgshapiro###################################################################### 248490792SgshapiroSsrv_features 248590792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl 248690792SgshapiroR$* $: $1 $| $>"Local_srv_features" $1 248790792SgshapiroR$* $| $#$* $#$2 248890792SgshapiroR$* $| $* $: $1', `dnl') 248990792SgshapiroR$* $: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <> 249090792SgshapiroR<?>$* $: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <> 249190792SgshapiroR<?>$* $: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)> 249290792SgshapiroR<?>$* $@ OK 249390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 249490792SgshapiroR<$* _ATMPF_>$* $#temp', `dnl') 249590792SgshapiroR<$+>$* $# $1 249690792Sgshapiro 249790792Sgshapiro###################################################################### 249890792Sgshapiro### try_tls: try to use STARTTLS? 249990792Sgshapiro### (done in client) 250090792Sgshapiro###################################################################### 250190792SgshapiroStry_tls 250290792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl 250390792SgshapiroR$* $: $1 $| $>"Local_try_tls" $1 250490792SgshapiroR$* $| $#$* $#$2 250590792SgshapiroR$* $| $* $: $1', `dnl') 250690792SgshapiroR$* $: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <> 250790792SgshapiroR<?>$* $: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <> 250890792SgshapiroR<?>$* $: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)> 250990792SgshapiroR<?>$* $@ OK 251090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 251190792SgshapiroR<$* _ATMPF_>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 251264562SgshapiroR<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 251390792Sgshapiro 251490792Sgshapiro###################################################################### 251590792Sgshapiro### tls_rcpt: is connection with server "good" enough? 251690792Sgshapiro### (done in client, per recipient) 251790792Sgshapirodnl called from deliver() before RCPT command 251890792Sgshapiro### 251990792Sgshapiro### Parameters: 252064562Sgshapiro### $1: recipient 252164562Sgshapiro###################################################################### 252264562SgshapiroStls_rcpt 252390792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl 252490792SgshapiroR$* $: $1 $| $>"Local_tls_rcpt" $1 252590792SgshapiroR$* $| $#$* $#$2 252690792SgshapiroR$* $| $* $: $1', `dnl') 252764562Sgshapirodnl store name of other side 252890792SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 252990792Sgshapirodnl canonify recipient address 253064562SgshapiroR$+ $: <?> $>CanonAddr $1 253164562Sgshapirodnl strip trailing dots 253264562SgshapiroR<?> $+ < @ $+ . > <?> $1 <@ $2 > 253364562Sgshapirodnl full address? 253490792SgshapiroR<?> $+ < @ $+ > $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:> 253590792Sgshapirodnl only localpart? 253664562SgshapiroR<?> $+ $: $1 $| <U:$1@> <E:> 253764562Sgshapirodnl look it up 253890792Sgshapirodnl also look up a default value via E: 253990792SgshapiroR$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <> 254090792Sgshapirodnl found nothing: stop here 254190792SgshapiroR$* $| <?> $@ OK 254264562Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 254390792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 254490792Sgshapirodnl use the generic routine (for now) 254590792SgshapiroR$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>') 254690792Sgshapiro 254790792Sgshapiro###################################################################### 254890792Sgshapiro### tls_client: is connection with client "good" enough? 254990792Sgshapiro### (done in server) 255064562Sgshapiro### 255164562Sgshapiro### Parameters: 255264562Sgshapiro### ${verify} $| (MAIL|STARTTLS) 255390792Sgshapiro###################################################################### 255490792Sgshapirodnl MAIL: called from check_mail 255590792Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted 255690792SgshapiroStls_client 255764562Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl 255890792SgshapiroR$* $: $1 $| $>"Local_tls_client" $1 255990792SgshapiroR$* $| $#$* $#$2 256090792SgshapiroR$* $| $* $: $1', `dnl') 256190792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 256264562Sgshapirodnl store name of other side 256364562SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 256490792Sgshapirodnl ignore second arg for now 256590792Sgshapirodnl maybe use it to distinguish permanent/temporary error? 256690792Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered) 256790792Sgshapirodnl if STARTTLS: temporary (offered but maybe failed) 256864562SgshapiroR$* $| $* $: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <> 256990792SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <> 257090792Sgshapirodnl do a default lookup: just TLS_CLT_TAG 257190792SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 257290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 257364562SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 257490792SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 257590792SgshapiroR$* $| $* $@ $>"TLS_connection" $1') 257690792Sgshapiro 257790792Sgshapiro###################################################################### 257890792Sgshapiro### tls_server: is connection with server "good" enough? 257990792Sgshapiro### (done in client) 258090792Sgshapiro### 258190792Sgshapiro### Parameter: 258290792Sgshapiro### ${verify} 258390792Sgshapiro###################################################################### 258490792Sgshapirodnl i.e. has the server been authenticated and is encryption active? 258590792Sgshapirodnl called from deliver() after STARTTLS command 258690792SgshapiroStls_server 258764562Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl 258890792SgshapiroR$* $: $1 $| $>"Local_tls_server" $1 258964562SgshapiroR$* $| $#$* $#$2 259064562SgshapiroR$* $| $* $: $1', `dnl') 259190792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 259290792Sgshapirodnl store name of other side 259364562SgshapiroR$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 259464562SgshapiroR$* $: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <> 259564562SgshapiroR$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <> 259664562Sgshapirodnl do a default lookup: just TLS_SRV_TAG 259764562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 259890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail? 259990792SgshapiroR$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 260064562SgshapiroR$* $@ $>"TLS_connection" $1', `dnl 260164562SgshapiroR$* $@ $>"TLS_connection" $1') 260264562Sgshapiro 260364562Sgshapiro###################################################################### 260490792Sgshapiro### TLS_connection: is TLS connection "good" enough? 260590792Sgshapiro### 260690792Sgshapiro### Parameters: 260790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 260890792Sgshapiro### ${verify} $| <Requirement> [<>]', `dnl 260990792Sgshapiro### ${verify}') 261064562Sgshapiro### Requirement: RHS from access map, may be ? for none. 261164562Sgshapirodnl syntax for Requirement: 261264562Sgshapirodnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions] 261364562Sgshapirodnl extensions: could be a list of further requirements 261464562Sgshapirodnl for now: CN:string {cn_subject} == string 261590792Sgshapiro###################################################################### 261664562SgshapiroSTLS_connection 261790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error 261890792Sgshapirodnl deal with TLS handshake failures: abort 261990792SgshapiroRSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake." 262090792Sgshapirodivert(-1)') 262164562Sgshapirodnl common ruleset for tls_{client|server} 262290792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>] 262364562Sgshapirodnl remove optional <> 262490792SgshapiroR$* $| <$*>$* $: $1 $| <$2> 262590792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup> 262690792Sgshapiro# create the appropriate error codes 262790792Sgshapirodnl permanent or temporary error? 262890792SgshapiroR$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 262990792SgshapiroR$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 263090792Sgshapirodnl default case depends on TLS_PERM_ERR 263190792SgshapiroR$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 263290792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup> 263390792Sgshapiro# deal with TLS handshake failures: abort 263464562SgshapiroRSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 263590792Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 263690792Sgshapirodnl use default error 263790792SgshapiroRSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 263864562SgshapiroR$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1 263990792Sgshapirodnl separate optional requirements 264090792SgshapiroR$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1 264190792SgshapiroR$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> <> $1 264290792Sgshapirodnl separate optional requirements 264390792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$* $: <$2> <$3:$4> <$5> $1 264490792Sgshapirodnl some other value in access map: accept 264590792Sgshapirodnl this also allows to override the default case (if used) 264690792SgshapiroR$* $| $* $@ OK 264790792Sgshapiro# authentication required: give appropriate error 264890792Sgshapiro# other side did authenticate (via STARTTLS) 264990792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify} 265090792Sgshapirodnl only verification required and it succeeded 265190792SgshapiroR<$*><VERIFY> <> OK $@ OK 265290792Sgshapirodnl verification required and it succeeded but extensions are given 265390792Sgshapirodnl change it to <SMTP:ESC> <REQ:0> <extensions> 265490792SgshapiroR<$*><VERIFY> <$+> OK $: <$1> <REQ:0> <$2> 265590792Sgshapirodnl verification required + some level of encryption 265690792SgshapiroR<$*><VERIFY:$-> <$*> OK $: <$1> <REQ:$2> <$3> 265764562Sgshapirodnl just some level of encryption required 265890792SgshapiroR<$*><ENCR:$-> <$*> $* $: <$1> <REQ:$2> <$3> 265990792Sgshapirodnl workspace: 266090792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]> <[extensions]> {verify} (!= OK) 266190792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits> <[extensions]> 266290792Sgshapirodnl verification required but ${verify} is not set (case 1.) 266390792SgshapiroR<$-:$+><VERIFY $*> <$*> $#error $@ $2 $: $1 " authentication required" 266490792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL $#error $@ $2 $: $1 " authentication failed" 266590792SgshapiroR<$-:$+><VERIFY $*> <$*> NO $#error $@ $2 $: $1 " not authenticated" 266690792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT $#error $@ $2 $: $1 " no authentication requested" 266790792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 266890792Sgshapirodnl some other value for ${verify} 266990792SgshapiroR<$-:$+><VERIFY $*> <$*> $+ $#error $@ $2 $: $1 " authentication failure " $4 267090792Sgshapirodnl some level of encryption required: get the maximum level (case 2.) 267190792SgshapiroR<$*><REQ:$-> <$*> $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf} 267290792Sgshapirodnl compare required bits with actual bits 267390792SgshapiroR<$*><REQ:$-> <$*> $- $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $) 267490792SgshapiroR<$-:$+><$-:$-> <$*> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 267590792Sgshapirodnl strength requirements fulfilled 267690792Sgshapirodnl TLS Additional Requirements Separator 267790792Sgshapirodnl this should be something which does not appear in the extensions itself 267890792Sgshapirodnl @ could be part of a CN, DN, etc... 267990792Sgshapirodnl use < > ? those are encoded in CN, DN, ... 268090792Sgshapirodefine(`_TLS_ARS_', `++')dnl 268190792Sgshapirodnl workspace: 268290792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare 268390792SgshapiroR<$-:$+><$-:$-> <$*> $* $: <$1:$2 _TLS_ARS_ $5> 268490792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions> 268590792Sgshapirodnl continue: check extensions 268690792SgshapiroR<$-:$+ _TLS_ARS_ > $@ OK 268790792Sgshapirodnl split extensions into own list 268890792SgshapiroR<$-:$+ _TLS_ARS_ $+ > $: <$1:$2> <$3> 268990792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ > <$1:$2> <$3> <$4> 269090792SgshapiroR<$-:$+> $+ $@ $>"TLS_req" $3 $| <$1:$2> 269190792Sgshapiro 269290792Sgshapiro###################################################################### 269390792Sgshapiro### TLS_req: check additional TLS requirements 269490792Sgshapiro### 269590792Sgshapiro### Parameters: [<list> <of> <req>] $| <$-:$+> 269690792Sgshapiro### $-: SMTP reply code 269790792Sgshapiro### $+: Enhanced Status Code 269890792Sgshapirodnl further requirements for this ruleset: 269990792Sgshapirodnl name of "other side" is stored is {TLS_name} (client/server_name) 270090792Sgshapirodnl 270190792Sgshapirodnl currently only CN[:common_name] is implemented 270264562Sgshapirodnl right now this is only a logical AND 270364562Sgshapirodnl i.e. all requirements must be true 270464562Sgshapirodnl how about an OR? CN must be X or CN must be Y or .. 270564562Sgshapirodnl use a macro to compute this as a trivial sequential 270664562Sgshapirodnl operations (no precedences etc)? 270764562Sgshapiro###################################################################### 270890792SgshapiroSTLS_req 270990792Sgshapirodnl no additional requirements: ok 271090792SgshapiroR $| $+ $@ OK 271164562Sgshapirodnl require CN: but no CN specified: use name of other side 271290792SgshapiroR<CN> $* $| <$+> $: <CN:$&{TLS_Name}> $1 $| <$2> 271390792Sgshapirodnl match, check rest 271490792SgshapiroR<CN:$&{cn_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 271590792Sgshapirodnl CN does not match 271690792Sgshapirodnl 1 2 3 4 271790792SgshapiroR<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1 271890792Sgshapirodnl cert subject 271964562SgshapiroR<CS:$&{cert_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 272064562Sgshapirodnl CS does not match 272164562Sgshapirodnl 1 2 3 4 272264562SgshapiroR<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1 272364562Sgshapirodnl match, check rest 272464562SgshapiroR<CI:$&{cert_issuer}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 272564562Sgshapirodnl CI does not match 272664562Sgshapirodnl 1 2 3 4 272764562SgshapiroR<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1 272864562Sgshapirodnl return from recursive call 272964562SgshapiroROK $@ OK 273064562Sgshapiro 273164562Sgshapiro###################################################################### 273290792Sgshapiro### max: return the maximum of two values separated by : 273390792Sgshapiro### 273490792Sgshapiro### Parameters: [$-]:[$-] 273564562Sgshapiro###################################################################### 273690792SgshapiroSmax 273790792SgshapiroR: $: 0 273890792SgshapiroR:$- $: $1 273964562SgshapiroR$-: $: $1 274090792SgshapiroR$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 274164562SgshapiroRTRUE:$-:$- $: $2 274290792SgshapiroR$-:$-:$- $: $2 274390792Sgshapirodnl endif _ACCESS_TABLE_ 274490792Sgshapirodivert(0) 274590792Sgshapiro 274690792Sgshapiro###################################################################### 274764562Sgshapiro### RelayTLS: allow relaying based on TLS authentication 274890792Sgshapiro### 274990792Sgshapiro### Parameters: 275090792Sgshapiro### none 275190792Sgshapiro###################################################################### 275290792SgshapiroSRelayTLS 275390792Sgshapiro# authenticated? 275490792Sgshapirodnl we do not allow relaying for anyone who can present a cert 275590792Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns 275690792Sgshapirodnl CA in CertPath so we can authenticate users, we do not allow 275790792Sgshapirodnl them to abuse our server (they might be easier to get hold of, 275890792Sgshapirodnl but anyway). 275990792Sgshapirodnl so here is the trick: if the verification succeeded 276090792Sgshapirodnl we look up the cert issuer in the access map 276190792Sgshapirodnl (maybe after extracting a part with a regular expression) 276290792Sgshapirodnl if this returns RELAY we relay without further questions 276390792Sgshapirodnl if it returns SUBJECT we perform a similar check on the 276490792Sgshapirodnl cert subject. 276590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 276690792SgshapiroR$* $: <?> $&{verify} 276790792SgshapiroR<?> OK $: OK authenticated: continue 276890792SgshapiroR<?> $* $@ NO not authenticated 276990792Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 277090792SgshapiroR$* $: $(CERTIssuer $&{cert_issuer} $)', 277190792Sgshapiro`R$* $: $&{cert_issuer}') 277290792SgshapiroR$+ $: $(access CERTISSUER`'_TAG_DELIM_`'$1 $) 277390792Sgshapirodnl use $# to stop further checks (delay_check) 277490792SgshapiroRRELAY $# RELAY 277590792Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 277690792SgshapiroRSUBJECT $: <@> $(CERTSubject $&{cert_subject} $)', 277790792Sgshapiro`RSUBJECT $: <@> $&{cert_subject}') 277864562SgshapiroR<@> $+ $: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $) 277938032SpeterR<@> RELAY $# RELAY 278038032SpeterR$* $: NO', `dnl') 278138032Speter 278238032Speter###################################################################### 278364562Sgshapiro### authinfo: lookup authinfo in the access map 278464562Sgshapiro### 278564562Sgshapiro### Parameters: 278664562Sgshapiro### $1: {server_name} 278790792Sgshapiro### $2: {server_addr} 278864562Sgshapirodnl both are currently ignored 278964562Sgshapirodnl if it should be done via another map, we either need to restrict 279064562Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another 279164562Sgshapirodnl parameter which I want to avoid, it's quite complex already) 279238032Speter###################################################################### 279338032Speterdnl omit this ruleset if neither is defined? 279438032Speterdnl it causes DefaultAuthInfo to be ignored 279538032Speterdnl (which may be considered a good thing). 279664562SgshapiroSauthinfo 279766494Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl 2798R$* $: <$(authinfo AuthInfo:$&{server_name} $: ? $)> 2799R<?> $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)> 2800R<?> $: <$(authinfo AuthInfo: $: ? $)> 2801R<?> $@ no no authinfo available 2802R<$*> $# $1 2803dnl', `dnl 2804ifdef(`_ACCESS_TABLE_', `dnl 2805R$* $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <> 2806R$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <> 2807R$* $| <?>$* $: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <> 2808R$* $| <?>$* $@ no no authinfo available 2809R$* $| <$*> <> $# $2 2810dnl', `dnl')') 2811 2812undivert(9)dnl LOCAL_RULESETS 2813# 2814###################################################################### 2815###################################################################### 2816##### 2817`##### MAIL FILTER DEFINITIONS' 2818##### 2819###################################################################### 2820###################################################################### 2821_MAIL_FILTERS_ 2822# 2823###################################################################### 2824###################################################################### 2825##### 2826`##### MAILER DEFINITIONS' 2827##### 2828###################################################################### 2829###################################################################### 2830undivert(7)dnl MAILER_DEFINITIONS 2831 2832