proto.m4 revision 95154
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
1695154SgshapiroVERSIONID(`$Id: proto.m4,v 1.1.1.11 2002/04/10 03:04:58 gshapiro Exp $')
1738032Speter
1864562Sgshapiro# level CF_LEVEL config file format
1964562SgshapiroV`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley')
2038032Speterdivert(-1)
2138032Speter
2290792Sgshapirodnl if MAILER(`local') not defined: do it ourself; be nice
2390792Sgshapirodnl maybe we should issue a warning?
2490792Sgshapiroifdef(`_MAILER_local_',`', `MAILER(local)')
2590792Sgshapiro
2638032Speter# do some sanity checking
2738032Speterifdef(`__OSTYPE__',,
2864562Sgshapiro	`errprint(`*** ERROR: No system type defined (use OSTYPE macro)
2964562Sgshapiro')')
3038032Speter
3138032Speter# pick our default mailers
3238032Speterifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')')
3338032Speterifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')')
3438032Speterifdef(`confRELAY_MAILER',,
3538032Speter	`define(`confRELAY_MAILER',
3638032Speter		`ifdef(`_MAILER_smtp_', `relay',
3738032Speter			`ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')')
3838032Speterifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')')
3938032Speterdefine(`_SMTP_', `confSMTP_MAILER')dnl		for readability only
4038032Speterdefine(`_LOCAL_', `confLOCAL_MAILER')dnl	for readability only
4138032Speterdefine(`_RELAY_', `confRELAY_MAILER')dnl	for readability only
4238032Speterdefine(`_UUCP_', `confUUCP_MAILER')dnl		for readability only
4338032Speter
4438032Speter# back compatibility with old config files
4538032Speterifdef(`confDEF_GROUP_ID',
4664562Sgshapiro`errprint(`*** confDEF_GROUP_ID is obsolete.
4764562Sgshapiro    Use confDEF_USER_ID with a colon in the value instead.
4864562Sgshapiro')')
4938032Speterifdef(`confREAD_TIMEOUT',
5064562Sgshapiro`errprint(`*** confREAD_TIMEOUT is obsolete.
5164562Sgshapiro    Use individual confTO_<timeout> parameters instead.
5264562Sgshapiro')')
5338032Speterifdef(`confMESSAGE_TIMEOUT',
5438032Speter	`define(`_ARG_', index(confMESSAGE_TIMEOUT, /))
5538032Speter	 ifelse(_ARG_, -1,
5638032Speter		`define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)',
5738032Speter		`define(`confTO_QUEUERETURN',
5838032Speter			substr(confMESSAGE_TIMEOUT, 0, _ARG_))
5938032Speter		 define(`confTO_QUEUEWARN',
6038032Speter			substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')')
6138032Speterifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,,
6264562Sgshapiro`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete.
6364562Sgshapiro    Use confMAX_MESSAGE_SIZE for the second part of the value.
6464562Sgshapiro')')')
6538032Speter
6664562Sgshapiro
6764562Sgshapiro# Sanity check on ldap_routing feature
6864562Sgshapiro# If the user doesn't specify a new map, they better have given as a
6964562Sgshapiro# default LDAP specification which has the LDAP base (and most likely the host)
7064562Sgshapiroifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(`
7164562SgshapiroWARNING: Using default FEATURE(ldap_routing) map definition(s)
7264562Sgshapirowithout setting confLDAP_DEFAULT_SPEC option.
7364562Sgshapiro')')')dnl
7464562Sgshapiro
7538032Speter# clean option definitions below....
7664562Sgshapirodefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl
7738032Speter
7864562Sgshapirodnl required to "rename" the check_* rulesets...
7964562Sgshapirodefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_'))
8064562Sgshapirodnl default relaying denied message
8190792Sgshapiroifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG',
8290792Sgshapiroifdef(`_USE_AUTH_', `"550 Relaying denied. Proper authentication required."', `"550 Relaying denied"'))')
8390792Sgshapiroifdef(`confRCPTREJ_MSG', `', `define(`confRCPTREJ_MSG', `"550 Mailbox disabled for this recipient"')')
8490792Sgshapirodefine(`_CODE553', `553')
8538032Speterdivert(0)dnl
8638032Speter
8764562Sgshapiro# override file safeties - setting this option compromises system security,
8864562Sgshapiro# addressing the actual file configuration problem is preferred
8964562Sgshapiro# need to set this before any file actions are encountered in the cf file
9064562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe')
9138032Speter
9264562Sgshapiro# default LDAP map specification
9364562Sgshapiro# need to set this now before any LDAP maps are defined
9464562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost')
9564562Sgshapiro
9638032Speter##################
9738032Speter#   local info   #
9838032Speter##################
9938032Speter
10090792Sgshapiro# my LDAP cluster
10190792Sgshapiro# need to set this before any LDAP lookups are done (including classes)
10290792Sgshapiroifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m')
10390792Sgshapiro
10438032SpeterCwlocalhost
10538032Speterifdef(`USE_CW_FILE',
10638032Speter`# file containing names of hosts for which we receive email
10738032SpeterFw`'confCW_FILE',
10838032Speter	`dnl')
10938032Speter
11038032Speter# my official domain name
11138032Speter# ... `define' this only if sendmail cannot automatically determine your domain
11238032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM')
11338032Speter
11438032SpeterCP.
11538032Speter
11638032Speterifdef(`UUCP_RELAY',
11738032Speter`# UUCP relay host
11838032SpeterDY`'UUCP_RELAY
11938032SpeterCPUUCP
12038032Speter
12138032Speter')dnl
12238032Speterifdef(`BITNET_RELAY',
12338032Speter`#  BITNET relay host
12438032SpeterDB`'BITNET_RELAY
12538032SpeterCPBITNET
12638032Speter
12738032Speter')dnl
12838032Speterifdef(`DECNET_RELAY',
12938032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl
13038032Speter# DECnet relay host
13138032SpeterDC`'DECNET_RELAY
13238032SpeterCPDECNET
13338032Speter
13438032Speter')dnl
13538032Speterifdef(`FAX_RELAY',
13638032Speter`# FAX relay host
13738032SpeterDF`'FAX_RELAY
13838032SpeterCPFAX
13938032Speter
14038032Speter')dnl
14138032Speter# "Smart" relay host (may be null)
14290792SgshapiroDS`'ifdef(`SMART_HOST', `SMART_HOST')
14338032Speter
14438032Speterifdef(`LUSER_RELAY', `dnl
14538032Speter# place to which unknown users should be forwarded
14638032SpeterKuser user -m -a<>
14738032SpeterDL`'LUSER_RELAY',
14838032Speter`dnl')
14938032Speter
15038032Speter# operators that cannot be in local usernames (i.e., network indicators)
15138032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!')
15238032Speter
15338032Speter# a class with just dot (for identifying canonical names)
15438032SpeterC..
15538032Speter
15638032Speter# a class with just a left bracket (for identifying domain literals)
15738032SpeterC[[
15838032Speter
15964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
16064562Sgshapiro# access_db acceptance class
16164562SgshapiroC{Accept}OK RELAY
16290792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
16364562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl
16464562Sgshapiro# possible access_db RHS for spam friends/haters
16564562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')',
16638032Speter`dnl')
16738032Speter
16890792Sgshapirodnl mark for "domain is ok" (resolved or accepted anyway)
16990792Sgshapirodefine(`_RES_OK_', `OKR')dnl
17038032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
17138032Speter# Resolve map (to check if a host exists in check_mail)
17290792SgshapiroKresolve host -a<_RES_OK_> -T<TEMP>')
17390792SgshapiroC{ResOk}_RES_OK_
17438032Speter
17580785Sgshapiroifdef(`_NEED_MACRO_MAP_', `dnl
17680785Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map
17780785Sgshapirodefine(`_MACRO_MAP_', `1')dnl
17880785SgshapiroKmacro macro')', `dnl')
17966494Sgshapiro
18038032Speterifdef(`confCR_FILE', `dnl
18166494Sgshapiro# Hosts for which relaying is permitted ($=R)
18238032SpeterFR`'confCR_FILE',
18338032Speter`dnl')
18438032Speter
18590792Sgshapirodefine(`TLS_SRV_TAG', `"TLS_Srv"')dnl
18690792Sgshapirodefine(`TLS_CLT_TAG', `"TLS_Clt"')dnl
18790792Sgshapirodefine(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl
18890792Sgshapirodefine(`TLS_TRY_TAG', `"Try_TLS"')dnl
18990792Sgshapirodefine(`SRV_FEAT_TAG', `"Srv_Features"')dnl
19064562Sgshapirodnl this may be useful in other contexts too
19164562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map
19264562Sgshapirodefine(`_ARITH_MAP_', `1')dnl
19364562SgshapiroKarith arith')
19464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
19590792Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map
19690792Sgshapirodefine(`_MACRO_MAP_', `1')dnl
19790792SgshapiroKmacro macro')
19890792Sgshapiro# possible values for TLS_connection in access map
19964562SgshapiroC{tls}VERIFY ENCR', `dnl')
20064562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
20164562Sgshapiro# extract relevant part from cert issuer
20264562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
20364562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
20464562Sgshapiro# extract relevant part from cert subject
20564562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
20664562Sgshapiro
20790792Sgshapiroifdef(`LOCAL_RELAY', `dnl
20838032Speter# who I send unqualified names to (null means deliver locally)
20990792SgshapiroDR`'LOCAL_RELAY')
21038032Speter
21190792Sgshapiroifdef(`MAIL_HUB', `dnl
21238032Speter# who gets all local email traffic ($R has precedence for unqualified names)
21390792SgshapiroDH`'MAIL_HUB')
21438032Speter
21538032Speter# dequoting map
21690792SgshapiroKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `')
21738032Speter
21838032Speterdivert(0)dnl	# end of nullclient diversion
21938032Speter# class E: names that should be exposed as from this host, even if we masquerade
22064562Sgshapiro# class L: names that should be delivered locally, even if we have a relay
22138032Speter# class M: domains that should be converted to $M
22264562Sgshapiro# class N: domains that should not be converted to $M
22338032Speter#CL root
22438032Speterundivert(5)dnl
22564562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
22638032Speter
22790792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
22838032Speter# who I masquerade as (null for no masquerading) (see also $=M)
22990792SgshapiroDM`'MASQUERADE_NAME')
23038032Speter
23138032Speter# my name for error messages
23238032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
23338032Speter
23464562Sgshapiroundivert(6)dnl LOCAL_CONFIG
23538032Speterinclude(_CF_DIR_`m4/version.m4')
23638032Speter
23738032Speter###############
23838032Speter#   Options   #
23938032Speter###############
24090792Sgshapiroifdef(`confAUTO_REBUILD',
24190792Sgshapiro`errprint(WARNING: `confAUTO_REBUILD' is no longer valid.
24290792Sgshapiro	There was a potential for a denial of service attack if this is set.
24390792Sgshapiro)')dnl
24438032Speter
24538032Speter# strip message body to 7 bits on input?
24664562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
24738032Speter
24838032Speter# 8-bit data handling
24977349Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8')
25038032Speter
25138032Speter# wait for alias file rebuild (default units: minutes)
25264562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m')
25338032Speter
25438032Speter# location of alias file
25564562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
25664562Sgshapiro
25738032Speter# minimum number of free blocks on filesystem
25864562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
25938032Speter
26038032Speter# maximum message size
26164562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000')
26238032Speter
26338032Speter# substitution for space (blank) characters
26464562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_')
26538032Speter
26638032Speter# avoid connecting to "expensive" mailers on initial submission?
26764562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
26838032Speter
26938032Speter# checkpoint queue runs after every N successful deliveries
27064562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
27138032Speter
27238032Speter# default delivery mode
27364562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
27438032Speter
27538032Speter# error message header/file
27664562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
27738032Speter
27838032Speter# error mode
27964562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print')
28038032Speter
28138032Speter# save Unix-style "From_" lines at top of header?
28264562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
28338032Speter
28490792Sgshapiro# queue file mode (qf files)
28590792Sgshapiro_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600')
28690792Sgshapiro
28738032Speter# temporary file mode
28864562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
28938032Speter
29038032Speter# match recipients against GECOS field?
29164562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
29238032Speter
29338032Speter# maximum hop count
29490792Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `25')
29538032Speter
29638032Speter# location of help file
29764562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
29838032Speter
29938032Speter# ignore dots as terminators in incoming messages?
30064562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
30138032Speter
30238032Speter# name resolver options
30364562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
30438032Speter
30538032Speter# deliver MIME-encapsulated error messages?
30664562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
30738032Speter
30838032Speter# Forward file search path
30964562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
31038032Speter
31138032Speter# open connection cache size
31264562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
31338032Speter
31438032Speter# open connection cache timeout
31564562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
31638032Speter
31738032Speter# persistent host status directory
31864562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
31938032Speter
32038032Speter# single thread deliveries (requires HostStatusDirectory)?
32164562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
32238032Speter
32338032Speter# use Errors-To: header?
32464562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
32538032Speter
32638032Speter# log level
32764562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10')
32838032Speter
32938032Speter# send to me too, even in an alias expansion?
33064562Sgshapiro_OPTION(MeToo, `confME_TOO', `True')
33138032Speter
33238032Speter# verify RHS in newaliases?
33364562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
33438032Speter
33538032Speter# default messages to old style headers if no special punctuation?
33664562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
33738032Speter
33838032Speter# SMTP daemon options
33964562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
34094334Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.
34194334Sgshapiro	Use `DAEMON_OPTIONS()'; see cf/README.
34264562Sgshapiro)'dnl
34364562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
34466494Sgshapiroifelse(defn(`_DPO_'), `',
34590792Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet
34690792SgshapiroO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
34764562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
34838032Speter
34964562Sgshapiro# SMTP client options
35090792Sgshapiroifelse(defn(`confCLIENT_OPTIONS'), `', `dnl',
35190792Sgshapiro`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid.  See cf/README for more information.
35290792Sgshapiro)'dnl
35390792Sgshapiro`CLIENT_OPTIONS(`confCLIENT_OPTIONS')')
35490792Sgshapiroifelse(defn(`_CPO_'), `',
35590792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_')
35664562Sgshapiro
35790792Sgshapiro# Modifiers to `define' {daemon_flags} for direct submissions
35890792Sgshapiro_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `')
35990792Sgshapiro
36090792Sgshapiro# Use as mail submission program? See sendmail/SECURITY
36190792Sgshapiro_OPTION(UseMSP, `confUSE_MSP', `')
36290792Sgshapiro
36338032Speter# privacy flags
36464562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
36538032Speter
36638032Speter# who (if anyone) should get extra copies of error messages
36764562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
36838032Speter
36938032Speter# slope of queue-only function
37064562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
37138032Speter
37290792Sgshapiro# limit on number of concurrent queue runners
37390792Sgshapiro_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `')
37490792Sgshapiro
37590792Sgshapiro# maximum number of queue-runners per queue-grouping with multiple queues
37690792Sgshapiro_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1')
37790792Sgshapiro
37890792Sgshapiro# priority of queue runners (nice(3))
37990792Sgshapiro_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `')
38090792Sgshapiro
38190792Sgshapiro# shall we sort the queue by hostname first?
38290792Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
38390792Sgshapiro
38490792Sgshapiro# minimum time in queue before retry
38590792Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
38690792Sgshapiro
38790792Sgshapiro# how many jobs can you process in the queue?
38890792Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
38990792Sgshapiro
39090792Sgshapiro# perform initial split of envelope without checking MX records
39190792Sgshapiro_OPTION(FastSplit, `confFAST_SPLIT', `1')
39290792Sgshapiro
39338032Speter# queue directory
39464562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
39538032Speter
39690792Sgshapiro# key for shared memory; 0 to turn off
39790792Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
39890792Sgshapiro
39994334Sgshapiroifdef(`confSHARED_MEMORY_KEY_FILE', `dnl
40094334Sgshapiro# file to store key for shared memory (if SharedMemoryKey = -1)
40194334SgshapiroO SharedMemoryKeyFile=confSHARED_MEMORY_KEY_FILE')
40294334Sgshapiro
40338032Speter# timeouts (many of these)
40464562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
40564562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
40690792Sgshapiro_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s')
40764562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
40864562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m')
40964562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m')
41064562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
41164562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
41264562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
41364562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
41464562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m')
41564562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m')
41664562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m')
41764562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h')
41864562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s')
41964562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
42064562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m')
42164562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
42264562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
42364562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
42464562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
42564562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
42664562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
42764562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
42864562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
42964562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
43064562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
43164562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
43264562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
43364562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
43464562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
43564562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
43690792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
43790792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m')
43890792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
43938032Speter
44090792Sgshapiro# time for DeliverBy; extension disabled if less than 0
44190792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
44290792Sgshapiro
44338032Speter# should we not prune routes in route-addr syntax addresses?
44464562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
44538032Speter
44638032Speter# queue up everything before forking?
44764562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
44838032Speter
44938032Speter# status file
45064562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
45138032Speter
45238032Speter# time zone handling:
45338032Speter#  if undefined, use system default
45438032Speter#  if defined but null, use TZ envariable passed in
45538032Speter#  if defined and non-null, use that info
45638032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
45738032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
45838032Speter	`O TimeZoneSpec=confTIME_ZONE')
45938032Speter
46038032Speter# default UID (can be username or userid:groupid)
46164562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
46238032Speter
46338032Speter# list of locations of user database file (null means no lookup)
46464562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
46538032Speter
46638032Speter# fallback MX host
46764562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
46838032Speter
46938032Speter# if we are the best MX host for a site, try it directly instead of config err
47064562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
47138032Speter
47238032Speter# load average at which we just queue messages
47364562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8')
47438032Speter
47538032Speter# load average at which we refuse connections
47664562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
47738032Speter
47890792Sgshapiro# load average at which we delay connections; 0 means no limit
47990792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0')
48090792Sgshapiro
48138032Speter# maximum number of children we allow at one time
48264562Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12')
48338032Speter
48438032Speter# maximum number of new connections per second
48571345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
48638032Speter
48738032Speter# work recipient factor
48864562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
48938032Speter
49038032Speter# deliver each queued job in a separate process?
49164562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
49238032Speter
49338032Speter# work class factor
49464562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
49538032Speter
49638032Speter# work time factor
49764562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
49838032Speter
49938032Speter# default character set
50064562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
50138032Speter
50290792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
50364562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
50438032Speter
50538032Speter# hosts file (normally /etc/hosts)
50664562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
50738032Speter
50838032Speter# dialup line delay on connection failure
50964562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s')
51038032Speter
51138032Speter# action to take if there are no recipients in the message
51264562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed')
51338032Speter
51438032Speter# chrooted environment for writing to files
51564562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
51638032Speter
51738032Speter# are colons OK in addresses?
51864562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
51938032Speter
52038032Speter# shall I avoid expanding CNAMEs (violates protocols)?
52164562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
52238032Speter
52338032Speter# SMTP initial login message (old $e macro)
52464562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
52538032Speter
52638032Speter# UNIX initial From header format (old $l macro)
52764562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
52838032Speter
52938032Speter# From: lines that have embedded newlines are unwrapped onto one line
53064562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
53138032Speter
53238032Speter# Allow HELO SMTP command that does not `include' a host name
53364562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
53438032Speter
53538032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
53664562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
53738032Speter
53838032Speter# delimiter (operator) characters (old $o macro)
53964562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
54038032Speter
54138032Speter# shall I avoid calling initgroups(3) because of high NIS costs?
54264562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
54338032Speter
54438032Speter# are group-writable `:include:' and .forward files (un)trustworthy?
54590792Sgshapiro# True (the default) means they are not trustworthy.
54664562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
54790792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES',
54890792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
54990792Sgshapiro')')
55038032Speter
55138032Speter# where do errors that occur when sending errors get sent?
55264562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
55338032Speter
55464562Sgshapiro# where to save bounces if all else fails
55564562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
55664562Sgshapiro
55738032Speter# what user id do we assume for the majority of the processing?
55864562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
55938032Speter
56038032Speter# maximum number of recipients per SMTP envelope
56164562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
56238032Speter
56390792Sgshapiro# limit the rate recipients per SMTP envelope are accepted
56490792Sgshapiro# once the threshold number of recipients have been rejected
56590792Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20')
56690792Sgshapiro
56738032Speter# shall we get local names from our installed interfaces?
56864562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
56938032Speter
57064562Sgshapiro# Return-Receipt-To: header implies DSN request
57164562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
57264562Sgshapiro
57364562Sgshapiro# override connection address (for testing)
57464562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
57564562Sgshapiro
57664562Sgshapiro# Trusted user for file ownership and starting the daemon
57764562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
57864562Sgshapiro
57964562Sgshapiro# Control socket for daemon management
58064562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
58164562Sgshapiro
58264562Sgshapiro# Maximum MIME header length to protect MUAs
58364562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
58464562Sgshapiro
58564562Sgshapiro# Maximum length of the sum of all headers
58664562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
58764562Sgshapiro
58864562Sgshapiro# Maximum depth of alias recursion
58964562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
59064562Sgshapiro
59164562Sgshapiro# location of pid file
59264562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
59364562Sgshapiro
59464562Sgshapiro# Prefix string for the process title shown on 'ps' listings
59564562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
59664562Sgshapiro
59764562Sgshapiro# Data file (df) memory-buffer file maximum size
59864562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
59964562Sgshapiro
60064562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
60164562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
60264562Sgshapiro
60390792Sgshapiro# lookup type to find information about local mailboxes
60490792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
60590792Sgshapiro
60664562Sgshapiro# list of authentication mechanisms
60790792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
60864562Sgshapiro
60964562Sgshapiro# default authentication information for outgoing connections
61064562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
61164562Sgshapiro
61264562Sgshapiro# SMTP AUTH flags
61364562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
61464562Sgshapiro
61590792Sgshapiro# SMTP AUTH maximum encryption strength
61690792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
61790792Sgshapiro
61890792Sgshapiro# SMTP STARTTLS server options
61990792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
62090792Sgshapiro
62164562Sgshapiro# Input mail filters
62264562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
62364562Sgshapiro
62490792Sgshapiroifdef(`confINPUT_MAIL_FILTERS', `dnl
62564562Sgshapiro# Milter options
62690792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
62764562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
62864562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
62964562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
63064562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')')
63164562Sgshapiro
63264562Sgshapiro# CA directory
63364562Sgshapiro_OPTION(CACERTPath, `confCACERT_PATH', `')
63464562Sgshapiro# CA file
63564562Sgshapiro_OPTION(CACERTFile, `confCACERT', `')
63664562Sgshapiro# Server Cert
63764562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
63864562Sgshapiro# Server private key
63964562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
64064562Sgshapiro# Client Cert
64164562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
64264562Sgshapiro# Client private key
64364562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
64464562Sgshapiro# DHParameters (only required if DSA/DH is used)
64564562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
64664562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
64764562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
64864562Sgshapiro
64990792Sgshapiro############################
65090792Sgshapiro`# QUEUE GROUP DEFINITIONS  #'
65190792Sgshapiro############################
65290792Sgshapiro_QUEUE_GROUP_
65342575Speter
65438032Speter###########################
65538032Speter#   Message precedences   #
65638032Speter###########################
65738032Speter
65838032SpeterPfirst-class=0
65938032SpeterPspecial-delivery=100
66038032SpeterPlist=-30
66138032SpeterPbulk=-60
66238032SpeterPjunk=-100
66338032Speter
66438032Speter#####################
66538032Speter#   Trusted users   #
66638032Speter#####################
66738032Speter
66838032Speter# this is equivalent to setting class "t"
66964562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
67038032SpeterTroot
67138032SpeterTdaemon
67238032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp')
67338032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
67438032Speter
67538032Speter#########################
67638032Speter#   Format of headers   #
67738032Speter#########################
67838032Speter
67938032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
68038032SpeterH?P?Return-Path: <$g>
68138032SpeterHReceived: confRECEIVED_HEADER
68238032SpeterH?D?Resent-Date: $a
68338032SpeterH?D?Date: $a
68438032SpeterH?F?Resent-From: confFROM_HEADER
68538032SpeterH?F?From: confFROM_HEADER
68638032SpeterH?x?Full-Name: $x
68738032Speter# HPosted-Date: $a
68838032Speter# H?l?Received-Date: $b
68938032SpeterH?M?Resent-Message-Id: <$t.$i@$j>
69038032SpeterH?M?Message-Id: <$t.$i@$j>
69164562Sgshapiro
69238032Speter#
69338032Speter######################################################################
69438032Speter######################################################################
69538032Speter#####
69638032Speter#####			REWRITING RULES
69738032Speter#####
69838032Speter######################################################################
69938032Speter######################################################################
70038032Speter
70138032Speter############################################
70238032Speter###  Ruleset 3 -- Name Canonicalization  ###
70338032Speter############################################
70464562SgshapiroScanonify=3
70538032Speter
70638032Speter# handle null input (translate to <@> special case)
70738032SpeterR$@			$@ <@>
70838032Speter
70938032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
71038032SpeterR$*			$: $1 <@>			mark addresses
71138032SpeterR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
71238032SpeterR@ $* <@>		$: @ $1				unmark @host:...
71390792SgshapiroR$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
71438032SpeterR$* :: $* <@>		$: $1 :: $2			unmark node::addr
71538032SpeterR:`include': $* <@>	$: :`include': $1			unmark :`include':...
71638032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
71738032SpeterR$* : $* <@>		$: $2				strip colon if marked
71838032SpeterR$* <@>			$: $1				unmark
71938032SpeterR$* ;			   $1				strip trailing semi
72071345SgshapiroR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
72138032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
72238032Speter
72338032Speter# null input now results from list:; syntax
72438032SpeterR$@			$@ :; <@>
72538032Speter
72638032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
72738032SpeterR$*			$: < $1 >			housekeeping <>
72838032SpeterR$+ < $* >		   < $2 >			strip excess on left
72938032SpeterR< $* > $+		   < $1 >			strip excess on right
73038032SpeterR<>			$@ < @ >			MAIL FROM:<> case
73138032SpeterR< $+ >			$: $1				remove housekeeping <>
73238032Speter
73364562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
73438032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
73538032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
73638032Speter
73738032Speter# localize and dispose of route-based addresses
73890792Sgshapirodnl XXX: IPv6 colon conflict
73990792Sgshapiroifdef(`NO_NETINET6', `dnl',
74090792Sgshapiro`R@ [$+] : $+		$@ $>Canonify2 < @ [$1] > : $2	handle <route-addr>')
74164562SgshapiroR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
74264562Sgshapirodnl',`dnl
74364562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d>
74464562SgshapiroR@ $+ , $+		$2
74590792Sgshapiroifdef(`NO_NETINET6', `dnl',
74690792Sgshapiro`R@ [ $* ] : $+		$2')
74764562SgshapiroR@ $+ : $+		$2
74864562Sgshapirodnl')
74938032Speter
75038032Speter# find focus for list syntax
75164562SgshapiroR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
75238032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
75338032Speter
75438032Speter# find focus for @ syntax addresses
75538032SpeterR$+ @ $+		$: $1 < @ $2 >			focus on domain
75638032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
75764562SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
75838032Speter
75990792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here.
76090792Sgshapirodnl # do some sanity checking
76190792Sgshapirodnl R$* < @ $~[ $* : $* > $*	$1 < @ $2 $3 > $4	nix colons in addrs
76238032Speter
76338032Speterifdef(`_NO_UUCP_', `dnl',
76438032Speter`# convert old-style addresses to a domain-based address
76564562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
76664562SgshapiroR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
76764562SgshapiroR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
76838032Speter')
76938032Speterifdef(`_USE_DECNET_SYNTAX_',
77038032Speter`# convert node::user addresses into a domain-based address
77164562SgshapiroR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
77264562SgshapiroR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
77338032Speter',
77438032Speter	`dnl')
77538032Speter# if we have % signs, take the rightmost one
77638032SpeterR$* % $*		$1 @ $2				First make them all @s.
77738032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
77864562SgshapiroR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
77938032Speter
78038032Speter# else we must be a local name
78164562SgshapiroR$*			$@ $>Canonify2 $1
78238032Speter
78338032Speter
78438032Speter################################################
78538032Speter###  Ruleset 96 -- bottom half of ruleset 3  ###
78638032Speter################################################
78738032Speter
78864562SgshapiroSCanonify2=96
78938032Speter
79038032Speter# handle special cases for local names
79138032SpeterR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
79238032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
79338032Speterifdef(`_NO_UUCP_', `dnl',
79438032Speter`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
79564562Sgshapiro
79690792Sgshapiro# check for IPv4/IPv6 domain literal
79790792SgshapiroR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [addr]
79838032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
79938032SpeterR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
80038032Speter
80164562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl
80238032Speter# look up domains in the domain table
80338032SpeterR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
80438032Speter
80564562Sgshapiroundivert(2)dnl LOCAL_RULE_3
80638032Speter
80764562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl
80838032Speter# handle BITNET mapping
80938032SpeterR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
81038032Speter
81164562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl
81238032Speter# handle UUCP mapping
81338032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
81438032Speter
81538032Speterifdef(`_NO_UUCP_', `dnl',
81638032Speter`ifdef(`UUCP_RELAY',
81738032Speter`# pass UUCP addresses straight through
81838032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
81938032Speter`# if really UUCP, handle it immediately
82038032Speterifdef(`_CLASS_U_',
82138032Speter`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82238032Speterifdef(`_CLASS_V_',
82338032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82438032Speterifdef(`_CLASS_W_',
82538032Speter`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82638032Speterifdef(`_CLASS_X_',
82738032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82838032Speterifdef(`_CLASS_Y_',
82938032Speter`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83038032Speter
83138032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl
83238032Speter# try UUCP traffic as a local address
83338032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
83438032SpeterR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
83538032Speter')')
83664562Sgshapiro# hostnames ending in class P are always canonical
83764562SgshapiroR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
83864562Sgshapirodnl apply the next rule only for hostnames not in class P
83964562Sgshapirodnl this even works for phrases in class P since . is in class P
84064562Sgshapirodnl which daemon flags are set?
84164562SgshapiroR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
84264562Sgshapirodnl the other rules in this section only apply if the hostname
84364562Sgshapirodnl does not end in class P hence no further checks are done here
84464562Sgshapirodnl if this ever changes make sure the lookups are "protected" again!
84564562Sgshapiroifdef(`_NO_CANONIFY_', `dnl
84664562Sgshapirodnl do not canonify unless:
84764562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection
84864562Sgshapirodnl	with class P is non-empty)
84964562Sgshapirodnl or {daemon_flags} has c set
85064562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify}
85164562SgshapiroR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
85264562Sgshapiro# pass to name server to make hostname canonical if requested
85364562SgshapiroR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
85464562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_
85564562SgshapiroR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
85664562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work
85764562SgshapiroR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
85864562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl
85964562Sgshapirodnl this should only apply to unqualified hostnames
86064562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
86164562Sgshapirodnl then $- does not work.
86264562Sgshapiro# lookup unqualified hostnames
86390792SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
86464562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
86564562Sgshapirodnl {daemon_flags} contains CC (do not canonify)
86671345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work
86771345Sgshapirodnl should we do this for every hostname: even unqualified?
86871345SgshapiroR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
86964562SgshapiroR$* CC $* $| $*			$: $3
87090792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
87190792Sgshapiro# do not canonify header addresses
87290792SgshapiroR$* $| $* < @ $* $~P > $*	$: $&{addr_type} $| $2 < @ $3 $4 > $5
87390792SgshapiroR$* h $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
87490792SgshapiroR$* h $* $| $*			$: $3', `dnl')
87538032Speter# pass to name server to make hostname canonical
87664562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
87764562Sgshapirodnl remove {daemon_flags} for other cases
87864562SgshapiroR$* $| $*			$: $2
87938032Speter
88038032Speter# local host aliases and pseudo-domains are always canonical
88138032SpeterR$* < @ $=w > $*		$: $1 < @ $2 . > $3
88238032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
88338032Speter`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
88438032Speter`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
88564562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
88664562Sgshapirodnl virtual hosts are also canonical
88764562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
88864562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
88964562Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
89064562Sgshapiro`dnl')
89190792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
89290792Sgshapirodnl hosts for genericstable are also canonical
89390792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_',
89490792Sgshapiro`R$* < @ $* $=G > $* 	$: $1 < @ $2 $3 . > $4',
89590792Sgshapiro`R$* < @ $=G > $* 	$: $1 < @ $2 . > $3')',
89690792Sgshapiro`dnl')
89764562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added
89864562Sgshapirodnl by one of the rules before
89938032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
90038032Speter
90138032Speter
90238032Speter##################################################
90338032Speter###  Ruleset 4 -- Final Output Post-rewriting  ###
90438032Speter##################################################
90564562SgshapiroSfinal=4
90638032Speter
90771345SgshapiroR$+ :; <@>		$@ $1 :				handle <list:;>
90838032SpeterR$* <@>			$@				handle <> and list:;
90938032Speter
91038032Speter# strip trailing dot off possibly canonical name
91138032SpeterR$* < @ $+ . > $*	$1 < @ $2 > $3
91238032Speter
91364562Sgshapiro# eliminate internal code
91438032SpeterR$* < @ *LOCAL* > $*	$1 < @ $j > $2
91538032Speter
91638032Speter# externalize local domain info
91738032SpeterR$* < $+ > $*		$1 $2 $3			defocus
91838032SpeterR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
91938032SpeterR@ $*			$@ @ $1				... and exit
92038032Speter
92138032Speterifdef(`_NO_UUCP_', `dnl',
92238032Speter`# UUCP must always be presented in old form
92338032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
92438032Speter
92538032Speterifdef(`_USE_DECNET_SYNTAX_',
92638032Speter`# put DECnet back in :: form
92738032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
92838032Speter	`dnl')
92938032Speter# delete duplicate local names
93038032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
93138032Speter
93238032Speter
93338032Speter
93438032Speter##############################################################
93538032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
93638032Speter###		   (used for recursive calls)		   ###
93738032Speter##############################################################
93838032Speter
93964562SgshapiroSRecurse=97
94064562SgshapiroR$*			$: $>canonify $1
94164562SgshapiroR$*			$@ $>parse $1
94238032Speter
94338032Speter
94438032Speter######################################
94538032Speter###   Ruleset 0 -- Parse Address   ###
94638032Speter######################################
94738032Speter
94864562SgshapiroSparse=0
94938032Speter
95038032SpeterR$*			$: $>Parse0 $1		initial parsing
95138032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
95264562SgshapiroR$*			$: $>ParseLocal $1	handle local hacks
95338032SpeterR$*			$: $>Parse1 $1		final parsing
95438032Speter
95538032Speter#
95638032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
95738032Speter#	This should either return with the (possibly modified) input
95838032Speter#	or return with a #error mailer.  It should not return with a
95938032Speter#	#mailer other than the #error mailer.
96038032Speter#
96138032Speter
96238032SpeterSParse0
96338032SpeterR<@>			$@ <@>			special case error msgs
96490792SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
96564562SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
96690792SgshapiroR<@ $+>			$#error $@ 5.1.3 $: "_CODE553 User address required"
96790792SgshapiroR$+ <@>			$#error $@ 5.1.3 $: "_CODE553 Hostname required"
96838032SpeterR$*			$: <> $1
96990792Sgshapirodnl allow tricks like [host1]:[host2]
97090792SgshapiroR<> $* < @ [ $* ] : $+ > $*	$1 < @ [ $2 ] : $3 > $4
97190792SgshapiroR<> $* < @ [ $* ] , $+ > $*	$1 < @ [ $2 ] , $3 > $4
97290792Sgshapirodnl but no a@[b]c
97390792SgshapiroR<> $* < @ [ $* ] $+ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid address"
97490792SgshapiroR<> $* < @ [ $+ ] > $*		$1 < @ [ $2 ] > $3
97590792SgshapiroR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
97638032SpeterR<> $*			$1
97790792SgshapiroR$* < @ . $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
97890792SgshapiroR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
97990792Sgshapirodnl no a@b@
98090792SgshapiroR$* < @ $* @ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid route address"
98190792Sgshapirodnl no a@b@c
98290792SgshapiroR$* @ $* < @ $* > $*	$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
98364562Sgshapirodnl comma only allowed before @; this check is not complete
98490792SgshapiroR$* , $~O $*		$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
98538032Speter
98690792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks
98790792SgshapiroR$* . < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
98890792SgshapiroR. $* < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
98990792Sgshapirodnl', `dnl')
99090792Sgshapiro
99138032Speter# now delete the local info -- note $=O to find characters that cause forwarding
99264562SgshapiroR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
99364562SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
99438032SpeterR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
99590792SgshapiroR< @ $+ >		$#error $@ 5.1.3 $: "_CODE553 User address required"
99664562SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
99738032SpeterR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
99890792SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "_CODE553 User address required"
99938032SpeterR$* $=O $* < @ *LOCAL* >
100064562Sgshapiro			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
100138032SpeterR$* < @ *LOCAL* >	$: $1
100238032Speter
100338032Speter#
100438032Speter#  Parse1 -- the bottom half of ruleset 0.
100538032Speter#
100638032Speter
100738032SpeterSParse1
100864562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
100964562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute}
101090792SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
101190792SgshapiroR$+ < @ $={LDAPRouteEquiv} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
101264562Sgshapiro`dnl')
101364562Sgshapiro
101438032Speterifdef(`_MAILER_smtp_',
101538032Speter`# handle numeric address spec
101664562Sgshapirodnl there is no check whether this is really an IP number
101764562SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
101864562SgshapiroR$* < @ [ $+ ] > $*	$1 < @ [ $2 ] : $S > $3		Add smart host to path
101990792SgshapiroR$* < @ [ $+ ] : > $*		$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
102064562SgshapiroR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
102164562SgshapiroR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
102238032Speter	`dnl')
102338032Speter
102464562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
102538032Speter# handle virtual users
102690792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
102790792Sgshapirodnl this is not a documented option
102890792Sgshapirodnl it stops looping in virtusertable mapping if input and output
102990792Sgshapirodnl are identical, i.e., if address A is mapped to A.
103090792Sgshapirodnl it does not deal with multi-level recursion
103190792Sgshapiro# handle full domains in RHS of virtusertable
103290792SgshapiroR$+ < @ $+ >			$: $(macro {RecipientAddress} $) $1 < @ $2 >
103390792SgshapiroR$+ < @ $+ > 			$: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
103490792SgshapiroR<?> $+ $| $+			$: $1 $(macro {RecipientAddress} $@ $2 $)
103590792SgshapiroR<?> $+ $| $*			$: $1',
103690792Sgshapiro`dnl')
103764562SgshapiroR$+			$: <!> $1		Mark for lookup
103890792Sgshapirodnl input: <!> local<@domain>
103964562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
104064562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
104164562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
104290792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
104364562SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
104490792Sgshapirodnl if <@> local<@domain>: no match but try lookup
104590792Sgshapirodnl user+detail: try user++@domain if detail not empty
104690792SgshapiroR<@> $+ + $+ < @ $* . >
104790792Sgshapiro			$: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
104890792Sgshapirodnl user+detail: try user+*@domain
104938032SpeterR<@> $+ + $* < @ $* . >
105090792Sgshapiro			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105190792Sgshapirodnl user+detail: try user@domain
105238032SpeterR<@> $+ + $* < @ $* . >
105390792Sgshapiro			$: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105464562Sgshapirodnl try default entry: @domain
105590792Sgshapirodnl ++@domain
105690792SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105764562Sgshapirodnl +*@domain
105890792SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105964562Sgshapirodnl @domain if +detail exists
106090792SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
106164562Sgshapirodnl without +detail (or no match)
106238032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
106390792Sgshapirodnl no match
106438032SpeterR<@> $+			$: $1
106590792Sgshapirodnl remove mark
106664562SgshapiroR<!> $+			$: $1
106764562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
106838032SpeterR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
106990792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
107090792Sgshapiro# check virtuser input address against output address, if same, skip recursion
107190792SgshapiroR< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
107290792Sgshapiro# it is the same: stop now
107390792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
107490792SgshapiroR< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
107590792Sgshapirodnl', `dnl')
107680785Sgshapirodnl this is not a documented option
107780785Sgshapirodnl it performs no looping at all for virtusertable
107877349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_',
107977349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
108077349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
108177349Sgshapirodnl', `dnl')
108238032Speter
108338032Speter# short circuit local delivery so forwarded email works
108438032Speterifdef(`_MAILER_usenet_', `dnl
108564562SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
108666494Sgshapiro
108766494Sgshapiro
108838032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
108938032Speter`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
109064562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
109164562Sgshapirodnl $H empty (but @$=w.)
109238032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
109338032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
109464562Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
109538032SpeterR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
109638032Speter
109764562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
109838032Speter# not local -- try mailer table lookup
109938032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
110038032SpeterR< $+ . > $*		$: < $1 > $2			strip trailing dot
110138032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
110264562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
110364562SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
110464562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
110538032Speter`dnl')
110664562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)'
110738032Speter
110838032Speterifdef(`_NO_UUCP_', `dnl',
110938032Speter`# resolve remotely connected UUCP links (if any)
111038032Speterifdef(`_CLASS_V_',
111164562Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
111238032Speter	`dnl')
111338032Speterifdef(`_CLASS_W_',
111464562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
111538032Speter	`dnl')
111638032Speterifdef(`_CLASS_X_',
111764562Sgshapiro`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
111838032Speter	`dnl')')
111938032Speter
112038032Speter# resolve fake top level domains by forwarding to other hosts
112138032Speterifdef(`BITNET_RELAY',
112264562Sgshapiro`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
112338032Speter	`dnl')
112438032Speterifdef(`DECNET_RELAY',
112564562Sgshapiro`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
112638032Speter	`dnl')
112738032Speterifdef(`_MAILER_pop_',
112838032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
112938032Speter	`dnl')
113038032Speterifdef(`_MAILER_fax_',
113138032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
113238032Speter`ifdef(`FAX_RELAY',
113364562Sgshapiro`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
113438032Speter	`dnl')')
113538032Speter
113638032Speterifdef(`UUCP_RELAY',
113738032Speter`# forward non-local UUCP traffic to our UUCP relay
113864562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
113938032Speter`ifdef(`_MAILER_uucp_',
114038032Speter`# forward other UUCP traffic straight to UUCP
114138032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
114238032Speter	`dnl')')
114338032Speterifdef(`_MAILER_usenet_', `
114438032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
114564562SgshapiroR$+ . USENET		$#usenet $@ usenet $: $1',
114638032Speter	`dnl')
114738032Speter
114838032Speterifdef(`_LOCAL_RULES_',
114938032Speter`# figure out what should stay in our local mail system
115038032Speterundivert(1)', `dnl')
115138032Speter
115238032Speter# pass names that still have a host to a smarthost (if defined)
115364562SgshapiroR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
115438032Speter
115538032Speter# deal with other remote names
115638032Speterifdef(`_MAILER_smtp_',
115764562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
115890792Sgshapiro`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
115938032Speter
116038032Speter# handle locally delivered names
116164562SgshapiroR$=L			$#_LOCAL_ $: @ $1		special local names
116238032SpeterR$+			$#_LOCAL_ $: $1			regular local names
116338032Speter
116438032Speter###########################################################################
116538032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
116638032Speter###########################################################################
116738032Speter
116864562SgshapiroSLocal_localaddr
116964562SgshapiroSlocaladdr=5
117064562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
117190792SgshapiroR$+ $| $#ok		$@ $1			no change
117264562SgshapiroR$+ $| $#$*		$#$2
117364562SgshapiroR$+ $| $*		$: $1
117438032Speter
117590792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
117690792Sgshapiro# Preserve rcpt_host in {Host}
117790792SgshapiroR$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
117890792SgshapiroR$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
117990792SgshapiroR$+ $| $| $+		$: $1			h not set, {Host} set
118090792SgshapiroR$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
118195154SgshapiroR$+ $| $* @ $+ $| $*	$: $(macro {Host} $@ @$3 $) $1	set {Host} to host in h
118290792SgshapiroR$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
118390792Sgshapiro')dnl
118490792Sgshapiro
118590792Sgshapiroifdef(`_FFR_5_', `dnl
118666494Sgshapiro# Preserve host in a macro
118766494SgshapiroR$+			$: $(macro {LocalAddrHost} $) $1
118866494SgshapiroR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
118966494Sgshapiro
119090792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
119138032Speter# deal with plussed users so aliases work nicely
119266494SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
119366494SgshapiroR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
119466494Sgshapiro')
119538032Speter# prepend an empty "forward host" on the front
119638032SpeterR$+			$: <> $1
119738032Speter
119838032Speterifdef(`LUSER_RELAY', `dnl
119938032Speter# send unrecognized local users to a relay host
120090792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
120166494SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
120266494SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
120366494SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
120466494SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
120564562SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
120690792SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')
120790792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
120890792SgshapiroR< $+ > $+		$: < $1 > $2 $&{Host}')
120990792Sgshapirodnl')
121038032Speter
121190792Sgshapiroifdef(`MAIL_HUB', `dnl
121290792SgshapiroR< > $+			$: < $H > $1			try hub', `dnl')
121390792Sgshapiroifdef(`LOCAL_RELAY', `dnl
121490792SgshapiroR< > $+			$: < $R > $1			try relay', `dnl')
121590792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
121690792SgshapiroR< > $+			$@ $1', `dnl
121764562SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
121890792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
121990792SgshapiroR< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
122064562SgshapiroR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
122164562SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
122238032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
122366494SgshapiroR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
122438032SpeterR< > < $+ >		$@ $1				no +detail
122543730SpeterR$+			$: $1 <> $&h			add +detail back in
122690792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
122790792SgshapiroR$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
122843730SpeterR$+ <> + $*		$: $1 + $2			check whether +detail
122966494SgshapiroR$+ <> $*		$: $1				else discard')
123064562SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
123164562SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
123290792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
123390792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
123490792SgshapiroR< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
123590792SgshapiroR< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
123690792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
123790792SgshapiroR< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
123864562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
123938032Speter
124064562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
124190792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
124238032Speter###################################################################
124390792Sgshapiro###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
124490792Sgshapirodnl input: <Domain> FullAddress
124590792Sgshapiro###################################################################
124690792Sgshapiro
124790792SgshapiroSLDAPMailertable
124890792SgshapiroR< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
124990792SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
125090792SgshapiroR< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
125190792SgshapiroR< $+ > $#$*		$#$2					found
125290792SgshapiroR< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
125390792Sgshapiro`dnl')
125490792Sgshapiro
125590792Sgshapiro###################################################################
125638032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
125764562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
125838032Speter###################################################################
125938032Speter
126064562SgshapiroSMailertable=90
126164562Sgshapirodnl shift and check
126264562Sgshapirodnl %2 is not documented in cf/README
126338032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
126464562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
126564562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
126664562SgshapiroR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
126764562Sgshapirodnl is $2 always empty?
126838032SpeterR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
126964562SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
127064562Sgshapirodnl return full address
127138032SpeterR< $* > $*		$@ $2				no mailertable match',
127238032Speter`dnl')
127338032Speter
127438032Speter###################################################################
127538032Speter###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
127664562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
127764562Sgshapirodnl	<> address				-> address
127864562Sgshapirodnl	<error:d.s.n:text>			-> error
127964562Sgshapirodnl	<error:text>				-> error
128064562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
128164562Sgshapirodnl	<mailer:host> address			-> mailer host address
128264562Sgshapirodnl	<localdomain> address			-> address
128364562Sgshapirodnl	<host> address				-> relay host address
128438032Speter###################################################################
128538032Speter
128664562SgshapiroSMailerToTriple=95
128738032SpeterR< > $*				$@ $1			strip off null relay
128864562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
128938032SpeterR< error : $- $+ > $*		$#error $@ $(dequote $1 $) $: $2
129038032SpeterR< local : $* > $*		$>CanonLocal < $1 > $2
129190792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
129290792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
129390792SgshapiroR< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
129438032SpeterR< $=w > $*			$@ $2			delete local host
129538032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
129638032Speter
129738032Speter###################################################################
129838032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
129964562Sgshapirodnl input: <user> address
130064562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
130164562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
130264562Sgshapirodnl <> user <@host> rest		-> local user@host user
130364562Sgshapirodnl <> user				-> local user user
130464562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
130564562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
130664562Sgshapirodnl <user> lp				-> local lp user
130738032Speter###################################################################
130838032Speter
130938032SpeterSCanonLocal
131043730Speter# strip local host from routed addresses
131164562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
131264562SgshapiroR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
131343730Speter
131438032Speter# strip trailing dot from any host name that may appear
131538032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
131638032Speter
131738032Speter# handle local: syntax -- use old user, either with or without host
131838032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
131938032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
132038032Speter
132138032Speter# handle local:user@host syntax -- ignore host part
132238032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
132338032Speter
132438032Speter# handle local:user syntax
132538032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
132638032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
132738032Speter
132838032Speter###################################################################
132938032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
133038032Speter###################################################################
133138032Speter
133264562SgshapiroSMasqHdr=93
133338032Speter
133464562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
133538032Speter# handle generics database
133638032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
133764562Sgshapirodnl if generics should be applied add a @ as mark
133838032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
133938032Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
134038032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
134164562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
134264562Sgshapirodnl ignore the first case for now
134364562Sgshapirodnl if it has the mark lookup full address
134490792Sgshapirodnl broken: %1 is full address not just detail
134564562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
134664562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
134764562Sgshapirodnl no match, try user+detail@domain
134864562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
134964562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
135064562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
135164562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
135264562Sgshapirodnl no match, remove mark
135364562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
135464562Sgshapirodnl no match, try @domain for exceptions
135564562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
135664562Sgshapirodnl workspace: ... or <match> user <@domain>
135764562Sgshapirodnl no match, try local part
135838032SpeterR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
135964562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
136064562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
136164562SgshapiroR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
136264562SgshapiroR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
136338032SpeterR< > $*			$: $1				not found',
136438032Speter`dnl')
136538032Speter
136664562Sgshapiro# do not masquerade anything in class N
136764562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
136864562Sgshapiro
136990792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
137038032Speter# special case the users that should be exposed
137138032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
137238032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
137338032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
137438032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
137538032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
137638032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
137738032Speter
137838032Speter# handle domain-specific masquerading
137938032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
138038032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
138138032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
138238032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
138338032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
138438032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
138538032SpeterR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
138638032SpeterR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
138790792Sgshapirodnl', `dnl no masquerading
138890792Sgshapirodnl just fix *LOCAL* leftovers
138990792SgshapiroR$* < @ *LOCAL* >	$@ $1 < @ $j . >')
139038032Speter
139138032Speter###################################################################
139238032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
139338032Speter###################################################################
139438032Speter
139564562SgshapiroSMasqEnv=94
139638032Speterifdef(`_MASQUERADE_ENVELOPE_',
139764562Sgshapiro`R$+			$@ $>MasqHdr $1',
139838032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
139938032Speter
140038032Speter###################################################################
140138032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
140238032Speter###################################################################
140338032Speter
140464562SgshapiroSParseLocal=98
140564562Sgshapiroundivert(3)dnl LOCAL_RULE_0
140638032Speter
140764562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
140890792Sgshapiro######################################################################
140990792Sgshapiro###  LDAPExpand: Expand address using LDAP routing
141090792Sgshapiro###
141190792Sgshapiro###	Parameters:
141290792Sgshapiro###		<$1> -- parsed address (user < @ domain . >) (pass through)
141390792Sgshapiro###		<$2> -- RFC822 address (user @ domain) (used for lookup)
141490792Sgshapiro###		<$3> -- +detail information
141590792Sgshapiro###
141690792Sgshapiro###	Returns:
141790792Sgshapiro###		Mailer triplet ($#mailer $@ host $: address)
141890792Sgshapiro###		Parsed address (user < @ domain . >)
141990792Sgshapiro######################################################################
142090792Sgshapiro
142164562SgshapiroSLDAPExpand
142264562Sgshapiro# do the LDAP lookups
142390792SgshapiroR<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
142464562Sgshapiro
142594334Sgshapiro# look for temporary failures (return original address, MTA will queue up)
142694334SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*>	$@ $2
142794334SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*>	$@ $2
142894334Sgshapiro
142964562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
143064562Sgshapiro# return the new mailRoutingAddress
143190792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
143290792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
143390792SgshapiroR<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
143490792SgshapiroR<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
143590792SgshapiroR<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
143664562Sgshapiro
143764562Sgshapiro# if mailRoutingAddress and non-local mailHost,
143864562Sgshapiro# relay to mailHost with new mailRoutingAddress
143990792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
144090792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
144190792Sgshapiro# check mailertable for host, relay from there
144290792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
144390792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
144490792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
144590792Sgshapiro# check mailertable for host, relay from there
144690792SgshapiroR<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
144790792Sgshapiro`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
144864562Sgshapiro
144964562Sgshapiro# if no mailRoutingAddress and local mailHost,
145064562Sgshapiro# return original address
145190792SgshapiroR<> <$=w> <$+> <$+> <$*>	$@ $2
145264562Sgshapiro
145364562Sgshapiro# if no mailRoutingAddress and non-local mailHost,
145464562Sgshapiro# relay to mailHost with original address
145590792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
145690792Sgshapiro# check mailertable for host, relay from there
145790792SgshapiroR<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
145890792Sgshapiro`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
145964562Sgshapiro
146090792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_',
146190792Sgshapiro`# if no mailRoutingAddress and no mailHost,
146290792Sgshapiro# try without +detail
146390792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
146490792Sgshapiro
146590792Sgshapiro# if still no mailRoutingAddress and no mailHost,
146664562Sgshapiro# try @domain
146790792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
146890792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
146990792SgshapiroR<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>
147064562Sgshapiro
147164562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
147264562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
147364562Sgshapiro# user does not exist
147490792SgshapiroR<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
147590792Sgshapiro# only give error for envelope recipient
147690792SgshapiroR<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
147790792SgshapiroR<?> <$*> <$+>			$@ $2',
147864562Sgshapiro`dnl
147964562Sgshapiro# return the original address
148090792SgshapiroR<> <> <$+> <@ $+> <$*>		$@ $1')',
148164562Sgshapiro`dnl')
148264562Sgshapiro
148364562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
148464562Sgshapiro')')
148590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
148638032Speter######################################################################
148790792Sgshapiro###  D: LookUpDomain -- search for domain in access database
148838032Speter###
148938032Speter###	Parameters:
149038032Speter###		<$1> -- key (domain name)
149138032Speter###		<$2> -- default (what to return if not found in db)
149264562Sgshapirodnl			must not be empty
149390792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
149464562Sgshapiro###			! does lookup only with tag
149564562Sgshapiro###			+ does lookup with and without tag
149690792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
149764562Sgshapirodnl returns:		<default> <passthru>
149864562Sgshapirodnl 			<result> <passthru>
149938032Speter######################################################################
150038032Speter
150190792SgshapiroSD
150264562Sgshapirodnl workspace <key> <default> <passthru> <mark>
150364562Sgshapirodnl lookup with tag (in front, no delimiter here)
150490792Sgshapirodnl    2    3  4    5
150590792SgshapiroR<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
150664562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
150764562Sgshapirodnl lookup without tag?
150890792Sgshapirodnl   1    2      3    4
150990792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
151090792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
151190792Sgshapirodnl XXX apply this also to IP addresses?
151290792Sgshapirodnl currently it works the wrong way round for [1.2.3.4]
151390792Sgshapirodnl   1  2    3    4  5    6
151490792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
151590792Sgshapirodnl   1  2    3      4    5
151690792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
151790792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
151890792Sgshapirodnl found SKIP: return <default> and <passthru>
151990792Sgshapirodnl      1    2    3  4    5
152090792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
152190792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!)
152290792Sgshapirodnl    1  2     3    4  5    6
152390792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
152490792Sgshapiroifdef(`NO_NETINET6', `dnl',
152590792Sgshapiro`dnl not found: IPv6 net
152690792Sgshapirodnl (could be merged with previous rule if we have a class containing .:)
152790792Sgshapirodnl    1   2     3    4  5    6
152890792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
152990792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
153064562Sgshapirodnl not found, but subdomain: try again
153190792Sgshapirodnl   1  2    3    4  5    6
153290792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
153390792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
153490792Sgshapirodnl   1    2      3    4
153590792SgshapiroR<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
153690792Sgshapirodnl not found, no subdomain: return <default> and <passthru>
153790792Sgshapirodnl   1    2    3  4    5
153890792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
153990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
154090792Sgshapirodnl            2    3    4  5    6
154190792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
154290792Sgshapirodnl return <result of lookup> and <passthru>
154390792Sgshapirodnl    2    3    4  5    6
154490792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
154538032Speter
154638032Speter######################################################################
154790792Sgshapiro###  A: LookUpAddress -- search for host address in access database
154838032Speter###
154938032Speter###	Parameters:
155038032Speter###		<$1> -- key (dot quadded host address)
155138032Speter###		<$2> -- default (what to return if not found in db)
155264562Sgshapirodnl			must not be empty
155390792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
155464562Sgshapiro###			! does lookup only with tag
155564562Sgshapiro###			+ does lookup with and without tag
155690792Sgshapiro###		<$4> -- passthru (additional data passed through)
155764562Sgshapirodnl	returns:	<default> <passthru>
155864562Sgshapirodnl			<result> <passthru>
155938032Speter######################################################################
156038032Speter
156190792SgshapiroSA
156264562Sgshapirodnl lookup with tag
156390792Sgshapirodnl    2    3  4    5
156490792SgshapiroR<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
156564562Sgshapirodnl lookup without tag
156690792Sgshapirodnl   1    2      3    4
156790792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
156890792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
156990792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
157090792Sgshapirodnl found SKIP: return <default> and <passthru>
157190792Sgshapirodnl      1    2    3  4    5
157290792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
157390792Sgshapiroifdef(`NO_NETINET6', `dnl',
157490792Sgshapiro`dnl no match; IPv6: remove last part
157590792Sgshapirodnl   1   2    3    4  5    6
157690792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
157790792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
157864562Sgshapirodnl no match; IPv4: remove last part
157990792Sgshapirodnl   1  2    3    4  5    6
158090792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
158164562Sgshapirodnl no match: return default
158290792Sgshapirodnl   1    2    3  4    5
158390792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
158490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
158590792Sgshapirodnl            2    3    4  5    6
158690792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
158764562Sgshapirodnl match: return result
158890792Sgshapirodnl    2    3    4  5    6
158990792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
159090792Sgshapirodnl endif _ACCESS_TABLE_
159190792Sgshapirodivert(0)
159238032Speter######################################################################
159342575Speter###  CanonAddr --	Convert an address into a standard form for
159442575Speter###			relay checking.  Route address syntax is
159542575Speter###			crudely converted into a %-hack address.
159642575Speter###
159742575Speter###	Parameters:
159842575Speter###		$1 -- full recipient address
159942575Speter###
160042575Speter###	Returns:
160142575Speter###		parsed address, not in source route form
160264562Sgshapirodnl		user%host%host<@domain>
160364562Sgshapirodnl		host!user<@domain>
160442575Speter######################################################################
160542575Speter
160642575SpeterSCanonAddr
160764562SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
160864562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
160942575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
161042575SpeterR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
161142575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
161264562Sgshapirodnl')
161342575Speter
161442575Speter######################################################################
161538032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
161638032Speter###			$* $=m or the access database.
161738032Speter###			Check user portion for host separators.
161838032Speter###
161938032Speter###	Parameters:
162038032Speter###		$1 -- full recipient address
162138032Speter###
162238032Speter###	Returns:
162338032Speter###		parsed, non-local-relaying address
162438032Speter######################################################################
162538032Speter
162638032SpeterSParseRecipient
162764562Sgshapirodnl mark and canonify address
162842575SpeterR$*				$: <?> $>CanonAddr $1
162964562Sgshapirodnl workspace: <?> localpart<@domain[.]>
163042575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
163164562Sgshapirodnl workspace: <?> localpart<@domain>
163242575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
163338032Speter
163438032Speter# if no $=O character, no host in the user portion, we are done
163542575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
163664562Sgshapirodnl no $=O in localpart: return
163742575SpeterR<?> $*				$@ $1
163838032Speter
163990792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O
164064562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
164138032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
164238032Speter# if we relay, check username portion for user%host so host can be checked also
164342575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
164464562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
164564562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
164690792Sgshapiro
164790792Sgshapirodnl what if access map returns something else than RELAY?
164890792Sgshapirodnl we are only interested in RELAY entries...
164990792Sgshapirodnl other To: entries: blacklist recipient; generic entries?
165090792Sgshapirodnl if it is an error we probably do not want to relay anyway
165138032Speterifdef(`_RELAY_HOSTS_ONLY_',
165242575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
165364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
165464562SgshapiroR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
165542575SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
165642575Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
165764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
165890792SgshapiroR<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
165942575SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
166038032Speter
166164562Sgshapiro
166290792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl
166390792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
166490792SgshapiroR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
166590792SgshapiroR<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
166690792Sgshapirodnl yes: mark it as <RELAY>
166790792SgshapiroR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
166890792Sgshapirodnl no: put old <NO> mark back
166990792SgshapiroR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
167090792Sgshapiro
167190792Sgshapirodnl do we relay to this recipient domain?
167242575SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
167390792Sgshapirodnl something else
167490792SgshapiroR<$+> $*			$@ $2
167542575Speter
167664562Sgshapiro
167738032Speter######################################################################
167838032Speter###  check_relay -- check hostname/address on SMTP startup
167938032Speter######################################################################
168038032Speter
168138032SpeterSLocal_check_relay
168264562SgshapiroScheck`'_U_`'relay
168338032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
168438032SpeterR$* $| $* $| $#$*	$#$3
168538032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
168638032Speter
168738032SpeterSBasic_check_relay
168838032Speter# check for deferred delivery mode
168938032SpeterR$*			$: < ${deliveryMode} > $1
169038032SpeterR< d > $*		$@ deferred
169138032SpeterR< $* > $*		$: $2
169238032Speter
169364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
169466494Sgshapirodnl workspace: {client_name} $| {client_addr}
169590792SgshapiroR$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
169666494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
169790792SgshapiroR<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
169890792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>)
169990792SgshapiroR<?> <$*>		$: OK				found nothing
170090792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
170190792SgshapiroR<$={Accept}> <$*>	$@ $1				return value of lookup
170290792SgshapiroR<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
170390792SgshapiroR<DISCARD> <$*>		$#discard $: discard
170490792Sgshapiroifdef(`_FFR_QUARANTINE',
170590792Sgshapiro`R<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1', `dnl')
170664562Sgshapirodnl error tag
170766494SgshapiroR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
170866494SgshapiroR<ERROR:$+> <$*>		$#error $: $1
170990792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
171064562Sgshapirodnl generic error from access map
171166494SgshapiroR<$+> <$*>		$#error $: $1', `dnl')
171238032Speter
171364562Sgshapiroifdef(`_RBL_',`dnl
171464562Sgshapiro# DNS based IP address spam list
171590792Sgshapirodnl workspace: ignored...
171638032SpeterR$*			$: $&{client_addr}
171764562SgshapiroR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
171864562SgshapiroR<?>OK			$: OKSOFAR
171964562SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"',
172038032Speter`dnl')
172164562Sgshapiroundivert(8)
172238032Speter
172338032Speter######################################################################
172438032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
172538032Speter######################################################################
172638032Speter
172738032SpeterSLocal_check_mail
172864562SgshapiroScheck`'_U_`'mail
172938032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
173038032SpeterR$* $| $#$*		$#$2
173138032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
173238032Speter
173338032SpeterSBasic_check_mail
173438032Speter# check for deferred delivery mode
173538032SpeterR$*			$: < ${deliveryMode} > $1
173638032SpeterR< d > $*		$@ deferred
173738032SpeterR< $* > $*		$: $2
173838032Speter
173964562Sgshapiro# authenticated?
174064562Sgshapirodnl done first: we can require authentication for every mail transaction
174164562Sgshapirodnl workspace: address as given by MAIL FROM: (sender)
174264562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
174364562SgshapiroR$* $| $#$+		$#$2
174464562Sgshapirodnl undo damage: remove result of tls_client call
174564562SgshapiroR$* $| $*		$: $1
174638032Speter
174764562Sgshapirodnl workspace: address as given by MAIL FROM:
174864562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
174938032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
175064562Sgshapirodnl do some additional checks
175164562Sgshapirodnl no user@host
175264562Sgshapirodnl no user@localhost (if nonlocal sender)
175364562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
175464562Sgshapirodnl just make sure the address has <> around it (which is required by
175564562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
175664562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
175764562Sgshapirodnl not be modified by host lookups.
175864562SgshapiroR$+			$: <?> $1
175964562SgshapiroR<?><$+>		$: <@> <$1>
176064562SgshapiroR<?>$+			$: <@> <$1>
176164562Sgshapirodnl workspace: <@> <address>
176264562Sgshapirodnl prepend daemon_flags
176364562SgshapiroR$*			$: $&{daemon_flags} $| $1
176464562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
176564562Sgshapirodnl do not allow these at all or only from local systems?
176664562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
176764562Sgshapirodnl accept unqualified sender: change mark to avoid test
176864562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
176964562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
177064562Sgshapirodnl        or:                    <? ${client_name} > <address>
177164562Sgshapirodnl        or:                    <?> <address>
177264562Sgshapirodnl remove daemon_flags
177364562SgshapiroR$* $| $*		$: $2
177438032Speter# handle case of @localhost on address
177564562SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
177664562SgshapiroR<@> < $* @ [127.0.0.1] >
177764562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
177864562SgshapiroR<@> < $* @ localhost.$m >
177964562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
178038032Speterifdef(`_NO_UUCP_', `dnl',
178164562Sgshapiro`R<@> < $* @ localhost.UUCP >
178264562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
178364562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
178464562Sgshapirodnl	or:    <@> <address>
178564562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
178664562SgshapiroR<@> $*			$: $1			no localhost as domain
178764562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
178864562Sgshapirodnl	or:    <address>
178964562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
179064562SgshapiroR<? $=w> $*		$: $2			local client: ok
179190792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
179264562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
179364562SgshapiroR<?> $*			$: $1')
179464562Sgshapirodnl workspace: address (or <address>)
179564562SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
179664562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
179764562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
179864562SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
179964562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
180064562SgshapiroR<?> $* < @ $* $=P >	$: <OK> $1 < @ $2 $3 >
180164562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
180264562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
180390792Sgshapiro`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
180464562Sgshapiro`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
180564562SgshapiroR<? $* <$->> $* < @ $+ >
180664562Sgshapiro			$: <$2> $3 < @ $4 >')
180790792Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
180864562Sgshapirodnl mark is ? iff the address is user (wo @domain)
180938032Speter
181064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
181164562Sgshapiro# check sender address: user@address, user@, address
181264562Sgshapirodnl should we remove +ext from user?
181390792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
181490792SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
181564562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
181664562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
181764562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
181864562Sgshapirodnl will only return user<@domain when "reversing" the args
181990792SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
182064562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
182164562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
182264562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
182338032Speter# retransform for further use
182464562Sgshapirodnl required form:
182564562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
182664562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
182764562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
182864562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
182964562Sgshapirodnl mark is ? iff the address is user (wo @domain)
183038032Speter
183138032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
183238032Speter# handle case of no @domain on address
183364562Sgshapirodnl prepend daemon_flags
183464562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
183564562Sgshapirodnl accept unqualified sender: change mark to avoid test
183690792SgshapiroR$* u $* $| <?> $*	$: <_RES_OK_> $3
183764562Sgshapirodnl remove daemon_flags
183864562SgshapiroR$* $| $*		$: $2
183938032SpeterR<?> $*			$: < ? $&{client_name} > $1
184038032SpeterR<?> $*			$@ <OK>				...local unqualed ok
184190792SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
184238032Speter							...remote is not')
184338032Speter# check results
184464562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
184590792SgshapiroR<$={ResOk}> $*		$@ <_RES_OK_>	domain ok: stop
184664562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
184790792SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
184864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
184990792SgshapiroR<$={Accept}> $*	$# $1		accept from access map
185038032SpeterR<DISCARD> $*		$#discard $: discard
185190792Sgshapiroifdef(`_FFR_QUARANTINE',
185290792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
185364562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
185464562Sgshapirodnl error tag
185564562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
185664562SgshapiroR<ERROR:$+> $*		$#error $: $1
185790792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
185864562Sgshapirodnl generic error from access map
185964562SgshapiroR<$+> $*		$#error $: $1		error from access db',
186038032Speter`dnl')
186138032Speter
186238032Speter######################################################################
186338032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
186438032Speter######################################################################
186538032Speter
186638032SpeterSLocal_check_rcpt
186764562SgshapiroScheck`'_U_`'rcpt
186838032SpeterR$*			$: $1 $| $>"Local_check_rcpt" $1
186938032SpeterR$* $| $#$*		$#$2
187038032SpeterR$* $| $*		$@ $>"Basic_check_rcpt" $1
187138032Speter
187238032SpeterSBasic_check_rcpt
187390792Sgshapiro# empty address?
187490792SgshapiroR<>			$#error $@ nouser $: "553 User address required"
187590792SgshapiroR$@			$#error $@ nouser $: "553 User address required"
187638032Speter# check for deferred delivery mode
187738032SpeterR$*			$: < ${deliveryMode} > $1
187838032SpeterR< d > $*		$@ deferred
187938032SpeterR< $* > $*		$: $2
188038032Speter
188164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
188290792Sgshapirodnl this code checks for user@host where host is not a FQHN.
188390792Sgshapirodnl it is not activated.
188490792Sgshapirodnl notice: code to check for a recipient without a domain name is
188590792Sgshapirodnl available down below; look for the same macro.
188690792Sgshapirodnl this check is done here because the name might be qualified by the
188790792Sgshapirodnl canonicalization.
188890792Sgshapiro# require fully qualified domain part?
188990792Sgshapirodnl very simple canonification: make sure the address is in < >
189064562SgshapiroR$+			$: <?> $1
189190792SgshapiroR<?> <$+>		$: <@> <$1>
189290792SgshapiroR<?> $+			$: <@> <$1>
189390792SgshapiroR<@> < postmaster >	$: postmaster
189490792SgshapiroR<@> < $* @ $+ . $+ >	$: < $3 @ $4 . $5 >
189564562Sgshapirodnl prepend daemon_flags
189690792SgshapiroR<@> $*			$: $&{daemon_flags} $| <@> $1
189764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
189864562Sgshapirodnl do not allow these at all or only from local systems?
189990792SgshapiroR$* r $* $| <@> < $* @ $* >	$: < ? $&{client_name} > < $3 @ $4 >
190064562SgshapiroR<?> < $* >		$: <$1>
190164562SgshapiroR<? $=w> < $* >		$: <$1>
190290792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
190364562Sgshapirodnl remove daemon_flags for other cases
190464562SgshapiroR$* $| <@> $*		$: $2', `dnl')
190564562Sgshapiro
190690792Sgshapirodnl ##################################################################
190790792Sgshapirodnl call subroutines for recipient and relay
190890792Sgshapirodnl possible returns from subroutines:
190990792Sgshapirodnl $#TEMP	temporary failure
191090792Sgshapirodnl $#error	permanent failure (or temporary if from access map)
191190792Sgshapirodnl $#other	stop processing
191290792Sgshapirodnl RELAY	RELAYing allowed
191390792Sgshapirodnl other	otherwise
191490792Sgshapiro######################################################################
191590792SgshapiroR$*			$: $1 $| @ $>"Rcpt_ok" $1
191690792Sgshapirodnl temporary failure? remove mark @ and remember
191790792SgshapiroR$* $| @ $#TEMP $+	$: $1 $| T $2
191890792Sgshapirodnl error or ok (stop)
191990792SgshapiroR$* $| @ $#$*		$#$2
192090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
192190792SgshapiroR$* $| @ RELAY		$@ RELAY
192290792Sgshapirodnl something else: call check sender (relay)
192390792SgshapiroR$* $| @ $*		$: O $| $>"Relay_ok" $1
192490792Sgshapirodnl temporary failure: call check sender (relay)
192590792SgshapiroR$* $| T $+		$: T $2 $| $>"Relay_ok" $1
192690792Sgshapirodnl temporary failure? return that
192790792SgshapiroR$* $| $#TEMP $+	$#error $2
192890792Sgshapirodnl error or ok (stop)
192990792SgshapiroR$* $| $#$*		$#$2
193090792SgshapiroR$* $| RELAY		$@ RELAY
193190792Sgshapirodnl something else: return previous temp failure
193290792SgshapiroR T $+ $| $*		$#error $1
193390792Sgshapiro# anything else is bogus
193490792SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
193590792Sgshapirodivert(0)
193690792Sgshapiro
193790792Sgshapiro######################################################################
193890792Sgshapiro### Rcpt_ok: is the recipient ok?
193990792Sgshapirodnl input: recipient address (RCPT TO)
194090792Sgshapirodnl output: see explanation at call
194190792Sgshapiro######################################################################
194290792SgshapiroSRcpt_ok
194338032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
194442575SpeterR$*			$: $>CanonAddr $1
194538032SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
194638032Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
194738032Speter
194842575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
194942575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
195042575Speter# unlimited bestmx
195142575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
195242575Speter`dnl
195342575Speter# limit bestmx to $=B
195443730SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
195590792SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
195642575SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
195742575SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
195842575Speter
195938032Speterifdef(`_BLACKLIST_RCPT_',`dnl
196064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
196138032Speter# blacklist local users or any host from receiving mail
196238032SpeterR$*			$: <?> $1
196364562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
196464562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
196590792SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
196690792SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
196764562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
196864562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
196964562Sgshapirodnl will only return user<@domain when "reversing" the args
197090792SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
197164562SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
197264562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
197390792Sgshapirodnl we may have to filter here because otherwise some RHSs
197490792Sgshapirodnl would be interpreted as generic error messages...
197590792Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
197690792Sgshapirodnl that would make a lot of things easier.
197764562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
197890792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
197990792SgshapiroR<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
198090792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
198190792Sgshapirodnl compatility with 8.11/8.10:
198264562Sgshapirodnl we have to filter these because otherwise they would be interpreted
198364562Sgshapirodnl as generic error message...
198464562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
198564562Sgshapirodnl that would make a lot of things easier.
198664562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
198764562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
198890792SgshapiroR<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
198964562SgshapiroR<DISCARD> $*		$#discard $: discard
199090792Sgshapiroifdef(`_FFR_QUARANTINE',
199190792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
199264562Sgshapirodnl error tag
199364562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
199464562SgshapiroR<ERROR:$+> $*		$#error $: $1
199590792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
199664562Sgshapirodnl generic error from access map
199764562SgshapiroR<$+> $*		$#error $: $1		error from access db
199864562SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
199938032Speter
200090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
200190792Sgshapiro# authenticated via TLS?
200290792SgshapiroR$*			$: $1 $| $>RelayTLS	client authenticated?
200390792SgshapiroR$* $| $# $+		$# $2			error/ok?
200490792SgshapiroR$* $| $*		$: $1			no
200564562Sgshapiro
200690792SgshapiroR$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
200790792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth
200890792SgshapiroR$* $| $# $*		$# $2
200990792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
201090792SgshapiroR$* $| NO		$: $1
201190792SgshapiroR$* $| $*		$: $1 $| $&{auth_type}
201290792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ]
201364562Sgshapirodnl empty ${auth_type}?
201464562SgshapiroR$* $|			$: $1
201564562Sgshapirodnl mechanism ${auth_type} accepted?
201664562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
201790792SgshapiroR$* $| $={TrustAuthMech}	$# RELAY
201890792Sgshapirodnl remove ${auth_type}
201964562SgshapiroR$* $| $*		$: $1
202071345Sgshapirodnl workspace: localpart<@domain> | localpart
202164562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
202271345Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
202371345SgshapiroR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
202438032Speter# anything terminating locally is ok
202538032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
202690792SgshapiroR$+ < @ $* $=m >	$@ RELAY', `dnl')
202790792SgshapiroR$+ < @ $=w >		$@ RELAY
202838032Speterifdef(`_RELAY_HOSTS_ONLY_',
202990792Sgshapiro`R$+ < @ $=R >		$@ RELAY
203064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
203164562SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
203264562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
203364562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
203490792Sgshapiro`R$+ < @ $* $=R >	$@ RELAY
203564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
203690792SgshapiroR$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')')
203764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
203864562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
203990792SgshapiroR<RELAY> $*		$@ RELAY
204090792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
204138032SpeterR<$*> <$*>		$: $2',`dnl')
204238032Speter
204364562Sgshapiro
204438032Speterifdef(`_RELAY_MX_SERVED_', `dnl
204538032Speter# allow relaying for hosts which we MX serve
204664562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
204764562Sgshapirodnl this must not necessarily happen if the client is checked first...
204890792SgshapiroR< : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
204990792SgshapiroR<$* : $=w . : $*> $*	$@ RELAY
205042575SpeterR< : $* : > $*		$: $2',
205138032Speter`dnl')
205238032Speter
205338032Speter# check for local user (i.e. unqualified address)
205438032SpeterR$*			$: <?> $1
205542575SpeterR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
205638032Speter# local user is ok
205764562Sgshapirodnl is it really? the standard requires user@domain, not just user
205864562Sgshapirodnl but we should accept it anyway (maybe making it an option:
205964562Sgshapirodnl RequireFQDN ?)
206064562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
206164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
206290792SgshapiroR<?> postmaster		$@ OK
206364562Sgshapiro# require qualified recipient?
206464562Sgshapirodnl prepend daemon_flags
206564562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
206664562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
206764562Sgshapirodnl do not allow these at all or only from local systems?
206864562Sgshapirodnl r flag? add client_name
206964562SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
207064562Sgshapirodnl no r flag: relay to local user (only local part)
207164562Sgshapiro# no qualified recipient required
207290792SgshapiroR$* $| <?> $+		$@ RELAY
207364562Sgshapirodnl client_name is empty
207490792SgshapiroR<?> <?> $+		$@ RELAY
207564562Sgshapirodnl client_name is local
207690792SgshapiroR<? $=w> <?> $+		$@ RELAY
207764562Sgshapirodnl client_name is not local
207864562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
207964562Sgshapirodnl no qualified recipient required
208090792SgshapiroR<?> $+			$@ RELAY')
208164562Sgshapirodnl it is a remote user: remove mark and then check client
208238032SpeterR<$+> $*		$: $2
208364562Sgshapirodnl currently the recipient address is not used below
208438032Speter
208590792Sgshapiro######################################################################
208690792Sgshapiro### Relay_ok: is the relay/sender ok?
208790792Sgshapirodnl input: ignored
208890792Sgshapirodnl output: see explanation at call
208990792Sgshapiro######################################################################
209090792SgshapiroSRelay_ok
209138032Speter# anything originating locally is ok
209264562Sgshapiro# check IP address
209364562SgshapiroR$*			$: $&{client_addr}
209490792SgshapiroR$@			$@ RELAY		originated locally
209590792SgshapiroR0			$@ RELAY		originated locally
209690792SgshapiroR$=R $*			$@ RELAY		relayable IP address
209764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
209890792SgshapiroR$*			$: $>A <$1> <?> <+ Connect> <$1>
209990792SgshapiroR<RELAY> $* 		$@ RELAY		relayable IP address
210090792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
210164562SgshapiroR<$*> <$*>		$: $2', `dnl')
210264562SgshapiroR$*			$: [ $1 ]		put brackets around it...
210390792SgshapiroR$=w			$@ RELAY		... and see if it is local
210464562Sgshapiro
210564562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
210664562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
210764562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
210864562Sgshapirodnl input: {client_addr} or something "broken"
210964562Sgshapirodnl just throw the input away; we do not need it.
211064562Sgshapiro# check whether FROM is allowed to use system as relay
211164562SgshapiroR$*			$: <?> $>CanonAddr $&f
211290792SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
211364562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
211464562Sgshapiro# check whether local FROM is ok
211590792SgshapiroR<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
211664562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
211794334SgshapiroR<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <>
211890792SgshapiroR<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
211990792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
212090792Sgshapiro', `dnl
212190792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_',
212290792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
212364562Sgshapiro')',
212464562Sgshapiro`dnl')
212564562Sgshapirodnl')', `dnl')
212690792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind.
212790792Sgshapirodnl it does not matter in this case because the following rule ignores
212890792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace.
212964562Sgshapiro
213064562Sgshapiro# check client name: first: did it resolve?
213164562Sgshapirodnl input: ignored
213264562SgshapiroR$*			$: < $&{client_resolve} >
213390792SgshapiroR<TEMP>			$#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
213464562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
213564562SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
213664562Sgshapirodnl ${client_resolve} should be OK, so go ahead
213790792SgshapiroR$*			$: <@> $&{client_name}
213890792Sgshapirodnl should not be necessary since it has been done for client_addr already
213990792SgshapiroR<@>			$@ RELAY
214090792Sgshapirodnl workspace: <@> ${client_name} (not empty)
214138032Speter# pass to name server to make hostname canonical
214290792SgshapiroR<@> $* $=P 		$:<?>  $1 $2
214390792SgshapiroR<@> $+			$:<?>  $[ $1 $]
214490792Sgshapirodnl workspace: <?> ${client_name} (canonified)
214564562SgshapiroR$* .			$1			strip trailing dots
214638032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
214790792SgshapiroR<?> $* $=m		$@ RELAY', `dnl')
214890792SgshapiroR<?> $=w		$@ RELAY
214938032Speterifdef(`_RELAY_HOSTS_ONLY_',
215090792Sgshapiro`R<?> $=R		$@ RELAY
215164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
215264562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
215364562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
215490792Sgshapiro`R<?> $* $=R			$@ RELAY
215564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
215690792SgshapiroR<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
215764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
215890792SgshapiroR<RELAY> $*		$@ RELAY
215990792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
216038032SpeterR<$*> <$*>		$: $2',`dnl')
216190792Sgshapirodnl end of _PROMISCUOUS_RELAY_
216264562Sgshapirodivert(0)
216364562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
216464562Sgshapiro# turn a canonical address in the form user<@domain>
216564562Sgshapiro# qualify unqual. addresses with $j
216664562Sgshapirodnl it might have been only user (without <@domain>)
216764562SgshapiroSFullAddr
216864562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
216964562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
217064562SgshapiroR$+			$@ $1 <@ $j >
217138032Speter
217264562Sgshapiro# call all necessary rulesets
217364562SgshapiroScheck_rcpt
217464562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
217564562Sgshapirodnl which is the correct DSN code?
217664562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
217764562SgshapiroR$+			$: $1 $| $>checkrcpt $1
217864562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
217964562SgshapiroR$+ $| $#$*		$#$2
218064562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
218164562Sgshapiroifdef(`_SPAM_FH_',
218264562Sgshapiro`dnl lookup user@ and user@address
218364562Sgshapiroifdef(`_ACCESS_TABLE_', `',
218464562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
218564562Sgshapiro')')dnl
218664562Sgshapirodnl one of the next two rules is supposed to match
218764562Sgshapirodnl this code has been copied from BLACKLIST... etc
218864562Sgshapirodnl and simplified by omitting some < >.
218990792SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
219090792SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
219164562Sgshapirodnl R<?>		$@ something_is_very_wrong_here
219290792Sgshapiro# lookup the addresses only with Spam tag
219390792SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
219464562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
219564562Sgshapirodnl', `dnl')
219664562Sgshapiroifdef(`_SPAM_FRIEND_',
219764562Sgshapiro`# is the recipient a spam friend?
219864562Sgshapiroifdef(`_SPAM_HATER_',
219964562Sgshapiro	`errprint(`*** ERROR: define either SpamHater or SpamFriend
220064562Sgshapiro')', `dnl')
220190792SgshapiroR<FRIEND> $+		$@ SPAMFRIEND
220264562SgshapiroR<$*> $+		$: $2',
220364562Sgshapiro`dnl')
220464562Sgshapiroifdef(`_SPAM_HATER_',
220564562Sgshapiro`# is the recipient no spam hater?
220690792SgshapiroR<HATER> $+		$: $1			spam hater: continue checks
220764562SgshapiroR<$*> $+		$@ NOSPAMHATER		everyone else: stop
220864562Sgshapirodnl',`dnl')
220964562Sgshapirodnl run further checks: check_mail
221064562Sgshapirodnl should we "clean up" $&f?
221190792Sgshapiroifdef(`_FFR_MAIL_MACRO',
221290792Sgshapiro`R$*			$: $1 $| $>checkmail $&{mail_from}',
221390792Sgshapiro`R$*			$: $1 $| $>checkmail <$&f>')
221494334Sgshapirodnl recipient (canonical format) $| result of checkmail
221564562SgshapiroR$* $| $#$*		$#$2
221664562Sgshapirodnl run further checks: check_relay
221794334SgshapiroR$* $| $*		$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
221864562SgshapiroR$* $| $#$*		$#$2
221938032SpeterR$* $| $*		$: $1
222038032Speter', `dnl')
222190792Sgshapiro
222290792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
222364562Sgshapiro######################################################################
222490792Sgshapiro###  F: LookUpFull -- search for an entry in access database
222590792Sgshapiro###
222690792Sgshapiro###	lookup of full key (which should be an address) and
222790792Sgshapiro###	variations if +detail exists: +* and without +detail
222890792Sgshapiro###
222990792Sgshapiro###	Parameters:
223090792Sgshapiro###		<$1> -- key
223190792Sgshapiro###		<$2> -- default (what to return if not found in db)
223290792Sgshapirodnl			must not be empty
223390792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
223490792Sgshapiro###			! does lookup only with tag
223590792Sgshapiro###			+ does lookup with and without tag
223690792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
223790792Sgshapirodnl returns:		<default> <passthru>
223890792Sgshapirodnl 			<result> <passthru>
223990792Sgshapiro######################################################################
224090792Sgshapiro
224190792SgshapiroSF
224290792Sgshapirodnl workspace: <key> <def> <o tag> <thru>
224390792Sgshapirodnl full lookup
224490792Sgshapirodnl    2    3  4    5
224590792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
224690792Sgshapirodnl no match, try without tag
224790792Sgshapirodnl   1    2      3    4
224890792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
224990792Sgshapirodnl no match, +detail: try +*
225090792Sgshapirodnl   1    2    3    4    5  6    7
225190792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
225290792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
225390792Sgshapirodnl no match, +detail: try +* without tag
225490792Sgshapirodnl   1    2    3    4      5    6
225590792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
225690792Sgshapiro			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
225790792Sgshapirodnl no match, +detail: try without +detail
225890792Sgshapirodnl   1    2    3    4    5  6    7
225990792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
226090792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
226190792Sgshapirodnl no match, +detail: try without +detail and without tag
226290792Sgshapirodnl   1    2    3    4      5    6
226390792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
226490792Sgshapiro			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
226590792Sgshapirodnl no match, return <default> <passthru>
226690792Sgshapirodnl   1    2    3  4    5
226790792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
226890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
226990792Sgshapirodnl            2    3  4    5
227090792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
227190792Sgshapirodnl match, return <match> <passthru>
227290792Sgshapirodnl    2    3  4    5
227390792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
227490792Sgshapiro
227590792Sgshapiro######################################################################
227690792Sgshapiro###  E: LookUpExact -- search for an entry in access database
227790792Sgshapiro###
227890792Sgshapiro###	Parameters:
227990792Sgshapiro###		<$1> -- key
228090792Sgshapiro###		<$2> -- default (what to return if not found in db)
228190792Sgshapirodnl			must not be empty
228290792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
228390792Sgshapiro###			! does lookup only with tag
228490792Sgshapiro###			+ does lookup with and without tag
228590792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
228690792Sgshapirodnl returns:		<default> <passthru>
228790792Sgshapirodnl 			<result> <passthru>
228890792Sgshapiro######################################################################
228990792Sgshapiro
229090792SgshapiroSE
229190792Sgshapirodnl    2    3  4    5
229290792SgshapiroR<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
229390792Sgshapirodnl no match, try without tag
229490792Sgshapirodnl   1    2      3    4
229590792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
229690792Sgshapirodnl no match, return default passthru
229790792Sgshapirodnl   1    2    3  4    5
229890792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
229990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
230090792Sgshapirodnl            2    3  4    5
230190792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
230290792Sgshapirodnl match, return <match> <passthru>
230390792Sgshapirodnl    2    3  4    5
230490792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
230590792Sgshapiro
230690792Sgshapiro######################################################################
230790792Sgshapiro###  U: LookUpUser -- search for an entry in access database
230890792Sgshapiro###
230990792Sgshapiro###	lookup of key (which should be a local part) and
231090792Sgshapiro###	variations if +detail exists: +* and without +detail
231190792Sgshapiro###
231290792Sgshapiro###	Parameters:
231390792Sgshapiro###		<$1> -- key (user@)
231490792Sgshapiro###		<$2> -- default (what to return if not found in db)
231590792Sgshapirodnl			must not be empty
231690792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
231790792Sgshapiro###			! does lookup only with tag
231890792Sgshapiro###			+ does lookup with and without tag
231990792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
232090792Sgshapirodnl returns:		<default> <passthru>
232190792Sgshapirodnl 			<result> <passthru>
232290792Sgshapiro######################################################################
232390792Sgshapiro
232490792SgshapiroSU
232590792Sgshapirodnl user lookups are always with trailing @
232690792Sgshapirodnl    2    3  4    5
232790792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
232890792Sgshapirodnl no match, try without tag
232990792Sgshapirodnl   1    2      3    4
233090792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
233190792Sgshapirodnl do not remove the @ from the lookup:
233290792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
233390792Sgshapirodnl no match, +detail: try +*
233490792Sgshapirodnl   1    2      3    4  5    6
233590792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
233690792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
233790792Sgshapirodnl no match, +detail: try +* without tag
233890792Sgshapirodnl   1    2      3      4    5
233990792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
234090792Sgshapiro			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
234190792Sgshapirodnl no match, +detail: try without +detail
234290792Sgshapirodnl   1    2      3    4  5    6
234390792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
234490792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
234590792Sgshapirodnl no match, +detail: try without +detail and without tag
234690792Sgshapirodnl   1    2      3      4    5
234790792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
234890792Sgshapiro			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
234990792Sgshapirodnl no match, return <default> <passthru>
235090792Sgshapirodnl   1    2    3  4    5
235190792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
235290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
235390792Sgshapirodnl            2    3  4    5
235490792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
235590792Sgshapirodnl match, return <match> <passthru>
235690792Sgshapirodnl    2    3  4    5
235790792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
235890792Sgshapiro
235990792Sgshapiro######################################################################
236064562Sgshapiro###  SearchList: search a list of items in the access map
236164562Sgshapiro###	Parameters:
236264562Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
236364562Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
236464562Sgshapirodnl	avoid errorneous matches (with error messages?)
236564562Sgshapirodnl	if we can make sure that tag is always a single token
236664562Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
236790792Sgshapirodnl	to avoid errorneous matchs (first rule: D: if there
236864562Sgshapirodnl	is that mark somewhere in the list, it will be taken).
236964562Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
237064562Sgshapirodnl	the tag only, e.g.:
237164562Sgshapiro###	where "exact" is either "+" or "!":
237264562Sgshapiro###	<+ TAG>	lookup with and w/o tag
237364562Sgshapiro###	<! TAG>	lookup with tag
237464562Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
237564562Sgshapirodnl		a blank between them and the tag.
237664562Sgshapiro###	possible values for "mark" are:
237790792Sgshapiro###		D: recursive host lookup (LookUpDomain)
237864562Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
237964562Sgshapiro###		E: exact lookup, no modifications
238064562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
238164562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
238264562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
238364562Sgshapiro######################################################################
238438032Speter
238564562Sgshapiro# class with valid marks for SearchList
238664562Sgshapirodnl if A is activated: add it
238790792SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
238864562SgshapiroSSearchList
238990792Sgshapiro# just call the ruleset with the name of the tag... nice trick...
239090792Sgshapirodnl       2       3    4
239190792SgshapiroR<$+> $| <$={src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
239290792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <>
239390792Sgshapirodnl no match and nothing left: return
239490792SgshapiroR<$+> $| <> $| <?> <>		$@ <?>
239590792Sgshapirodnl no match but something left: continue
239690792SgshapiroR<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
239790792Sgshapirodnl match: return
239890792SgshapiroR<$+> $| <$*> $| <$+> <>	$@ <$3>
239964562Sgshapirodnl return result from recursive invocation
240090792SgshapiroR<$+> $| <$+>			$@ <$2>
240190792Sgshapirodnl endif _ACCESS_TABLE_
240290792Sgshapirodivert(0)
240338032Speter
240490792Sgshapiro######################################################################
240590792Sgshapiro###  trust_auth: is user trusted to authenticate as someone else?
240690792Sgshapiro###
240790792Sgshapiro###	Parameters:
240890792Sgshapiro###		$1: AUTH= parameter from MAIL command
240990792Sgshapiro######################################################################
241090792Sgshapiro
241190792Sgshapirodnl empty ruleset definition so it can be called
241290792SgshapiroSLocal_trust_auth
241364562SgshapiroStrust_auth
241464562SgshapiroR$*			$: $&{auth_type} $| $1
241564562Sgshapiro# required by RFC 2554 section 4.
241664562SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
241764562Sgshapirodnl seems to be useful...
241864562SgshapiroR$* $| $&{auth_authen}		$@ identical
241964562SgshapiroR$* $| <$&{auth_authen}>	$@ identical
242064562Sgshapirodnl call user supplied code
242164562SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $1
242264562SgshapiroR$* $| $#$*		$#$2
242364562Sgshapirodnl default: error
242464562SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
242564562Sgshapiro
242690792Sgshapiro######################################################################
242790792Sgshapiro###  Relay_Auth: allow relaying based on authentication?
242890792Sgshapiro###
242990792Sgshapiro###	Parameters:
243090792Sgshapiro###		$1: ${auth_type}
243190792Sgshapiro######################################################################
243290792SgshapiroSLocal_Relay_Auth
243364562Sgshapiro
243490792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
243590792Sgshapiro######################################################################
243690792Sgshapiro###  srv_features: which features to offer to a client?
243790792Sgshapiro###	(done in server)
243890792Sgshapiro######################################################################
243990792SgshapiroSsrv_features
244090792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl
244190792SgshapiroR$*			$: $1 $| $>"Local_srv_features" $1
244290792SgshapiroR$* $| $#$*		$#$2
244390792SgshapiroR$* $| $*		$: $1', `dnl')
244490792SgshapiroR$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
244590792SgshapiroR<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
244690792SgshapiroR<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
244764562SgshapiroR<?>$*		$@ OK
244890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
244990792SgshapiroR<$* _ATMPF_>$*	$#temp', `dnl')
245090792SgshapiroR<$+>$*		$# $1
245164562Sgshapiro
245290792Sgshapiro######################################################################
245390792Sgshapiro###  try_tls: try to use STARTTLS?
245490792Sgshapiro###	(done in client)
245590792Sgshapiro######################################################################
245664562SgshapiroStry_tls
245790792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl
245890792SgshapiroR$*			$: $1 $| $>"Local_try_tls" $1
245990792SgshapiroR$* $| $#$*		$#$2
246090792SgshapiroR$* $| $*		$: $1', `dnl')
246190792SgshapiroR$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
246290792SgshapiroR<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
246390792SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
246464562SgshapiroR<?>$*		$@ OK
246590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
246690792SgshapiroR<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
246771345SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
246890792Sgshapiro  
246990792Sgshapiro######################################################################
247090792Sgshapiro###  tls_rcpt: is connection with server "good" enough?
247190792Sgshapiro###	(done in client, per recipient)
247290792Sgshapirodnl called from deliver() before RCPT command
247390792Sgshapiro###
247490792Sgshapiro###	Parameters:
247590792Sgshapiro###		$1: recipient
247690792Sgshapiro######################################################################
247790792SgshapiroStls_rcpt
247890792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl
247990792SgshapiroR$*			$: $1 $| $>"Local_tls_rcpt" $1
248090792SgshapiroR$* $| $#$*		$#$2
248190792SgshapiroR$* $| $*		$: $1', `dnl')
248290792Sgshapirodnl store name of other side
248390792SgshapiroR$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
248490792Sgshapirodnl canonify recipient address
248590792SgshapiroR$+			$: <?> $>CanonAddr $1
248690792Sgshapirodnl strip trailing dots
248790792SgshapiroR<?> $+ < @ $+ . >	<?> $1 <@ $2 >
248890792Sgshapirodnl full address?
248990792SgshapiroR<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
249090792Sgshapirodnl only localpart?
249190792SgshapiroR<?> $+			$: $1 $| <U:$1@> <E:>
249290792Sgshapirodnl look it up
249390792Sgshapirodnl also look up a default value via E:
249490792SgshapiroR$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
249590792Sgshapirodnl found nothing: stop here
249690792SgshapiroR$* $| <?>	$@ OK
249790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
249890792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
249990792Sgshapirodnl use the generic routine (for now)
250090792SgshapiroR$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
250164562Sgshapiro
250290792Sgshapiro######################################################################
250390792Sgshapiro###  tls_client: is connection with client "good" enough?
250490792Sgshapiro###	(done in server)
250590792Sgshapiro###
250690792Sgshapiro###	Parameters:
250790792Sgshapiro###		${verify} $| (MAIL|STARTTLS)
250890792Sgshapiro######################################################################
250964562Sgshapirodnl MAIL: called from check_mail
251064562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
251164562SgshapiroStls_client
251290792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl
251390792SgshapiroR$*			$: $1 $| $>"Local_tls_client" $1
251490792SgshapiroR$* $| $#$*		$#$2
251590792SgshapiroR$* $| $*		$: $1', `dnl')
251664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
251790792Sgshapirodnl store name of other side
251890792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
251964562Sgshapirodnl ignore second arg for now
252064562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
252164562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
252264562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
252390792SgshapiroR$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
252490792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
252564562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
252664562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
252790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
252890792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
252990792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
253090792SgshapiroR$* $| $*	$@ $>"TLS_connection" $1')
253164562Sgshapiro
253290792Sgshapiro######################################################################
253390792Sgshapiro###  tls_server: is connection with server "good" enough?
253490792Sgshapiro###	(done in client)
253590792Sgshapiro###
253690792Sgshapiro###	Parameter:
253790792Sgshapiro###		${verify}
253890792Sgshapiro######################################################################
253964562Sgshapirodnl i.e. has the server been authenticated and is encryption active?
254064562Sgshapirodnl called from deliver() after STARTTLS command
254164562SgshapiroStls_server
254290792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl
254390792SgshapiroR$*			$: $1 $| $>"Local_tls_server" $1
254490792SgshapiroR$* $| $#$*		$#$2
254590792SgshapiroR$* $| $*		$: $1', `dnl')
254664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
254790792Sgshapirodnl store name of other side
254890792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
254990792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
255090792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
255164562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
255264562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
255390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
255490792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
255590792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
255690792SgshapiroR$*		$@ $>"TLS_connection" $1')
255764562Sgshapiro
255890792Sgshapiro######################################################################
255990792Sgshapiro###  TLS_connection: is TLS connection "good" enough?
256090792Sgshapiro###
256190792Sgshapiro###	Parameters:
256264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
256390792Sgshapiro###		${verify} $| <Requirement> [<>]', `dnl
256490792Sgshapiro###		${verify}')
256590792Sgshapiro###		Requirement: RHS from access map, may be ? for none.
256690792Sgshapirodnl	syntax for Requirement:
256790792Sgshapirodnl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
256890792Sgshapirodnl	extensions: could be a list of further requirements
256990792Sgshapirodnl		for now: CN:string	{cn_subject} == string
257090792Sgshapiro######################################################################
257190792SgshapiroSTLS_connection
257290792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
257390792Sgshapirodnl deal with TLS handshake failures: abort
257490792SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
257590792Sgshapirodivert(-1)')
257664562Sgshapirodnl common ruleset for tls_{client|server}
257790792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>]
257864562Sgshapirodnl remove optional <>
257964562SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
258090792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup>
258190792Sgshapiro# create the appropriate error codes
258264562Sgshapirodnl permanent or temporary error?
258364562SgshapiroR$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
258464562SgshapiroR$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
258564562Sgshapirodnl default case depends on TLS_PERM_ERR
258664562SgshapiroR$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
258790792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
258890792Sgshapiro# deal with TLS handshake failures: abort
258964562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
259064562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
259164562Sgshapirodnl use default error
259264562SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
259390792SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
259490792Sgshapirodnl separate optional requirements
259590792SgshapiroR$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
259690792SgshapiroR$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> <> $1
259790792Sgshapirodnl separate optional requirements
259890792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
259964562Sgshapirodnl some other value in access map: accept
260064562Sgshapirodnl this also allows to override the default case (if used)
260164562SgshapiroR$* $| $*			$@ OK
260264562Sgshapiro# authentication required: give appropriate error
260364562Sgshapiro# other side did authenticate (via STARTTLS)
260490792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
260564562Sgshapirodnl only verification required and it succeeded
260690792SgshapiroR<$*><VERIFY> <> OK		$@ OK
260790792Sgshapirodnl verification required and it succeeded but extensions are given
260890792Sgshapirodnl change it to <SMTP:ESC> <REQ:0>  <extensions>
260990792SgshapiroR<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
261064562Sgshapirodnl verification required + some level of encryption
261190792SgshapiroR<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
261264562Sgshapirodnl just some level of encryption required
261390792SgshapiroR<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
261490792Sgshapirodnl workspace:
261590792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
261690792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
261790792Sgshapirodnl verification required but ${verify} is not set (case 1.)
261890792SgshapiroR<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
261990792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
262090792SgshapiroR<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
262190792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
262290792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
262364562Sgshapirodnl some other value for ${verify}
262490792SgshapiroR<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
262590792Sgshapirodnl some level of encryption required: get the maximum level (case 2.)
262690792SgshapiroR<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
262764562Sgshapirodnl compare required bits with actual bits
262890792SgshapiroR<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
262990792SgshapiroR<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
263090792Sgshapirodnl strength requirements fulfilled
263190792Sgshapirodnl TLS Additional Requirements Separator
263290792Sgshapirodnl this should be something which does not appear in the extensions itself
263390792Sgshapirodnl @ could be part of a CN, DN, etc...
263490792Sgshapirodnl use < > ? those are encoded in CN, DN, ...
263590792Sgshapirodefine(`_TLS_ARS_', `++')dnl
263690792Sgshapirodnl workspace:
263790792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
263890792SgshapiroR<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
263990792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
264090792Sgshapirodnl continue: check  extensions
264190792SgshapiroR<$-:$+ _TLS_ARS_ >			$@ OK
264290792Sgshapirodnl split extensions into own list
264390792SgshapiroR<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
264490792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
264590792SgshapiroR<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
264664562Sgshapiro
264790792Sgshapiro######################################################################
264890792Sgshapiro###  TLS_req: check additional TLS requirements
264990792Sgshapiro###
265090792Sgshapiro###	Parameters: [<list> <of> <req>] $| <$-:$+>
265190792Sgshapiro###		$-: SMTP reply code
265290792Sgshapiro###		$+: Enhanced Status Code
265390792Sgshapirodnl  further requirements for this ruleset:
265490792Sgshapirodnl	name of "other side" is stored is {TLS_name} (client/server_name)
265590792Sgshapirodnl
265690792Sgshapirodnl	currently only CN[:common_name] is implemented
265790792Sgshapirodnl	right now this is only a logical AND
265890792Sgshapirodnl	i.e. all requirements must be true
265990792Sgshapirodnl	how about an OR? CN must be X or CN must be Y or ..
266090792Sgshapirodnl	use a macro to compute this as a trivial sequential
266190792Sgshapirodnl	operations (no precedences etc)?
266290792Sgshapiro######################################################################
266390792SgshapiroSTLS_req
266490792Sgshapirodnl no additional requirements: ok
266590792SgshapiroR $| $+		$@ OK
266690792Sgshapirodnl require CN: but no CN specified: use name of other side
266790792SgshapiroR<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
266890792Sgshapirodnl match, check rest
266990792SgshapiroR<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
267090792Sgshapirodnl CN does not match
267190792Sgshapirodnl  1   2      3  4
267290792SgshapiroR<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
267390792Sgshapirodnl cert subject
267490792SgshapiroR<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
267590792Sgshapirodnl CS does not match
267690792Sgshapirodnl  1   2      3  4
267790792SgshapiroR<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CERT Subject " $&{cert_subject} " does not match " $1
267890792Sgshapirodnl match, check rest
267990792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
268090792Sgshapirodnl CI does not match
268190792Sgshapirodnl  1   2      3  4
268290792SgshapiroR<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CERT Issuer " $&{cert_issuer} " does not match " $1
268390792Sgshapirodnl return from recursive call
268490792SgshapiroROK			$@ OK
268590792Sgshapiro
268690792Sgshapiro######################################################################
268790792Sgshapiro###  max: return the maximum of two values separated by :
268890792Sgshapiro###
268990792Sgshapiro###	Parameters: [$-]:[$-]
269090792Sgshapiro######################################################################
269164562SgshapiroSmax
269264562SgshapiroR:		$: 0
269364562SgshapiroR:$-		$: $1
269464562SgshapiroR$-:		$: $1
269564562SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
269664562SgshapiroRTRUE:$-:$-	$: $2
269790792SgshapiroR$-:$-:$-	$: $2
269890792Sgshapirodnl endif _ACCESS_TABLE_
269990792Sgshapirodivert(0)
270064562Sgshapiro
270190792Sgshapiro######################################################################
270290792Sgshapiro###  RelayTLS: allow relaying based on TLS authentication
270390792Sgshapiro###
270490792Sgshapiro###	Parameters:
270590792Sgshapiro###		none
270690792Sgshapiro######################################################################
270790792SgshapiroSRelayTLS
270864562Sgshapiro# authenticated?
270964562Sgshapirodnl we do not allow relaying for anyone who can present a cert
271064562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
271164562Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow
271264562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
271364562Sgshapirodnl but anyway).
271464562Sgshapirodnl so here is the trick: if the verification succeeded
271564562Sgshapirodnl we look up the cert issuer in the access map
271664562Sgshapirodnl (maybe after extracting a part with a regular expression)
271764562Sgshapirodnl if this returns RELAY we relay without further questions
271864562Sgshapirodnl if it returns SUBJECT we perform a similar check on the
271964562Sgshapirodnl cert subject.
272064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
272190792SgshapiroR$*			$: <?> $&{verify}
272290792SgshapiroR<?> OK			$: OK		authenticated: continue
272390792SgshapiroR<?> $*			$@ NO		not authenticated
272464562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
272590792SgshapiroR$*			$: $(CERTIssuer $&{cert_issuer} $)',
272690792Sgshapiro`R$*			$: $&{cert_issuer}')
272790792SgshapiroR$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
272864562Sgshapirodnl use $# to stop further checks (delay_check)
272990792SgshapiroRRELAY			$# RELAY
273064562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
273190792SgshapiroRSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
273290792Sgshapiro`RSUBJECT		$: <@> $&{cert_subject}')
273390792SgshapiroR<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
273490792SgshapiroR<@> RELAY		$# RELAY
273590792SgshapiroR$*			$: NO', `dnl')
273664562Sgshapiro
273790792Sgshapiro######################################################################
273890792Sgshapiro###  authinfo: lookup authinfo in the access map
273990792Sgshapiro###
274090792Sgshapiro###	Parameters:
274190792Sgshapiro###		$1: {server_name}
274290792Sgshapiro###		$2: {server_addr}
274390792Sgshapirodnl	both are currently ignored
274490792Sgshapirodnl if it should be done via another map, we either need to restrict
274590792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another
274690792Sgshapirodnl parameter which I want to avoid, it's quite complex already)
274790792Sgshapiro######################################################################
274890792Sgshapirodnl omit this ruleset if neither is defined?
274990792Sgshapirodnl it causes DefaultAuthInfo to be ignored
275090792Sgshapirodnl (which may be considered a good thing).
275190792SgshapiroSauthinfo
275290792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl
275390792SgshapiroR$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
275490792SgshapiroR<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
275590792SgshapiroR<?>		$: <$(authinfo AuthInfo: $: ? $)>
275690792SgshapiroR<?>		$@ no				no authinfo available
275790792SgshapiroR<$*>		$# $1
275890792Sgshapirodnl', `dnl
275990792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
276090792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
276190792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
276290792SgshapiroR$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
276390792SgshapiroR$* $| <?>$*	$@ no				no authinfo available
276490792SgshapiroR$* $| <$*> <>	$# $2
276590792Sgshapirodnl', `dnl')')
276690792Sgshapiro
276764562Sgshapiroundivert(9)dnl LOCAL_RULESETS
276838032Speter#
276938032Speter######################################################################
277038032Speter######################################################################
277138032Speter#####
277264562Sgshapiro`#####			MAIL FILTER DEFINITIONS'
277364562Sgshapiro#####
277464562Sgshapiro######################################################################
277564562Sgshapiro######################################################################
277690792Sgshapiro_MAIL_FILTERS_
277764562Sgshapiro#
277864562Sgshapiro######################################################################
277964562Sgshapiro######################################################################
278064562Sgshapiro#####
278138032Speter`#####			MAILER DEFINITIONS'
278238032Speter#####
278338032Speter######################################################################
278438032Speter######################################################################
278564562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
278666494Sgshapiro
2787