proto.m4 revision 125820
138032Speterdivert(-1)
238032Speter#
3125820Sgshapiro# Copyright (c) 1998-2004 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
16125820SgshapiroVERSIONID(`$Id: proto.m4,v 8.649.2.30 2004/01/11 17:54:06 ca Exp $')
1738032Speter
1864562Sgshapiro# level CF_LEVEL config file format
1964562SgshapiroV`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley')
2038032Speterdivert(-1)
2138032Speter
2290792Sgshapirodnl if MAILER(`local') not defined: do it ourself; be nice
2390792Sgshapirodnl maybe we should issue a warning?
2490792Sgshapiroifdef(`_MAILER_local_',`', `MAILER(local)')
2590792Sgshapiro
2638032Speter# do some sanity checking
2738032Speterifdef(`__OSTYPE__',,
2864562Sgshapiro	`errprint(`*** ERROR: No system type defined (use OSTYPE macro)
2964562Sgshapiro')')
3038032Speter
3138032Speter# pick our default mailers
3238032Speterifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')')
3338032Speterifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')')
3438032Speterifdef(`confRELAY_MAILER',,
3538032Speter	`define(`confRELAY_MAILER',
3638032Speter		`ifdef(`_MAILER_smtp_', `relay',
3738032Speter			`ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')')
3838032Speterifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')')
3938032Speterdefine(`_SMTP_', `confSMTP_MAILER')dnl		for readability only
4038032Speterdefine(`_LOCAL_', `confLOCAL_MAILER')dnl	for readability only
4138032Speterdefine(`_RELAY_', `confRELAY_MAILER')dnl	for readability only
4238032Speterdefine(`_UUCP_', `confUUCP_MAILER')dnl		for readability only
4338032Speter
4438032Speter# back compatibility with old config files
4538032Speterifdef(`confDEF_GROUP_ID',
4664562Sgshapiro`errprint(`*** confDEF_GROUP_ID is obsolete.
4764562Sgshapiro    Use confDEF_USER_ID with a colon in the value instead.
4864562Sgshapiro')')
4938032Speterifdef(`confREAD_TIMEOUT',
5064562Sgshapiro`errprint(`*** confREAD_TIMEOUT is obsolete.
5164562Sgshapiro    Use individual confTO_<timeout> parameters instead.
5264562Sgshapiro')')
5338032Speterifdef(`confMESSAGE_TIMEOUT',
5438032Speter	`define(`_ARG_', index(confMESSAGE_TIMEOUT, /))
5538032Speter	 ifelse(_ARG_, -1,
5638032Speter		`define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)',
5738032Speter		`define(`confTO_QUEUERETURN',
5838032Speter			substr(confMESSAGE_TIMEOUT, 0, _ARG_))
5938032Speter		 define(`confTO_QUEUEWARN',
6038032Speter			substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')')
6138032Speterifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,,
6264562Sgshapiro`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete.
6364562Sgshapiro    Use confMAX_MESSAGE_SIZE for the second part of the value.
6464562Sgshapiro')')')
6538032Speter
6664562Sgshapiro
6764562Sgshapiro# Sanity check on ldap_routing feature
6864562Sgshapiro# If the user doesn't specify a new map, they better have given as a
6964562Sgshapiro# default LDAP specification which has the LDAP base (and most likely the host)
7064562Sgshapiroifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(`
7164562SgshapiroWARNING: Using default FEATURE(ldap_routing) map definition(s)
7264562Sgshapirowithout setting confLDAP_DEFAULT_SPEC option.
7364562Sgshapiro')')')dnl
7464562Sgshapiro
7538032Speter# clean option definitions below....
7664562Sgshapirodefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl
7738032Speter
7864562Sgshapirodnl required to "rename" the check_* rulesets...
7964562Sgshapirodefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_'))
8064562Sgshapirodnl default relaying denied message
8190792Sgshapiroifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG',
8290792Sgshapiroifdef(`_USE_AUTH_', `"550 Relaying denied. Proper authentication required."', `"550 Relaying denied"'))')
8390792Sgshapiroifdef(`confRCPTREJ_MSG', `', `define(`confRCPTREJ_MSG', `"550 Mailbox disabled for this recipient"')')
8490792Sgshapirodefine(`_CODE553', `553')
8538032Speterdivert(0)dnl
8638032Speter
8764562Sgshapiro# override file safeties - setting this option compromises system security,
8864562Sgshapiro# addressing the actual file configuration problem is preferred
8964562Sgshapiro# need to set this before any file actions are encountered in the cf file
9064562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe')
9138032Speter
9264562Sgshapiro# default LDAP map specification
9364562Sgshapiro# need to set this now before any LDAP maps are defined
9464562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost')
9564562Sgshapiro
9638032Speter##################
9738032Speter#   local info   #
9838032Speter##################
9938032Speter
10090792Sgshapiro# my LDAP cluster
10190792Sgshapiro# need to set this before any LDAP lookups are done (including classes)
10290792Sgshapiroifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m')
10390792Sgshapiro
10438032SpeterCwlocalhost
10538032Speterifdef(`USE_CW_FILE',
10638032Speter`# file containing names of hosts for which we receive email
10738032SpeterFw`'confCW_FILE',
10838032Speter	`dnl')
10938032Speter
11038032Speter# my official domain name
11138032Speter# ... `define' this only if sendmail cannot automatically determine your domain
11238032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM')
11338032Speter
114125820Sgshapiro# host/domain names ending with a token in class P are canonical
11538032SpeterCP.
11638032Speter
11738032Speterifdef(`UUCP_RELAY',
11838032Speter`# UUCP relay host
11938032SpeterDY`'UUCP_RELAY
12038032SpeterCPUUCP
12138032Speter
12238032Speter')dnl
12338032Speterifdef(`BITNET_RELAY',
12438032Speter`#  BITNET relay host
12538032SpeterDB`'BITNET_RELAY
12638032SpeterCPBITNET
12738032Speter
12838032Speter')dnl
12938032Speterifdef(`DECNET_RELAY',
13038032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl
13138032Speter# DECnet relay host
13238032SpeterDC`'DECNET_RELAY
13338032SpeterCPDECNET
13438032Speter
13538032Speter')dnl
13638032Speterifdef(`FAX_RELAY',
13738032Speter`# FAX relay host
13838032SpeterDF`'FAX_RELAY
13938032SpeterCPFAX
14038032Speter
14138032Speter')dnl
14238032Speter# "Smart" relay host (may be null)
14390792SgshapiroDS`'ifdef(`SMART_HOST', `SMART_HOST')
14438032Speter
14538032Speterifdef(`LUSER_RELAY', `dnl
14638032Speter# place to which unknown users should be forwarded
14738032SpeterKuser user -m -a<>
14838032SpeterDL`'LUSER_RELAY',
14938032Speter`dnl')
15038032Speter
15138032Speter# operators that cannot be in local usernames (i.e., network indicators)
15238032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!')
15338032Speter
15438032Speter# a class with just dot (for identifying canonical names)
15538032SpeterC..
15638032Speter
15738032Speter# a class with just a left bracket (for identifying domain literals)
15838032SpeterC[[
15938032Speter
16064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
16164562Sgshapiro# access_db acceptance class
16264562SgshapiroC{Accept}OK RELAY
16390792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
16464562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl
16564562Sgshapiro# possible access_db RHS for spam friends/haters
16664562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')',
16738032Speter`dnl')
16838032Speter
16990792Sgshapirodnl mark for "domain is ok" (resolved or accepted anyway)
17090792Sgshapirodefine(`_RES_OK_', `OKR')dnl
17138032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
17238032Speter# Resolve map (to check if a host exists in check_mail)
17390792SgshapiroKresolve host -a<_RES_OK_> -T<TEMP>')
17490792SgshapiroC{ResOk}_RES_OK_
17538032Speter
17680785Sgshapiroifdef(`_NEED_MACRO_MAP_', `dnl
17780785Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map
17880785Sgshapirodefine(`_MACRO_MAP_', `1')dnl
17980785SgshapiroKmacro macro')', `dnl')
18066494Sgshapiro
18138032Speterifdef(`confCR_FILE', `dnl
18266494Sgshapiro# Hosts for which relaying is permitted ($=R)
18338032SpeterFR`'confCR_FILE',
18438032Speter`dnl')
18538032Speter
18690792Sgshapirodefine(`TLS_SRV_TAG', `"TLS_Srv"')dnl
18790792Sgshapirodefine(`TLS_CLT_TAG', `"TLS_Clt"')dnl
18890792Sgshapirodefine(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl
18990792Sgshapirodefine(`TLS_TRY_TAG', `"Try_TLS"')dnl
19090792Sgshapirodefine(`SRV_FEAT_TAG', `"Srv_Features"')dnl
19164562Sgshapirodnl this may be useful in other contexts too
19264562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map
19364562Sgshapirodefine(`_ARITH_MAP_', `1')dnl
19464562SgshapiroKarith arith')
19564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
19690792Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map
19790792Sgshapirodefine(`_MACRO_MAP_', `1')dnl
19890792SgshapiroKmacro macro')
19990792Sgshapiro# possible values for TLS_connection in access map
20064562SgshapiroC{tls}VERIFY ENCR', `dnl')
20164562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
20264562Sgshapiro# extract relevant part from cert issuer
20364562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
20464562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
20564562Sgshapiro# extract relevant part from cert subject
20664562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
20764562Sgshapiro
20890792Sgshapiroifdef(`LOCAL_RELAY', `dnl
209110647Sgshapiro# who I send unqualified names to if `FEATURE(stickyhost)' is used
210110560Sgshapiro# (null means deliver locally)
21190792SgshapiroDR`'LOCAL_RELAY')
21238032Speter
21390792Sgshapiroifdef(`MAIL_HUB', `dnl
214110560Sgshapiro# who gets all local email traffic
215110647Sgshapiro# ($R has precedence for unqualified names if `FEATURE(stickyhost)' is used)
21690792SgshapiroDH`'MAIL_HUB')
21738032Speter
21838032Speter# dequoting map
21990792SgshapiroKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `')
22038032Speter
22138032Speterdivert(0)dnl	# end of nullclient diversion
22238032Speter# class E: names that should be exposed as from this host, even if we masquerade
22364562Sgshapiro# class L: names that should be delivered locally, even if we have a relay
22438032Speter# class M: domains that should be converted to $M
22564562Sgshapiro# class N: domains that should not be converted to $M
22638032Speter#CL root
22738032Speterundivert(5)dnl
22864562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
22938032Speter
23090792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
23138032Speter# who I masquerade as (null for no masquerading) (see also $=M)
23290792SgshapiroDM`'MASQUERADE_NAME')
23338032Speter
23438032Speter# my name for error messages
23538032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
23638032Speter
23764562Sgshapiroundivert(6)dnl LOCAL_CONFIG
23838032Speterinclude(_CF_DIR_`m4/version.m4')
23938032Speter
24038032Speter###############
24138032Speter#   Options   #
24238032Speter###############
24390792Sgshapiroifdef(`confAUTO_REBUILD',
24490792Sgshapiro`errprint(WARNING: `confAUTO_REBUILD' is no longer valid.
24590792Sgshapiro	There was a potential for a denial of service attack if this is set.
24690792Sgshapiro)')dnl
24738032Speter
24838032Speter# strip message body to 7 bits on input?
24964562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
25038032Speter
25138032Speter# 8-bit data handling
25277349Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8')
25338032Speter
25438032Speter# wait for alias file rebuild (default units: minutes)
25564562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m')
25638032Speter
25738032Speter# location of alias file
25864562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
25964562Sgshapiro
26038032Speter# minimum number of free blocks on filesystem
26164562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
26238032Speter
26338032Speter# maximum message size
26464562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000')
26538032Speter
26638032Speter# substitution for space (blank) characters
26764562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_')
26838032Speter
26938032Speter# avoid connecting to "expensive" mailers on initial submission?
27064562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
27138032Speter
27238032Speter# checkpoint queue runs after every N successful deliveries
27364562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
27438032Speter
27538032Speter# default delivery mode
27664562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
27738032Speter
27838032Speter# error message header/file
27964562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
28038032Speter
28138032Speter# error mode
28264562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print')
28338032Speter
28438032Speter# save Unix-style "From_" lines at top of header?
28564562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
28638032Speter
28790792Sgshapiro# queue file mode (qf files)
28890792Sgshapiro_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600')
28990792Sgshapiro
29038032Speter# temporary file mode
29164562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
29238032Speter
29338032Speter# match recipients against GECOS field?
29464562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
29538032Speter
29638032Speter# maximum hop count
29790792Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `25')
29838032Speter
29938032Speter# location of help file
30064562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
30138032Speter
30238032Speter# ignore dots as terminators in incoming messages?
30364562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
30438032Speter
30538032Speter# name resolver options
30664562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
30738032Speter
30838032Speter# deliver MIME-encapsulated error messages?
30964562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
31038032Speter
31138032Speter# Forward file search path
31264562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
31338032Speter
31438032Speter# open connection cache size
31564562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
31638032Speter
31738032Speter# open connection cache timeout
31864562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
31938032Speter
32038032Speter# persistent host status directory
32164562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
32238032Speter
32338032Speter# single thread deliveries (requires HostStatusDirectory)?
32464562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
32538032Speter
32638032Speter# use Errors-To: header?
32764562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
32838032Speter
32938032Speter# log level
33064562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10')
33138032Speter
33238032Speter# send to me too, even in an alias expansion?
33364562Sgshapiro_OPTION(MeToo, `confME_TOO', `True')
33438032Speter
33538032Speter# verify RHS in newaliases?
33664562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
33738032Speter
33838032Speter# default messages to old style headers if no special punctuation?
33964562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
34038032Speter
34138032Speter# SMTP daemon options
34264562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
34394334Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.
34494334Sgshapiro	Use `DAEMON_OPTIONS()'; see cf/README.
34564562Sgshapiro)'dnl
34664562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
34766494Sgshapiroifelse(defn(`_DPO_'), `',
34890792Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet
34990792SgshapiroO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
35064562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
35138032Speter
35264562Sgshapiro# SMTP client options
35390792Sgshapiroifelse(defn(`confCLIENT_OPTIONS'), `', `dnl',
35490792Sgshapiro`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid.  See cf/README for more information.
35590792Sgshapiro)'dnl
35690792Sgshapiro`CLIENT_OPTIONS(`confCLIENT_OPTIONS')')
35790792Sgshapiroifelse(defn(`_CPO_'), `',
35890792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_')
35964562Sgshapiro
36090792Sgshapiro# Modifiers to `define' {daemon_flags} for direct submissions
36190792Sgshapiro_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `')
36290792Sgshapiro
36390792Sgshapiro# Use as mail submission program? See sendmail/SECURITY
36490792Sgshapiro_OPTION(UseMSP, `confUSE_MSP', `')
36590792Sgshapiro
36638032Speter# privacy flags
36764562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
36838032Speter
36938032Speter# who (if anyone) should get extra copies of error messages
37064562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
37138032Speter
37238032Speter# slope of queue-only function
37364562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
37438032Speter
37590792Sgshapiro# limit on number of concurrent queue runners
37690792Sgshapiro_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `')
37790792Sgshapiro
37890792Sgshapiro# maximum number of queue-runners per queue-grouping with multiple queues
37990792Sgshapiro_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1')
38090792Sgshapiro
38190792Sgshapiro# priority of queue runners (nice(3))
38290792Sgshapiro_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `')
38390792Sgshapiro
38490792Sgshapiro# shall we sort the queue by hostname first?
38590792Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
38690792Sgshapiro
38790792Sgshapiro# minimum time in queue before retry
38890792Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
38990792Sgshapiro
39090792Sgshapiro# how many jobs can you process in the queue?
39190792Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
39290792Sgshapiro
39390792Sgshapiro# perform initial split of envelope without checking MX records
39490792Sgshapiro_OPTION(FastSplit, `confFAST_SPLIT', `1')
39590792Sgshapiro
39638032Speter# queue directory
39764562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
39838032Speter
39990792Sgshapiro# key for shared memory; 0 to turn off
40090792Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
40190792Sgshapiro
40294334Sgshapiroifdef(`confSHARED_MEMORY_KEY_FILE', `dnl
40394334Sgshapiro# file to store key for shared memory (if SharedMemoryKey = -1)
40494334SgshapiroO SharedMemoryKeyFile=confSHARED_MEMORY_KEY_FILE')
40594334Sgshapiro
40638032Speter# timeouts (many of these)
40764562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
40864562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
40990792Sgshapiro_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s')
41064562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
41164562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m')
41264562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m')
41364562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
41464562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
41564562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
41664562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
41764562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m')
41864562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m')
41964562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m')
42064562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h')
42164562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s')
42264562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
42364562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m')
42464562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
42564562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
42664562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
42764562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
428112810Sgshapiroifdef(`confTO_QUEUERETURN_DSN', `dnl
429112810SgshapiroO Timeout.queuereturn.dsn=confTO_QUEUERETURN_DSN')
43064562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
43164562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
43264562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
43364562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
434112810Sgshapiroifdef(`confTO_QUEUEWARN_DSN', `dnl
435112810SgshapiroO Timeout.queuewarn.dsn=confTO_QUEUEWARN_DSN')
43664562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
43764562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
43864562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
43964562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
44064562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
44164562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
44264562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
44390792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
44490792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m')
44590792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
44638032Speter
44790792Sgshapiro# time for DeliverBy; extension disabled if less than 0
44890792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
44990792Sgshapiro
45038032Speter# should we not prune routes in route-addr syntax addresses?
45164562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
45238032Speter
45338032Speter# queue up everything before forking?
45464562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
45538032Speter
45638032Speter# status file
45764562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
45838032Speter
45938032Speter# time zone handling:
46038032Speter#  if undefined, use system default
46138032Speter#  if defined but null, use TZ envariable passed in
46238032Speter#  if defined and non-null, use that info
46338032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
46438032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
46538032Speter	`O TimeZoneSpec=confTIME_ZONE')
46638032Speter
46738032Speter# default UID (can be username or userid:groupid)
46864562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
46938032Speter
47038032Speter# list of locations of user database file (null means no lookup)
47164562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
47238032Speter
47338032Speter# fallback MX host
47464562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
47538032Speter
47638032Speter# if we are the best MX host for a site, try it directly instead of config err
47764562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
47838032Speter
47938032Speter# load average at which we just queue messages
48064562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8')
48138032Speter
48238032Speter# load average at which we refuse connections
48364562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
48438032Speter
48590792Sgshapiro# load average at which we delay connections; 0 means no limit
48690792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0')
48790792Sgshapiro
48838032Speter# maximum number of children we allow at one time
48998841Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0')
49038032Speter
49138032Speter# maximum number of new connections per second
49271345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
49338032Speter
49438032Speter# work recipient factor
49564562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
49638032Speter
49738032Speter# deliver each queued job in a separate process?
49864562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
49938032Speter
50038032Speter# work class factor
50164562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
50238032Speter
50338032Speter# work time factor
50464562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
50538032Speter
50638032Speter# default character set
50764562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
50838032Speter
50990792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
51064562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
51138032Speter
51238032Speter# hosts file (normally /etc/hosts)
51364562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
51438032Speter
51538032Speter# dialup line delay on connection failure
51664562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s')
51738032Speter
51838032Speter# action to take if there are no recipients in the message
51964562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed')
52038032Speter
52138032Speter# chrooted environment for writing to files
52264562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
52338032Speter
52438032Speter# are colons OK in addresses?
52564562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
52638032Speter
52738032Speter# shall I avoid expanding CNAMEs (violates protocols)?
52864562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
52938032Speter
53038032Speter# SMTP initial login message (old $e macro)
53164562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
53238032Speter
53338032Speter# UNIX initial From header format (old $l macro)
53464562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
53538032Speter
53638032Speter# From: lines that have embedded newlines are unwrapped onto one line
53764562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
53838032Speter
53938032Speter# Allow HELO SMTP command that does not `include' a host name
54064562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
54138032Speter
54238032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
54364562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
54438032Speter
54538032Speter# delimiter (operator) characters (old $o macro)
54664562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
54738032Speter
54838032Speter# shall I avoid calling initgroups(3) because of high NIS costs?
54964562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
55038032Speter
55138032Speter# are group-writable `:include:' and .forward files (un)trustworthy?
55290792Sgshapiro# True (the default) means they are not trustworthy.
55364562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
55490792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES',
55590792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
55690792Sgshapiro')')
55738032Speter
55838032Speter# where do errors that occur when sending errors get sent?
55964562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
56038032Speter
56164562Sgshapiro# where to save bounces if all else fails
56264562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
56364562Sgshapiro
56438032Speter# what user id do we assume for the majority of the processing?
56564562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
56638032Speter
56738032Speter# maximum number of recipients per SMTP envelope
56864562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
56938032Speter
57090792Sgshapiro# limit the rate recipients per SMTP envelope are accepted
57190792Sgshapiro# once the threshold number of recipients have been rejected
57290792Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20')
57390792Sgshapiro
57438032Speter# shall we get local names from our installed interfaces?
57564562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
57638032Speter
57764562Sgshapiro# Return-Receipt-To: header implies DSN request
57864562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
57964562Sgshapiro
58064562Sgshapiro# override connection address (for testing)
58164562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
58264562Sgshapiro
58364562Sgshapiro# Trusted user for file ownership and starting the daemon
58464562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
58564562Sgshapiro
58664562Sgshapiro# Control socket for daemon management
58764562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
58864562Sgshapiro
58964562Sgshapiro# Maximum MIME header length to protect MUAs
590112810Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `2048/1024')
59164562Sgshapiro
59264562Sgshapiro# Maximum length of the sum of all headers
59364562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
59464562Sgshapiro
59564562Sgshapiro# Maximum depth of alias recursion
59664562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
59764562Sgshapiro
59864562Sgshapiro# location of pid file
59964562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
60064562Sgshapiro
60164562Sgshapiro# Prefix string for the process title shown on 'ps' listings
60264562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
60364562Sgshapiro
60464562Sgshapiro# Data file (df) memory-buffer file maximum size
60564562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
60664562Sgshapiro
60764562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
60864562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
60964562Sgshapiro
61090792Sgshapiro# lookup type to find information about local mailboxes
61190792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
61290792Sgshapiro
61364562Sgshapiro# list of authentication mechanisms
61490792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
61564562Sgshapiro
61664562Sgshapiro# default authentication information for outgoing connections
61764562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
61864562Sgshapiro
61964562Sgshapiro# SMTP AUTH flags
62064562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
62164562Sgshapiro
62290792Sgshapiro# SMTP AUTH maximum encryption strength
62390792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
62490792Sgshapiro
62590792Sgshapiro# SMTP STARTTLS server options
62690792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
62790792Sgshapiro
62864562Sgshapiro# Input mail filters
62964562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
63064562Sgshapiro
63198841Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl
63264562Sgshapiro# Milter options
63390792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
63464562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
63564562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
63664562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
637125820Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')
638125820Sgshapiro')
63964562Sgshapiro
64064562Sgshapiro# CA directory
641110560Sgshapiro_OPTION(CACertPath, `confCACERT_PATH', `')
64264562Sgshapiro# CA file
643110560Sgshapiro_OPTION(CACertFile, `confCACERT', `')
64464562Sgshapiro# Server Cert
64564562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
64664562Sgshapiro# Server private key
64764562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
64864562Sgshapiro# Client Cert
64964562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
65064562Sgshapiro# Client private key
65164562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
65264562Sgshapiro# DHParameters (only required if DSA/DH is used)
65364562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
65464562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
65564562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
65664562Sgshapiro
65790792Sgshapiro############################
65890792Sgshapiro`# QUEUE GROUP DEFINITIONS  #'
65990792Sgshapiro############################
66090792Sgshapiro_QUEUE_GROUP_
66142575Speter
66238032Speter###########################
66338032Speter#   Message precedences   #
66438032Speter###########################
66538032Speter
66638032SpeterPfirst-class=0
66738032SpeterPspecial-delivery=100
66838032SpeterPlist=-30
66938032SpeterPbulk=-60
67038032SpeterPjunk=-100
67138032Speter
67238032Speter#####################
67338032Speter#   Trusted users   #
67438032Speter#####################
67538032Speter
67638032Speter# this is equivalent to setting class "t"
67764562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
67838032SpeterTroot
67938032SpeterTdaemon
68038032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp')
68138032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
68238032Speter
68338032Speter#########################
68438032Speter#   Format of headers   #
68538032Speter#########################
68638032Speter
68738032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
68838032SpeterH?P?Return-Path: <$g>
68938032SpeterHReceived: confRECEIVED_HEADER
69038032SpeterH?D?Resent-Date: $a
69138032SpeterH?D?Date: $a
69238032SpeterH?F?Resent-From: confFROM_HEADER
69338032SpeterH?F?From: confFROM_HEADER
69438032SpeterH?x?Full-Name: $x
69538032Speter# HPosted-Date: $a
69638032Speter# H?l?Received-Date: $b
69738032SpeterH?M?Resent-Message-Id: <$t.$i@$j>
69838032SpeterH?M?Message-Id: <$t.$i@$j>
69964562Sgshapiro
70038032Speter#
70138032Speter######################################################################
70238032Speter######################################################################
70338032Speter#####
70438032Speter#####			REWRITING RULES
70538032Speter#####
70638032Speter######################################################################
70738032Speter######################################################################
70838032Speter
70938032Speter############################################
71038032Speter###  Ruleset 3 -- Name Canonicalization  ###
71138032Speter############################################
71264562SgshapiroScanonify=3
71338032Speter
71438032Speter# handle null input (translate to <@> special case)
71538032SpeterR$@			$@ <@>
71638032Speter
71738032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
71838032SpeterR$*			$: $1 <@>			mark addresses
71938032SpeterR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
72038032SpeterR@ $* <@>		$: @ $1				unmark @host:...
72190792SgshapiroR$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
72238032SpeterR$* :: $* <@>		$: $1 :: $2			unmark node::addr
72338032SpeterR:`include': $* <@>	$: :`include': $1			unmark :`include':...
72438032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
72538032SpeterR$* : $* <@>		$: $2				strip colon if marked
72638032SpeterR$* <@>			$: $1				unmark
72738032SpeterR$* ;			   $1				strip trailing semi
72871345SgshapiroR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
72938032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
73038032Speter
73138032Speter# null input now results from list:; syntax
73238032SpeterR$@			$@ :; <@>
73338032Speter
73438032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
73538032SpeterR$*			$: < $1 >			housekeeping <>
73638032SpeterR$+ < $* >		   < $2 >			strip excess on left
73738032SpeterR< $* > $+		   < $1 >			strip excess on right
73838032SpeterR<>			$@ < @ >			MAIL FROM:<> case
73938032SpeterR< $+ >			$: $1				remove housekeeping <>
74038032Speter
74164562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
74238032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
74338032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
74438032Speter
74538032Speter# localize and dispose of route-based addresses
74690792Sgshapirodnl XXX: IPv6 colon conflict
74790792Sgshapiroifdef(`NO_NETINET6', `dnl',
74890792Sgshapiro`R@ [$+] : $+		$@ $>Canonify2 < @ [$1] > : $2	handle <route-addr>')
74964562SgshapiroR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
75064562Sgshapirodnl',`dnl
75164562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d>
75264562SgshapiroR@ $+ , $+		$2
75390792Sgshapiroifdef(`NO_NETINET6', `dnl',
75490792Sgshapiro`R@ [ $* ] : $+		$2')
75564562SgshapiroR@ $+ : $+		$2
75664562Sgshapirodnl')
75738032Speter
75838032Speter# find focus for list syntax
75964562SgshapiroR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
76038032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
76138032Speter
76238032Speter# find focus for @ syntax addresses
76338032SpeterR$+ @ $+		$: $1 < @ $2 >			focus on domain
76438032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
76564562SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
76638032Speter
76790792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here.
76890792Sgshapirodnl # do some sanity checking
76990792Sgshapirodnl R$* < @ $~[ $* : $* > $*	$1 < @ $2 $3 > $4	nix colons in addrs
77038032Speter
77138032Speterifdef(`_NO_UUCP_', `dnl',
77238032Speter`# convert old-style addresses to a domain-based address
77364562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
77464562SgshapiroR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
77564562SgshapiroR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
77638032Speter')
77738032Speterifdef(`_USE_DECNET_SYNTAX_',
77838032Speter`# convert node::user addresses into a domain-based address
77964562SgshapiroR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
78064562SgshapiroR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
78138032Speter',
78238032Speter	`dnl')
78338032Speter# if we have % signs, take the rightmost one
78438032SpeterR$* % $*		$1 @ $2				First make them all @s.
78538032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
78664562SgshapiroR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
78738032Speter
78838032Speter# else we must be a local name
78964562SgshapiroR$*			$@ $>Canonify2 $1
79038032Speter
79138032Speter
79238032Speter################################################
79338032Speter###  Ruleset 96 -- bottom half of ruleset 3  ###
79438032Speter################################################
79538032Speter
79664562SgshapiroSCanonify2=96
79738032Speter
79838032Speter# handle special cases for local names
79938032SpeterR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
80038032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
80138032Speterifdef(`_NO_UUCP_', `dnl',
80238032Speter`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
80364562Sgshapiro
80490792Sgshapiro# check for IPv4/IPv6 domain literal
80590792SgshapiroR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [addr]
80638032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
80738032SpeterR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
80838032Speter
80964562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl
81038032Speter# look up domains in the domain table
81138032SpeterR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
81238032Speter
81364562Sgshapiroundivert(2)dnl LOCAL_RULE_3
81438032Speter
81564562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl
81638032Speter# handle BITNET mapping
81738032SpeterR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
81838032Speter
81964562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl
82038032Speter# handle UUCP mapping
82138032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
82238032Speter
82338032Speterifdef(`_NO_UUCP_', `dnl',
82438032Speter`ifdef(`UUCP_RELAY',
82538032Speter`# pass UUCP addresses straight through
82638032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
82738032Speter`# if really UUCP, handle it immediately
82838032Speterifdef(`_CLASS_U_',
82938032Speter`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83038032Speterifdef(`_CLASS_V_',
83138032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83238032Speterifdef(`_CLASS_W_',
83338032Speter`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83438032Speterifdef(`_CLASS_X_',
83538032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83638032Speterifdef(`_CLASS_Y_',
83738032Speter`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83838032Speter
83938032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl
84038032Speter# try UUCP traffic as a local address
84138032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
84238032SpeterR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
84338032Speter')')
84464562Sgshapiro# hostnames ending in class P are always canonical
84564562SgshapiroR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
84664562Sgshapirodnl apply the next rule only for hostnames not in class P
84764562Sgshapirodnl this even works for phrases in class P since . is in class P
84864562Sgshapirodnl which daemon flags are set?
84964562SgshapiroR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
85064562Sgshapirodnl the other rules in this section only apply if the hostname
85164562Sgshapirodnl does not end in class P hence no further checks are done here
85264562Sgshapirodnl if this ever changes make sure the lookups are "protected" again!
85364562Sgshapiroifdef(`_NO_CANONIFY_', `dnl
85464562Sgshapirodnl do not canonify unless:
85564562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection
85664562Sgshapirodnl	with class P is non-empty)
85764562Sgshapirodnl or {daemon_flags} has c set
85864562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify}
85964562SgshapiroR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
86064562Sgshapiro# pass to name server to make hostname canonical if requested
86164562SgshapiroR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
86264562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_
86364562SgshapiroR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
86464562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work
86564562SgshapiroR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
86664562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl
86764562Sgshapirodnl this should only apply to unqualified hostnames
86864562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
86964562Sgshapirodnl then $- does not work.
87064562Sgshapiro# lookup unqualified hostnames
87190792SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
87264562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
87364562Sgshapirodnl {daemon_flags} contains CC (do not canonify)
87471345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work
87571345Sgshapirodnl should we do this for every hostname: even unqualified?
87671345SgshapiroR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
87764562SgshapiroR$* CC $* $| $*			$: $3
87890792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
87990792Sgshapiro# do not canonify header addresses
88090792SgshapiroR$* $| $* < @ $* $~P > $*	$: $&{addr_type} $| $2 < @ $3 $4 > $5
88190792SgshapiroR$* h $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
88290792SgshapiroR$* h $* $| $*			$: $3', `dnl')
88338032Speter# pass to name server to make hostname canonical
88464562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
88564562Sgshapirodnl remove {daemon_flags} for other cases
88664562SgshapiroR$* $| $*			$: $2
88738032Speter
88838032Speter# local host aliases and pseudo-domains are always canonical
88938032SpeterR$* < @ $=w > $*		$: $1 < @ $2 . > $3
89038032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
89138032Speter`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
89238032Speter`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
89364562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
89464562Sgshapirodnl virtual hosts are also canonical
89564562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
89664562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
89764562Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
89864562Sgshapiro`dnl')
89990792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
90090792Sgshapirodnl hosts for genericstable are also canonical
90190792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_',
90290792Sgshapiro`R$* < @ $* $=G > $* 	$: $1 < @ $2 $3 . > $4',
90390792Sgshapiro`R$* < @ $=G > $* 	$: $1 < @ $2 . > $3')',
90490792Sgshapiro`dnl')
90564562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added
90664562Sgshapirodnl by one of the rules before
90738032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
90838032Speter
90938032Speter
91038032Speter##################################################
91138032Speter###  Ruleset 4 -- Final Output Post-rewriting  ###
91238032Speter##################################################
91364562SgshapiroSfinal=4
91438032Speter
91571345SgshapiroR$+ :; <@>		$@ $1 :				handle <list:;>
91638032SpeterR$* <@>			$@				handle <> and list:;
91738032Speter
91838032Speter# strip trailing dot off possibly canonical name
91938032SpeterR$* < @ $+ . > $*	$1 < @ $2 > $3
92038032Speter
92164562Sgshapiro# eliminate internal code
92238032SpeterR$* < @ *LOCAL* > $*	$1 < @ $j > $2
92338032Speter
92438032Speter# externalize local domain info
92538032SpeterR$* < $+ > $*		$1 $2 $3			defocus
92638032SpeterR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
92738032SpeterR@ $*			$@ @ $1				... and exit
92838032Speter
92938032Speterifdef(`_NO_UUCP_', `dnl',
93038032Speter`# UUCP must always be presented in old form
93138032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
93238032Speter
93338032Speterifdef(`_USE_DECNET_SYNTAX_',
93438032Speter`# put DECnet back in :: form
93538032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
93638032Speter	`dnl')
93738032Speter# delete duplicate local names
93838032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
93938032Speter
94038032Speter
94138032Speter
94238032Speter##############################################################
94338032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
94438032Speter###		   (used for recursive calls)		   ###
94538032Speter##############################################################
94638032Speter
94764562SgshapiroSRecurse=97
94864562SgshapiroR$*			$: $>canonify $1
94964562SgshapiroR$*			$@ $>parse $1
95038032Speter
95138032Speter
95238032Speter######################################
95338032Speter###   Ruleset 0 -- Parse Address   ###
95438032Speter######################################
95538032Speter
95664562SgshapiroSparse=0
95738032Speter
95838032SpeterR$*			$: $>Parse0 $1		initial parsing
95938032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
96064562SgshapiroR$*			$: $>ParseLocal $1	handle local hacks
96138032SpeterR$*			$: $>Parse1 $1		final parsing
96238032Speter
96338032Speter#
96438032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
96538032Speter#	This should either return with the (possibly modified) input
96638032Speter#	or return with a #error mailer.  It should not return with a
96738032Speter#	#mailer other than the #error mailer.
96838032Speter#
96938032Speter
97038032SpeterSParse0
97138032SpeterR<@>			$@ <@>			special case error msgs
97290792SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
97364562SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
97490792SgshapiroR<@ $+>			$#error $@ 5.1.3 $: "_CODE553 User address required"
97590792SgshapiroR$+ <@>			$#error $@ 5.1.3 $: "_CODE553 Hostname required"
97638032SpeterR$*			$: <> $1
97790792Sgshapirodnl allow tricks like [host1]:[host2]
97890792SgshapiroR<> $* < @ [ $* ] : $+ > $*	$1 < @ [ $2 ] : $3 > $4
97990792SgshapiroR<> $* < @ [ $* ] , $+ > $*	$1 < @ [ $2 ] , $3 > $4
98090792Sgshapirodnl but no a@[b]c
98190792SgshapiroR<> $* < @ [ $* ] $+ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid address"
98290792SgshapiroR<> $* < @ [ $+ ] > $*		$1 < @ [ $2 ] > $3
98390792SgshapiroR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
98438032SpeterR<> $*			$1
98590792SgshapiroR$* < @ . $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
98690792SgshapiroR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
98790792Sgshapirodnl no a@b@
98890792SgshapiroR$* < @ $* @ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid route address"
98990792Sgshapirodnl no a@b@c
99090792SgshapiroR$* @ $* < @ $* > $*	$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
99164562Sgshapirodnl comma only allowed before @; this check is not complete
99290792SgshapiroR$* , $~O $*		$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
99338032Speter
99490792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks
99590792SgshapiroR$* . < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
99690792SgshapiroR. $* < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
99790792Sgshapirodnl', `dnl')
99890792Sgshapiro
99938032Speter# now delete the local info -- note $=O to find characters that cause forwarding
100064562SgshapiroR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
100164562SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
100238032SpeterR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
100390792SgshapiroR< @ $+ >		$#error $@ 5.1.3 $: "_CODE553 User address required"
100464562SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
100538032SpeterR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
100690792SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "_CODE553 User address required"
100738032SpeterR$* $=O $* < @ *LOCAL* >
100864562Sgshapiro			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
100938032SpeterR$* < @ *LOCAL* >	$: $1
101038032Speter
101138032Speter#
101238032Speter#  Parse1 -- the bottom half of ruleset 0.
101338032Speter#
101438032Speter
101538032SpeterSParse1
101664562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
101764562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute}
101890792SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
101990792SgshapiroR$+ < @ $={LDAPRouteEquiv} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
102064562Sgshapiro`dnl')
102164562Sgshapiro
102238032Speterifdef(`_MAILER_smtp_',
102338032Speter`# handle numeric address spec
102464562Sgshapirodnl there is no check whether this is really an IP number
102564562SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
1026112810SgshapiroR$* < @ [ $+ ] > $*	$: $1 < @ [ $2 ] : $S > $3	Add smart host to path
102790792SgshapiroR$* < @ [ $+ ] : > $*		$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
102864562SgshapiroR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
102964562SgshapiroR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
103038032Speter	`dnl')
103138032Speter
103264562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
103338032Speter# handle virtual users
103490792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
103590792Sgshapirodnl this is not a documented option
103690792Sgshapirodnl it stops looping in virtusertable mapping if input and output
103790792Sgshapirodnl are identical, i.e., if address A is mapped to A.
103890792Sgshapirodnl it does not deal with multi-level recursion
103990792Sgshapiro# handle full domains in RHS of virtusertable
104090792SgshapiroR$+ < @ $+ >			$: $(macro {RecipientAddress} $) $1 < @ $2 >
104190792SgshapiroR$+ < @ $+ > 			$: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
104290792SgshapiroR<?> $+ $| $+			$: $1 $(macro {RecipientAddress} $@ $2 $)
104390792SgshapiroR<?> $+ $| $*			$: $1',
104490792Sgshapiro`dnl')
104564562SgshapiroR$+			$: <!> $1		Mark for lookup
104690792Sgshapirodnl input: <!> local<@domain>
104764562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
104864562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
104964562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
105090792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
105164562SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
105290792Sgshapirodnl if <@> local<@domain>: no match but try lookup
105390792Sgshapirodnl user+detail: try user++@domain if detail not empty
105490792SgshapiroR<@> $+ + $+ < @ $* . >
105590792Sgshapiro			$: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105690792Sgshapirodnl user+detail: try user+*@domain
105738032SpeterR<@> $+ + $* < @ $* . >
105890792Sgshapiro			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105990792Sgshapirodnl user+detail: try user@domain
106038032SpeterR<@> $+ + $* < @ $* . >
106190792Sgshapiro			$: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
106264562Sgshapirodnl try default entry: @domain
106390792Sgshapirodnl ++@domain
106490792SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
106564562Sgshapirodnl +*@domain
106690792SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
106764562Sgshapirodnl @domain if +detail exists
106898121Sgshapirodnl if no match, change marker to prevent a second @domain lookup
106998121SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . >
107098121Sgshapirodnl without +detail
107138032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
107290792Sgshapirodnl no match
107338032SpeterR<@> $+			$: $1
107490792Sgshapirodnl remove mark
107564562SgshapiroR<!> $+			$: $1
107664562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
107738032SpeterR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
107890792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
107990792Sgshapiro# check virtuser input address against output address, if same, skip recursion
108090792SgshapiroR< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
108190792Sgshapiro# it is the same: stop now
108290792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
108390792SgshapiroR< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
108490792Sgshapirodnl', `dnl')
108580785Sgshapirodnl this is not a documented option
108680785Sgshapirodnl it performs no looping at all for virtusertable
108777349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_',
108877349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
108977349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
109077349Sgshapirodnl', `dnl')
109138032Speter
109238032Speter# short circuit local delivery so forwarded email works
109338032Speterifdef(`_MAILER_usenet_', `dnl
109464562SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
109566494Sgshapiro
109666494Sgshapiro
109738032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
109838032Speter`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
109964562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
110064562Sgshapirodnl $H empty (but @$=w.)
110138032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
110238032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
110364562Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
110438032SpeterR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
110538032Speter
110664562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
110738032Speter# not local -- try mailer table lookup
110838032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
110938032SpeterR< $+ . > $*		$: < $1 > $2			strip trailing dot
111038032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
111164562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
111264562SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
111364562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
111438032Speter`dnl')
111564562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)'
111638032Speter
111738032Speterifdef(`_NO_UUCP_', `dnl',
111838032Speter`# resolve remotely connected UUCP links (if any)
111938032Speterifdef(`_CLASS_V_',
112064562Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
112138032Speter	`dnl')
112238032Speterifdef(`_CLASS_W_',
112364562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
112438032Speter	`dnl')
112538032Speterifdef(`_CLASS_X_',
112664562Sgshapiro`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
112738032Speter	`dnl')')
112838032Speter
112938032Speter# resolve fake top level domains by forwarding to other hosts
113038032Speterifdef(`BITNET_RELAY',
113164562Sgshapiro`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
113238032Speter	`dnl')
113338032Speterifdef(`DECNET_RELAY',
113464562Sgshapiro`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
113538032Speter	`dnl')
113638032Speterifdef(`_MAILER_pop_',
113738032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
113838032Speter	`dnl')
113938032Speterifdef(`_MAILER_fax_',
114038032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
114138032Speter`ifdef(`FAX_RELAY',
114264562Sgshapiro`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
114338032Speter	`dnl')')
114438032Speter
114538032Speterifdef(`UUCP_RELAY',
114638032Speter`# forward non-local UUCP traffic to our UUCP relay
114764562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
114838032Speter`ifdef(`_MAILER_uucp_',
114938032Speter`# forward other UUCP traffic straight to UUCP
115038032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
115138032Speter	`dnl')')
115238032Speterifdef(`_MAILER_usenet_', `
115338032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
115464562SgshapiroR$+ . USENET		$#usenet $@ usenet $: $1',
115538032Speter	`dnl')
115638032Speter
115738032Speterifdef(`_LOCAL_RULES_',
115838032Speter`# figure out what should stay in our local mail system
115938032Speterundivert(1)', `dnl')
116038032Speter
116138032Speter# pass names that still have a host to a smarthost (if defined)
116264562SgshapiroR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
116338032Speter
116438032Speter# deal with other remote names
116538032Speterifdef(`_MAILER_smtp_',
116664562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
116790792Sgshapiro`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
116838032Speter
116938032Speter# handle locally delivered names
117064562SgshapiroR$=L			$#_LOCAL_ $: @ $1		special local names
117138032SpeterR$+			$#_LOCAL_ $: $1			regular local names
117238032Speter
117338032Speter###########################################################################
117438032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
117538032Speter###########################################################################
117638032Speter
117764562SgshapiroSLocal_localaddr
117864562SgshapiroSlocaladdr=5
117964562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
118090792SgshapiroR$+ $| $#ok		$@ $1			no change
118164562SgshapiroR$+ $| $#$*		$#$2
118264562SgshapiroR$+ $| $*		$: $1
118338032Speter
118490792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
118590792Sgshapiro# Preserve rcpt_host in {Host}
118690792SgshapiroR$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
118790792SgshapiroR$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
118890792SgshapiroR$+ $| $| $+		$: $1			h not set, {Host} set
118990792SgshapiroR$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
119095154SgshapiroR$+ $| $* @ $+ $| $*	$: $(macro {Host} $@ @$3 $) $1	set {Host} to host in h
119190792SgshapiroR$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
119290792Sgshapiro')dnl
119390792Sgshapiro
119490792Sgshapiroifdef(`_FFR_5_', `dnl
119566494Sgshapiro# Preserve host in a macro
119666494SgshapiroR$+			$: $(macro {LocalAddrHost} $) $1
119766494SgshapiroR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
119866494Sgshapiro
119990792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
120038032Speter# deal with plussed users so aliases work nicely
120166494SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
120266494SgshapiroR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
120366494Sgshapiro')
120438032Speter# prepend an empty "forward host" on the front
120538032SpeterR$+			$: <> $1
120638032Speter
120738032Speterifdef(`LUSER_RELAY', `dnl
120838032Speter# send unrecognized local users to a relay host
120990792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
121066494SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
121166494SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
121266494SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
121366494SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
121464562SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
121590792SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')
121690792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
121790792SgshapiroR< $+ > $+		$: < $1 > $2 $&{Host}')
121890792Sgshapirodnl')
121938032Speter
122090792Sgshapiroifdef(`MAIL_HUB', `dnl
122190792SgshapiroR< > $+			$: < $H > $1			try hub', `dnl')
122290792Sgshapiroifdef(`LOCAL_RELAY', `dnl
122390792SgshapiroR< > $+			$: < $R > $1			try relay', `dnl')
122490792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
122590792SgshapiroR< > $+			$@ $1', `dnl
122664562SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
122790792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
122890792SgshapiroR< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
122964562SgshapiroR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
123064562SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
123138032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
123266494SgshapiroR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
123338032SpeterR< > < $+ >		$@ $1				no +detail
123443730SpeterR$+			$: $1 <> $&h			add +detail back in
123590792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
123690792SgshapiroR$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
123743730SpeterR$+ <> + $*		$: $1 + $2			check whether +detail
123866494SgshapiroR$+ <> $*		$: $1				else discard')
123964562SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
124064562SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
124190792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
124290792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
124390792SgshapiroR< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
124490792SgshapiroR< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
124590792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
124690792SgshapiroR< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
124764562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
124838032Speter
124964562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
125090792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
125138032Speter###################################################################
125290792Sgshapiro###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
125390792Sgshapirodnl input: <Domain> FullAddress
125490792Sgshapiro###################################################################
125590792Sgshapiro
125690792SgshapiroSLDAPMailertable
125790792SgshapiroR< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
125890792SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
125990792SgshapiroR< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
126090792SgshapiroR< $+ > $#$*		$#$2					found
126190792SgshapiroR< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
126290792Sgshapiro`dnl')
126390792Sgshapiro
126490792Sgshapiro###################################################################
126538032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
126664562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
126738032Speter###################################################################
126838032Speter
126964562SgshapiroSMailertable=90
127064562Sgshapirodnl shift and check
127164562Sgshapirodnl %2 is not documented in cf/README
127238032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
127364562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
127464562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
127564562SgshapiroR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
127664562Sgshapirodnl is $2 always empty?
127738032SpeterR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
127864562SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
127964562Sgshapirodnl return full address
128038032SpeterR< $* > $*		$@ $2				no mailertable match',
128138032Speter`dnl')
128238032Speter
128338032Speter###################################################################
128438032Speter###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
128564562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
128664562Sgshapirodnl	<> address				-> address
128764562Sgshapirodnl	<error:d.s.n:text>			-> error
1288120256Sgshapirodnl	<error:keyword:text>			-> error
128964562Sgshapirodnl	<error:text>				-> error
129064562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
129164562Sgshapirodnl	<mailer:host> address			-> mailer host address
129264562Sgshapirodnl	<localdomain> address			-> address
129364562Sgshapirodnl	<host> address				-> relay host address
129438032Speter###################################################################
129538032Speter
129664562SgshapiroSMailerToTriple=95
129738032SpeterR< > $*				$@ $1			strip off null relay
129864562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
1299120256SgshapiroR< error : $- : $+ > $*		$#error $@ $(dequote $1 $) $: $2
1300120256SgshapiroR< error : $+ > $*		$#error $: $1
130138032SpeterR< local : $* > $*		$>CanonLocal < $1 > $2
130290792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
130390792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
130490792SgshapiroR< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
130538032SpeterR< $=w > $*			$@ $2			delete local host
130638032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
130738032Speter
130838032Speter###################################################################
130938032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
131064562Sgshapirodnl input: <user> address
131164562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
131264562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
131364562Sgshapirodnl <> user <@host> rest		-> local user@host user
131464562Sgshapirodnl <> user				-> local user user
131564562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
131664562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
131764562Sgshapirodnl <user> lp				-> local lp user
131838032Speter###################################################################
131938032Speter
132038032SpeterSCanonLocal
132143730Speter# strip local host from routed addresses
132264562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
132364562SgshapiroR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
132443730Speter
132538032Speter# strip trailing dot from any host name that may appear
132638032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
132738032Speter
132838032Speter# handle local: syntax -- use old user, either with or without host
132938032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
133038032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
133138032Speter
133238032Speter# handle local:user@host syntax -- ignore host part
133338032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
133438032Speter
133538032Speter# handle local:user syntax
133638032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
133738032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
133838032Speter
133938032Speter###################################################################
134038032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
134138032Speter###################################################################
134238032Speter
134364562SgshapiroSMasqHdr=93
134438032Speter
134564562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
134638032Speter# handle generics database
134738032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
134864562Sgshapirodnl if generics should be applied add a @ as mark
134938032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
135038032Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
135138032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
135264562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
135364562Sgshapirodnl ignore the first case for now
135464562Sgshapirodnl if it has the mark lookup full address
135590792Sgshapirodnl broken: %1 is full address not just detail
135664562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
135764562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
135864562Sgshapirodnl no match, try user+detail@domain
135964562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
136064562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
136164562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
136264562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
136364562Sgshapirodnl no match, remove mark
136464562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
136564562Sgshapirodnl no match, try @domain for exceptions
136664562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
136764562Sgshapirodnl workspace: ... or <match> user <@domain>
136864562Sgshapirodnl no match, try local part
136938032SpeterR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
137064562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
137164562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
137264562SgshapiroR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
137364562SgshapiroR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
137438032SpeterR< > $*			$: $1				not found',
137538032Speter`dnl')
137638032Speter
137764562Sgshapiro# do not masquerade anything in class N
137864562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
137964562Sgshapiro
138090792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
138138032Speter# special case the users that should be exposed
138238032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
138338032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
138438032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
138538032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
138638032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
138738032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
138838032Speter
138938032Speter# handle domain-specific masquerading
139038032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
139138032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
139238032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
139338032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
139438032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
139538032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
139638032SpeterR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
139738032SpeterR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
139890792Sgshapirodnl', `dnl no masquerading
139990792Sgshapirodnl just fix *LOCAL* leftovers
140090792SgshapiroR$* < @ *LOCAL* >	$@ $1 < @ $j . >')
140138032Speter
140238032Speter###################################################################
140338032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
140438032Speter###################################################################
140538032Speter
140664562SgshapiroSMasqEnv=94
140738032Speterifdef(`_MASQUERADE_ENVELOPE_',
140864562Sgshapiro`R$+			$@ $>MasqHdr $1',
140938032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
141038032Speter
141138032Speter###################################################################
141238032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
141338032Speter###################################################################
141438032Speter
141564562SgshapiroSParseLocal=98
141664562Sgshapiroundivert(3)dnl LOCAL_RULE_0
141738032Speter
141864562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
141990792Sgshapiro######################################################################
142090792Sgshapiro###  LDAPExpand: Expand address using LDAP routing
142190792Sgshapiro###
142290792Sgshapiro###	Parameters:
142390792Sgshapiro###		<$1> -- parsed address (user < @ domain . >) (pass through)
142490792Sgshapiro###		<$2> -- RFC822 address (user @ domain) (used for lookup)
142590792Sgshapiro###		<$3> -- +detail information
142690792Sgshapiro###
142790792Sgshapiro###	Returns:
142890792Sgshapiro###		Mailer triplet ($#mailer $@ host $: address)
142990792Sgshapiro###		Parsed address (user < @ domain . >)
143090792Sgshapiro######################################################################
143190792Sgshapiro
143264562SgshapiroSLDAPExpand
143364562Sgshapiro# do the LDAP lookups
143490792SgshapiroR<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
143564562Sgshapiro
143694334Sgshapiro# look for temporary failures (return original address, MTA will queue up)
1437102528SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*>	$@ $3
1438102528SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*>	$@ $3
143994334Sgshapiro
144064562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
144164562Sgshapiro# return the new mailRoutingAddress
144290792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
144390792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
144490792SgshapiroR<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
144590792SgshapiroR<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
144690792SgshapiroR<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
144764562Sgshapiro
144898121Sgshapiro
144964562Sgshapiro# if mailRoutingAddress and non-local mailHost,
145064562Sgshapiro# relay to mailHost with new mailRoutingAddress
145190792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
145290792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
145390792Sgshapiro# check mailertable for host, relay from there
145490792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
145590792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
145690792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
145790792Sgshapiro# check mailertable for host, relay from there
145890792SgshapiroR<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
145990792Sgshapiro`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
146064562Sgshapiro
146164562Sgshapiro# if no mailRoutingAddress and local mailHost,
146264562Sgshapiro# return original address
146390792SgshapiroR<> <$=w> <$+> <$+> <$*>	$@ $2
146464562Sgshapiro
146598121Sgshapiro
146664562Sgshapiro# if no mailRoutingAddress and non-local mailHost,
146764562Sgshapiro# relay to mailHost with original address
146890792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
146990792Sgshapiro# check mailertable for host, relay from there
147090792SgshapiroR<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
147190792Sgshapiro`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
147264562Sgshapiro
147390792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_',
147490792Sgshapiro`# if no mailRoutingAddress and no mailHost,
147590792Sgshapiro# try without +detail
147690792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
147790792Sgshapiro
147890792Sgshapiro# if still no mailRoutingAddress and no mailHost,
147964562Sgshapiro# try @domain
148090792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
148190792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
148290792SgshapiroR<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>
148364562Sgshapiro
148464562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
148564562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
148664562Sgshapiro# user does not exist
148790792SgshapiroR<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
148890792Sgshapiro# only give error for envelope recipient
148990792SgshapiroR<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
149090792SgshapiroR<?> <$*> <$+>			$@ $2',
149164562Sgshapiro`dnl
149264562Sgshapiro# return the original address
149390792SgshapiroR<> <> <$+> <@ $+> <$*>		$@ $1')',
149464562Sgshapiro`dnl')
149564562Sgshapiro
149664562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
149764562Sgshapiro')')
149890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
149938032Speter######################################################################
150090792Sgshapiro###  D: LookUpDomain -- search for domain in access database
150138032Speter###
150238032Speter###	Parameters:
150338032Speter###		<$1> -- key (domain name)
150438032Speter###		<$2> -- default (what to return if not found in db)
150564562Sgshapirodnl			must not be empty
150690792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
150764562Sgshapiro###			! does lookup only with tag
150864562Sgshapiro###			+ does lookup with and without tag
150990792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
151064562Sgshapirodnl returns:		<default> <passthru>
151164562Sgshapirodnl 			<result> <passthru>
151238032Speter######################################################################
151338032Speter
151490792SgshapiroSD
151564562Sgshapirodnl workspace <key> <default> <passthru> <mark>
151664562Sgshapirodnl lookup with tag (in front, no delimiter here)
151790792Sgshapirodnl    2    3  4    5
151890792SgshapiroR<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
151964562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
152064562Sgshapirodnl lookup without tag?
152190792Sgshapirodnl   1    2      3    4
152290792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
152390792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
152490792Sgshapirodnl XXX apply this also to IP addresses?
152590792Sgshapirodnl currently it works the wrong way round for [1.2.3.4]
152690792Sgshapirodnl   1  2    3    4  5    6
152790792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
152890792Sgshapirodnl   1  2    3      4    5
152990792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
153090792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
153190792Sgshapirodnl found SKIP: return <default> and <passthru>
153290792Sgshapirodnl      1    2    3  4    5
153390792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
153490792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!)
153590792Sgshapirodnl    1  2     3    4  5    6
153690792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
153790792Sgshapiroifdef(`NO_NETINET6', `dnl',
153890792Sgshapiro`dnl not found: IPv6 net
153990792Sgshapirodnl (could be merged with previous rule if we have a class containing .:)
154090792Sgshapirodnl    1   2     3    4  5    6
154190792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
154290792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
154364562Sgshapirodnl not found, but subdomain: try again
154490792Sgshapirodnl   1  2    3    4  5    6
154590792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
154690792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
154790792Sgshapirodnl   1    2      3    4
154890792SgshapiroR<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
154990792Sgshapirodnl not found, no subdomain: return <default> and <passthru>
155090792Sgshapirodnl   1    2    3  4    5
155190792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
155290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
155390792Sgshapirodnl            2    3    4  5    6
155490792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
155590792Sgshapirodnl return <result of lookup> and <passthru>
155690792Sgshapirodnl    2    3    4  5    6
155790792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
155838032Speter
155938032Speter######################################################################
156090792Sgshapiro###  A: LookUpAddress -- search for host address in access database
156138032Speter###
156238032Speter###	Parameters:
156338032Speter###		<$1> -- key (dot quadded host address)
156438032Speter###		<$2> -- default (what to return if not found in db)
156564562Sgshapirodnl			must not be empty
156690792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
156764562Sgshapiro###			! does lookup only with tag
156864562Sgshapiro###			+ does lookup with and without tag
156990792Sgshapiro###		<$4> -- passthru (additional data passed through)
157064562Sgshapirodnl	returns:	<default> <passthru>
157164562Sgshapirodnl			<result> <passthru>
157238032Speter######################################################################
157338032Speter
157490792SgshapiroSA
157564562Sgshapirodnl lookup with tag
157690792Sgshapirodnl    2    3  4    5
157790792SgshapiroR<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
157864562Sgshapirodnl lookup without tag
157990792Sgshapirodnl   1    2      3    4
158090792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
158190792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
158290792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
158390792Sgshapirodnl found SKIP: return <default> and <passthru>
158490792Sgshapirodnl      1    2    3  4    5
158590792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
158690792Sgshapiroifdef(`NO_NETINET6', `dnl',
158790792Sgshapiro`dnl no match; IPv6: remove last part
158890792Sgshapirodnl   1   2    3    4  5    6
158990792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
159090792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
159164562Sgshapirodnl no match; IPv4: remove last part
159290792Sgshapirodnl   1  2    3    4  5    6
159390792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
159464562Sgshapirodnl no match: return default
159590792Sgshapirodnl   1    2    3  4    5
159690792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
159790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
159890792Sgshapirodnl            2    3    4  5    6
159990792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
160064562Sgshapirodnl match: return result
160190792Sgshapirodnl    2    3    4  5    6
160290792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
160390792Sgshapirodnl endif _ACCESS_TABLE_
160490792Sgshapirodivert(0)
160538032Speter######################################################################
160642575Speter###  CanonAddr --	Convert an address into a standard form for
160742575Speter###			relay checking.  Route address syntax is
160842575Speter###			crudely converted into a %-hack address.
160942575Speter###
161042575Speter###	Parameters:
161142575Speter###		$1 -- full recipient address
161242575Speter###
161342575Speter###	Returns:
161442575Speter###		parsed address, not in source route form
161564562Sgshapirodnl		user%host%host<@domain>
161664562Sgshapirodnl		host!user<@domain>
161742575Speter######################################################################
161842575Speter
161942575SpeterSCanonAddr
162064562SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
162164562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
162242575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
162342575SpeterR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
162442575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
162564562Sgshapirodnl')
162642575Speter
162742575Speter######################################################################
162838032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
162938032Speter###			$* $=m or the access database.
163038032Speter###			Check user portion for host separators.
163138032Speter###
163238032Speter###	Parameters:
163338032Speter###		$1 -- full recipient address
163438032Speter###
163538032Speter###	Returns:
163638032Speter###		parsed, non-local-relaying address
163738032Speter######################################################################
163838032Speter
163938032SpeterSParseRecipient
164064562Sgshapirodnl mark and canonify address
164142575SpeterR$*				$: <?> $>CanonAddr $1
164264562Sgshapirodnl workspace: <?> localpart<@domain[.]>
164342575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
164464562Sgshapirodnl workspace: <?> localpart<@domain>
164542575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
164638032Speter
164738032Speter# if no $=O character, no host in the user portion, we are done
164842575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
164964562Sgshapirodnl no $=O in localpart: return
165042575SpeterR<?> $*				$@ $1
165138032Speter
165290792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O
165364562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
165438032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
165538032Speter# if we relay, check username portion for user%host so host can be checked also
165642575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
165764562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
165864562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
165990792Sgshapiro
166090792Sgshapirodnl what if access map returns something else than RELAY?
166190792Sgshapirodnl we are only interested in RELAY entries...
166290792Sgshapirodnl other To: entries: blacklist recipient; generic entries?
166390792Sgshapirodnl if it is an error we probably do not want to relay anyway
166438032Speterifdef(`_RELAY_HOSTS_ONLY_',
166542575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
166664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
166764562SgshapiroR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
166842575SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
166942575Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
167064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
167190792SgshapiroR<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
167242575SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
167338032Speter
167464562Sgshapiro
167590792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl
167690792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
167790792SgshapiroR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
167890792SgshapiroR<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
167990792Sgshapirodnl yes: mark it as <RELAY>
168090792SgshapiroR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
168190792Sgshapirodnl no: put old <NO> mark back
168290792SgshapiroR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
168390792Sgshapiro
168490792Sgshapirodnl do we relay to this recipient domain?
168542575SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
168690792Sgshapirodnl something else
168790792SgshapiroR<$+> $*			$@ $2
168842575Speter
168964562Sgshapiro
169038032Speter######################################################################
169138032Speter###  check_relay -- check hostname/address on SMTP startup
169238032Speter######################################################################
169338032Speter
169438032SpeterSLocal_check_relay
169564562SgshapiroScheck`'_U_`'relay
169638032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
169738032SpeterR$* $| $* $| $#$*	$#$3
169838032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
169938032Speter
170038032SpeterSBasic_check_relay
170138032Speter# check for deferred delivery mode
170298121SgshapiroR$*			$: < $&{deliveryMode} > $1
170338032SpeterR< d > $*		$@ deferred
170438032SpeterR< $* > $*		$: $2
170538032Speter
170664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
170766494Sgshapirodnl workspace: {client_name} $| {client_addr}
170890792SgshapiroR$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
170966494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
1710110560Sgshapirodnl OR $| $+ if client_name is empty
1711110560SgshapiroR   $| $+		$: $>A < $1 > <?> <+ Connect> <>	empty client_name
1712110560Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
171390792SgshapiroR<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
171490792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>)
171590792SgshapiroR<?> <$*>		$: OK				found nothing
171690792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
171790792SgshapiroR<$={Accept}> <$*>	$@ $1				return value of lookup
171890792SgshapiroR<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
171990792SgshapiroR<DISCARD> <$*>		$#discard $: discard
172090792Sgshapiroifdef(`_FFR_QUARANTINE',
172190792Sgshapiro`R<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1', `dnl')
172264562Sgshapirodnl error tag
172366494SgshapiroR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
172466494SgshapiroR<ERROR:$+> <$*>		$#error $: $1
172590792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
172664562Sgshapirodnl generic error from access map
172766494SgshapiroR<$+> <$*>		$#error $: $1', `dnl')
172838032Speter
172964562Sgshapiroifdef(`_RBL_',`dnl
173064562Sgshapiro# DNS based IP address spam list
173190792Sgshapirodnl workspace: ignored...
173238032SpeterR$*			$: $&{client_addr}
173364562SgshapiroR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
173464562SgshapiroR<?>OK			$: OKSOFAR
173598121SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"',
173638032Speter`dnl')
173764562Sgshapiroundivert(8)
173838032Speter
173938032Speter######################################################################
174038032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
174138032Speter######################################################################
174238032Speter
174338032SpeterSLocal_check_mail
174464562SgshapiroScheck`'_U_`'mail
174538032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
174638032SpeterR$* $| $#$*		$#$2
174738032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
174838032Speter
174938032SpeterSBasic_check_mail
175038032Speter# check for deferred delivery mode
175198121SgshapiroR$*			$: < $&{deliveryMode} > $1
175238032SpeterR< d > $*		$@ deferred
175338032SpeterR< $* > $*		$: $2
175438032Speter
175564562Sgshapiro# authenticated?
175664562Sgshapirodnl done first: we can require authentication for every mail transaction
175764562Sgshapirodnl workspace: address as given by MAIL FROM: (sender)
175864562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
175964562SgshapiroR$* $| $#$+		$#$2
176064562Sgshapirodnl undo damage: remove result of tls_client call
176164562SgshapiroR$* $| $*		$: $1
176238032Speter
176364562Sgshapirodnl workspace: address as given by MAIL FROM:
176464562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
176538032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
176664562Sgshapirodnl do some additional checks
176764562Sgshapirodnl no user@host
176864562Sgshapirodnl no user@localhost (if nonlocal sender)
176964562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
177064562Sgshapirodnl just make sure the address has <> around it (which is required by
177164562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
177264562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
177364562Sgshapirodnl not be modified by host lookups.
177464562SgshapiroR$+			$: <?> $1
177564562SgshapiroR<?><$+>		$: <@> <$1>
177664562SgshapiroR<?>$+			$: <@> <$1>
177764562Sgshapirodnl workspace: <@> <address>
177864562Sgshapirodnl prepend daemon_flags
177964562SgshapiroR$*			$: $&{daemon_flags} $| $1
178064562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
178164562Sgshapirodnl do not allow these at all or only from local systems?
178264562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
178364562Sgshapirodnl accept unqualified sender: change mark to avoid test
178464562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
178564562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
178664562Sgshapirodnl        or:                    <? ${client_name} > <address>
178764562Sgshapirodnl        or:                    <?> <address>
178864562Sgshapirodnl remove daemon_flags
178964562SgshapiroR$* $| $*		$: $2
179038032Speter# handle case of @localhost on address
179164562SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
179264562SgshapiroR<@> < $* @ [127.0.0.1] >
179364562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
179464562SgshapiroR<@> < $* @ localhost.$m >
179564562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
179638032Speterifdef(`_NO_UUCP_', `dnl',
179764562Sgshapiro`R<@> < $* @ localhost.UUCP >
179864562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
179964562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
180064562Sgshapirodnl	or:    <@> <address>
180164562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
180264562SgshapiroR<@> $*			$: $1			no localhost as domain
180364562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
180464562Sgshapirodnl	or:    <address>
180564562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
180664562SgshapiroR<? $=w> $*		$: $2			local client: ok
180790792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
180864562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
180964562SgshapiroR<?> $*			$: $1')
181064562Sgshapirodnl workspace: address (or <address>)
181164562SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
181264562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
181364562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
181464562SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
181564562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
1816102528SgshapiroR<?> $* < @ $* $=P >	$: <_RES_OK_> $1 < @ $2 $3 >
181764562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
181898121Sgshapirodnl A sender address with my local host name ($j) is safe
1819102528SgshapiroR<?> $* < @ $j >	$: <_RES_OK_> $1 < @ $j >
182064562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
182190792Sgshapiro`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
182264562Sgshapiro`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
182364562SgshapiroR<? $* <$->> $* < @ $+ >
182464562Sgshapiro			$: <$2> $3 < @ $4 >')
182590792Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
182664562Sgshapirodnl mark is ? iff the address is user (wo @domain)
182738032Speter
182864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
182964562Sgshapiro# check sender address: user@address, user@, address
183064562Sgshapirodnl should we remove +ext from user?
183190792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
183290792SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
183364562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
183464562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
183564562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
183664562Sgshapirodnl will only return user<@domain when "reversing" the args
183790792SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
183864562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
183964562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
184064562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
184138032Speter# retransform for further use
184264562Sgshapirodnl required form:
184364562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
184464562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
184564562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
184664562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
184764562Sgshapirodnl mark is ? iff the address is user (wo @domain)
184838032Speter
184938032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
185038032Speter# handle case of no @domain on address
185164562Sgshapirodnl prepend daemon_flags
185264562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
185364562Sgshapirodnl accept unqualified sender: change mark to avoid test
185490792SgshapiroR$* u $* $| <?> $*	$: <_RES_OK_> $3
185564562Sgshapirodnl remove daemon_flags
185664562SgshapiroR$* $| $*		$: $2
1857110560SgshapiroR<?> $*			$: < ? $&{client_addr} > $1
1858102528SgshapiroR<?> $*			$@ <_RES_OK_>			...local unqualed ok
185990792SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
186038032Speter							...remote is not')
186138032Speter# check results
186264562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
186390792SgshapiroR<$={ResOk}> $*		$@ <_RES_OK_>	domain ok: stop
186464562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
186590792SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
186664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
186790792SgshapiroR<$={Accept}> $*	$# $1		accept from access map
186838032SpeterR<DISCARD> $*		$#discard $: discard
186990792Sgshapiroifdef(`_FFR_QUARANTINE',
187090792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
187164562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
187264562Sgshapirodnl error tag
187364562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
187464562SgshapiroR<ERROR:$+> $*		$#error $: $1
187590792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
187664562Sgshapirodnl generic error from access map
187764562SgshapiroR<$+> $*		$#error $: $1		error from access db',
187838032Speter`dnl')
187938032Speter
188038032Speter######################################################################
188138032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
188238032Speter######################################################################
188338032Speter
188438032SpeterSLocal_check_rcpt
188564562SgshapiroScheck`'_U_`'rcpt
188638032SpeterR$*			$: $1 $| $>"Local_check_rcpt" $1
188738032SpeterR$* $| $#$*		$#$2
188838032SpeterR$* $| $*		$@ $>"Basic_check_rcpt" $1
188938032Speter
189038032SpeterSBasic_check_rcpt
189190792Sgshapiro# empty address?
189290792SgshapiroR<>			$#error $@ nouser $: "553 User address required"
189390792SgshapiroR$@			$#error $@ nouser $: "553 User address required"
189438032Speter# check for deferred delivery mode
189598121SgshapiroR$*			$: < $&{deliveryMode} > $1
189638032SpeterR< d > $*		$@ deferred
189738032SpeterR< $* > $*		$: $2
189838032Speter
189964562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
190090792Sgshapirodnl this code checks for user@host where host is not a FQHN.
190190792Sgshapirodnl it is not activated.
190290792Sgshapirodnl notice: code to check for a recipient without a domain name is
190390792Sgshapirodnl available down below; look for the same macro.
190490792Sgshapirodnl this check is done here because the name might be qualified by the
190590792Sgshapirodnl canonicalization.
190690792Sgshapiro# require fully qualified domain part?
190790792Sgshapirodnl very simple canonification: make sure the address is in < >
190864562SgshapiroR$+			$: <?> $1
190990792SgshapiroR<?> <$+>		$: <@> <$1>
191090792SgshapiroR<?> $+			$: <@> <$1>
191190792SgshapiroR<@> < postmaster >	$: postmaster
1912110560SgshapiroR<@> < $* @ $+ . $+ >	$: < $1 @ $2 . $3 >
191364562Sgshapirodnl prepend daemon_flags
191490792SgshapiroR<@> $*			$: $&{daemon_flags} $| <@> $1
191564562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
1916120256Sgshapirodnl 'r'equire qual.rcpt: ok
1917120256SgshapiroR$* r $* $| <@> < $+ @ $+ >	$: < $3 @ $4 >
191864562Sgshapirodnl do not allow these at all or only from local systems?
1919120256SgshapiroR$* r $* $| <@> < $* >	$: < ? $&{client_name} > < $3 >
192064562SgshapiroR<?> < $* >		$: <$1>
192164562SgshapiroR<? $=w> < $* >		$: <$1>
192290792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
192364562Sgshapirodnl remove daemon_flags for other cases
192464562SgshapiroR$* $| <@> $*		$: $2', `dnl')
192564562Sgshapiro
192690792Sgshapirodnl ##################################################################
192790792Sgshapirodnl call subroutines for recipient and relay
192890792Sgshapirodnl possible returns from subroutines:
192990792Sgshapirodnl $#TEMP	temporary failure
193090792Sgshapirodnl $#error	permanent failure (or temporary if from access map)
193190792Sgshapirodnl $#other	stop processing
193290792Sgshapirodnl RELAY	RELAYing allowed
193390792Sgshapirodnl other	otherwise
193490792Sgshapiro######################################################################
193590792SgshapiroR$*			$: $1 $| @ $>"Rcpt_ok" $1
193690792Sgshapirodnl temporary failure? remove mark @ and remember
193790792SgshapiroR$* $| @ $#TEMP $+	$: $1 $| T $2
193890792Sgshapirodnl error or ok (stop)
193990792SgshapiroR$* $| @ $#$*		$#$2
194090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
194190792SgshapiroR$* $| @ RELAY		$@ RELAY
194290792Sgshapirodnl something else: call check sender (relay)
194390792SgshapiroR$* $| @ $*		$: O $| $>"Relay_ok" $1
194490792Sgshapirodnl temporary failure: call check sender (relay)
194590792SgshapiroR$* $| T $+		$: T $2 $| $>"Relay_ok" $1
194690792Sgshapirodnl temporary failure? return that
194790792SgshapiroR$* $| $#TEMP $+	$#error $2
194890792Sgshapirodnl error or ok (stop)
194990792SgshapiroR$* $| $#$*		$#$2
195090792SgshapiroR$* $| RELAY		$@ RELAY
195190792Sgshapirodnl something else: return previous temp failure
195290792SgshapiroR T $+ $| $*		$#error $1
195390792Sgshapiro# anything else is bogus
195490792SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
195590792Sgshapirodivert(0)
195690792Sgshapiro
195790792Sgshapiro######################################################################
195890792Sgshapiro### Rcpt_ok: is the recipient ok?
195990792Sgshapirodnl input: recipient address (RCPT TO)
196090792Sgshapirodnl output: see explanation at call
196190792Sgshapiro######################################################################
196290792SgshapiroSRcpt_ok
196338032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
196442575SpeterR$*			$: $>CanonAddr $1
196538032SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
196638032Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
196738032Speter
196842575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
196942575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
197042575Speter# unlimited bestmx
197142575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
197242575Speter`dnl
197342575Speter# limit bestmx to $=B
197443730SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
197590792SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
197642575SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
197742575SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
197842575Speter
197938032Speterifdef(`_BLACKLIST_RCPT_',`dnl
198064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
198138032Speter# blacklist local users or any host from receiving mail
198238032SpeterR$*			$: <?> $1
198364562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
198464562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
198590792SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
198690792SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
198764562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
198864562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
198964562Sgshapirodnl will only return user<@domain when "reversing" the args
199090792SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
199164562SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
199264562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
199390792Sgshapirodnl we may have to filter here because otherwise some RHSs
199490792Sgshapirodnl would be interpreted as generic error messages...
199590792Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
199690792Sgshapirodnl that would make a lot of things easier.
199764562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
199890792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
199990792SgshapiroR<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
200090792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
200190792Sgshapirodnl compatility with 8.11/8.10:
200264562Sgshapirodnl we have to filter these because otherwise they would be interpreted
200364562Sgshapirodnl as generic error message...
200464562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
200564562Sgshapirodnl that would make a lot of things easier.
200664562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
200764562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
200890792SgshapiroR<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
200964562SgshapiroR<DISCARD> $*		$#discard $: discard
201090792Sgshapiroifdef(`_FFR_QUARANTINE',
201190792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
201264562Sgshapirodnl error tag
201364562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
201464562SgshapiroR<ERROR:$+> $*		$#error $: $1
201590792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
201664562Sgshapirodnl generic error from access map
201764562SgshapiroR<$+> $*		$#error $: $1		error from access db
201864562SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
201938032Speter
202090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
202190792Sgshapiro# authenticated via TLS?
202290792SgshapiroR$*			$: $1 $| $>RelayTLS	client authenticated?
202390792SgshapiroR$* $| $# $+		$# $2			error/ok?
202490792SgshapiroR$* $| $*		$: $1			no
202564562Sgshapiro
202690792SgshapiroR$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
202790792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth
202890792SgshapiroR$* $| $# $*		$# $2
202990792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
203090792SgshapiroR$* $| NO		$: $1
203190792SgshapiroR$* $| $*		$: $1 $| $&{auth_type}
203290792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ]
203364562Sgshapirodnl empty ${auth_type}?
203464562SgshapiroR$* $|			$: $1
203564562Sgshapirodnl mechanism ${auth_type} accepted?
203664562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
203790792SgshapiroR$* $| $={TrustAuthMech}	$# RELAY
203890792Sgshapirodnl remove ${auth_type}
203964562SgshapiroR$* $| $*		$: $1
204071345Sgshapirodnl workspace: localpart<@domain> | localpart
204164562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
204271345Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
204371345SgshapiroR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
204438032Speter# anything terminating locally is ok
204538032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
204690792SgshapiroR$+ < @ $* $=m >	$@ RELAY', `dnl')
204790792SgshapiroR$+ < @ $=w >		$@ RELAY
204838032Speterifdef(`_RELAY_HOSTS_ONLY_',
204990792Sgshapiro`R$+ < @ $=R >		$@ RELAY
205064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
205164562SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
205264562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
205364562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
205490792Sgshapiro`R$+ < @ $* $=R >	$@ RELAY
205564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
205690792SgshapiroR$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')')
205764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
205864562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
205990792SgshapiroR<RELAY> $*		$@ RELAY
206090792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
206138032SpeterR<$*> <$*>		$: $2',`dnl')
206238032Speter
206364562Sgshapiro
206438032Speterifdef(`_RELAY_MX_SERVED_', `dnl
206538032Speter# allow relaying for hosts which we MX serve
206664562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
206764562Sgshapirodnl this must not necessarily happen if the client is checked first...
206890792SgshapiroR< : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
206990792SgshapiroR<$* : $=w . : $*> $*	$@ RELAY
207042575SpeterR< : $* : > $*		$: $2',
207138032Speter`dnl')
207238032Speter
207338032Speter# check for local user (i.e. unqualified address)
207438032SpeterR$*			$: <?> $1
207542575SpeterR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
207638032Speter# local user is ok
207764562Sgshapirodnl is it really? the standard requires user@domain, not just user
207864562Sgshapirodnl but we should accept it anyway (maybe making it an option:
207964562Sgshapirodnl RequireFQDN ?)
208064562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
208164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
208290792SgshapiroR<?> postmaster		$@ OK
208364562Sgshapiro# require qualified recipient?
208464562Sgshapirodnl prepend daemon_flags
208564562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
208664562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
208764562Sgshapirodnl do not allow these at all or only from local systems?
208864562Sgshapirodnl r flag? add client_name
208964562SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
209064562Sgshapirodnl no r flag: relay to local user (only local part)
209164562Sgshapiro# no qualified recipient required
209290792SgshapiroR$* $| <?> $+		$@ RELAY
209364562Sgshapirodnl client_name is empty
209490792SgshapiroR<?> <?> $+		$@ RELAY
209564562Sgshapirodnl client_name is local
209690792SgshapiroR<? $=w> <?> $+		$@ RELAY
209764562Sgshapirodnl client_name is not local
209864562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
209964562Sgshapirodnl no qualified recipient required
210090792SgshapiroR<?> $+			$@ RELAY')
210164562Sgshapirodnl it is a remote user: remove mark and then check client
210238032SpeterR<$+> $*		$: $2
210364562Sgshapirodnl currently the recipient address is not used below
210438032Speter
210590792Sgshapiro######################################################################
210690792Sgshapiro### Relay_ok: is the relay/sender ok?
210790792Sgshapirodnl input: ignored
210890792Sgshapirodnl output: see explanation at call
210990792Sgshapiro######################################################################
211090792SgshapiroSRelay_ok
211138032Speter# anything originating locally is ok
211264562Sgshapiro# check IP address
211364562SgshapiroR$*			$: $&{client_addr}
211490792SgshapiroR$@			$@ RELAY		originated locally
211590792SgshapiroR0			$@ RELAY		originated locally
2116110560SgshapiroR127.0.0.1		$@ RELAY		originated locally
2117110560SgshapiroRIPv6:::1		$@ RELAY		originated locally
211890792SgshapiroR$=R $*			$@ RELAY		relayable IP address
211964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
212090792SgshapiroR$*			$: $>A <$1> <?> <+ Connect> <$1>
212190792SgshapiroR<RELAY> $* 		$@ RELAY		relayable IP address
2122102528Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl
2123102528Sgshapirodnl this will cause rejections in cases like:
2124102528Sgshapirodnl Connect:My.Host.Domain	RELAY
2125102528Sgshapirodnl Connect:My.Net		REJECT
2126102528Sgshapirodnl since in check_relay client_name is checked before client_addr
2127102528SgshapiroR<REJECT> $* 		$@ REJECT		rejected IP address')
212890792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
212964562SgshapiroR<$*> <$*>		$: $2', `dnl')
213064562SgshapiroR$*			$: [ $1 ]		put brackets around it...
213190792SgshapiroR$=w			$@ RELAY		... and see if it is local
213264562Sgshapiro
213364562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
213464562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
213564562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
213664562Sgshapirodnl input: {client_addr} or something "broken"
213764562Sgshapirodnl just throw the input away; we do not need it.
213864562Sgshapiro# check whether FROM is allowed to use system as relay
213964562SgshapiroR$*			$: <?> $>CanonAddr $&f
214090792SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
214164562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
214264562Sgshapiro# check whether local FROM is ok
214390792SgshapiroR<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
214464562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
214594334SgshapiroR<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <>
214690792SgshapiroR<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
214790792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
214890792Sgshapiro', `dnl
214990792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_',
215090792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
215164562Sgshapiro')',
215264562Sgshapiro`dnl')
215364562Sgshapirodnl')', `dnl')
215490792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind.
215590792Sgshapirodnl it does not matter in this case because the following rule ignores
215690792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace.
215764562Sgshapiro
215864562Sgshapiro# check client name: first: did it resolve?
215964562Sgshapirodnl input: ignored
216064562SgshapiroR$*			$: < $&{client_resolve} >
216190792SgshapiroR<TEMP>			$#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
216264562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
216364562SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
216464562Sgshapirodnl ${client_resolve} should be OK, so go ahead
216590792SgshapiroR$*			$: <@> $&{client_name}
216690792Sgshapirodnl should not be necessary since it has been done for client_addr already
2167110560Sgshapirodnl this rule actually may cause a problem if {client_name} resolves to ""
2168110560Sgshapirodnl however, this should not happen since the forward lookup should fail
2169110560Sgshapirodnl and {client_resolve} should be TEMP or FAIL.
2170110560Sgshapirodnl nevertheless, removing the rule doesn't hurt.
2171110560Sgshapirodnl R<@>			$@ RELAY
217290792Sgshapirodnl workspace: <@> ${client_name} (not empty)
217338032Speter# pass to name server to make hostname canonical
217490792SgshapiroR<@> $* $=P 		$:<?>  $1 $2
217590792SgshapiroR<@> $+			$:<?>  $[ $1 $]
217690792Sgshapirodnl workspace: <?> ${client_name} (canonified)
217764562SgshapiroR$* .			$1			strip trailing dots
217838032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
217990792SgshapiroR<?> $* $=m		$@ RELAY', `dnl')
218090792SgshapiroR<?> $=w		$@ RELAY
218138032Speterifdef(`_RELAY_HOSTS_ONLY_',
218290792Sgshapiro`R<?> $=R		$@ RELAY
218364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
218464562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
218564562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
218690792Sgshapiro`R<?> $* $=R			$@ RELAY
218764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
218890792SgshapiroR<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
218964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
219090792SgshapiroR<RELAY> $*		$@ RELAY
219190792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
219238032SpeterR<$*> <$*>		$: $2',`dnl')
219390792Sgshapirodnl end of _PROMISCUOUS_RELAY_
219464562Sgshapirodivert(0)
219564562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
219664562Sgshapiro# turn a canonical address in the form user<@domain>
219764562Sgshapiro# qualify unqual. addresses with $j
219864562Sgshapirodnl it might have been only user (without <@domain>)
219964562SgshapiroSFullAddr
220064562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
220164562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
220264562SgshapiroR$+			$@ $1 <@ $j >
220338032Speter
2204120256SgshapiroSDelay_TLS_Clt
2205110560Sgshapiro# authenticated?
2206110560Sgshapirodnl code repeated here from Basic_check_mail
2207110560Sgshapirodnl only called from check_rcpt in delay mode if checkrcpt returns $#
2208110560SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
2209110560SgshapiroR$* $| $#$+		$#$2
2210110560Sgshapirodnl return result from checkrcpt
2211120256SgshapiroR$* $| $*		$# $1
2212110560SgshapiroR$*			$# $1
2213110560Sgshapiro
2214120256SgshapiroSDelay_TLS_Clt2
2215110560Sgshapiro# authenticated?
2216110560Sgshapirodnl code repeated here from Basic_check_mail
2217110560Sgshapirodnl only called from check_rcpt in delay mode if stopping due to Friend/Hater
2218110560SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
2219110560SgshapiroR$* $| $#$+		$#$2
2220110560Sgshapirodnl return result from friend/hater check
2221120256SgshapiroR$* $| $*		$@ $1
2222110560SgshapiroR$*			$@ $1
2223110560Sgshapiro
222464562Sgshapiro# call all necessary rulesets
222564562SgshapiroScheck_rcpt
222664562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
222764562Sgshapirodnl which is the correct DSN code?
222864562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
2229110560Sgshapiro
223064562SgshapiroR$+			$: $1 $| $>checkrcpt $1
223164562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
2232110560Sgshapirodnl on error (or discard) stop now
2233110560SgshapiroR$+ $| $#error $*	$#error $2
2234110560SgshapiroR$+ $| $#discard $*	$#discard $2
2235110560Sgshapirodnl otherwise call tls_client; see above
2236120256SgshapiroR$+ $| $#$*		$@ $>"Delay_TLS_Clt" $2
223764562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
223864562Sgshapiroifdef(`_SPAM_FH_',
223964562Sgshapiro`dnl lookup user@ and user@address
224064562Sgshapiroifdef(`_ACCESS_TABLE_', `',
224164562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
224264562Sgshapiro')')dnl
224364562Sgshapirodnl one of the next two rules is supposed to match
224464562Sgshapirodnl this code has been copied from BLACKLIST... etc
224564562Sgshapirodnl and simplified by omitting some < >.
224690792SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
224790792SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
224864562Sgshapirodnl R<?>		$@ something_is_very_wrong_here
224990792Sgshapiro# lookup the addresses only with Spam tag
225090792SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
225164562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
225264562Sgshapirodnl', `dnl')
225364562Sgshapiroifdef(`_SPAM_FRIEND_',
225464562Sgshapiro`# is the recipient a spam friend?
225564562Sgshapiroifdef(`_SPAM_HATER_',
2256110560Sgshapiro	`errprint(`*** ERROR: define either Hater or Friend -- not both.
225764562Sgshapiro')', `dnl')
2258120256SgshapiroR<FRIEND> $+		$@ $>"Delay_TLS_Clt2" SPAMFRIEND
225964562SgshapiroR<$*> $+		$: $2',
226064562Sgshapiro`dnl')
226164562Sgshapiroifdef(`_SPAM_HATER_',
226264562Sgshapiro`# is the recipient no spam hater?
226390792SgshapiroR<HATER> $+		$: $1			spam hater: continue checks
2264120256SgshapiroR<$*> $+		$@ $>"Delay_TLS_Clt2" NOSPAMHATER	everyone else: stop
226564562Sgshapirodnl',`dnl')
226664562Sgshapirodnl run further checks: check_mail
226764562Sgshapirodnl should we "clean up" $&f?
226890792Sgshapiroifdef(`_FFR_MAIL_MACRO',
226990792Sgshapiro`R$*			$: $1 $| $>checkmail $&{mail_from}',
227090792Sgshapiro`R$*			$: $1 $| $>checkmail <$&f>')
227194334Sgshapirodnl recipient (canonical format) $| result of checkmail
227264562SgshapiroR$* $| $#$*		$#$2
227364562Sgshapirodnl run further checks: check_relay
227494334SgshapiroR$* $| $*		$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
227564562SgshapiroR$* $| $#$*		$#$2
227638032SpeterR$* $| $*		$: $1
227738032Speter', `dnl')
227890792Sgshapiro
227990792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
228064562Sgshapiro######################################################################
228190792Sgshapiro###  F: LookUpFull -- search for an entry in access database
228290792Sgshapiro###
228390792Sgshapiro###	lookup of full key (which should be an address) and
228490792Sgshapiro###	variations if +detail exists: +* and without +detail
228590792Sgshapiro###
228690792Sgshapiro###	Parameters:
228790792Sgshapiro###		<$1> -- key
228890792Sgshapiro###		<$2> -- default (what to return if not found in db)
228990792Sgshapirodnl			must not be empty
229090792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
229190792Sgshapiro###			! does lookup only with tag
229290792Sgshapiro###			+ does lookup with and without tag
229390792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
229490792Sgshapirodnl returns:		<default> <passthru>
229590792Sgshapirodnl 			<result> <passthru>
229690792Sgshapiro######################################################################
229790792Sgshapiro
229890792SgshapiroSF
229990792Sgshapirodnl workspace: <key> <def> <o tag> <thru>
230090792Sgshapirodnl full lookup
230190792Sgshapirodnl    2    3  4    5
230290792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
230390792Sgshapirodnl no match, try without tag
230490792Sgshapirodnl   1    2      3    4
230590792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
230690792Sgshapirodnl no match, +detail: try +*
230790792Sgshapirodnl   1    2    3    4    5  6    7
230890792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
230990792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
231090792Sgshapirodnl no match, +detail: try +* without tag
231190792Sgshapirodnl   1    2    3    4      5    6
231290792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
231390792Sgshapiro			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
231490792Sgshapirodnl no match, +detail: try without +detail
231590792Sgshapirodnl   1    2    3    4    5  6    7
231690792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
231790792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
231890792Sgshapirodnl no match, +detail: try without +detail and without tag
231990792Sgshapirodnl   1    2    3    4      5    6
232090792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
232190792Sgshapiro			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
232290792Sgshapirodnl no match, return <default> <passthru>
232390792Sgshapirodnl   1    2    3  4    5
232490792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
232590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
232690792Sgshapirodnl            2    3  4    5
232790792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
232890792Sgshapirodnl match, return <match> <passthru>
232990792Sgshapirodnl    2    3  4    5
233090792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
233190792Sgshapiro
233290792Sgshapiro######################################################################
233390792Sgshapiro###  E: LookUpExact -- search for an entry in access database
233490792Sgshapiro###
233590792Sgshapiro###	Parameters:
233690792Sgshapiro###		<$1> -- key
233790792Sgshapiro###		<$2> -- default (what to return if not found in db)
233890792Sgshapirodnl			must not be empty
233990792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
234090792Sgshapiro###			! does lookup only with tag
234190792Sgshapiro###			+ does lookup with and without tag
234290792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
234390792Sgshapirodnl returns:		<default> <passthru>
234490792Sgshapirodnl 			<result> <passthru>
234590792Sgshapiro######################################################################
234690792Sgshapiro
234790792SgshapiroSE
234890792Sgshapirodnl    2    3  4    5
234990792SgshapiroR<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
235090792Sgshapirodnl no match, try without tag
235190792Sgshapirodnl   1    2      3    4
235290792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
235390792Sgshapirodnl no match, return default passthru
235490792Sgshapirodnl   1    2    3  4    5
235590792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
235690792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
235790792Sgshapirodnl            2    3  4    5
235890792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
235990792Sgshapirodnl match, return <match> <passthru>
236090792Sgshapirodnl    2    3  4    5
236190792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
236290792Sgshapiro
236390792Sgshapiro######################################################################
236490792Sgshapiro###  U: LookUpUser -- search for an entry in access database
236590792Sgshapiro###
236690792Sgshapiro###	lookup of key (which should be a local part) and
236790792Sgshapiro###	variations if +detail exists: +* and without +detail
236890792Sgshapiro###
236990792Sgshapiro###	Parameters:
237090792Sgshapiro###		<$1> -- key (user@)
237190792Sgshapiro###		<$2> -- default (what to return if not found in db)
237290792Sgshapirodnl			must not be empty
237390792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
237490792Sgshapiro###			! does lookup only with tag
237590792Sgshapiro###			+ does lookup with and without tag
237690792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
237790792Sgshapirodnl returns:		<default> <passthru>
237890792Sgshapirodnl 			<result> <passthru>
237990792Sgshapiro######################################################################
238090792Sgshapiro
238190792SgshapiroSU
238290792Sgshapirodnl user lookups are always with trailing @
238390792Sgshapirodnl    2    3  4    5
238490792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
238590792Sgshapirodnl no match, try without tag
238690792Sgshapirodnl   1    2      3    4
238790792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
238890792Sgshapirodnl do not remove the @ from the lookup:
238990792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
239090792Sgshapirodnl no match, +detail: try +*
239190792Sgshapirodnl   1    2      3    4  5    6
239290792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
239390792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
239490792Sgshapirodnl no match, +detail: try +* without tag
239590792Sgshapirodnl   1    2      3      4    5
239690792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
239790792Sgshapiro			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
239890792Sgshapirodnl no match, +detail: try without +detail
239990792Sgshapirodnl   1    2      3    4  5    6
240090792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
240190792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
240290792Sgshapirodnl no match, +detail: try without +detail and without tag
240390792Sgshapirodnl   1    2      3      4    5
240490792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
240590792Sgshapiro			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
240690792Sgshapirodnl no match, return <default> <passthru>
240790792Sgshapirodnl   1    2    3  4    5
240890792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
240990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
241090792Sgshapirodnl            2    3  4    5
241190792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
241290792Sgshapirodnl match, return <match> <passthru>
241390792Sgshapirodnl    2    3  4    5
241490792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
241590792Sgshapiro
241690792Sgshapiro######################################################################
241764562Sgshapiro###  SearchList: search a list of items in the access map
241864562Sgshapiro###	Parameters:
241964562Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
242064562Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
242164562Sgshapirodnl	avoid errorneous matches (with error messages?)
242264562Sgshapirodnl	if we can make sure that tag is always a single token
242364562Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
242490792Sgshapirodnl	to avoid errorneous matchs (first rule: D: if there
242564562Sgshapirodnl	is that mark somewhere in the list, it will be taken).
242664562Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
242764562Sgshapirodnl	the tag only, e.g.:
242864562Sgshapiro###	where "exact" is either "+" or "!":
242964562Sgshapiro###	<+ TAG>	lookup with and w/o tag
243064562Sgshapiro###	<! TAG>	lookup with tag
243164562Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
243264562Sgshapirodnl		a blank between them and the tag.
243364562Sgshapiro###	possible values for "mark" are:
243490792Sgshapiro###		D: recursive host lookup (LookUpDomain)
243564562Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
243664562Sgshapiro###		E: exact lookup, no modifications
243764562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
243864562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
243964562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
244064562Sgshapiro######################################################################
244138032Speter
244264562Sgshapiro# class with valid marks for SearchList
244364562Sgshapirodnl if A is activated: add it
244490792SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
244564562SgshapiroSSearchList
244690792Sgshapiro# just call the ruleset with the name of the tag... nice trick...
244790792Sgshapirodnl       2       3    4
244890792SgshapiroR<$+> $| <$={src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
244990792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <>
245090792Sgshapirodnl no match and nothing left: return
245190792SgshapiroR<$+> $| <> $| <?> <>		$@ <?>
245290792Sgshapirodnl no match but something left: continue
245390792SgshapiroR<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
245490792Sgshapirodnl match: return
245590792SgshapiroR<$+> $| <$*> $| <$+> <>	$@ <$3>
245664562Sgshapirodnl return result from recursive invocation
245790792SgshapiroR<$+> $| <$+>			$@ <$2>
245890792Sgshapirodnl endif _ACCESS_TABLE_
245990792Sgshapirodivert(0)
246038032Speter
246190792Sgshapiro######################################################################
246290792Sgshapiro###  trust_auth: is user trusted to authenticate as someone else?
246390792Sgshapiro###
246490792Sgshapiro###	Parameters:
246590792Sgshapiro###		$1: AUTH= parameter from MAIL command
246690792Sgshapiro######################################################################
246790792Sgshapiro
246890792Sgshapirodnl empty ruleset definition so it can be called
246990792SgshapiroSLocal_trust_auth
247064562SgshapiroStrust_auth
247164562SgshapiroR$*			$: $&{auth_type} $| $1
247264562Sgshapiro# required by RFC 2554 section 4.
247364562SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
247464562Sgshapirodnl seems to be useful...
247564562SgshapiroR$* $| $&{auth_authen}		$@ identical
247664562SgshapiroR$* $| <$&{auth_authen}>	$@ identical
247764562Sgshapirodnl call user supplied code
2478120256SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $2
247964562SgshapiroR$* $| $#$*		$#$2
248064562Sgshapirodnl default: error
248164562SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
248264562Sgshapiro
248390792Sgshapiro######################################################################
248490792Sgshapiro###  Relay_Auth: allow relaying based on authentication?
248590792Sgshapiro###
248690792Sgshapiro###	Parameters:
248790792Sgshapiro###		$1: ${auth_type}
248890792Sgshapiro######################################################################
248990792SgshapiroSLocal_Relay_Auth
249064562Sgshapiro
249190792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
249290792Sgshapiro######################################################################
249390792Sgshapiro###  srv_features: which features to offer to a client?
249490792Sgshapiro###	(done in server)
249590792Sgshapiro######################################################################
249690792SgshapiroSsrv_features
249790792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl
249890792SgshapiroR$*			$: $1 $| $>"Local_srv_features" $1
249990792SgshapiroR$* $| $#$*		$#$2
250090792SgshapiroR$* $| $*		$: $1', `dnl')
250190792SgshapiroR$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
250290792SgshapiroR<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
250390792SgshapiroR<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
250464562SgshapiroR<?>$*		$@ OK
250590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
250690792SgshapiroR<$* _ATMPF_>$*	$#temp', `dnl')
250790792SgshapiroR<$+>$*		$# $1
250864562Sgshapiro
250990792Sgshapiro######################################################################
251090792Sgshapiro###  try_tls: try to use STARTTLS?
251190792Sgshapiro###	(done in client)
251290792Sgshapiro######################################################################
251364562SgshapiroStry_tls
251490792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl
251590792SgshapiroR$*			$: $1 $| $>"Local_try_tls" $1
251690792SgshapiroR$* $| $#$*		$#$2
251790792SgshapiroR$* $| $*		$: $1', `dnl')
251890792SgshapiroR$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
251990792SgshapiroR<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
252090792SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
252164562SgshapiroR<?>$*		$@ OK
252290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
252390792SgshapiroR<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
252471345SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
2525102528Sgshapiro 
252690792Sgshapiro######################################################################
252790792Sgshapiro###  tls_rcpt: is connection with server "good" enough?
252890792Sgshapiro###	(done in client, per recipient)
252990792Sgshapirodnl called from deliver() before RCPT command
253090792Sgshapiro###
253190792Sgshapiro###	Parameters:
253290792Sgshapiro###		$1: recipient
253390792Sgshapiro######################################################################
253490792SgshapiroStls_rcpt
253590792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl
253690792SgshapiroR$*			$: $1 $| $>"Local_tls_rcpt" $1
253790792SgshapiroR$* $| $#$*		$#$2
253890792SgshapiroR$* $| $*		$: $1', `dnl')
253990792Sgshapirodnl store name of other side
254090792SgshapiroR$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
254190792Sgshapirodnl canonify recipient address
254290792SgshapiroR$+			$: <?> $>CanonAddr $1
254390792Sgshapirodnl strip trailing dots
254490792SgshapiroR<?> $+ < @ $+ . >	<?> $1 <@ $2 >
254590792Sgshapirodnl full address?
254690792SgshapiroR<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
254790792Sgshapirodnl only localpart?
254890792SgshapiroR<?> $+			$: $1 $| <U:$1@> <E:>
254990792Sgshapirodnl look it up
255090792Sgshapirodnl also look up a default value via E:
255190792SgshapiroR$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
255290792Sgshapirodnl found nothing: stop here
255390792SgshapiroR$* $| <?>	$@ OK
255490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
255590792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
255690792Sgshapirodnl use the generic routine (for now)
255790792SgshapiroR$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
255864562Sgshapiro
255990792Sgshapiro######################################################################
256090792Sgshapiro###  tls_client: is connection with client "good" enough?
256190792Sgshapiro###	(done in server)
256290792Sgshapiro###
256390792Sgshapiro###	Parameters:
256490792Sgshapiro###		${verify} $| (MAIL|STARTTLS)
256590792Sgshapiro######################################################################
256664562Sgshapirodnl MAIL: called from check_mail
256764562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
256864562SgshapiroStls_client
256990792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl
257090792SgshapiroR$*			$: $1 $| $>"Local_tls_client" $1
257190792SgshapiroR$* $| $#$*		$#$2
257290792SgshapiroR$* $| $*		$: $1', `dnl')
257364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
257490792Sgshapirodnl store name of other side
257590792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
257664562Sgshapirodnl ignore second arg for now
257764562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
257864562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
257964562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
258090792SgshapiroR$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
258190792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
258264562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
258364562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
258490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
258590792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
258690792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
258790792SgshapiroR$* $| $*	$@ $>"TLS_connection" $1')
258864562Sgshapiro
258990792Sgshapiro######################################################################
259090792Sgshapiro###  tls_server: is connection with server "good" enough?
259190792Sgshapiro###	(done in client)
259290792Sgshapiro###
259390792Sgshapiro###	Parameter:
259490792Sgshapiro###		${verify}
259590792Sgshapiro######################################################################
259664562Sgshapirodnl i.e. has the server been authenticated and is encryption active?
259764562Sgshapirodnl called from deliver() after STARTTLS command
259864562SgshapiroStls_server
259990792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl
260090792SgshapiroR$*			$: $1 $| $>"Local_tls_server" $1
260190792SgshapiroR$* $| $#$*		$#$2
260290792SgshapiroR$* $| $*		$: $1', `dnl')
260364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
260490792Sgshapirodnl store name of other side
260590792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
260690792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
260790792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
260864562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
260964562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
261090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
261190792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
261290792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
261390792SgshapiroR$*		$@ $>"TLS_connection" $1')
261464562Sgshapiro
261590792Sgshapiro######################################################################
261690792Sgshapiro###  TLS_connection: is TLS connection "good" enough?
261790792Sgshapiro###
261890792Sgshapiro###	Parameters:
261964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
262090792Sgshapiro###		${verify} $| <Requirement> [<>]', `dnl
262190792Sgshapiro###		${verify}')
262290792Sgshapiro###		Requirement: RHS from access map, may be ? for none.
262390792Sgshapirodnl	syntax for Requirement:
262490792Sgshapirodnl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
262590792Sgshapirodnl	extensions: could be a list of further requirements
262690792Sgshapirodnl		for now: CN:string	{cn_subject} == string
262790792Sgshapiro######################################################################
262890792SgshapiroSTLS_connection
262990792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
263090792Sgshapirodnl deal with TLS handshake failures: abort
263190792SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
263290792Sgshapirodivert(-1)')
263364562Sgshapirodnl common ruleset for tls_{client|server}
263490792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>]
263564562Sgshapirodnl remove optional <>
263664562SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
263790792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup>
263890792Sgshapiro# create the appropriate error codes
263964562Sgshapirodnl permanent or temporary error?
264064562SgshapiroR$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
264164562SgshapiroR$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
264264562Sgshapirodnl default case depends on TLS_PERM_ERR
264364562SgshapiroR$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
264490792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
264590792Sgshapiro# deal with TLS handshake failures: abort
264664562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
264764562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
264864562Sgshapirodnl use default error
264964562SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
265090792SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
265190792Sgshapirodnl separate optional requirements
265290792SgshapiroR$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
265390792SgshapiroR$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> <> $1
265490792Sgshapirodnl separate optional requirements
265590792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
265664562Sgshapirodnl some other value in access map: accept
265764562Sgshapirodnl this also allows to override the default case (if used)
265864562SgshapiroR$* $| $*			$@ OK
265964562Sgshapiro# authentication required: give appropriate error
266064562Sgshapiro# other side did authenticate (via STARTTLS)
266190792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
266264562Sgshapirodnl only verification required and it succeeded
266390792SgshapiroR<$*><VERIFY> <> OK		$@ OK
266490792Sgshapirodnl verification required and it succeeded but extensions are given
266590792Sgshapirodnl change it to <SMTP:ESC> <REQ:0>  <extensions>
266690792SgshapiroR<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
266764562Sgshapirodnl verification required + some level of encryption
266890792SgshapiroR<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
266964562Sgshapirodnl just some level of encryption required
267090792SgshapiroR<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
267190792Sgshapirodnl workspace:
267290792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
267390792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
267490792Sgshapirodnl verification required but ${verify} is not set (case 1.)
267590792SgshapiroR<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
267690792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
267790792SgshapiroR<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
267890792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
267990792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
268064562Sgshapirodnl some other value for ${verify}
268190792SgshapiroR<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
268290792Sgshapirodnl some level of encryption required: get the maximum level (case 2.)
268390792SgshapiroR<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
268464562Sgshapirodnl compare required bits with actual bits
268590792SgshapiroR<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
268690792SgshapiroR<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
268790792Sgshapirodnl strength requirements fulfilled
268890792Sgshapirodnl TLS Additional Requirements Separator
268990792Sgshapirodnl this should be something which does not appear in the extensions itself
269090792Sgshapirodnl @ could be part of a CN, DN, etc...
269190792Sgshapirodnl use < > ? those are encoded in CN, DN, ...
269290792Sgshapirodefine(`_TLS_ARS_', `++')dnl
269390792Sgshapirodnl workspace:
269490792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
269590792SgshapiroR<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
269690792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
269790792Sgshapirodnl continue: check  extensions
269890792SgshapiroR<$-:$+ _TLS_ARS_ >			$@ OK
269990792Sgshapirodnl split extensions into own list
270090792SgshapiroR<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
270190792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
270290792SgshapiroR<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
270364562Sgshapiro
270490792Sgshapiro######################################################################
270590792Sgshapiro###  TLS_req: check additional TLS requirements
270690792Sgshapiro###
270790792Sgshapiro###	Parameters: [<list> <of> <req>] $| <$-:$+>
270890792Sgshapiro###		$-: SMTP reply code
270990792Sgshapiro###		$+: Enhanced Status Code
271090792Sgshapirodnl  further requirements for this ruleset:
271190792Sgshapirodnl	name of "other side" is stored is {TLS_name} (client/server_name)
271290792Sgshapirodnl
271390792Sgshapirodnl	currently only CN[:common_name] is implemented
271490792Sgshapirodnl	right now this is only a logical AND
271590792Sgshapirodnl	i.e. all requirements must be true
271690792Sgshapirodnl	how about an OR? CN must be X or CN must be Y or ..
271790792Sgshapirodnl	use a macro to compute this as a trivial sequential
271890792Sgshapirodnl	operations (no precedences etc)?
271990792Sgshapiro######################################################################
272090792SgshapiroSTLS_req
272190792Sgshapirodnl no additional requirements: ok
272290792SgshapiroR $| $+		$@ OK
272390792Sgshapirodnl require CN: but no CN specified: use name of other side
272490792SgshapiroR<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
272590792Sgshapirodnl match, check rest
272690792SgshapiroR<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
272790792Sgshapirodnl CN does not match
272890792Sgshapirodnl  1   2      3  4
272990792SgshapiroR<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
273090792Sgshapirodnl cert subject
273190792SgshapiroR<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
273290792Sgshapirodnl CS does not match
273390792Sgshapirodnl  1   2      3  4
2734110560SgshapiroR<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1
273590792Sgshapirodnl match, check rest
273690792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
273790792Sgshapirodnl CI does not match
273890792Sgshapirodnl  1   2      3  4
2739110560SgshapiroR<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1
274090792Sgshapirodnl return from recursive call
274190792SgshapiroROK			$@ OK
274290792Sgshapiro
274390792Sgshapiro######################################################################
274490792Sgshapiro###  max: return the maximum of two values separated by :
274590792Sgshapiro###
274690792Sgshapiro###	Parameters: [$-]:[$-]
274790792Sgshapiro######################################################################
274864562SgshapiroSmax
274964562SgshapiroR:		$: 0
275064562SgshapiroR:$-		$: $1
275164562SgshapiroR$-:		$: $1
275264562SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
275364562SgshapiroRTRUE:$-:$-	$: $2
275490792SgshapiroR$-:$-:$-	$: $2
275590792Sgshapirodnl endif _ACCESS_TABLE_
275690792Sgshapirodivert(0)
275764562Sgshapiro
275890792Sgshapiro######################################################################
275990792Sgshapiro###  RelayTLS: allow relaying based on TLS authentication
276090792Sgshapiro###
276190792Sgshapiro###	Parameters:
276290792Sgshapiro###		none
276390792Sgshapiro######################################################################
276490792SgshapiroSRelayTLS
276564562Sgshapiro# authenticated?
276664562Sgshapirodnl we do not allow relaying for anyone who can present a cert
276764562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
2768110560Sgshapirodnl CA in CertPath so we can authenticate users, we do not allow
276964562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
277064562Sgshapirodnl but anyway).
277164562Sgshapirodnl so here is the trick: if the verification succeeded
277264562Sgshapirodnl we look up the cert issuer in the access map
277364562Sgshapirodnl (maybe after extracting a part with a regular expression)
277464562Sgshapirodnl if this returns RELAY we relay without further questions
277564562Sgshapirodnl if it returns SUBJECT we perform a similar check on the
277664562Sgshapirodnl cert subject.
277764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
277890792SgshapiroR$*			$: <?> $&{verify}
277990792SgshapiroR<?> OK			$: OK		authenticated: continue
278090792SgshapiroR<?> $*			$@ NO		not authenticated
278164562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
278290792SgshapiroR$*			$: $(CERTIssuer $&{cert_issuer} $)',
278390792Sgshapiro`R$*			$: $&{cert_issuer}')
278490792SgshapiroR$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
278564562Sgshapirodnl use $# to stop further checks (delay_check)
278690792SgshapiroRRELAY			$# RELAY
278764562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
278890792SgshapiroRSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
278990792Sgshapiro`RSUBJECT		$: <@> $&{cert_subject}')
279090792SgshapiroR<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
279190792SgshapiroR<@> RELAY		$# RELAY
279290792SgshapiroR$*			$: NO', `dnl')
279364562Sgshapiro
279490792Sgshapiro######################################################################
279590792Sgshapiro###  authinfo: lookup authinfo in the access map
279690792Sgshapiro###
279790792Sgshapiro###	Parameters:
279890792Sgshapiro###		$1: {server_name}
279990792Sgshapiro###		$2: {server_addr}
280090792Sgshapirodnl	both are currently ignored
280190792Sgshapirodnl if it should be done via another map, we either need to restrict
280290792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another
280390792Sgshapirodnl parameter which I want to avoid, it's quite complex already)
280490792Sgshapiro######################################################################
280590792Sgshapirodnl omit this ruleset if neither is defined?
280690792Sgshapirodnl it causes DefaultAuthInfo to be ignored
280790792Sgshapirodnl (which may be considered a good thing).
280890792SgshapiroSauthinfo
280990792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl
281090792SgshapiroR$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
281190792SgshapiroR<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
281290792SgshapiroR<?>		$: <$(authinfo AuthInfo: $: ? $)>
281390792SgshapiroR<?>		$@ no				no authinfo available
281490792SgshapiroR<$*>		$# $1
281590792Sgshapirodnl', `dnl
281690792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
281790792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
281890792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
281990792SgshapiroR$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
282090792SgshapiroR$* $| <?>$*	$@ no				no authinfo available
282190792SgshapiroR$* $| <$*> <>	$# $2
282290792Sgshapirodnl', `dnl')')
282390792Sgshapiro
282464562Sgshapiroundivert(9)dnl LOCAL_RULESETS
282538032Speter#
282638032Speter######################################################################
282738032Speter######################################################################
282838032Speter#####
282964562Sgshapiro`#####			MAIL FILTER DEFINITIONS'
283064562Sgshapiro#####
283164562Sgshapiro######################################################################
283264562Sgshapiro######################################################################
283390792Sgshapiro_MAIL_FILTERS_
283464562Sgshapiro#
283564562Sgshapiro######################################################################
283664562Sgshapiro######################################################################
283764562Sgshapiro#####
283838032Speter`#####			MAILER DEFINITIONS'
283938032Speter#####
284038032Speter######################################################################
284138032Speter######################################################################
284264562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
284366494Sgshapiro
2844