proto.m4 revision 98121
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
1698121SgshapiroVERSIONID(`$Id: proto.m4,v 8.646 2002/05/19 21:22:40 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
106098121Sgshapirodnl if no match, change marker to prevent a second @domain lookup
106198121SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . >
106298121Sgshapirodnl without +detail
106338032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
106490792Sgshapirodnl no match
106538032SpeterR<@> $+			$: $1
106690792Sgshapirodnl remove mark
106764562SgshapiroR<!> $+			$: $1
106864562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
106938032SpeterR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
107090792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
107190792Sgshapiro# check virtuser input address against output address, if same, skip recursion
107290792SgshapiroR< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
107390792Sgshapiro# it is the same: stop now
107490792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
107590792SgshapiroR< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
107690792Sgshapirodnl', `dnl')
107780785Sgshapirodnl this is not a documented option
107880785Sgshapirodnl it performs no looping at all for virtusertable
107977349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_',
108077349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
108177349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
108277349Sgshapirodnl', `dnl')
108338032Speter
108438032Speter# short circuit local delivery so forwarded email works
108538032Speterifdef(`_MAILER_usenet_', `dnl
108664562SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
108766494Sgshapiro
108866494Sgshapiro
108938032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
109038032Speter`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
109164562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
109264562Sgshapirodnl $H empty (but @$=w.)
109338032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
109438032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
109564562Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
109638032SpeterR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
109738032Speter
109864562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
109938032Speter# not local -- try mailer table lookup
110038032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
110138032SpeterR< $+ . > $*		$: < $1 > $2			strip trailing dot
110238032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
110364562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
110464562SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
110564562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
110638032Speter`dnl')
110764562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)'
110838032Speter
110938032Speterifdef(`_NO_UUCP_', `dnl',
111038032Speter`# resolve remotely connected UUCP links (if any)
111138032Speterifdef(`_CLASS_V_',
111264562Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
111338032Speter	`dnl')
111438032Speterifdef(`_CLASS_W_',
111564562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
111638032Speter	`dnl')
111738032Speterifdef(`_CLASS_X_',
111864562Sgshapiro`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
111938032Speter	`dnl')')
112038032Speter
112138032Speter# resolve fake top level domains by forwarding to other hosts
112238032Speterifdef(`BITNET_RELAY',
112364562Sgshapiro`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
112438032Speter	`dnl')
112538032Speterifdef(`DECNET_RELAY',
112664562Sgshapiro`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
112738032Speter	`dnl')
112838032Speterifdef(`_MAILER_pop_',
112938032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
113038032Speter	`dnl')
113138032Speterifdef(`_MAILER_fax_',
113238032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
113338032Speter`ifdef(`FAX_RELAY',
113464562Sgshapiro`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
113538032Speter	`dnl')')
113638032Speter
113738032Speterifdef(`UUCP_RELAY',
113838032Speter`# forward non-local UUCP traffic to our UUCP relay
113964562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
114038032Speter`ifdef(`_MAILER_uucp_',
114138032Speter`# forward other UUCP traffic straight to UUCP
114238032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
114338032Speter	`dnl')')
114438032Speterifdef(`_MAILER_usenet_', `
114538032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
114664562SgshapiroR$+ . USENET		$#usenet $@ usenet $: $1',
114738032Speter	`dnl')
114838032Speter
114938032Speterifdef(`_LOCAL_RULES_',
115038032Speter`# figure out what should stay in our local mail system
115138032Speterundivert(1)', `dnl')
115238032Speter
115338032Speter# pass names that still have a host to a smarthost (if defined)
115464562SgshapiroR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
115538032Speter
115638032Speter# deal with other remote names
115738032Speterifdef(`_MAILER_smtp_',
115864562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
115990792Sgshapiro`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
116038032Speter
116138032Speter# handle locally delivered names
116264562SgshapiroR$=L			$#_LOCAL_ $: @ $1		special local names
116338032SpeterR$+			$#_LOCAL_ $: $1			regular local names
116438032Speter
116538032Speter###########################################################################
116638032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
116738032Speter###########################################################################
116838032Speter
116964562SgshapiroSLocal_localaddr
117064562SgshapiroSlocaladdr=5
117164562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
117290792SgshapiroR$+ $| $#ok		$@ $1			no change
117364562SgshapiroR$+ $| $#$*		$#$2
117464562SgshapiroR$+ $| $*		$: $1
117538032Speter
117690792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
117790792Sgshapiro# Preserve rcpt_host in {Host}
117890792SgshapiroR$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
117990792SgshapiroR$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
118090792SgshapiroR$+ $| $| $+		$: $1			h not set, {Host} set
118190792SgshapiroR$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
118295154SgshapiroR$+ $| $* @ $+ $| $*	$: $(macro {Host} $@ @$3 $) $1	set {Host} to host in h
118390792SgshapiroR$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
118490792Sgshapiro')dnl
118590792Sgshapiro
118690792Sgshapiroifdef(`_FFR_5_', `dnl
118766494Sgshapiro# Preserve host in a macro
118866494SgshapiroR$+			$: $(macro {LocalAddrHost} $) $1
118966494SgshapiroR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
119066494Sgshapiro
119190792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
119238032Speter# deal with plussed users so aliases work nicely
119366494SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
119466494SgshapiroR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
119566494Sgshapiro')
119638032Speter# prepend an empty "forward host" on the front
119738032SpeterR$+			$: <> $1
119838032Speter
119938032Speterifdef(`LUSER_RELAY', `dnl
120038032Speter# send unrecognized local users to a relay host
120190792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
120266494SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
120366494SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
120466494SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
120566494SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
120664562SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
120790792SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')
120890792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
120990792SgshapiroR< $+ > $+		$: < $1 > $2 $&{Host}')
121090792Sgshapirodnl')
121138032Speter
121290792Sgshapiroifdef(`MAIL_HUB', `dnl
121390792SgshapiroR< > $+			$: < $H > $1			try hub', `dnl')
121490792Sgshapiroifdef(`LOCAL_RELAY', `dnl
121590792SgshapiroR< > $+			$: < $R > $1			try relay', `dnl')
121690792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
121790792SgshapiroR< > $+			$@ $1', `dnl
121864562SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
121990792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
122090792SgshapiroR< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
122164562SgshapiroR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
122264562SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
122338032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
122466494SgshapiroR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
122538032SpeterR< > < $+ >		$@ $1				no +detail
122643730SpeterR$+			$: $1 <> $&h			add +detail back in
122790792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
122890792SgshapiroR$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
122943730SpeterR$+ <> + $*		$: $1 + $2			check whether +detail
123066494SgshapiroR$+ <> $*		$: $1				else discard')
123164562SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
123264562SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
123390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
123490792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
123590792SgshapiroR< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
123690792SgshapiroR< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
123790792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
123890792SgshapiroR< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
123964562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
124038032Speter
124164562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
124290792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
124338032Speter###################################################################
124490792Sgshapiro###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
124590792Sgshapirodnl input: <Domain> FullAddress
124690792Sgshapiro###################################################################
124790792Sgshapiro
124890792SgshapiroSLDAPMailertable
124990792SgshapiroR< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
125090792SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
125190792SgshapiroR< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
125290792SgshapiroR< $+ > $#$*		$#$2					found
125390792SgshapiroR< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
125490792Sgshapiro`dnl')
125590792Sgshapiro
125690792Sgshapiro###################################################################
125738032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
125864562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
125938032Speter###################################################################
126038032Speter
126164562SgshapiroSMailertable=90
126264562Sgshapirodnl shift and check
126364562Sgshapirodnl %2 is not documented in cf/README
126438032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
126564562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
126664562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
126764562SgshapiroR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
126864562Sgshapirodnl is $2 always empty?
126938032SpeterR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
127064562SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
127164562Sgshapirodnl return full address
127238032SpeterR< $* > $*		$@ $2				no mailertable match',
127338032Speter`dnl')
127438032Speter
127538032Speter###################################################################
127638032Speter###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
127764562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
127864562Sgshapirodnl	<> address				-> address
127964562Sgshapirodnl	<error:d.s.n:text>			-> error
128064562Sgshapirodnl	<error:text>				-> error
128164562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
128264562Sgshapirodnl	<mailer:host> address			-> mailer host address
128364562Sgshapirodnl	<localdomain> address			-> address
128464562Sgshapirodnl	<host> address				-> relay host address
128538032Speter###################################################################
128638032Speter
128764562SgshapiroSMailerToTriple=95
128838032SpeterR< > $*				$@ $1			strip off null relay
128964562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
129038032SpeterR< error : $- $+ > $*		$#error $@ $(dequote $1 $) $: $2
129138032SpeterR< local : $* > $*		$>CanonLocal < $1 > $2
129290792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
129390792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
129490792SgshapiroR< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
129538032SpeterR< $=w > $*			$@ $2			delete local host
129638032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
129738032Speter
129838032Speter###################################################################
129938032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
130064562Sgshapirodnl input: <user> address
130164562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
130264562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
130364562Sgshapirodnl <> user <@host> rest		-> local user@host user
130464562Sgshapirodnl <> user				-> local user user
130564562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
130664562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
130764562Sgshapirodnl <user> lp				-> local lp user
130838032Speter###################################################################
130938032Speter
131038032SpeterSCanonLocal
131143730Speter# strip local host from routed addresses
131264562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
131364562SgshapiroR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
131443730Speter
131538032Speter# strip trailing dot from any host name that may appear
131638032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
131738032Speter
131838032Speter# handle local: syntax -- use old user, either with or without host
131938032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
132038032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
132138032Speter
132238032Speter# handle local:user@host syntax -- ignore host part
132338032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
132438032Speter
132538032Speter# handle local:user syntax
132638032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
132738032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
132838032Speter
132938032Speter###################################################################
133038032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
133138032Speter###################################################################
133238032Speter
133364562SgshapiroSMasqHdr=93
133438032Speter
133564562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
133638032Speter# handle generics database
133738032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
133864562Sgshapirodnl if generics should be applied add a @ as mark
133938032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
134038032Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
134138032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
134264562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
134364562Sgshapirodnl ignore the first case for now
134464562Sgshapirodnl if it has the mark lookup full address
134590792Sgshapirodnl broken: %1 is full address not just detail
134664562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
134764562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
134864562Sgshapirodnl no match, try user+detail@domain
134964562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
135064562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
135164562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
135264562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
135364562Sgshapirodnl no match, remove mark
135464562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
135564562Sgshapirodnl no match, try @domain for exceptions
135664562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
135764562Sgshapirodnl workspace: ... or <match> user <@domain>
135864562Sgshapirodnl no match, try local part
135938032SpeterR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
136064562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
136164562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
136264562SgshapiroR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
136364562SgshapiroR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
136438032SpeterR< > $*			$: $1				not found',
136538032Speter`dnl')
136638032Speter
136764562Sgshapiro# do not masquerade anything in class N
136864562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
136964562Sgshapiro
137090792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
137138032Speter# special case the users that should be exposed
137238032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
137338032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
137438032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
137538032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
137638032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
137738032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
137838032Speter
137938032Speter# handle domain-specific masquerading
138038032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
138138032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
138238032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
138338032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
138438032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
138538032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
138638032SpeterR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
138738032SpeterR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
138890792Sgshapirodnl', `dnl no masquerading
138990792Sgshapirodnl just fix *LOCAL* leftovers
139090792SgshapiroR$* < @ *LOCAL* >	$@ $1 < @ $j . >')
139138032Speter
139238032Speter###################################################################
139338032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
139438032Speter###################################################################
139538032Speter
139664562SgshapiroSMasqEnv=94
139738032Speterifdef(`_MASQUERADE_ENVELOPE_',
139864562Sgshapiro`R$+			$@ $>MasqHdr $1',
139938032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
140038032Speter
140138032Speter###################################################################
140238032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
140338032Speter###################################################################
140438032Speter
140564562SgshapiroSParseLocal=98
140664562Sgshapiroundivert(3)dnl LOCAL_RULE_0
140738032Speter
140864562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
140990792Sgshapiro######################################################################
141090792Sgshapiro###  LDAPExpand: Expand address using LDAP routing
141190792Sgshapiro###
141290792Sgshapiro###	Parameters:
141390792Sgshapiro###		<$1> -- parsed address (user < @ domain . >) (pass through)
141490792Sgshapiro###		<$2> -- RFC822 address (user @ domain) (used for lookup)
141590792Sgshapiro###		<$3> -- +detail information
141690792Sgshapiro###
141790792Sgshapiro###	Returns:
141890792Sgshapiro###		Mailer triplet ($#mailer $@ host $: address)
141990792Sgshapiro###		Parsed address (user < @ domain . >)
142090792Sgshapiro######################################################################
142190792Sgshapiro
142264562SgshapiroSLDAPExpand
142364562Sgshapiro# do the LDAP lookups
142490792SgshapiroR<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
142564562Sgshapiro
142694334Sgshapiro# look for temporary failures (return original address, MTA will queue up)
142794334SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*>	$@ $2
142894334SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*>	$@ $2
142994334Sgshapiro
143064562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
143164562Sgshapiro# return the new mailRoutingAddress
143290792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
143390792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
143490792SgshapiroR<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
143590792SgshapiroR<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
143690792SgshapiroR<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
143764562Sgshapiro
143898121Sgshapiro
143964562Sgshapiro# if mailRoutingAddress and non-local mailHost,
144064562Sgshapiro# relay to mailHost with new mailRoutingAddress
144190792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
144290792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
144390792Sgshapiro# check mailertable for host, relay from there
144490792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
144590792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
144690792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
144790792Sgshapiro# check mailertable for host, relay from there
144890792SgshapiroR<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
144990792Sgshapiro`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
145064562Sgshapiro
145164562Sgshapiro# if no mailRoutingAddress and local mailHost,
145264562Sgshapiro# return original address
145390792SgshapiroR<> <$=w> <$+> <$+> <$*>	$@ $2
145464562Sgshapiro
145598121Sgshapiro
145664562Sgshapiro# if no mailRoutingAddress and non-local mailHost,
145764562Sgshapiro# relay to mailHost with original address
145890792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
145990792Sgshapiro# check mailertable for host, relay from there
146090792SgshapiroR<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
146190792Sgshapiro`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
146264562Sgshapiro
146390792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_',
146490792Sgshapiro`# if no mailRoutingAddress and no mailHost,
146590792Sgshapiro# try without +detail
146690792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
146790792Sgshapiro
146890792Sgshapiro# if still no mailRoutingAddress and no mailHost,
146964562Sgshapiro# try @domain
147090792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
147190792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
147290792SgshapiroR<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>
147364562Sgshapiro
147464562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
147564562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
147664562Sgshapiro# user does not exist
147790792SgshapiroR<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
147890792Sgshapiro# only give error for envelope recipient
147990792SgshapiroR<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
148090792SgshapiroR<?> <$*> <$+>			$@ $2',
148164562Sgshapiro`dnl
148264562Sgshapiro# return the original address
148390792SgshapiroR<> <> <$+> <@ $+> <$*>		$@ $1')',
148464562Sgshapiro`dnl')
148564562Sgshapiro
148664562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
148764562Sgshapiro')')
148890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
148938032Speter######################################################################
149090792Sgshapiro###  D: LookUpDomain -- search for domain in access database
149138032Speter###
149238032Speter###	Parameters:
149338032Speter###		<$1> -- key (domain name)
149438032Speter###		<$2> -- default (what to return if not found in db)
149564562Sgshapirodnl			must not be empty
149690792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
149764562Sgshapiro###			! does lookup only with tag
149864562Sgshapiro###			+ does lookup with and without tag
149990792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
150064562Sgshapirodnl returns:		<default> <passthru>
150164562Sgshapirodnl 			<result> <passthru>
150238032Speter######################################################################
150338032Speter
150490792SgshapiroSD
150564562Sgshapirodnl workspace <key> <default> <passthru> <mark>
150664562Sgshapirodnl lookup with tag (in front, no delimiter here)
150790792Sgshapirodnl    2    3  4    5
150890792SgshapiroR<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
150964562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
151064562Sgshapirodnl lookup without tag?
151190792Sgshapirodnl   1    2      3    4
151290792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
151390792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
151490792Sgshapirodnl XXX apply this also to IP addresses?
151590792Sgshapirodnl currently it works the wrong way round for [1.2.3.4]
151690792Sgshapirodnl   1  2    3    4  5    6
151790792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
151890792Sgshapirodnl   1  2    3      4    5
151990792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
152090792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
152190792Sgshapirodnl found SKIP: return <default> and <passthru>
152290792Sgshapirodnl      1    2    3  4    5
152390792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
152490792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!)
152590792Sgshapirodnl    1  2     3    4  5    6
152690792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
152790792Sgshapiroifdef(`NO_NETINET6', `dnl',
152890792Sgshapiro`dnl not found: IPv6 net
152990792Sgshapirodnl (could be merged with previous rule if we have a class containing .:)
153090792Sgshapirodnl    1   2     3    4  5    6
153190792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
153290792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
153364562Sgshapirodnl not found, but subdomain: try again
153490792Sgshapirodnl   1  2    3    4  5    6
153590792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
153690792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
153790792Sgshapirodnl   1    2      3    4
153890792SgshapiroR<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
153990792Sgshapirodnl not found, no subdomain: return <default> and <passthru>
154090792Sgshapirodnl   1    2    3  4    5
154190792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
154290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
154390792Sgshapirodnl            2    3    4  5    6
154490792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
154590792Sgshapirodnl return <result of lookup> and <passthru>
154690792Sgshapirodnl    2    3    4  5    6
154790792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
154838032Speter
154938032Speter######################################################################
155090792Sgshapiro###  A: LookUpAddress -- search for host address in access database
155138032Speter###
155238032Speter###	Parameters:
155338032Speter###		<$1> -- key (dot quadded host address)
155438032Speter###		<$2> -- default (what to return if not found in db)
155564562Sgshapirodnl			must not be empty
155690792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
155764562Sgshapiro###			! does lookup only with tag
155864562Sgshapiro###			+ does lookup with and without tag
155990792Sgshapiro###		<$4> -- passthru (additional data passed through)
156064562Sgshapirodnl	returns:	<default> <passthru>
156164562Sgshapirodnl			<result> <passthru>
156238032Speter######################################################################
156338032Speter
156490792SgshapiroSA
156564562Sgshapirodnl lookup with tag
156690792Sgshapirodnl    2    3  4    5
156790792SgshapiroR<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
156864562Sgshapirodnl lookup without tag
156990792Sgshapirodnl   1    2      3    4
157090792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
157190792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
157290792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
157390792Sgshapirodnl found SKIP: return <default> and <passthru>
157490792Sgshapirodnl      1    2    3  4    5
157590792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
157690792Sgshapiroifdef(`NO_NETINET6', `dnl',
157790792Sgshapiro`dnl no match; IPv6: remove last part
157890792Sgshapirodnl   1   2    3    4  5    6
157990792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
158090792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
158164562Sgshapirodnl no match; IPv4: remove last part
158290792Sgshapirodnl   1  2    3    4  5    6
158390792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
158464562Sgshapirodnl no match: return default
158590792Sgshapirodnl   1    2    3  4    5
158690792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
158790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
158890792Sgshapirodnl            2    3    4  5    6
158990792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
159064562Sgshapirodnl match: return result
159190792Sgshapirodnl    2    3    4  5    6
159290792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
159390792Sgshapirodnl endif _ACCESS_TABLE_
159490792Sgshapirodivert(0)
159538032Speter######################################################################
159642575Speter###  CanonAddr --	Convert an address into a standard form for
159742575Speter###			relay checking.  Route address syntax is
159842575Speter###			crudely converted into a %-hack address.
159942575Speter###
160042575Speter###	Parameters:
160142575Speter###		$1 -- full recipient address
160242575Speter###
160342575Speter###	Returns:
160442575Speter###		parsed address, not in source route form
160564562Sgshapirodnl		user%host%host<@domain>
160664562Sgshapirodnl		host!user<@domain>
160742575Speter######################################################################
160842575Speter
160942575SpeterSCanonAddr
161064562SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
161164562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
161242575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
161342575SpeterR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
161442575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
161564562Sgshapirodnl')
161642575Speter
161742575Speter######################################################################
161838032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
161938032Speter###			$* $=m or the access database.
162038032Speter###			Check user portion for host separators.
162138032Speter###
162238032Speter###	Parameters:
162338032Speter###		$1 -- full recipient address
162438032Speter###
162538032Speter###	Returns:
162638032Speter###		parsed, non-local-relaying address
162738032Speter######################################################################
162838032Speter
162938032SpeterSParseRecipient
163064562Sgshapirodnl mark and canonify address
163142575SpeterR$*				$: <?> $>CanonAddr $1
163264562Sgshapirodnl workspace: <?> localpart<@domain[.]>
163342575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
163464562Sgshapirodnl workspace: <?> localpart<@domain>
163542575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
163638032Speter
163738032Speter# if no $=O character, no host in the user portion, we are done
163842575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
163964562Sgshapirodnl no $=O in localpart: return
164042575SpeterR<?> $*				$@ $1
164138032Speter
164290792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O
164364562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
164438032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
164538032Speter# if we relay, check username portion for user%host so host can be checked also
164642575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
164764562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
164864562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
164990792Sgshapiro
165090792Sgshapirodnl what if access map returns something else than RELAY?
165190792Sgshapirodnl we are only interested in RELAY entries...
165290792Sgshapirodnl other To: entries: blacklist recipient; generic entries?
165390792Sgshapirodnl if it is an error we probably do not want to relay anyway
165438032Speterifdef(`_RELAY_HOSTS_ONLY_',
165542575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
165664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
165764562SgshapiroR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
165842575SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
165942575Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
166064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
166190792SgshapiroR<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
166242575SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
166338032Speter
166464562Sgshapiro
166590792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl
166690792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
166790792SgshapiroR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
166890792SgshapiroR<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
166990792Sgshapirodnl yes: mark it as <RELAY>
167090792SgshapiroR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
167190792Sgshapirodnl no: put old <NO> mark back
167290792SgshapiroR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
167390792Sgshapiro
167490792Sgshapirodnl do we relay to this recipient domain?
167542575SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
167690792Sgshapirodnl something else
167790792SgshapiroR<$+> $*			$@ $2
167842575Speter
167964562Sgshapiro
168038032Speter######################################################################
168138032Speter###  check_relay -- check hostname/address on SMTP startup
168238032Speter######################################################################
168338032Speter
168438032SpeterSLocal_check_relay
168564562SgshapiroScheck`'_U_`'relay
168638032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
168738032SpeterR$* $| $* $| $#$*	$#$3
168838032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
168938032Speter
169038032SpeterSBasic_check_relay
169138032Speter# check for deferred delivery mode
169298121SgshapiroR$*			$: < $&{deliveryMode} > $1
169338032SpeterR< d > $*		$@ deferred
169438032SpeterR< $* > $*		$: $2
169538032Speter
169664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
169766494Sgshapirodnl workspace: {client_name} $| {client_addr}
169890792SgshapiroR$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
169966494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
170090792SgshapiroR<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
170190792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>)
170290792SgshapiroR<?> <$*>		$: OK				found nothing
170390792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
170490792SgshapiroR<$={Accept}> <$*>	$@ $1				return value of lookup
170590792SgshapiroR<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
170690792SgshapiroR<DISCARD> <$*>		$#discard $: discard
170790792Sgshapiroifdef(`_FFR_QUARANTINE',
170890792Sgshapiro`R<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1', `dnl')
170964562Sgshapirodnl error tag
171066494SgshapiroR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
171166494SgshapiroR<ERROR:$+> <$*>		$#error $: $1
171290792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
171364562Sgshapirodnl generic error from access map
171466494SgshapiroR<$+> <$*>		$#error $: $1', `dnl')
171538032Speter
171664562Sgshapiroifdef(`_RBL_',`dnl
171764562Sgshapiro# DNS based IP address spam list
171890792Sgshapirodnl workspace: ignored...
171938032SpeterR$*			$: $&{client_addr}
172064562SgshapiroR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
172164562SgshapiroR<?>OK			$: OKSOFAR
172298121SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"',
172338032Speter`dnl')
172464562Sgshapiroundivert(8)
172538032Speter
172638032Speter######################################################################
172738032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
172838032Speter######################################################################
172938032Speter
173038032SpeterSLocal_check_mail
173164562SgshapiroScheck`'_U_`'mail
173238032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
173338032SpeterR$* $| $#$*		$#$2
173438032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
173538032Speter
173638032SpeterSBasic_check_mail
173738032Speter# check for deferred delivery mode
173898121SgshapiroR$*			$: < $&{deliveryMode} > $1
173938032SpeterR< d > $*		$@ deferred
174038032SpeterR< $* > $*		$: $2
174138032Speter
174264562Sgshapiro# authenticated?
174364562Sgshapirodnl done first: we can require authentication for every mail transaction
174464562Sgshapirodnl workspace: address as given by MAIL FROM: (sender)
174564562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
174664562SgshapiroR$* $| $#$+		$#$2
174764562Sgshapirodnl undo damage: remove result of tls_client call
174864562SgshapiroR$* $| $*		$: $1
174938032Speter
175064562Sgshapirodnl workspace: address as given by MAIL FROM:
175164562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
175238032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
175364562Sgshapirodnl do some additional checks
175464562Sgshapirodnl no user@host
175564562Sgshapirodnl no user@localhost (if nonlocal sender)
175664562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
175764562Sgshapirodnl just make sure the address has <> around it (which is required by
175864562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
175964562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
176064562Sgshapirodnl not be modified by host lookups.
176164562SgshapiroR$+			$: <?> $1
176264562SgshapiroR<?><$+>		$: <@> <$1>
176364562SgshapiroR<?>$+			$: <@> <$1>
176464562Sgshapirodnl workspace: <@> <address>
176564562Sgshapirodnl prepend daemon_flags
176664562SgshapiroR$*			$: $&{daemon_flags} $| $1
176764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
176864562Sgshapirodnl do not allow these at all or only from local systems?
176964562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
177064562Sgshapirodnl accept unqualified sender: change mark to avoid test
177164562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
177264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
177364562Sgshapirodnl        or:                    <? ${client_name} > <address>
177464562Sgshapirodnl        or:                    <?> <address>
177564562Sgshapirodnl remove daemon_flags
177664562SgshapiroR$* $| $*		$: $2
177738032Speter# handle case of @localhost on address
177864562SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
177964562SgshapiroR<@> < $* @ [127.0.0.1] >
178064562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
178164562SgshapiroR<@> < $* @ localhost.$m >
178264562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
178338032Speterifdef(`_NO_UUCP_', `dnl',
178464562Sgshapiro`R<@> < $* @ localhost.UUCP >
178564562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
178664562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
178764562Sgshapirodnl	or:    <@> <address>
178864562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
178964562SgshapiroR<@> $*			$: $1			no localhost as domain
179064562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
179164562Sgshapirodnl	or:    <address>
179264562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
179364562SgshapiroR<? $=w> $*		$: $2			local client: ok
179490792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
179564562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
179664562SgshapiroR<?> $*			$: $1')
179764562Sgshapirodnl workspace: address (or <address>)
179864562SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
179964562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
180064562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
180164562SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
180264562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
180364562SgshapiroR<?> $* < @ $* $=P >	$: <OK> $1 < @ $2 $3 >
180464562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
180598121Sgshapirodnl A sender address with my local host name ($j) is safe
180698121SgshapiroR<?> $* < @ $j >	$: <OK> $1 < @ $j >
180764562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
180890792Sgshapiro`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
180964562Sgshapiro`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
181064562SgshapiroR<? $* <$->> $* < @ $+ >
181164562Sgshapiro			$: <$2> $3 < @ $4 >')
181290792Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
181364562Sgshapirodnl mark is ? iff the address is user (wo @domain)
181438032Speter
181564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
181664562Sgshapiro# check sender address: user@address, user@, address
181764562Sgshapirodnl should we remove +ext from user?
181890792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
181990792SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
182064562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
182164562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
182264562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
182364562Sgshapirodnl will only return user<@domain when "reversing" the args
182490792SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
182564562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
182664562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
182764562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
182838032Speter# retransform for further use
182964562Sgshapirodnl required form:
183064562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
183164562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
183264562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
183364562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
183464562Sgshapirodnl mark is ? iff the address is user (wo @domain)
183538032Speter
183638032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
183738032Speter# handle case of no @domain on address
183864562Sgshapirodnl prepend daemon_flags
183964562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
184064562Sgshapirodnl accept unqualified sender: change mark to avoid test
184190792SgshapiroR$* u $* $| <?> $*	$: <_RES_OK_> $3
184264562Sgshapirodnl remove daemon_flags
184364562SgshapiroR$* $| $*		$: $2
184438032SpeterR<?> $*			$: < ? $&{client_name} > $1
184538032SpeterR<?> $*			$@ <OK>				...local unqualed ok
184690792SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
184738032Speter							...remote is not')
184838032Speter# check results
184964562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
185090792SgshapiroR<$={ResOk}> $*		$@ <_RES_OK_>	domain ok: stop
185164562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
185290792SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
185364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
185490792SgshapiroR<$={Accept}> $*	$# $1		accept from access map
185538032SpeterR<DISCARD> $*		$#discard $: discard
185690792Sgshapiroifdef(`_FFR_QUARANTINE',
185790792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
185864562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
185964562Sgshapirodnl error tag
186064562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
186164562SgshapiroR<ERROR:$+> $*		$#error $: $1
186290792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
186364562Sgshapirodnl generic error from access map
186464562SgshapiroR<$+> $*		$#error $: $1		error from access db',
186538032Speter`dnl')
186638032Speter
186738032Speter######################################################################
186838032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
186938032Speter######################################################################
187038032Speter
187138032SpeterSLocal_check_rcpt
187264562SgshapiroScheck`'_U_`'rcpt
187338032SpeterR$*			$: $1 $| $>"Local_check_rcpt" $1
187438032SpeterR$* $| $#$*		$#$2
187538032SpeterR$* $| $*		$@ $>"Basic_check_rcpt" $1
187638032Speter
187738032SpeterSBasic_check_rcpt
187890792Sgshapiro# empty address?
187990792SgshapiroR<>			$#error $@ nouser $: "553 User address required"
188090792SgshapiroR$@			$#error $@ nouser $: "553 User address required"
188138032Speter# check for deferred delivery mode
188298121SgshapiroR$*			$: < $&{deliveryMode} > $1
188338032SpeterR< d > $*		$@ deferred
188438032SpeterR< $* > $*		$: $2
188538032Speter
188664562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
188790792Sgshapirodnl this code checks for user@host where host is not a FQHN.
188890792Sgshapirodnl it is not activated.
188990792Sgshapirodnl notice: code to check for a recipient without a domain name is
189090792Sgshapirodnl available down below; look for the same macro.
189190792Sgshapirodnl this check is done here because the name might be qualified by the
189290792Sgshapirodnl canonicalization.
189390792Sgshapiro# require fully qualified domain part?
189490792Sgshapirodnl very simple canonification: make sure the address is in < >
189564562SgshapiroR$+			$: <?> $1
189690792SgshapiroR<?> <$+>		$: <@> <$1>
189790792SgshapiroR<?> $+			$: <@> <$1>
189890792SgshapiroR<@> < postmaster >	$: postmaster
189990792SgshapiroR<@> < $* @ $+ . $+ >	$: < $3 @ $4 . $5 >
190064562Sgshapirodnl prepend daemon_flags
190190792SgshapiroR<@> $*			$: $&{daemon_flags} $| <@> $1
190264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
190364562Sgshapirodnl do not allow these at all or only from local systems?
190490792SgshapiroR$* r $* $| <@> < $* @ $* >	$: < ? $&{client_name} > < $3 @ $4 >
190564562SgshapiroR<?> < $* >		$: <$1>
190664562SgshapiroR<? $=w> < $* >		$: <$1>
190790792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
190864562Sgshapirodnl remove daemon_flags for other cases
190964562SgshapiroR$* $| <@> $*		$: $2', `dnl')
191064562Sgshapiro
191190792Sgshapirodnl ##################################################################
191290792Sgshapirodnl call subroutines for recipient and relay
191390792Sgshapirodnl possible returns from subroutines:
191490792Sgshapirodnl $#TEMP	temporary failure
191590792Sgshapirodnl $#error	permanent failure (or temporary if from access map)
191690792Sgshapirodnl $#other	stop processing
191790792Sgshapirodnl RELAY	RELAYing allowed
191890792Sgshapirodnl other	otherwise
191990792Sgshapiro######################################################################
192090792SgshapiroR$*			$: $1 $| @ $>"Rcpt_ok" $1
192190792Sgshapirodnl temporary failure? remove mark @ and remember
192290792SgshapiroR$* $| @ $#TEMP $+	$: $1 $| T $2
192390792Sgshapirodnl error or ok (stop)
192490792SgshapiroR$* $| @ $#$*		$#$2
192590792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
192690792SgshapiroR$* $| @ RELAY		$@ RELAY
192790792Sgshapirodnl something else: call check sender (relay)
192890792SgshapiroR$* $| @ $*		$: O $| $>"Relay_ok" $1
192990792Sgshapirodnl temporary failure: call check sender (relay)
193090792SgshapiroR$* $| T $+		$: T $2 $| $>"Relay_ok" $1
193190792Sgshapirodnl temporary failure? return that
193290792SgshapiroR$* $| $#TEMP $+	$#error $2
193390792Sgshapirodnl error or ok (stop)
193490792SgshapiroR$* $| $#$*		$#$2
193590792SgshapiroR$* $| RELAY		$@ RELAY
193690792Sgshapirodnl something else: return previous temp failure
193790792SgshapiroR T $+ $| $*		$#error $1
193890792Sgshapiro# anything else is bogus
193990792SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
194090792Sgshapirodivert(0)
194190792Sgshapiro
194290792Sgshapiro######################################################################
194390792Sgshapiro### Rcpt_ok: is the recipient ok?
194490792Sgshapirodnl input: recipient address (RCPT TO)
194590792Sgshapirodnl output: see explanation at call
194690792Sgshapiro######################################################################
194790792SgshapiroSRcpt_ok
194838032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
194942575SpeterR$*			$: $>CanonAddr $1
195038032SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
195138032Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
195238032Speter
195342575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
195442575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
195542575Speter# unlimited bestmx
195642575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
195742575Speter`dnl
195842575Speter# limit bestmx to $=B
195943730SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
196090792SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
196142575SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
196242575SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
196342575Speter
196438032Speterifdef(`_BLACKLIST_RCPT_',`dnl
196564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
196638032Speter# blacklist local users or any host from receiving mail
196738032SpeterR$*			$: <?> $1
196864562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
196964562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
197090792SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
197190792SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
197264562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
197364562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
197464562Sgshapirodnl will only return user<@domain when "reversing" the args
197590792SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
197664562SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
197764562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
197890792Sgshapirodnl we may have to filter here because otherwise some RHSs
197990792Sgshapirodnl would be interpreted as generic error messages...
198090792Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
198190792Sgshapirodnl that would make a lot of things easier.
198264562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
198390792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
198490792SgshapiroR<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
198590792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
198690792Sgshapirodnl compatility with 8.11/8.10:
198764562Sgshapirodnl we have to filter these because otherwise they would be interpreted
198864562Sgshapirodnl as generic error message...
198964562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
199064562Sgshapirodnl that would make a lot of things easier.
199164562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
199264562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
199390792SgshapiroR<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
199464562SgshapiroR<DISCARD> $*		$#discard $: discard
199590792Sgshapiroifdef(`_FFR_QUARANTINE',
199690792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
199764562Sgshapirodnl error tag
199864562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
199964562SgshapiroR<ERROR:$+> $*		$#error $: $1
200090792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
200164562Sgshapirodnl generic error from access map
200264562SgshapiroR<$+> $*		$#error $: $1		error from access db
200364562SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
200438032Speter
200590792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
200690792Sgshapiro# authenticated via TLS?
200790792SgshapiroR$*			$: $1 $| $>RelayTLS	client authenticated?
200890792SgshapiroR$* $| $# $+		$# $2			error/ok?
200990792SgshapiroR$* $| $*		$: $1			no
201064562Sgshapiro
201190792SgshapiroR$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
201290792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth
201390792SgshapiroR$* $| $# $*		$# $2
201490792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
201590792SgshapiroR$* $| NO		$: $1
201690792SgshapiroR$* $| $*		$: $1 $| $&{auth_type}
201790792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ]
201864562Sgshapirodnl empty ${auth_type}?
201964562SgshapiroR$* $|			$: $1
202064562Sgshapirodnl mechanism ${auth_type} accepted?
202164562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
202290792SgshapiroR$* $| $={TrustAuthMech}	$# RELAY
202390792Sgshapirodnl remove ${auth_type}
202464562SgshapiroR$* $| $*		$: $1
202571345Sgshapirodnl workspace: localpart<@domain> | localpart
202664562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
202771345Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
202871345SgshapiroR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
202938032Speter# anything terminating locally is ok
203038032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
203190792SgshapiroR$+ < @ $* $=m >	$@ RELAY', `dnl')
203290792SgshapiroR$+ < @ $=w >		$@ RELAY
203338032Speterifdef(`_RELAY_HOSTS_ONLY_',
203490792Sgshapiro`R$+ < @ $=R >		$@ RELAY
203564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
203664562SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
203764562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
203864562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
203990792Sgshapiro`R$+ < @ $* $=R >	$@ RELAY
204064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
204190792SgshapiroR$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')')
204264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
204364562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
204490792SgshapiroR<RELAY> $*		$@ RELAY
204590792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
204638032SpeterR<$*> <$*>		$: $2',`dnl')
204738032Speter
204864562Sgshapiro
204938032Speterifdef(`_RELAY_MX_SERVED_', `dnl
205038032Speter# allow relaying for hosts which we MX serve
205164562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
205264562Sgshapirodnl this must not necessarily happen if the client is checked first...
205390792SgshapiroR< : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
205490792SgshapiroR<$* : $=w . : $*> $*	$@ RELAY
205542575SpeterR< : $* : > $*		$: $2',
205638032Speter`dnl')
205738032Speter
205838032Speter# check for local user (i.e. unqualified address)
205938032SpeterR$*			$: <?> $1
206042575SpeterR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
206138032Speter# local user is ok
206264562Sgshapirodnl is it really? the standard requires user@domain, not just user
206364562Sgshapirodnl but we should accept it anyway (maybe making it an option:
206464562Sgshapirodnl RequireFQDN ?)
206564562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
206664562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
206790792SgshapiroR<?> postmaster		$@ OK
206864562Sgshapiro# require qualified recipient?
206964562Sgshapirodnl prepend daemon_flags
207064562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
207164562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
207264562Sgshapirodnl do not allow these at all or only from local systems?
207364562Sgshapirodnl r flag? add client_name
207464562SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
207564562Sgshapirodnl no r flag: relay to local user (only local part)
207664562Sgshapiro# no qualified recipient required
207790792SgshapiroR$* $| <?> $+		$@ RELAY
207864562Sgshapirodnl client_name is empty
207990792SgshapiroR<?> <?> $+		$@ RELAY
208064562Sgshapirodnl client_name is local
208190792SgshapiroR<? $=w> <?> $+		$@ RELAY
208264562Sgshapirodnl client_name is not local
208364562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
208464562Sgshapirodnl no qualified recipient required
208590792SgshapiroR<?> $+			$@ RELAY')
208664562Sgshapirodnl it is a remote user: remove mark and then check client
208738032SpeterR<$+> $*		$: $2
208864562Sgshapirodnl currently the recipient address is not used below
208938032Speter
209090792Sgshapiro######################################################################
209190792Sgshapiro### Relay_ok: is the relay/sender ok?
209290792Sgshapirodnl input: ignored
209390792Sgshapirodnl output: see explanation at call
209490792Sgshapiro######################################################################
209590792SgshapiroSRelay_ok
209638032Speter# anything originating locally is ok
209764562Sgshapiro# check IP address
209864562SgshapiroR$*			$: $&{client_addr}
209990792SgshapiroR$@			$@ RELAY		originated locally
210090792SgshapiroR0			$@ RELAY		originated locally
210190792SgshapiroR$=R $*			$@ RELAY		relayable IP address
210264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
210390792SgshapiroR$*			$: $>A <$1> <?> <+ Connect> <$1>
210490792SgshapiroR<RELAY> $* 		$@ RELAY		relayable IP address
210598121SgshapiroR<REJECT> $* 		$@ REJECT		rejected IP address
210690792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
210764562SgshapiroR<$*> <$*>		$: $2', `dnl')
210864562SgshapiroR$*			$: [ $1 ]		put brackets around it...
210990792SgshapiroR$=w			$@ RELAY		... and see if it is local
211064562Sgshapiro
211164562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
211264562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
211364562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
211464562Sgshapirodnl input: {client_addr} or something "broken"
211564562Sgshapirodnl just throw the input away; we do not need it.
211664562Sgshapiro# check whether FROM is allowed to use system as relay
211764562SgshapiroR$*			$: <?> $>CanonAddr $&f
211890792SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
211964562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
212064562Sgshapiro# check whether local FROM is ok
212190792SgshapiroR<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
212264562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
212394334SgshapiroR<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <>
212490792SgshapiroR<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
212590792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
212690792Sgshapiro', `dnl
212790792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_',
212890792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
212964562Sgshapiro')',
213064562Sgshapiro`dnl')
213164562Sgshapirodnl')', `dnl')
213290792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind.
213390792Sgshapirodnl it does not matter in this case because the following rule ignores
213490792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace.
213564562Sgshapiro
213664562Sgshapiro# check client name: first: did it resolve?
213764562Sgshapirodnl input: ignored
213864562SgshapiroR$*			$: < $&{client_resolve} >
213990792SgshapiroR<TEMP>			$#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
214064562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
214164562SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
214264562Sgshapirodnl ${client_resolve} should be OK, so go ahead
214390792SgshapiroR$*			$: <@> $&{client_name}
214490792Sgshapirodnl should not be necessary since it has been done for client_addr already
214590792SgshapiroR<@>			$@ RELAY
214690792Sgshapirodnl workspace: <@> ${client_name} (not empty)
214738032Speter# pass to name server to make hostname canonical
214890792SgshapiroR<@> $* $=P 		$:<?>  $1 $2
214990792SgshapiroR<@> $+			$:<?>  $[ $1 $]
215090792Sgshapirodnl workspace: <?> ${client_name} (canonified)
215164562SgshapiroR$* .			$1			strip trailing dots
215238032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
215390792SgshapiroR<?> $* $=m		$@ RELAY', `dnl')
215490792SgshapiroR<?> $=w		$@ RELAY
215538032Speterifdef(`_RELAY_HOSTS_ONLY_',
215690792Sgshapiro`R<?> $=R		$@ RELAY
215764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
215864562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
215964562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
216090792Sgshapiro`R<?> $* $=R			$@ RELAY
216164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
216290792SgshapiroR<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
216364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
216490792SgshapiroR<RELAY> $*		$@ RELAY
216590792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
216638032SpeterR<$*> <$*>		$: $2',`dnl')
216790792Sgshapirodnl end of _PROMISCUOUS_RELAY_
216864562Sgshapirodivert(0)
216964562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
217064562Sgshapiro# turn a canonical address in the form user<@domain>
217164562Sgshapiro# qualify unqual. addresses with $j
217264562Sgshapirodnl it might have been only user (without <@domain>)
217364562SgshapiroSFullAddr
217464562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
217564562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
217664562SgshapiroR$+			$@ $1 <@ $j >
217738032Speter
217864562Sgshapiro# call all necessary rulesets
217964562SgshapiroScheck_rcpt
218064562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
218164562Sgshapirodnl which is the correct DSN code?
218264562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
218364562SgshapiroR$+			$: $1 $| $>checkrcpt $1
218464562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
218564562SgshapiroR$+ $| $#$*		$#$2
218664562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
218764562Sgshapiroifdef(`_SPAM_FH_',
218864562Sgshapiro`dnl lookup user@ and user@address
218964562Sgshapiroifdef(`_ACCESS_TABLE_', `',
219064562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
219164562Sgshapiro')')dnl
219264562Sgshapirodnl one of the next two rules is supposed to match
219364562Sgshapirodnl this code has been copied from BLACKLIST... etc
219464562Sgshapirodnl and simplified by omitting some < >.
219590792SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
219690792SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
219764562Sgshapirodnl R<?>		$@ something_is_very_wrong_here
219890792Sgshapiro# lookup the addresses only with Spam tag
219990792SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
220064562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
220164562Sgshapirodnl', `dnl')
220264562Sgshapiroifdef(`_SPAM_FRIEND_',
220364562Sgshapiro`# is the recipient a spam friend?
220464562Sgshapiroifdef(`_SPAM_HATER_',
220564562Sgshapiro	`errprint(`*** ERROR: define either SpamHater or SpamFriend
220664562Sgshapiro')', `dnl')
220790792SgshapiroR<FRIEND> $+		$@ SPAMFRIEND
220864562SgshapiroR<$*> $+		$: $2',
220964562Sgshapiro`dnl')
221064562Sgshapiroifdef(`_SPAM_HATER_',
221164562Sgshapiro`# is the recipient no spam hater?
221290792SgshapiroR<HATER> $+		$: $1			spam hater: continue checks
221364562SgshapiroR<$*> $+		$@ NOSPAMHATER		everyone else: stop
221464562Sgshapirodnl',`dnl')
221564562Sgshapirodnl run further checks: check_mail
221664562Sgshapirodnl should we "clean up" $&f?
221790792Sgshapiroifdef(`_FFR_MAIL_MACRO',
221890792Sgshapiro`R$*			$: $1 $| $>checkmail $&{mail_from}',
221990792Sgshapiro`R$*			$: $1 $| $>checkmail <$&f>')
222094334Sgshapirodnl recipient (canonical format) $| result of checkmail
222164562SgshapiroR$* $| $#$*		$#$2
222264562Sgshapirodnl run further checks: check_relay
222394334SgshapiroR$* $| $*		$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
222464562SgshapiroR$* $| $#$*		$#$2
222538032SpeterR$* $| $*		$: $1
222638032Speter', `dnl')
222790792Sgshapiro
222890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
222964562Sgshapiro######################################################################
223090792Sgshapiro###  F: LookUpFull -- search for an entry in access database
223190792Sgshapiro###
223290792Sgshapiro###	lookup of full key (which should be an address) and
223390792Sgshapiro###	variations if +detail exists: +* and without +detail
223490792Sgshapiro###
223590792Sgshapiro###	Parameters:
223690792Sgshapiro###		<$1> -- key
223790792Sgshapiro###		<$2> -- default (what to return if not found in db)
223890792Sgshapirodnl			must not be empty
223990792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
224090792Sgshapiro###			! does lookup only with tag
224190792Sgshapiro###			+ does lookup with and without tag
224290792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
224390792Sgshapirodnl returns:		<default> <passthru>
224490792Sgshapirodnl 			<result> <passthru>
224590792Sgshapiro######################################################################
224690792Sgshapiro
224790792SgshapiroSF
224890792Sgshapirodnl workspace: <key> <def> <o tag> <thru>
224990792Sgshapirodnl full lookup
225090792Sgshapirodnl    2    3  4    5
225190792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
225290792Sgshapirodnl no match, try without tag
225390792Sgshapirodnl   1    2      3    4
225490792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
225590792Sgshapirodnl no match, +detail: try +*
225690792Sgshapirodnl   1    2    3    4    5  6    7
225790792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
225890792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
225990792Sgshapirodnl no match, +detail: try +* without tag
226090792Sgshapirodnl   1    2    3    4      5    6
226190792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
226290792Sgshapiro			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
226390792Sgshapirodnl no match, +detail: try without +detail
226490792Sgshapirodnl   1    2    3    4    5  6    7
226590792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
226690792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
226790792Sgshapirodnl no match, +detail: try without +detail and without tag
226890792Sgshapirodnl   1    2    3    4      5    6
226990792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
227090792Sgshapiro			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
227190792Sgshapirodnl no match, return <default> <passthru>
227290792Sgshapirodnl   1    2    3  4    5
227390792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
227490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
227590792Sgshapirodnl            2    3  4    5
227690792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
227790792Sgshapirodnl match, return <match> <passthru>
227890792Sgshapirodnl    2    3  4    5
227990792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
228090792Sgshapiro
228190792Sgshapiro######################################################################
228290792Sgshapiro###  E: LookUpExact -- search for an entry in access database
228390792Sgshapiro###
228490792Sgshapiro###	Parameters:
228590792Sgshapiro###		<$1> -- key
228690792Sgshapiro###		<$2> -- default (what to return if not found in db)
228790792Sgshapirodnl			must not be empty
228890792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
228990792Sgshapiro###			! does lookup only with tag
229090792Sgshapiro###			+ does lookup with and without tag
229190792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
229290792Sgshapirodnl returns:		<default> <passthru>
229390792Sgshapirodnl 			<result> <passthru>
229490792Sgshapiro######################################################################
229590792Sgshapiro
229690792SgshapiroSE
229790792Sgshapirodnl    2    3  4    5
229890792SgshapiroR<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
229990792Sgshapirodnl no match, try without tag
230090792Sgshapirodnl   1    2      3    4
230190792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
230290792Sgshapirodnl no match, return default passthru
230390792Sgshapirodnl   1    2    3  4    5
230490792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
230590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
230690792Sgshapirodnl            2    3  4    5
230790792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
230890792Sgshapirodnl match, return <match> <passthru>
230990792Sgshapirodnl    2    3  4    5
231090792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
231190792Sgshapiro
231290792Sgshapiro######################################################################
231390792Sgshapiro###  U: LookUpUser -- search for an entry in access database
231490792Sgshapiro###
231590792Sgshapiro###	lookup of key (which should be a local part) and
231690792Sgshapiro###	variations if +detail exists: +* and without +detail
231790792Sgshapiro###
231890792Sgshapiro###	Parameters:
231990792Sgshapiro###		<$1> -- key (user@)
232090792Sgshapiro###		<$2> -- default (what to return if not found in db)
232190792Sgshapirodnl			must not be empty
232290792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
232390792Sgshapiro###			! does lookup only with tag
232490792Sgshapiro###			+ does lookup with and without tag
232590792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
232690792Sgshapirodnl returns:		<default> <passthru>
232790792Sgshapirodnl 			<result> <passthru>
232890792Sgshapiro######################################################################
232990792Sgshapiro
233090792SgshapiroSU
233190792Sgshapirodnl user lookups are always with trailing @
233290792Sgshapirodnl    2    3  4    5
233390792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
233490792Sgshapirodnl no match, try without tag
233590792Sgshapirodnl   1    2      3    4
233690792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
233790792Sgshapirodnl do not remove the @ from the lookup:
233890792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
233990792Sgshapirodnl no match, +detail: try +*
234090792Sgshapirodnl   1    2      3    4  5    6
234190792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
234290792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
234390792Sgshapirodnl no match, +detail: try +* without tag
234490792Sgshapirodnl   1    2      3      4    5
234590792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
234690792Sgshapiro			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
234790792Sgshapirodnl no match, +detail: try without +detail
234890792Sgshapirodnl   1    2      3    4  5    6
234990792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
235090792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
235190792Sgshapirodnl no match, +detail: try without +detail and without tag
235290792Sgshapirodnl   1    2      3      4    5
235390792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
235490792Sgshapiro			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
235590792Sgshapirodnl no match, return <default> <passthru>
235690792Sgshapirodnl   1    2    3  4    5
235790792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
235890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
235990792Sgshapirodnl            2    3  4    5
236090792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
236190792Sgshapirodnl match, return <match> <passthru>
236290792Sgshapirodnl    2    3  4    5
236390792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
236490792Sgshapiro
236590792Sgshapiro######################################################################
236664562Sgshapiro###  SearchList: search a list of items in the access map
236764562Sgshapiro###	Parameters:
236864562Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
236964562Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
237064562Sgshapirodnl	avoid errorneous matches (with error messages?)
237164562Sgshapirodnl	if we can make sure that tag is always a single token
237264562Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
237390792Sgshapirodnl	to avoid errorneous matchs (first rule: D: if there
237464562Sgshapirodnl	is that mark somewhere in the list, it will be taken).
237564562Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
237664562Sgshapirodnl	the tag only, e.g.:
237764562Sgshapiro###	where "exact" is either "+" or "!":
237864562Sgshapiro###	<+ TAG>	lookup with and w/o tag
237964562Sgshapiro###	<! TAG>	lookup with tag
238064562Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
238164562Sgshapirodnl		a blank between them and the tag.
238264562Sgshapiro###	possible values for "mark" are:
238390792Sgshapiro###		D: recursive host lookup (LookUpDomain)
238464562Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
238564562Sgshapiro###		E: exact lookup, no modifications
238664562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
238764562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
238864562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
238964562Sgshapiro######################################################################
239038032Speter
239164562Sgshapiro# class with valid marks for SearchList
239264562Sgshapirodnl if A is activated: add it
239390792SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
239464562SgshapiroSSearchList
239590792Sgshapiro# just call the ruleset with the name of the tag... nice trick...
239690792Sgshapirodnl       2       3    4
239790792SgshapiroR<$+> $| <$={src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
239890792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <>
239990792Sgshapirodnl no match and nothing left: return
240090792SgshapiroR<$+> $| <> $| <?> <>		$@ <?>
240190792Sgshapirodnl no match but something left: continue
240290792SgshapiroR<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
240390792Sgshapirodnl match: return
240490792SgshapiroR<$+> $| <$*> $| <$+> <>	$@ <$3>
240564562Sgshapirodnl return result from recursive invocation
240690792SgshapiroR<$+> $| <$+>			$@ <$2>
240790792Sgshapirodnl endif _ACCESS_TABLE_
240890792Sgshapirodivert(0)
240938032Speter
241090792Sgshapiro######################################################################
241190792Sgshapiro###  trust_auth: is user trusted to authenticate as someone else?
241290792Sgshapiro###
241390792Sgshapiro###	Parameters:
241490792Sgshapiro###		$1: AUTH= parameter from MAIL command
241590792Sgshapiro######################################################################
241690792Sgshapiro
241790792Sgshapirodnl empty ruleset definition so it can be called
241890792SgshapiroSLocal_trust_auth
241964562SgshapiroStrust_auth
242064562SgshapiroR$*			$: $&{auth_type} $| $1
242164562Sgshapiro# required by RFC 2554 section 4.
242264562SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
242364562Sgshapirodnl seems to be useful...
242464562SgshapiroR$* $| $&{auth_authen}		$@ identical
242564562SgshapiroR$* $| <$&{auth_authen}>	$@ identical
242664562Sgshapirodnl call user supplied code
242764562SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $1
242864562SgshapiroR$* $| $#$*		$#$2
242964562Sgshapirodnl default: error
243064562SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
243164562Sgshapiro
243290792Sgshapiro######################################################################
243390792Sgshapiro###  Relay_Auth: allow relaying based on authentication?
243490792Sgshapiro###
243590792Sgshapiro###	Parameters:
243690792Sgshapiro###		$1: ${auth_type}
243790792Sgshapiro######################################################################
243890792SgshapiroSLocal_Relay_Auth
243964562Sgshapiro
244090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
244190792Sgshapiro######################################################################
244290792Sgshapiro###  srv_features: which features to offer to a client?
244390792Sgshapiro###	(done in server)
244490792Sgshapiro######################################################################
244590792SgshapiroSsrv_features
244690792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl
244790792SgshapiroR$*			$: $1 $| $>"Local_srv_features" $1
244890792SgshapiroR$* $| $#$*		$#$2
244990792SgshapiroR$* $| $*		$: $1', `dnl')
245090792SgshapiroR$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
245190792SgshapiroR<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
245290792SgshapiroR<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
245364562SgshapiroR<?>$*		$@ OK
245490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
245590792SgshapiroR<$* _ATMPF_>$*	$#temp', `dnl')
245690792SgshapiroR<$+>$*		$# $1
245764562Sgshapiro
245890792Sgshapiro######################################################################
245990792Sgshapiro###  try_tls: try to use STARTTLS?
246090792Sgshapiro###	(done in client)
246190792Sgshapiro######################################################################
246264562SgshapiroStry_tls
246390792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl
246490792SgshapiroR$*			$: $1 $| $>"Local_try_tls" $1
246590792SgshapiroR$* $| $#$*		$#$2
246690792SgshapiroR$* $| $*		$: $1', `dnl')
246790792SgshapiroR$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
246890792SgshapiroR<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
246990792SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
247064562SgshapiroR<?>$*		$@ OK
247190792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
247290792SgshapiroR<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
247371345SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
247490792Sgshapiro  
247590792Sgshapiro######################################################################
247690792Sgshapiro###  tls_rcpt: is connection with server "good" enough?
247790792Sgshapiro###	(done in client, per recipient)
247890792Sgshapirodnl called from deliver() before RCPT command
247990792Sgshapiro###
248090792Sgshapiro###	Parameters:
248190792Sgshapiro###		$1: recipient
248290792Sgshapiro######################################################################
248390792SgshapiroStls_rcpt
248490792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl
248590792SgshapiroR$*			$: $1 $| $>"Local_tls_rcpt" $1
248690792SgshapiroR$* $| $#$*		$#$2
248790792SgshapiroR$* $| $*		$: $1', `dnl')
248890792Sgshapirodnl store name of other side
248990792SgshapiroR$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
249090792Sgshapirodnl canonify recipient address
249190792SgshapiroR$+			$: <?> $>CanonAddr $1
249290792Sgshapirodnl strip trailing dots
249390792SgshapiroR<?> $+ < @ $+ . >	<?> $1 <@ $2 >
249490792Sgshapirodnl full address?
249590792SgshapiroR<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
249690792Sgshapirodnl only localpart?
249790792SgshapiroR<?> $+			$: $1 $| <U:$1@> <E:>
249890792Sgshapirodnl look it up
249990792Sgshapirodnl also look up a default value via E:
250090792SgshapiroR$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
250190792Sgshapirodnl found nothing: stop here
250290792SgshapiroR$* $| <?>	$@ OK
250390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
250490792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
250590792Sgshapirodnl use the generic routine (for now)
250690792SgshapiroR$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
250764562Sgshapiro
250890792Sgshapiro######################################################################
250990792Sgshapiro###  tls_client: is connection with client "good" enough?
251090792Sgshapiro###	(done in server)
251190792Sgshapiro###
251290792Sgshapiro###	Parameters:
251390792Sgshapiro###		${verify} $| (MAIL|STARTTLS)
251490792Sgshapiro######################################################################
251564562Sgshapirodnl MAIL: called from check_mail
251664562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
251764562SgshapiroStls_client
251890792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl
251990792SgshapiroR$*			$: $1 $| $>"Local_tls_client" $1
252090792SgshapiroR$* $| $#$*		$#$2
252190792SgshapiroR$* $| $*		$: $1', `dnl')
252264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
252390792Sgshapirodnl store name of other side
252490792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
252564562Sgshapirodnl ignore second arg for now
252664562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
252764562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
252864562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
252990792SgshapiroR$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
253090792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
253164562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
253264562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
253390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
253490792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
253590792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
253690792SgshapiroR$* $| $*	$@ $>"TLS_connection" $1')
253764562Sgshapiro
253890792Sgshapiro######################################################################
253990792Sgshapiro###  tls_server: is connection with server "good" enough?
254090792Sgshapiro###	(done in client)
254190792Sgshapiro###
254290792Sgshapiro###	Parameter:
254390792Sgshapiro###		${verify}
254490792Sgshapiro######################################################################
254564562Sgshapirodnl i.e. has the server been authenticated and is encryption active?
254664562Sgshapirodnl called from deliver() after STARTTLS command
254764562SgshapiroStls_server
254890792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl
254990792SgshapiroR$*			$: $1 $| $>"Local_tls_server" $1
255090792SgshapiroR$* $| $#$*		$#$2
255190792SgshapiroR$* $| $*		$: $1', `dnl')
255264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
255390792Sgshapirodnl store name of other side
255490792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
255590792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
255690792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
255764562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
255864562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
255990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
256090792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
256190792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
256290792SgshapiroR$*		$@ $>"TLS_connection" $1')
256364562Sgshapiro
256490792Sgshapiro######################################################################
256590792Sgshapiro###  TLS_connection: is TLS connection "good" enough?
256690792Sgshapiro###
256790792Sgshapiro###	Parameters:
256864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
256990792Sgshapiro###		${verify} $| <Requirement> [<>]', `dnl
257090792Sgshapiro###		${verify}')
257190792Sgshapiro###		Requirement: RHS from access map, may be ? for none.
257290792Sgshapirodnl	syntax for Requirement:
257390792Sgshapirodnl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
257490792Sgshapirodnl	extensions: could be a list of further requirements
257590792Sgshapirodnl		for now: CN:string	{cn_subject} == string
257690792Sgshapiro######################################################################
257790792SgshapiroSTLS_connection
257890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
257990792Sgshapirodnl deal with TLS handshake failures: abort
258090792SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
258190792Sgshapirodivert(-1)')
258264562Sgshapirodnl common ruleset for tls_{client|server}
258390792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>]
258464562Sgshapirodnl remove optional <>
258564562SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
258690792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup>
258790792Sgshapiro# create the appropriate error codes
258864562Sgshapirodnl permanent or temporary error?
258964562SgshapiroR$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
259064562SgshapiroR$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
259164562Sgshapirodnl default case depends on TLS_PERM_ERR
259264562SgshapiroR$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
259390792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
259490792Sgshapiro# deal with TLS handshake failures: abort
259564562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
259664562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
259764562Sgshapirodnl use default error
259864562SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
259990792SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
260090792Sgshapirodnl separate optional requirements
260190792SgshapiroR$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
260290792SgshapiroR$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> <> $1
260390792Sgshapirodnl separate optional requirements
260490792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
260564562Sgshapirodnl some other value in access map: accept
260664562Sgshapirodnl this also allows to override the default case (if used)
260764562SgshapiroR$* $| $*			$@ OK
260864562Sgshapiro# authentication required: give appropriate error
260964562Sgshapiro# other side did authenticate (via STARTTLS)
261090792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
261164562Sgshapirodnl only verification required and it succeeded
261290792SgshapiroR<$*><VERIFY> <> OK		$@ OK
261390792Sgshapirodnl verification required and it succeeded but extensions are given
261490792Sgshapirodnl change it to <SMTP:ESC> <REQ:0>  <extensions>
261590792SgshapiroR<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
261664562Sgshapirodnl verification required + some level of encryption
261790792SgshapiroR<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
261864562Sgshapirodnl just some level of encryption required
261990792SgshapiroR<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
262090792Sgshapirodnl workspace:
262190792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
262290792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
262390792Sgshapirodnl verification required but ${verify} is not set (case 1.)
262490792SgshapiroR<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
262590792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
262690792SgshapiroR<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
262790792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
262890792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
262964562Sgshapirodnl some other value for ${verify}
263090792SgshapiroR<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
263190792Sgshapirodnl some level of encryption required: get the maximum level (case 2.)
263290792SgshapiroR<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
263364562Sgshapirodnl compare required bits with actual bits
263490792SgshapiroR<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
263590792SgshapiroR<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
263690792Sgshapirodnl strength requirements fulfilled
263790792Sgshapirodnl TLS Additional Requirements Separator
263890792Sgshapirodnl this should be something which does not appear in the extensions itself
263990792Sgshapirodnl @ could be part of a CN, DN, etc...
264090792Sgshapirodnl use < > ? those are encoded in CN, DN, ...
264190792Sgshapirodefine(`_TLS_ARS_', `++')dnl
264290792Sgshapirodnl workspace:
264390792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
264490792SgshapiroR<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
264590792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
264690792Sgshapirodnl continue: check  extensions
264790792SgshapiroR<$-:$+ _TLS_ARS_ >			$@ OK
264890792Sgshapirodnl split extensions into own list
264990792SgshapiroR<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
265090792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
265190792SgshapiroR<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
265264562Sgshapiro
265390792Sgshapiro######################################################################
265490792Sgshapiro###  TLS_req: check additional TLS requirements
265590792Sgshapiro###
265690792Sgshapiro###	Parameters: [<list> <of> <req>] $| <$-:$+>
265790792Sgshapiro###		$-: SMTP reply code
265890792Sgshapiro###		$+: Enhanced Status Code
265990792Sgshapirodnl  further requirements for this ruleset:
266090792Sgshapirodnl	name of "other side" is stored is {TLS_name} (client/server_name)
266190792Sgshapirodnl
266290792Sgshapirodnl	currently only CN[:common_name] is implemented
266390792Sgshapirodnl	right now this is only a logical AND
266490792Sgshapirodnl	i.e. all requirements must be true
266590792Sgshapirodnl	how about an OR? CN must be X or CN must be Y or ..
266690792Sgshapirodnl	use a macro to compute this as a trivial sequential
266790792Sgshapirodnl	operations (no precedences etc)?
266890792Sgshapiro######################################################################
266990792SgshapiroSTLS_req
267090792Sgshapirodnl no additional requirements: ok
267190792SgshapiroR $| $+		$@ OK
267290792Sgshapirodnl require CN: but no CN specified: use name of other side
267390792SgshapiroR<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
267490792Sgshapirodnl match, check rest
267590792SgshapiroR<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
267690792Sgshapirodnl CN does not match
267790792Sgshapirodnl  1   2      3  4
267890792SgshapiroR<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
267990792Sgshapirodnl cert subject
268090792SgshapiroR<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
268190792Sgshapirodnl CS does not match
268290792Sgshapirodnl  1   2      3  4
268390792SgshapiroR<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CERT Subject " $&{cert_subject} " does not match " $1
268490792Sgshapirodnl match, check rest
268590792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
268690792Sgshapirodnl CI does not match
268790792Sgshapirodnl  1   2      3  4
268890792SgshapiroR<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CERT Issuer " $&{cert_issuer} " does not match " $1
268990792Sgshapirodnl return from recursive call
269090792SgshapiroROK			$@ OK
269190792Sgshapiro
269290792Sgshapiro######################################################################
269390792Sgshapiro###  max: return the maximum of two values separated by :
269490792Sgshapiro###
269590792Sgshapiro###	Parameters: [$-]:[$-]
269690792Sgshapiro######################################################################
269764562SgshapiroSmax
269864562SgshapiroR:		$: 0
269964562SgshapiroR:$-		$: $1
270064562SgshapiroR$-:		$: $1
270164562SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
270264562SgshapiroRTRUE:$-:$-	$: $2
270390792SgshapiroR$-:$-:$-	$: $2
270490792Sgshapirodnl endif _ACCESS_TABLE_
270590792Sgshapirodivert(0)
270664562Sgshapiro
270790792Sgshapiro######################################################################
270890792Sgshapiro###  RelayTLS: allow relaying based on TLS authentication
270990792Sgshapiro###
271090792Sgshapiro###	Parameters:
271190792Sgshapiro###		none
271290792Sgshapiro######################################################################
271390792SgshapiroSRelayTLS
271464562Sgshapiro# authenticated?
271564562Sgshapirodnl we do not allow relaying for anyone who can present a cert
271664562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
271764562Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow
271864562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
271964562Sgshapirodnl but anyway).
272064562Sgshapirodnl so here is the trick: if the verification succeeded
272164562Sgshapirodnl we look up the cert issuer in the access map
272264562Sgshapirodnl (maybe after extracting a part with a regular expression)
272364562Sgshapirodnl if this returns RELAY we relay without further questions
272464562Sgshapirodnl if it returns SUBJECT we perform a similar check on the
272564562Sgshapirodnl cert subject.
272664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
272790792SgshapiroR$*			$: <?> $&{verify}
272890792SgshapiroR<?> OK			$: OK		authenticated: continue
272990792SgshapiroR<?> $*			$@ NO		not authenticated
273064562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
273190792SgshapiroR$*			$: $(CERTIssuer $&{cert_issuer} $)',
273290792Sgshapiro`R$*			$: $&{cert_issuer}')
273390792SgshapiroR$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
273464562Sgshapirodnl use $# to stop further checks (delay_check)
273590792SgshapiroRRELAY			$# RELAY
273664562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
273790792SgshapiroRSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
273890792Sgshapiro`RSUBJECT		$: <@> $&{cert_subject}')
273990792SgshapiroR<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
274090792SgshapiroR<@> RELAY		$# RELAY
274190792SgshapiroR$*			$: NO', `dnl')
274264562Sgshapiro
274390792Sgshapiro######################################################################
274490792Sgshapiro###  authinfo: lookup authinfo in the access map
274590792Sgshapiro###
274690792Sgshapiro###	Parameters:
274790792Sgshapiro###		$1: {server_name}
274890792Sgshapiro###		$2: {server_addr}
274990792Sgshapirodnl	both are currently ignored
275090792Sgshapirodnl if it should be done via another map, we either need to restrict
275190792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another
275290792Sgshapirodnl parameter which I want to avoid, it's quite complex already)
275390792Sgshapiro######################################################################
275490792Sgshapirodnl omit this ruleset if neither is defined?
275590792Sgshapirodnl it causes DefaultAuthInfo to be ignored
275690792Sgshapirodnl (which may be considered a good thing).
275790792SgshapiroSauthinfo
275890792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl
275990792SgshapiroR$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
276090792SgshapiroR<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
276190792SgshapiroR<?>		$: <$(authinfo AuthInfo: $: ? $)>
276290792SgshapiroR<?>		$@ no				no authinfo available
276390792SgshapiroR<$*>		$# $1
276490792Sgshapirodnl', `dnl
276590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
276690792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
276790792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
276890792SgshapiroR$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
276990792SgshapiroR$* $| <?>$*	$@ no				no authinfo available
277090792SgshapiroR$* $| <$*> <>	$# $2
277190792Sgshapirodnl', `dnl')')
277290792Sgshapiro
277364562Sgshapiroundivert(9)dnl LOCAL_RULESETS
277438032Speter#
277538032Speter######################################################################
277638032Speter######################################################################
277738032Speter#####
277864562Sgshapiro`#####			MAIL FILTER DEFINITIONS'
277964562Sgshapiro#####
278064562Sgshapiro######################################################################
278164562Sgshapiro######################################################################
278290792Sgshapiro_MAIL_FILTERS_
278364562Sgshapiro#
278464562Sgshapiro######################################################################
278564562Sgshapiro######################################################################
278664562Sgshapiro#####
278738032Speter`#####			MAILER DEFINITIONS'
278838032Speter#####
278938032Speter######################################################################
279038032Speter######################################################################
279164562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
279266494Sgshapiro
2793