proto.m4 revision 157001
138032Speterdivert(-1)
238032Speter#
3157001Sgshapiro# Copyright (c) 1998-2005 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
16157001SgshapiroVERSIONID(`$Id: proto.m4,v 8.718 2005/08/24 18:07:23 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
200132943SgshapiroC{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
264132943Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `0')
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?
391157001Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `0')
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')
428132943Sgshapiro_OPTION(Timeout.queuereturn.dsn, `confTO_QUEUERETURN_DSN', `5d')
42964562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
43064562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
43164562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
43264562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
433132943Sgshapiro_OPTION(Timeout.queuewarn.dsn, `confTO_QUEUEWARN_DSN', `4h')
43464562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
43564562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
43664562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
43764562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
43864562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
43964562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
44064562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
44190792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
44290792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m')
44390792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
44438032Speter
44590792Sgshapiro# time for DeliverBy; extension disabled if less than 0
44690792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
44790792Sgshapiro
44838032Speter# should we not prune routes in route-addr syntax addresses?
44964562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
45038032Speter
45138032Speter# queue up everything before forking?
45264562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
45338032Speter
45438032Speter# status file
45564562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
45638032Speter
45738032Speter# time zone handling:
45838032Speter#  if undefined, use system default
45938032Speter#  if defined but null, use TZ envariable passed in
46038032Speter#  if defined and non-null, use that info
46138032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
46238032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
46338032Speter	`O TimeZoneSpec=confTIME_ZONE')
46438032Speter
46538032Speter# default UID (can be username or userid:groupid)
46664562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
46738032Speter
46838032Speter# list of locations of user database file (null means no lookup)
46964562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
47038032Speter
47138032Speter# fallback MX host
47264562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
47338032Speter
474132943Sgshapiro# fallback smart host
475132943Sgshapiro_OPTION(FallbackSmartHost, `confFALLBACK_SMARTHOST', `fall.back.host.net')
476132943Sgshapiro
47738032Speter# if we are the best MX host for a site, try it directly instead of config err
47864562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
47938032Speter
48038032Speter# load average at which we just queue messages
48164562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8')
48238032Speter
48338032Speter# load average at which we refuse connections
48464562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
48538032Speter
486132943Sgshapiro# log interval when refusing connections for this long
487132943Sgshapiro_OPTION(RejectLogInterval, `confREJECT_LOG_INTERVAL', `3h')
488132943Sgshapiro
48990792Sgshapiro# load average at which we delay connections; 0 means no limit
49090792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0')
49190792Sgshapiro
49238032Speter# maximum number of children we allow at one time
49398841Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0')
49438032Speter
49538032Speter# maximum number of new connections per second
49671345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
49738032Speter
498132943Sgshapiro# Width of the window 
499132943Sgshapiro_OPTION(ConnectionRateWindowSize, `confCONNECTION_RATE_WINDOW_SIZE', `60s')
500132943Sgshapiro
50138032Speter# work recipient factor
50264562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
50338032Speter
50438032Speter# deliver each queued job in a separate process?
50564562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
50638032Speter
50738032Speter# work class factor
50864562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
50938032Speter
51038032Speter# work time factor
51164562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
51238032Speter
51338032Speter# default character set
514141858Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `unknown-8bit')
51538032Speter
51690792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
51764562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
51838032Speter
51938032Speter# hosts file (normally /etc/hosts)
52064562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
52138032Speter
52238032Speter# dialup line delay on connection failure
523157001Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `0s')
52438032Speter
52538032Speter# action to take if there are no recipients in the message
526157001Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `none')
52738032Speter
52838032Speter# chrooted environment for writing to files
529157001Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `')
53038032Speter
53138032Speter# are colons OK in addresses?
53264562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
53338032Speter
53438032Speter# shall I avoid expanding CNAMEs (violates protocols)?
53564562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
53638032Speter
53738032Speter# SMTP initial login message (old $e macro)
53864562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
53938032Speter
54038032Speter# UNIX initial From header format (old $l macro)
54164562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
54238032Speter
54338032Speter# From: lines that have embedded newlines are unwrapped onto one line
54464562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
54538032Speter
54638032Speter# Allow HELO SMTP command that does not `include' a host name
54764562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
54838032Speter
54938032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
55064562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
55138032Speter
55238032Speter# delimiter (operator) characters (old $o macro)
55364562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
55438032Speter
55538032Speter# shall I avoid calling initgroups(3) because of high NIS costs?
55664562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
55738032Speter
55838032Speter# are group-writable `:include:' and .forward files (un)trustworthy?
55990792Sgshapiro# True (the default) means they are not trustworthy.
56064562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
56190792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES',
56290792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
56390792Sgshapiro')')
56438032Speter
56538032Speter# where do errors that occur when sending errors get sent?
56664562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
56738032Speter
56864562Sgshapiro# where to save bounces if all else fails
56964562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
57064562Sgshapiro
57138032Speter# what user id do we assume for the majority of the processing?
57264562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
57338032Speter
57438032Speter# maximum number of recipients per SMTP envelope
575132943Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `0')
57638032Speter
57790792Sgshapiro# limit the rate recipients per SMTP envelope are accepted
57890792Sgshapiro# once the threshold number of recipients have been rejected
579132943Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `0')
58090792Sgshapiro
58138032Speter# shall we get local names from our installed interfaces?
58264562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
58338032Speter
58464562Sgshapiro# Return-Receipt-To: header implies DSN request
58564562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
58664562Sgshapiro
58764562Sgshapiro# override connection address (for testing)
58864562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
58964562Sgshapiro
59064562Sgshapiro# Trusted user for file ownership and starting the daemon
59164562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
59264562Sgshapiro
59364562Sgshapiro# Control socket for daemon management
59464562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
59564562Sgshapiro
59664562Sgshapiro# Maximum MIME header length to protect MUAs
597132943Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
59864562Sgshapiro
59964562Sgshapiro# Maximum length of the sum of all headers
60064562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
60164562Sgshapiro
60264562Sgshapiro# Maximum depth of alias recursion
60364562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
60464562Sgshapiro
60564562Sgshapiro# location of pid file
60664562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
60764562Sgshapiro
60864562Sgshapiro# Prefix string for the process title shown on 'ps' listings
60964562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
61064562Sgshapiro
61164562Sgshapiro# Data file (df) memory-buffer file maximum size
61264562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
61364562Sgshapiro
61464562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
61564562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
61664562Sgshapiro
61790792Sgshapiro# lookup type to find information about local mailboxes
61890792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
61990792Sgshapiro
620132943Sgshapiro# override compile time flag REQUIRES_DIR_FSYNC
621132943Sgshapiro_OPTION(RequiresDirfsync, `confREQUIRES_DIR_FSYNC', `true')
622132943Sgshapiro
62364562Sgshapiro# list of authentication mechanisms
62490792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
62564562Sgshapiro
626132943Sgshapiro# Authentication realm
627132943Sgshapiro_OPTION(AuthRealm, `confAUTH_REALM', `')
628132943Sgshapiro
62964562Sgshapiro# default authentication information for outgoing connections
63064562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
63164562Sgshapiro
63264562Sgshapiro# SMTP AUTH flags
63364562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
63464562Sgshapiro
63590792Sgshapiro# SMTP AUTH maximum encryption strength
63690792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
63790792Sgshapiro
63890792Sgshapiro# SMTP STARTTLS server options
63990792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
64090792Sgshapiro
64164562Sgshapiro# Input mail filters
64264562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
64364562Sgshapiro
64498841Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl
64564562Sgshapiro# Milter options
64690792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
64764562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
64864562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
64964562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
650125820Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')
651132943Sgshapiro_OPTION(Milter.macros.eom, `confMILTER_MACROS_EOM', `')')
65264562Sgshapiro
65364562Sgshapiro# CA directory
654110560Sgshapiro_OPTION(CACertPath, `confCACERT_PATH', `')
65564562Sgshapiro# CA file
656110560Sgshapiro_OPTION(CACertFile, `confCACERT', `')
65764562Sgshapiro# Server Cert
65864562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
65964562Sgshapiro# Server private key
66064562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
66164562Sgshapiro# Client Cert
66264562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
66364562Sgshapiro# Client private key
66464562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
665132943Sgshapiro# File containing certificate revocation lists 
666132943Sgshapiro_OPTION(CRLFile, `confCRL', `')
66764562Sgshapiro# DHParameters (only required if DSA/DH is used)
66864562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
66964562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
67064562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
67164562Sgshapiro
67290792Sgshapiro############################
67390792Sgshapiro`# QUEUE GROUP DEFINITIONS  #'
67490792Sgshapiro############################
67590792Sgshapiro_QUEUE_GROUP_
67642575Speter
67738032Speter###########################
67838032Speter#   Message precedences   #
67938032Speter###########################
68038032Speter
68138032SpeterPfirst-class=0
68238032SpeterPspecial-delivery=100
68338032SpeterPlist=-30
68438032SpeterPbulk=-60
68538032SpeterPjunk=-100
68638032Speter
68738032Speter#####################
68838032Speter#   Trusted users   #
68938032Speter#####################
69038032Speter
69138032Speter# this is equivalent to setting class "t"
69264562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
69338032SpeterTroot
69438032SpeterTdaemon
69538032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp')
69638032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
69738032Speter
69838032Speter#########################
69938032Speter#   Format of headers   #
70038032Speter#########################
70138032Speter
70238032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
703132943Sgshapiroifdef(`confMESSAGEID_HEADER',, `define(`confMESSAGEID_HEADER', `<$t.$i@$j>')')dnl
70438032SpeterH?P?Return-Path: <$g>
70538032SpeterHReceived: confRECEIVED_HEADER
70638032SpeterH?D?Resent-Date: $a
70738032SpeterH?D?Date: $a
70838032SpeterH?F?Resent-From: confFROM_HEADER
70938032SpeterH?F?From: confFROM_HEADER
71038032SpeterH?x?Full-Name: $x
71138032Speter# HPosted-Date: $a
71238032Speter# H?l?Received-Date: $b
713132943SgshapiroH?M?Resent-Message-Id: confMESSAGEID_HEADER
714132943SgshapiroH?M?Message-Id: confMESSAGEID_HEADER
71564562Sgshapiro
71638032Speter#
71738032Speter######################################################################
71838032Speter######################################################################
71938032Speter#####
72038032Speter#####			REWRITING RULES
72138032Speter#####
72238032Speter######################################################################
72338032Speter######################################################################
72438032Speter
72538032Speter############################################
72638032Speter###  Ruleset 3 -- Name Canonicalization  ###
72738032Speter############################################
72864562SgshapiroScanonify=3
72938032Speter
73038032Speter# handle null input (translate to <@> special case)
73138032SpeterR$@			$@ <@>
73238032Speter
73338032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
73438032SpeterR$*			$: $1 <@>			mark addresses
73538032SpeterR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
73638032SpeterR@ $* <@>		$: @ $1				unmark @host:...
73790792SgshapiroR$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
73838032SpeterR$* :: $* <@>		$: $1 :: $2			unmark node::addr
73938032SpeterR:`include': $* <@>	$: :`include': $1			unmark :`include':...
74038032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
74138032SpeterR$* : $* <@>		$: $2				strip colon if marked
74238032SpeterR$* <@>			$: $1				unmark
74338032SpeterR$* ;			   $1				strip trailing semi
74471345SgshapiroR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
74538032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
74638032Speter
74738032Speter# null input now results from list:; syntax
74838032SpeterR$@			$@ :; <@>
74938032Speter
75038032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
75138032SpeterR$*			$: < $1 >			housekeeping <>
75238032SpeterR$+ < $* >		   < $2 >			strip excess on left
75338032SpeterR< $* > $+		   < $1 >			strip excess on right
75438032SpeterR<>			$@ < @ >			MAIL FROM:<> case
75538032SpeterR< $+ >			$: $1				remove housekeeping <>
75638032Speter
75764562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
75838032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
75938032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
76038032Speter
76138032Speter# localize and dispose of route-based addresses
76290792Sgshapirodnl XXX: IPv6 colon conflict
76390792Sgshapiroifdef(`NO_NETINET6', `dnl',
76490792Sgshapiro`R@ [$+] : $+		$@ $>Canonify2 < @ [$1] > : $2	handle <route-addr>')
76564562SgshapiroR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
76664562Sgshapirodnl',`dnl
76764562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d>
76864562SgshapiroR@ $+ , $+		$2
76990792Sgshapiroifdef(`NO_NETINET6', `dnl',
77090792Sgshapiro`R@ [ $* ] : $+		$2')
77164562SgshapiroR@ $+ : $+		$2
77264562Sgshapirodnl')
77338032Speter
77438032Speter# find focus for list syntax
77564562SgshapiroR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
77638032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
77738032Speter
77838032Speter# find focus for @ syntax addresses
77938032SpeterR$+ @ $+		$: $1 < @ $2 >			focus on domain
78038032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
78164562SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
78238032Speter
78390792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here.
78490792Sgshapirodnl # do some sanity checking
78590792Sgshapirodnl R$* < @ $~[ $* : $* > $*	$1 < @ $2 $3 > $4	nix colons in addrs
78638032Speter
78738032Speterifdef(`_NO_UUCP_', `dnl',
78838032Speter`# convert old-style addresses to a domain-based address
78964562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
79064562SgshapiroR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
79164562SgshapiroR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
79238032Speter')
79338032Speterifdef(`_USE_DECNET_SYNTAX_',
79438032Speter`# convert node::user addresses into a domain-based address
79564562SgshapiroR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
79664562SgshapiroR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
79738032Speter',
79838032Speter	`dnl')
79938032Speter# if we have % signs, take the rightmost one
80038032SpeterR$* % $*		$1 @ $2				First make them all @s.
80138032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
80264562SgshapiroR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
80338032Speter
80438032Speter# else we must be a local name
80564562SgshapiroR$*			$@ $>Canonify2 $1
80638032Speter
80738032Speter
80838032Speter################################################
80938032Speter###  Ruleset 96 -- bottom half of ruleset 3  ###
81038032Speter################################################
81138032Speter
81264562SgshapiroSCanonify2=96
81338032Speter
81438032Speter# handle special cases for local names
81538032SpeterR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
81638032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
81738032Speterifdef(`_NO_UUCP_', `dnl',
81838032Speter`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
81964562Sgshapiro
82090792Sgshapiro# check for IPv4/IPv6 domain literal
82190792SgshapiroR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [addr]
82238032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
82338032SpeterR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
82438032Speter
82564562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl
82638032Speter# look up domains in the domain table
82738032SpeterR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
82838032Speter
82964562Sgshapiroundivert(2)dnl LOCAL_RULE_3
83038032Speter
83164562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl
83238032Speter# handle BITNET mapping
83338032SpeterR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
83438032Speter
83564562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl
83638032Speter# handle UUCP mapping
83738032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
83838032Speter
83938032Speterifdef(`_NO_UUCP_', `dnl',
84038032Speter`ifdef(`UUCP_RELAY',
84138032Speter`# pass UUCP addresses straight through
84238032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
84338032Speter`# if really UUCP, handle it immediately
84438032Speterifdef(`_CLASS_U_',
84538032Speter`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
84638032Speterifdef(`_CLASS_V_',
84738032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
84838032Speterifdef(`_CLASS_W_',
84938032Speter`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
85038032Speterifdef(`_CLASS_X_',
85138032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
85238032Speterifdef(`_CLASS_Y_',
85338032Speter`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
85438032Speter
85538032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl
85638032Speter# try UUCP traffic as a local address
85738032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
85838032SpeterR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
85938032Speter')')
86064562Sgshapiro# hostnames ending in class P are always canonical
86164562SgshapiroR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
86264562Sgshapirodnl apply the next rule only for hostnames not in class P
86364562Sgshapirodnl this even works for phrases in class P since . is in class P
86464562Sgshapirodnl which daemon flags are set?
86564562SgshapiroR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
86664562Sgshapirodnl the other rules in this section only apply if the hostname
86764562Sgshapirodnl does not end in class P hence no further checks are done here
86864562Sgshapirodnl if this ever changes make sure the lookups are "protected" again!
86964562Sgshapiroifdef(`_NO_CANONIFY_', `dnl
87064562Sgshapirodnl do not canonify unless:
87164562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection
87264562Sgshapirodnl	with class P is non-empty)
87364562Sgshapirodnl or {daemon_flags} has c set
87464562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify}
87564562SgshapiroR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
87664562Sgshapiro# pass to name server to make hostname canonical if requested
87764562SgshapiroR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
87864562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_
87964562SgshapiroR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
88064562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work
88164562SgshapiroR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
88264562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl
88364562Sgshapirodnl this should only apply to unqualified hostnames
88464562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
88564562Sgshapirodnl then $- does not work.
88664562Sgshapiro# lookup unqualified hostnames
88790792SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
88864562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
88964562Sgshapirodnl {daemon_flags} contains CC (do not canonify)
89071345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work
89171345Sgshapirodnl should we do this for every hostname: even unqualified?
89271345SgshapiroR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
89364562SgshapiroR$* CC $* $| $*			$: $3
89490792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
89590792Sgshapiro# do not canonify header addresses
89690792SgshapiroR$* $| $* < @ $* $~P > $*	$: $&{addr_type} $| $2 < @ $3 $4 > $5
89790792SgshapiroR$* h $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
89890792SgshapiroR$* h $* $| $*			$: $3', `dnl')
89938032Speter# pass to name server to make hostname canonical
90064562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
90164562Sgshapirodnl remove {daemon_flags} for other cases
90264562SgshapiroR$* $| $*			$: $2
90338032Speter
90438032Speter# local host aliases and pseudo-domains are always canonical
90538032SpeterR$* < @ $=w > $*		$: $1 < @ $2 . > $3
90638032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
90738032Speter`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
90838032Speter`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
90964562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
91064562Sgshapirodnl virtual hosts are also canonical
91164562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
91264562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
91364562Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
91464562Sgshapiro`dnl')
91590792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
91690792Sgshapirodnl hosts for genericstable are also canonical
91790792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_',
91890792Sgshapiro`R$* < @ $* $=G > $* 	$: $1 < @ $2 $3 . > $4',
91990792Sgshapiro`R$* < @ $=G > $* 	$: $1 < @ $2 . > $3')',
92090792Sgshapiro`dnl')
92164562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added
92264562Sgshapirodnl by one of the rules before
92338032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
92438032Speter
92538032Speter
92638032Speter##################################################
92738032Speter###  Ruleset 4 -- Final Output Post-rewriting  ###
92838032Speter##################################################
92964562SgshapiroSfinal=4
93038032Speter
93171345SgshapiroR$+ :; <@>		$@ $1 :				handle <list:;>
93238032SpeterR$* <@>			$@				handle <> and list:;
93338032Speter
93438032Speter# strip trailing dot off possibly canonical name
93538032SpeterR$* < @ $+ . > $*	$1 < @ $2 > $3
93638032Speter
93764562Sgshapiro# eliminate internal code
93838032SpeterR$* < @ *LOCAL* > $*	$1 < @ $j > $2
93938032Speter
94038032Speter# externalize local domain info
94138032SpeterR$* < $+ > $*		$1 $2 $3			defocus
94238032SpeterR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
94338032SpeterR@ $*			$@ @ $1				... and exit
94438032Speter
94538032Speterifdef(`_NO_UUCP_', `dnl',
94638032Speter`# UUCP must always be presented in old form
94738032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
94838032Speter
94938032Speterifdef(`_USE_DECNET_SYNTAX_',
95038032Speter`# put DECnet back in :: form
95138032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
95238032Speter	`dnl')
95338032Speter# delete duplicate local names
95438032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
95538032Speter
95638032Speter
95738032Speter
95838032Speter##############################################################
95938032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
96038032Speter###		   (used for recursive calls)		   ###
96138032Speter##############################################################
96238032Speter
96364562SgshapiroSRecurse=97
96464562SgshapiroR$*			$: $>canonify $1
96564562SgshapiroR$*			$@ $>parse $1
96638032Speter
96738032Speter
96838032Speter######################################
96938032Speter###   Ruleset 0 -- Parse Address   ###
97038032Speter######################################
97138032Speter
97264562SgshapiroSparse=0
97338032Speter
97438032SpeterR$*			$: $>Parse0 $1		initial parsing
97538032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
97664562SgshapiroR$*			$: $>ParseLocal $1	handle local hacks
97738032SpeterR$*			$: $>Parse1 $1		final parsing
97838032Speter
97938032Speter#
98038032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
98138032Speter#	This should either return with the (possibly modified) input
98238032Speter#	or return with a #error mailer.  It should not return with a
98338032Speter#	#mailer other than the #error mailer.
98438032Speter#
98538032Speter
98638032SpeterSParse0
98738032SpeterR<@>			$@ <@>			special case error msgs
98890792SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
98964562SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
99090792SgshapiroR<@ $+>			$#error $@ 5.1.3 $: "_CODE553 User address required"
99190792SgshapiroR$+ <@>			$#error $@ 5.1.3 $: "_CODE553 Hostname required"
99238032SpeterR$*			$: <> $1
99390792Sgshapirodnl allow tricks like [host1]:[host2]
99490792SgshapiroR<> $* < @ [ $* ] : $+ > $*	$1 < @ [ $2 ] : $3 > $4
99590792SgshapiroR<> $* < @ [ $* ] , $+ > $*	$1 < @ [ $2 ] , $3 > $4
99690792Sgshapirodnl but no a@[b]c
99790792SgshapiroR<> $* < @ [ $* ] $+ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid address"
99890792SgshapiroR<> $* < @ [ $+ ] > $*		$1 < @ [ $2 ] > $3
99990792SgshapiroR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
100038032SpeterR<> $*			$1
100190792SgshapiroR$* < @ . $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
100290792SgshapiroR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
100390792Sgshapirodnl no a@b@
100490792SgshapiroR$* < @ $* @ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid route address"
100590792Sgshapirodnl no a@b@c
100690792SgshapiroR$* @ $* < @ $* > $*	$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
100764562Sgshapirodnl comma only allowed before @; this check is not complete
100890792SgshapiroR$* , $~O $*		$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
100938032Speter
101090792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks
101190792SgshapiroR$* . < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
101290792SgshapiroR. $* < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
101390792Sgshapirodnl', `dnl')
101490792Sgshapiro
101538032Speter# now delete the local info -- note $=O to find characters that cause forwarding
101664562SgshapiroR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
101764562SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
101838032SpeterR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
101990792SgshapiroR< @ $+ >		$#error $@ 5.1.3 $: "_CODE553 User address required"
102064562SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
102138032SpeterR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
102290792SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "_CODE553 User address required"
102338032SpeterR$* $=O $* < @ *LOCAL* >
102464562Sgshapiro			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
102538032SpeterR$* < @ *LOCAL* >	$: $1
102638032Speter
102738032Speter#
102838032Speter#  Parse1 -- the bottom half of ruleset 0.
102938032Speter#
103038032Speter
103138032SpeterSParse1
103264562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
103364562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute}
103490792SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
103590792SgshapiroR$+ < @ $={LDAPRouteEquiv} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
103664562Sgshapiro`dnl')
103764562Sgshapiro
103838032Speterifdef(`_MAILER_smtp_',
103938032Speter`# handle numeric address spec
104064562Sgshapirodnl there is no check whether this is really an IP number
104164562SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
1042112810SgshapiroR$* < @ [ $+ ] > $*	$: $1 < @ [ $2 ] : $S > $3	Add smart host to path
104390792SgshapiroR$* < @ [ $+ ] : > $*		$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
104464562SgshapiroR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
104564562SgshapiroR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
104638032Speter	`dnl')
104738032Speter
104864562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
104938032Speter# handle virtual users
105090792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
105190792Sgshapirodnl this is not a documented option
105290792Sgshapirodnl it stops looping in virtusertable mapping if input and output
105390792Sgshapirodnl are identical, i.e., if address A is mapped to A.
105490792Sgshapirodnl it does not deal with multi-level recursion
105590792Sgshapiro# handle full domains in RHS of virtusertable
105690792SgshapiroR$+ < @ $+ >			$: $(macro {RecipientAddress} $) $1 < @ $2 >
105790792SgshapiroR$+ < @ $+ > 			$: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
105890792SgshapiroR<?> $+ $| $+			$: $1 $(macro {RecipientAddress} $@ $2 $)
105990792SgshapiroR<?> $+ $| $*			$: $1',
106090792Sgshapiro`dnl')
106164562SgshapiroR$+			$: <!> $1		Mark for lookup
106290792Sgshapirodnl input: <!> local<@domain>
106364562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
106464562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
106564562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
106690792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
106764562SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
106890792Sgshapirodnl if <@> local<@domain>: no match but try lookup
106990792Sgshapirodnl user+detail: try user++@domain if detail not empty
107090792SgshapiroR<@> $+ + $+ < @ $* . >
107190792Sgshapiro			$: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
107290792Sgshapirodnl user+detail: try user+*@domain
107338032SpeterR<@> $+ + $* < @ $* . >
107490792Sgshapiro			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
107590792Sgshapirodnl user+detail: try user@domain
107638032SpeterR<@> $+ + $* < @ $* . >
107790792Sgshapiro			$: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
107864562Sgshapirodnl try default entry: @domain
107990792Sgshapirodnl ++@domain
108090792SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
108164562Sgshapirodnl +*@domain
108290792SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
108364562Sgshapirodnl @domain if +detail exists
108498121Sgshapirodnl if no match, change marker to prevent a second @domain lookup
108598121SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . >
108698121Sgshapirodnl without +detail
108738032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
108890792Sgshapirodnl no match
108938032SpeterR<@> $+			$: $1
109090792Sgshapirodnl remove mark
109164562SgshapiroR<!> $+			$: $1
109264562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
109338032SpeterR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
109490792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
109590792Sgshapiro# check virtuser input address against output address, if same, skip recursion
109690792SgshapiroR< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
109790792Sgshapiro# it is the same: stop now
109890792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
109990792SgshapiroR< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
110090792Sgshapirodnl', `dnl')
110180785Sgshapirodnl this is not a documented option
110280785Sgshapirodnl it performs no looping at all for virtusertable
110377349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_',
110477349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
110577349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
110677349Sgshapirodnl', `dnl')
110738032Speter
110838032Speter# short circuit local delivery so forwarded email works
110938032Speterifdef(`_MAILER_usenet_', `dnl
111064562SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
111166494Sgshapiro
111266494Sgshapiro
111338032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
111438032Speter`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
111564562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
111664562Sgshapirodnl $H empty (but @$=w.)
111738032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
111838032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
111964562Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
112038032SpeterR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
112138032Speter
112264562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
112338032Speter# not local -- try mailer table lookup
112438032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
112538032SpeterR< $+ . > $*		$: < $1 > $2			strip trailing dot
112638032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
112764562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
112864562SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
112964562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
113038032Speter`dnl')
113164562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)'
113238032Speter
113338032Speterifdef(`_NO_UUCP_', `dnl',
113438032Speter`# resolve remotely connected UUCP links (if any)
113538032Speterifdef(`_CLASS_V_',
113664562Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
113738032Speter	`dnl')
113838032Speterifdef(`_CLASS_W_',
113964562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
114038032Speter	`dnl')
114138032Speterifdef(`_CLASS_X_',
114264562Sgshapiro`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
114338032Speter	`dnl')')
114438032Speter
114538032Speter# resolve fake top level domains by forwarding to other hosts
114638032Speterifdef(`BITNET_RELAY',
114764562Sgshapiro`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
114838032Speter	`dnl')
114938032Speterifdef(`DECNET_RELAY',
115064562Sgshapiro`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
115138032Speter	`dnl')
115238032Speterifdef(`_MAILER_pop_',
115338032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
115438032Speter	`dnl')
115538032Speterifdef(`_MAILER_fax_',
115638032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
115738032Speter`ifdef(`FAX_RELAY',
115864562Sgshapiro`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
115938032Speter	`dnl')')
116038032Speter
116138032Speterifdef(`UUCP_RELAY',
116238032Speter`# forward non-local UUCP traffic to our UUCP relay
116364562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
116438032Speter`ifdef(`_MAILER_uucp_',
116538032Speter`# forward other UUCP traffic straight to UUCP
116638032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
116738032Speter	`dnl')')
116838032Speterifdef(`_MAILER_usenet_', `
116938032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
117064562SgshapiroR$+ . USENET		$#usenet $@ usenet $: $1',
117138032Speter	`dnl')
117238032Speter
117338032Speterifdef(`_LOCAL_RULES_',
117438032Speter`# figure out what should stay in our local mail system
117538032Speterundivert(1)', `dnl')
117638032Speter
117738032Speter# pass names that still have a host to a smarthost (if defined)
117864562SgshapiroR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
117938032Speter
118038032Speter# deal with other remote names
118138032Speterifdef(`_MAILER_smtp_',
118264562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
118390792Sgshapiro`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
118438032Speter
118538032Speter# handle locally delivered names
118664562SgshapiroR$=L			$#_LOCAL_ $: @ $1		special local names
118738032SpeterR$+			$#_LOCAL_ $: $1			regular local names
118838032Speter
118938032Speter###########################################################################
119038032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
119138032Speter###########################################################################
119238032Speter
119364562SgshapiroSLocal_localaddr
119464562SgshapiroSlocaladdr=5
119564562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
119690792SgshapiroR$+ $| $#ok		$@ $1			no change
119764562SgshapiroR$+ $| $#$*		$#$2
119864562SgshapiroR$+ $| $*		$: $1
119938032Speter
120090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
120190792Sgshapiro# Preserve rcpt_host in {Host}
120290792SgshapiroR$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
120390792SgshapiroR$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
120490792SgshapiroR$+ $| $| $+		$: $1			h not set, {Host} set
120590792SgshapiroR$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
120695154SgshapiroR$+ $| $* @ $+ $| $*	$: $(macro {Host} $@ @$3 $) $1	set {Host} to host in h
120790792SgshapiroR$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
120890792Sgshapiro')dnl
120990792Sgshapiro
121090792Sgshapiroifdef(`_FFR_5_', `dnl
121166494Sgshapiro# Preserve host in a macro
121266494SgshapiroR$+			$: $(macro {LocalAddrHost} $) $1
121366494SgshapiroR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
121466494Sgshapiro
121590792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
121638032Speter# deal with plussed users so aliases work nicely
121766494SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
121866494SgshapiroR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
121966494Sgshapiro')
122038032Speter# prepend an empty "forward host" on the front
122138032SpeterR$+			$: <> $1
122238032Speter
122338032Speterifdef(`LUSER_RELAY', `dnl
122438032Speter# send unrecognized local users to a relay host
122590792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
122666494SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
122766494SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
122866494SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
122966494SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
123064562SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
123190792SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')
123290792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
123390792SgshapiroR< $+ > $+		$: < $1 > $2 $&{Host}')
123490792Sgshapirodnl')
123538032Speter
123690792Sgshapiroifdef(`MAIL_HUB', `dnl
123790792SgshapiroR< > $+			$: < $H > $1			try hub', `dnl')
123890792Sgshapiroifdef(`LOCAL_RELAY', `dnl
123990792SgshapiroR< > $+			$: < $R > $1			try relay', `dnl')
124090792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
124190792SgshapiroR< > $+			$@ $1', `dnl
124264562SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
124390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
124490792SgshapiroR< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
124564562SgshapiroR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
124664562SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
124738032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
124866494SgshapiroR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
124938032SpeterR< > < $+ >		$@ $1				no +detail
125043730SpeterR$+			$: $1 <> $&h			add +detail back in
125190792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
125290792SgshapiroR$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
125343730SpeterR$+ <> + $*		$: $1 + $2			check whether +detail
125466494SgshapiroR$+ <> $*		$: $1				else discard')
125564562SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
125664562SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
125790792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
125890792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
125990792SgshapiroR< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
126090792SgshapiroR< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
126190792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
126290792SgshapiroR< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
126364562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
126438032Speter
126564562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
126690792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
126738032Speter###################################################################
126890792Sgshapiro###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
126990792Sgshapirodnl input: <Domain> FullAddress
127090792Sgshapiro###################################################################
127190792Sgshapiro
127290792SgshapiroSLDAPMailertable
127390792SgshapiroR< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
127490792SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
127590792SgshapiroR< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
127690792SgshapiroR< $+ > $#$*		$#$2					found
127790792SgshapiroR< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
127890792Sgshapiro`dnl')
127990792Sgshapiro
128090792Sgshapiro###################################################################
128138032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
128264562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
128338032Speter###################################################################
128438032Speter
128564562SgshapiroSMailertable=90
128664562Sgshapirodnl shift and check
128764562Sgshapirodnl %2 is not documented in cf/README
128838032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
128964562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
129064562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
129164562SgshapiroR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
129264562Sgshapirodnl is $2 always empty?
129338032SpeterR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
129464562SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
129564562Sgshapirodnl return full address
129638032SpeterR< $* > $*		$@ $2				no mailertable match',
129738032Speter`dnl')
129838032Speter
129938032Speter###################################################################
130038032Speter###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
130164562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
130264562Sgshapirodnl	<> address				-> address
130364562Sgshapirodnl	<error:d.s.n:text>			-> error
1304120256Sgshapirodnl	<error:keyword:text>			-> error
130564562Sgshapirodnl	<error:text>				-> error
130664562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
130764562Sgshapirodnl	<mailer:host> address			-> mailer host address
130864562Sgshapirodnl	<localdomain> address			-> address
130964562Sgshapirodnl	<host> address				-> relay host address
131038032Speter###################################################################
131138032Speter
131264562SgshapiroSMailerToTriple=95
131338032SpeterR< > $*				$@ $1			strip off null relay
131464562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
1315120256SgshapiroR< error : $- : $+ > $*		$#error $@ $(dequote $1 $) $: $2
1316120256SgshapiroR< error : $+ > $*		$#error $: $1
131738032SpeterR< local : $* > $*		$>CanonLocal < $1 > $2
131890792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
131990792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
132090792SgshapiroR< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
132138032SpeterR< $=w > $*			$@ $2			delete local host
132238032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
132338032Speter
132438032Speter###################################################################
132538032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
132664562Sgshapirodnl input: <user> address
132764562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
132864562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
132964562Sgshapirodnl <> user <@host> rest		-> local user@host user
133064562Sgshapirodnl <> user				-> local user user
133164562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
133264562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
133364562Sgshapirodnl <user> lp				-> local lp user
133438032Speter###################################################################
133538032Speter
133638032SpeterSCanonLocal
133743730Speter# strip local host from routed addresses
133864562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
133964562SgshapiroR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
134043730Speter
134138032Speter# strip trailing dot from any host name that may appear
134238032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
134338032Speter
134438032Speter# handle local: syntax -- use old user, either with or without host
134538032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
134638032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
134738032Speter
134838032Speter# handle local:user@host syntax -- ignore host part
134938032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
135038032Speter
135138032Speter# handle local:user syntax
135238032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
135338032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
135438032Speter
135538032Speter###################################################################
135638032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
135738032Speter###################################################################
135838032Speter
135964562SgshapiroSMasqHdr=93
136038032Speter
136164562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
136238032Speter# handle generics database
136338032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
136464562Sgshapirodnl if generics should be applied add a @ as mark
136538032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
136638032Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
136738032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
136864562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
136964562Sgshapirodnl ignore the first case for now
137064562Sgshapirodnl if it has the mark lookup full address
137190792Sgshapirodnl broken: %1 is full address not just detail
137264562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
137364562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
137464562Sgshapirodnl no match, try user+detail@domain
137564562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
137664562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
137764562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
137864562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
137964562Sgshapirodnl no match, remove mark
138064562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
138164562Sgshapirodnl no match, try @domain for exceptions
138264562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
138364562Sgshapirodnl workspace: ... or <match> user <@domain>
138464562Sgshapirodnl no match, try local part
138538032SpeterR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
138664562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
138764562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
138864562SgshapiroR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
138964562SgshapiroR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
139038032SpeterR< > $*			$: $1				not found',
139138032Speter`dnl')
139238032Speter
139364562Sgshapiro# do not masquerade anything in class N
139464562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
139564562Sgshapiro
139690792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
139738032Speter# special case the users that should be exposed
139838032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
139938032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
140038032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
140138032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
140238032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
140338032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
140438032Speter
140538032Speter# handle domain-specific masquerading
140638032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
140738032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
140838032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
140938032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
141038032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
141138032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
141238032SpeterR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
141338032SpeterR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
141490792Sgshapirodnl', `dnl no masquerading
141590792Sgshapirodnl just fix *LOCAL* leftovers
141690792SgshapiroR$* < @ *LOCAL* >	$@ $1 < @ $j . >')
141738032Speter
141838032Speter###################################################################
141938032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
142038032Speter###################################################################
142138032Speter
142264562SgshapiroSMasqEnv=94
142338032Speterifdef(`_MASQUERADE_ENVELOPE_',
142464562Sgshapiro`R$+			$@ $>MasqHdr $1',
142538032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
142638032Speter
142738032Speter###################################################################
142838032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
142938032Speter###################################################################
143038032Speter
143164562SgshapiroSParseLocal=98
143264562Sgshapiroundivert(3)dnl LOCAL_RULE_0
143338032Speter
143464562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
143590792Sgshapiro######################################################################
143690792Sgshapiro###  LDAPExpand: Expand address using LDAP routing
143790792Sgshapiro###
143890792Sgshapiro###	Parameters:
143990792Sgshapiro###		<$1> -- parsed address (user < @ domain . >) (pass through)
144090792Sgshapiro###		<$2> -- RFC822 address (user @ domain) (used for lookup)
144190792Sgshapiro###		<$3> -- +detail information
144290792Sgshapiro###
144390792Sgshapiro###	Returns:
144490792Sgshapiro###		Mailer triplet ($#mailer $@ host $: address)
144590792Sgshapiro###		Parsed address (user < @ domain . >)
144690792Sgshapiro######################################################################
144790792Sgshapiro
1448132943Sgshapiro# SMTP operation modes
1449132943SgshapiroC{SMTPOpModes} s d D
1450132943Sgshapiro
145164562SgshapiroSLDAPExpand
145264562Sgshapiro# do the LDAP lookups
145390792SgshapiroR<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
145464562Sgshapiro
1455132943Sgshapiro# look for temporary failures and...
1456132943SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*>	$: $&{opMode} $| TMPF <$&{addr_type}> $| $3
1457132943SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*>	$: $&{opMode} $| TMPF <$&{addr_type}> $| $3
1458132943Sgshapiroifelse(_LDAP_ROUTE_MAPTEMP_, `_TEMPFAIL_', `dnl
1459132943Sgshapiro# ... temp fail RCPT SMTP commands
1460132943SgshapiroR$={SMTPOpModes} $| TMPF <e r> $| $+	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."')
1461132943Sgshapiro# ... return original address for MTA to queue up
1462132943SgshapiroR$* $| TMPF <$*> $| $+			$@ $3
146394334Sgshapiro
146464562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
146564562Sgshapiro# return the new mailRoutingAddress
146690792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
146790792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
146890792SgshapiroR<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
146990792SgshapiroR<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
147090792SgshapiroR<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
147164562Sgshapiro
147298121Sgshapiro
147364562Sgshapiro# if mailRoutingAddress and non-local mailHost,
147464562Sgshapiro# relay to mailHost with new mailRoutingAddress
147590792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
147690792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
147790792Sgshapiro# check mailertable for host, relay from there
147890792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
147990792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
148090792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
148190792Sgshapiro# check mailertable for host, relay from there
148290792SgshapiroR<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
148390792Sgshapiro`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
148464562Sgshapiro
148564562Sgshapiro# if no mailRoutingAddress and local mailHost,
148664562Sgshapiro# return original address
148790792SgshapiroR<> <$=w> <$+> <$+> <$*>	$@ $2
148864562Sgshapiro
148998121Sgshapiro
149064562Sgshapiro# if no mailRoutingAddress and non-local mailHost,
149164562Sgshapiro# relay to mailHost with original address
149290792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
149390792Sgshapiro# check mailertable for host, relay from there
149490792SgshapiroR<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
149590792Sgshapiro`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
149664562Sgshapiro
149790792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_',
149890792Sgshapiro`# if no mailRoutingAddress and no mailHost,
149990792Sgshapiro# try without +detail
150090792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
150190792Sgshapiro
1502132943Sgshapiroifdef(`_LDAP_ROUTE_NODOMAIN_', `dnl', `
150390792Sgshapiro# if still no mailRoutingAddress and no mailHost,
150464562Sgshapiro# try @domain
150590792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
150690792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
1507132943SgshapiroR<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>')
150864562Sgshapiro
150964562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
151064562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
151164562Sgshapiro# user does not exist
151290792SgshapiroR<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
151390792Sgshapiro# only give error for envelope recipient
151490792SgshapiroR<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
1515132943Sgshapiroifdef(`_LDAP_SENDER_MUST_EXIST_', `dnl
1516132943Sgshapiro# and the sender too
1517132943SgshapiroR<?> <e s> <$+>			$#error $@ nouser $: "550 User unknown"')
151890792SgshapiroR<?> <$*> <$+>			$@ $2',
151964562Sgshapiro`dnl
152064562Sgshapiro# return the original address
152190792SgshapiroR<> <> <$+> <@ $+> <$*>		$@ $1')',
152264562Sgshapiro`dnl')
152364562Sgshapiro
152464562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
152564562Sgshapiro')')
152690792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
152738032Speter######################################################################
152890792Sgshapiro###  D: LookUpDomain -- search for domain in access database
152938032Speter###
153038032Speter###	Parameters:
153138032Speter###		<$1> -- key (domain name)
153238032Speter###		<$2> -- default (what to return if not found in db)
153364562Sgshapirodnl			must not be empty
153490792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
153564562Sgshapiro###			! does lookup only with tag
153664562Sgshapiro###			+ does lookup with and without tag
153790792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
153864562Sgshapirodnl returns:		<default> <passthru>
153964562Sgshapirodnl 			<result> <passthru>
154038032Speter######################################################################
154138032Speter
154290792SgshapiroSD
154364562Sgshapirodnl workspace <key> <default> <passthru> <mark>
154464562Sgshapirodnl lookup with tag (in front, no delimiter here)
154590792Sgshapirodnl    2    3  4    5
154690792SgshapiroR<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
154764562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
154864562Sgshapirodnl lookup without tag?
154990792Sgshapirodnl   1    2      3    4
155090792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
155190792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
155290792Sgshapirodnl XXX apply this also to IP addresses?
155390792Sgshapirodnl currently it works the wrong way round for [1.2.3.4]
155490792Sgshapirodnl   1  2    3    4  5    6
155590792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
155690792Sgshapirodnl   1  2    3      4    5
155790792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
155890792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
155990792Sgshapirodnl found SKIP: return <default> and <passthru>
156090792Sgshapirodnl      1    2    3  4    5
156190792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
156290792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!)
156390792Sgshapirodnl    1  2     3    4  5    6
156490792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
156590792Sgshapiroifdef(`NO_NETINET6', `dnl',
156690792Sgshapiro`dnl not found: IPv6 net
156790792Sgshapirodnl (could be merged with previous rule if we have a class containing .:)
156890792Sgshapirodnl    1   2     3    4  5    6
156990792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
157090792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
157164562Sgshapirodnl not found, but subdomain: try again
157290792Sgshapirodnl   1  2    3    4  5    6
157390792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
157490792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
157590792Sgshapirodnl   1    2      3    4
157690792SgshapiroR<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
157790792Sgshapirodnl not found, no subdomain: return <default> and <passthru>
157890792Sgshapirodnl   1    2    3  4    5
157990792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
158090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
158190792Sgshapirodnl            2    3    4  5    6
158290792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
158390792Sgshapirodnl return <result of lookup> and <passthru>
158490792Sgshapirodnl    2    3    4  5    6
158590792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
158638032Speter
158738032Speter######################################################################
158890792Sgshapiro###  A: LookUpAddress -- search for host address in access database
158938032Speter###
159038032Speter###	Parameters:
159138032Speter###		<$1> -- key (dot quadded host address)
159238032Speter###		<$2> -- default (what to return if not found in db)
159364562Sgshapirodnl			must not be empty
159490792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
159564562Sgshapiro###			! does lookup only with tag
159664562Sgshapiro###			+ does lookup with and without tag
159790792Sgshapiro###		<$4> -- passthru (additional data passed through)
159864562Sgshapirodnl	returns:	<default> <passthru>
159964562Sgshapirodnl			<result> <passthru>
160038032Speter######################################################################
160138032Speter
160290792SgshapiroSA
160364562Sgshapirodnl lookup with tag
160490792Sgshapirodnl    2    3  4    5
160590792SgshapiroR<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
160664562Sgshapirodnl lookup without tag
160790792Sgshapirodnl   1    2      3    4
160890792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
160990792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
161090792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
161190792Sgshapirodnl found SKIP: return <default> and <passthru>
161290792Sgshapirodnl      1    2    3  4    5
161390792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
161490792Sgshapiroifdef(`NO_NETINET6', `dnl',
161590792Sgshapiro`dnl no match; IPv6: remove last part
161690792Sgshapirodnl   1   2    3    4  5    6
161790792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
161890792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
161964562Sgshapirodnl no match; IPv4: remove last part
162090792Sgshapirodnl   1  2    3    4  5    6
162190792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
162264562Sgshapirodnl no match: return default
162390792Sgshapirodnl   1    2    3  4    5
162490792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
162590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
162690792Sgshapirodnl            2    3    4  5    6
162790792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
162864562Sgshapirodnl match: return result
162990792Sgshapirodnl    2    3    4  5    6
163090792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
163190792Sgshapirodnl endif _ACCESS_TABLE_
163290792Sgshapirodivert(0)
163338032Speter######################################################################
163442575Speter###  CanonAddr --	Convert an address into a standard form for
163542575Speter###			relay checking.  Route address syntax is
163642575Speter###			crudely converted into a %-hack address.
163742575Speter###
163842575Speter###	Parameters:
163942575Speter###		$1 -- full recipient address
164042575Speter###
164142575Speter###	Returns:
164242575Speter###		parsed address, not in source route form
164364562Sgshapirodnl		user%host%host<@domain>
164464562Sgshapirodnl		host!user<@domain>
164542575Speter######################################################################
164642575Speter
164742575SpeterSCanonAddr
164864562SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
164964562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
165042575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
165142575SpeterR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
165242575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
165364562Sgshapirodnl')
165442575Speter
165542575Speter######################################################################
165638032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
165738032Speter###			$* $=m or the access database.
165838032Speter###			Check user portion for host separators.
165938032Speter###
166038032Speter###	Parameters:
166138032Speter###		$1 -- full recipient address
166238032Speter###
166338032Speter###	Returns:
166438032Speter###		parsed, non-local-relaying address
166538032Speter######################################################################
166638032Speter
166738032SpeterSParseRecipient
166864562Sgshapirodnl mark and canonify address
166942575SpeterR$*				$: <?> $>CanonAddr $1
167064562Sgshapirodnl workspace: <?> localpart<@domain[.]>
167142575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
167264562Sgshapirodnl workspace: <?> localpart<@domain>
167342575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
167438032Speter
167538032Speter# if no $=O character, no host in the user portion, we are done
167642575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
167764562Sgshapirodnl no $=O in localpart: return
167842575SpeterR<?> $*				$@ $1
167938032Speter
168090792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O
168164562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
168238032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
168338032Speter# if we relay, check username portion for user%host so host can be checked also
168442575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
168564562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
168664562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
168790792Sgshapiro
168890792Sgshapirodnl what if access map returns something else than RELAY?
168990792Sgshapirodnl we are only interested in RELAY entries...
169090792Sgshapirodnl other To: entries: blacklist recipient; generic entries?
169190792Sgshapirodnl if it is an error we probably do not want to relay anyway
169238032Speterifdef(`_RELAY_HOSTS_ONLY_',
169342575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
169464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
169564562SgshapiroR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
169642575SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
169742575Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
169864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
169990792SgshapiroR<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
170042575SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
170138032Speter
170264562Sgshapiro
170390792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl
170490792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
170590792SgshapiroR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
1706132943SgshapiroR<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1
170790792Sgshapirodnl yes: mark it as <RELAY>
170890792SgshapiroR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
170990792Sgshapirodnl no: put old <NO> mark back
171090792SgshapiroR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
171190792Sgshapiro
171290792Sgshapirodnl do we relay to this recipient domain?
171342575SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
171490792Sgshapirodnl something else
171590792SgshapiroR<$+> $*			$@ $2
171642575Speter
171764562Sgshapiro
171838032Speter######################################################################
171938032Speter###  check_relay -- check hostname/address on SMTP startup
172038032Speter######################################################################
172138032Speter
1722132943Sgshapiroifdef(`_CONTROL_IMMEDIATE_',`dnl
1723132943SgshapiroScheck_relay
1724132943Sgshapiroifdef(`_RATE_CONTROL_IMMEDIATE_',`dnl
1725132943Sgshapirodnl workspace: ignored...
1726132943SgshapiroR$*		$: $>"RateControl" dummy', `dnl')
1727132943Sgshapiroifdef(`_CONN_CONTROL_IMMEDIATE_',`dnl
1728132943Sgshapirodnl workspace: ignored...
1729132943SgshapiroR$*		$: $>"ConnControl" dummy', `dnl')
1730132943Sgshapirodnl')
1731132943Sgshapiro
173238032SpeterSLocal_check_relay
173364562SgshapiroScheck`'_U_`'relay
1734132943Sgshapiroifdef(`_USE_CLIENT_PTR_',`dnl
1735132943SgshapiroR$* $| $*		$: $&{client_ptr} $| $2', `dnl')
173638032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
173738032SpeterR$* $| $* $| $#$*	$#$3
173838032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
173938032Speter
174038032SpeterSBasic_check_relay
174138032Speter# check for deferred delivery mode
174298121SgshapiroR$*			$: < $&{deliveryMode} > $1
174338032SpeterR< d > $*		$@ deferred
174438032SpeterR< $* > $*		$: $2
174538032Speter
174664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
174766494Sgshapirodnl workspace: {client_name} $| {client_addr}
174890792SgshapiroR$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
174966494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
1750110560Sgshapirodnl OR $| $+ if client_name is empty
1751110560SgshapiroR   $| $+		$: $>A < $1 > <?> <+ Connect> <>	empty client_name
1752110560Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
175390792SgshapiroR<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
175490792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>)
175590792SgshapiroR<?> <$*>		$: OK				found nothing
175690792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
175790792SgshapiroR<$={Accept}> <$*>	$@ $1				return value of lookup
1758132943SgshapiroR<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"')
175990792SgshapiroR<DISCARD> <$*>		$#discard $: discard
1760132943SgshapiroR<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1
176164562Sgshapirodnl error tag
176266494SgshapiroR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
176366494SgshapiroR<ERROR:$+> <$*>		$#error $: $1
176490792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
176564562Sgshapirodnl generic error from access map
176666494SgshapiroR<$+> <$*>		$#error $: $1', `dnl')
176738032Speter
176864562Sgshapiroifdef(`_RBL_',`dnl
176964562Sgshapiro# DNS based IP address spam list
177090792Sgshapirodnl workspace: ignored...
177138032SpeterR$*			$: $&{client_addr}
177264562SgshapiroR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
177364562SgshapiroR<?>OK			$: OKSOFAR
177498121SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"',
177538032Speter`dnl')
1776132943Sgshapiroifdef(`_RATE_CONTROL_',`dnl
1777132943Sgshapiroifdef(`_RATE_CONTROL_IMMEDIATE_',`', `dnl
1778132943Sgshapirodnl workspace: ignored...
1779132943SgshapiroR$*		$: $>"RateControl" dummy')', `dnl')
1780132943Sgshapiroifdef(`_CONN_CONTROL_',`dnl
1781132943Sgshapiroifdef(`_CONN_CONTROL_IMMEDIATE_',`',`dnl
1782132943Sgshapirodnl workspace: ignored...
1783132943SgshapiroR$*		$: $>"ConnControl" dummy')', `dnl')
178464562Sgshapiroundivert(8)
178538032Speter
178638032Speter######################################################################
178738032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
178838032Speter######################################################################
178938032Speter
179038032SpeterSLocal_check_mail
179164562SgshapiroScheck`'_U_`'mail
179238032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
179338032SpeterR$* $| $#$*		$#$2
179438032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
179538032Speter
179638032SpeterSBasic_check_mail
179738032Speter# check for deferred delivery mode
179898121SgshapiroR$*			$: < $&{deliveryMode} > $1
179938032SpeterR< d > $*		$@ deferred
180038032SpeterR< $* > $*		$: $2
180138032Speter
180264562Sgshapiro# authenticated?
180364562Sgshapirodnl done first: we can require authentication for every mail transaction
180464562Sgshapirodnl workspace: address as given by MAIL FROM: (sender)
180564562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
180664562SgshapiroR$* $| $#$+		$#$2
180764562Sgshapirodnl undo damage: remove result of tls_client call
180864562SgshapiroR$* $| $*		$: $1
180938032Speter
181064562Sgshapirodnl workspace: address as given by MAIL FROM:
181164562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
181238032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
181364562Sgshapirodnl do some additional checks
181464562Sgshapirodnl no user@host
181564562Sgshapirodnl no user@localhost (if nonlocal sender)
181664562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
181764562Sgshapirodnl just make sure the address has <> around it (which is required by
181864562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
181964562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
182064562Sgshapirodnl not be modified by host lookups.
182164562SgshapiroR$+			$: <?> $1
182264562SgshapiroR<?><$+>		$: <@> <$1>
182364562SgshapiroR<?>$+			$: <@> <$1>
182464562Sgshapirodnl workspace: <@> <address>
182564562Sgshapirodnl prepend daemon_flags
182664562SgshapiroR$*			$: $&{daemon_flags} $| $1
182764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
182864562Sgshapirodnl do not allow these at all or only from local systems?
182964562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
183064562Sgshapirodnl accept unqualified sender: change mark to avoid test
183164562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
183264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
183364562Sgshapirodnl        or:                    <? ${client_name} > <address>
183464562Sgshapirodnl        or:                    <?> <address>
183564562Sgshapirodnl remove daemon_flags
183664562SgshapiroR$* $| $*		$: $2
183738032Speter# handle case of @localhost on address
183864562SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
183964562SgshapiroR<@> < $* @ [127.0.0.1] >
184064562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
184164562SgshapiroR<@> < $* @ localhost.$m >
184264562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
184338032Speterifdef(`_NO_UUCP_', `dnl',
184464562Sgshapiro`R<@> < $* @ localhost.UUCP >
184564562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
184664562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
184764562Sgshapirodnl	or:    <@> <address>
184864562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
184964562SgshapiroR<@> $*			$: $1			no localhost as domain
185064562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
185164562Sgshapirodnl	or:    <address>
185264562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
185364562SgshapiroR<? $=w> $*		$: $2			local client: ok
185490792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
185564562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
185664562SgshapiroR<?> $*			$: $1')
185764562Sgshapirodnl workspace: address (or <address>)
185864562SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
185964562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
186064562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
186164562SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
186264562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
1863102528SgshapiroR<?> $* < @ $* $=P >	$: <_RES_OK_> $1 < @ $2 $3 >
186464562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
186598121Sgshapirodnl A sender address with my local host name ($j) is safe
1866102528SgshapiroR<?> $* < @ $j >	$: <_RES_OK_> $1 < @ $j >
186764562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
186890792Sgshapiro`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
186964562Sgshapiro`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
187064562SgshapiroR<? $* <$->> $* < @ $+ >
187164562Sgshapiro			$: <$2> $3 < @ $4 >')
187290792Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
187364562Sgshapirodnl mark is ? iff the address is user (wo @domain)
187438032Speter
187564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
187664562Sgshapiro# check sender address: user@address, user@, address
187764562Sgshapirodnl should we remove +ext from user?
187890792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
187990792SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
188064562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
188164562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
188264562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
188364562Sgshapirodnl will only return user<@domain when "reversing" the args
188490792SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
188564562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
188664562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
188764562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
188838032Speter# retransform for further use
188964562Sgshapirodnl required form:
189064562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
189164562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
189264562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
189364562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
189464562Sgshapirodnl mark is ? iff the address is user (wo @domain)
189538032Speter
189638032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
189738032Speter# handle case of no @domain on address
189864562Sgshapirodnl prepend daemon_flags
189964562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
190064562Sgshapirodnl accept unqualified sender: change mark to avoid test
190190792SgshapiroR$* u $* $| <?> $*	$: <_RES_OK_> $3
190264562Sgshapirodnl remove daemon_flags
190364562SgshapiroR$* $| $*		$: $2
1904110560SgshapiroR<?> $*			$: < ? $&{client_addr} > $1
1905102528SgshapiroR<?> $*			$@ <_RES_OK_>			...local unqualed ok
190690792SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
190738032Speter							...remote is not')
190838032Speter# check results
190964562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
191090792SgshapiroR<$={ResOk}> $*		$@ <_RES_OK_>	domain ok: stop
191164562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
191290792SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
191364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
191490792SgshapiroR<$={Accept}> $*	$# $1		accept from access map
191538032SpeterR<DISCARD> $*		$#discard $: discard
1916132943SgshapiroR<QUARANTINE:$+> $*	$#error $@ quarantine $: $1
1917132943SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"')
191864562Sgshapirodnl error tag
191964562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
192064562SgshapiroR<ERROR:$+> $*		$#error $: $1
192190792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
192264562Sgshapirodnl generic error from access map
192364562SgshapiroR<$+> $*		$#error $: $1		error from access db',
192438032Speter`dnl')
192538032Speter
192638032Speter######################################################################
192738032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
192838032Speter######################################################################
192938032Speter
193038032SpeterSLocal_check_rcpt
193164562SgshapiroScheck`'_U_`'rcpt
193238032SpeterR$*			$: $1 $| $>"Local_check_rcpt" $1
193338032SpeterR$* $| $#$*		$#$2
193438032SpeterR$* $| $*		$@ $>"Basic_check_rcpt" $1
193538032Speter
193638032SpeterSBasic_check_rcpt
193790792Sgshapiro# empty address?
193890792SgshapiroR<>			$#error $@ nouser $: "553 User address required"
193990792SgshapiroR$@			$#error $@ nouser $: "553 User address required"
194038032Speter# check for deferred delivery mode
194198121SgshapiroR$*			$: < $&{deliveryMode} > $1
194238032SpeterR< d > $*		$@ deferred
194338032SpeterR< $* > $*		$: $2
194438032Speter
194564562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
194690792Sgshapirodnl this code checks for user@host where host is not a FQHN.
194790792Sgshapirodnl it is not activated.
194890792Sgshapirodnl notice: code to check for a recipient without a domain name is
194990792Sgshapirodnl available down below; look for the same macro.
195090792Sgshapirodnl this check is done here because the name might be qualified by the
195190792Sgshapirodnl canonicalization.
195290792Sgshapiro# require fully qualified domain part?
195390792Sgshapirodnl very simple canonification: make sure the address is in < >
195464562SgshapiroR$+			$: <?> $1
195590792SgshapiroR<?> <$+>		$: <@> <$1>
195690792SgshapiroR<?> $+			$: <@> <$1>
195790792SgshapiroR<@> < postmaster >	$: postmaster
1958110560SgshapiroR<@> < $* @ $+ . $+ >	$: < $1 @ $2 . $3 >
195964562Sgshapirodnl prepend daemon_flags
196090792SgshapiroR<@> $*			$: $&{daemon_flags} $| <@> $1
196164562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
1962120256Sgshapirodnl 'r'equire qual.rcpt: ok
1963120256SgshapiroR$* r $* $| <@> < $+ @ $+ >	$: < $3 @ $4 >
196464562Sgshapirodnl do not allow these at all or only from local systems?
1965120256SgshapiroR$* r $* $| <@> < $* >	$: < ? $&{client_name} > < $3 >
196664562SgshapiroR<?> < $* >		$: <$1>
196764562SgshapiroR<? $=w> < $* >		$: <$1>
196890792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
196964562Sgshapirodnl remove daemon_flags for other cases
197064562SgshapiroR$* $| <@> $*		$: $2', `dnl')
197164562Sgshapiro
197290792Sgshapirodnl ##################################################################
197390792Sgshapirodnl call subroutines for recipient and relay
197490792Sgshapirodnl possible returns from subroutines:
197590792Sgshapirodnl $#TEMP	temporary failure
197690792Sgshapirodnl $#error	permanent failure (or temporary if from access map)
197790792Sgshapirodnl $#other	stop processing
197890792Sgshapirodnl RELAY	RELAYing allowed
197990792Sgshapirodnl other	otherwise
198090792Sgshapiro######################################################################
198190792SgshapiroR$*			$: $1 $| @ $>"Rcpt_ok" $1
198290792Sgshapirodnl temporary failure? remove mark @ and remember
198390792SgshapiroR$* $| @ $#TEMP $+	$: $1 $| T $2
198490792Sgshapirodnl error or ok (stop)
198590792SgshapiroR$* $| @ $#$*		$#$2
198690792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
198790792SgshapiroR$* $| @ RELAY		$@ RELAY
198890792Sgshapirodnl something else: call check sender (relay)
198990792SgshapiroR$* $| @ $*		$: O $| $>"Relay_ok" $1
199090792Sgshapirodnl temporary failure: call check sender (relay)
199190792SgshapiroR$* $| T $+		$: T $2 $| $>"Relay_ok" $1
199290792Sgshapirodnl temporary failure? return that
199390792SgshapiroR$* $| $#TEMP $+	$#error $2
199490792Sgshapirodnl error or ok (stop)
199590792SgshapiroR$* $| $#$*		$#$2
199690792SgshapiroR$* $| RELAY		$@ RELAY
199790792Sgshapirodnl something else: return previous temp failure
199890792SgshapiroR T $+ $| $*		$#error $1
199990792Sgshapiro# anything else is bogus
200090792SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
200190792Sgshapirodivert(0)
200290792Sgshapiro
200390792Sgshapiro######################################################################
200490792Sgshapiro### Rcpt_ok: is the recipient ok?
200590792Sgshapirodnl input: recipient address (RCPT TO)
200690792Sgshapirodnl output: see explanation at call
200790792Sgshapiro######################################################################
200890792SgshapiroSRcpt_ok
200938032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
201042575SpeterR$*			$: $>CanonAddr $1
201138032SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
201238032Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
201338032Speter
201442575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
201542575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
201642575Speter# unlimited bestmx
201742575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
201842575Speter`dnl
201942575Speter# limit bestmx to $=B
202043730SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
202190792SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
202242575SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
202342575SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
202442575Speter
202538032Speterifdef(`_BLACKLIST_RCPT_',`dnl
202664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
202738032Speter# blacklist local users or any host from receiving mail
202838032SpeterR$*			$: <?> $1
202964562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
203064562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
203190792SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
203290792SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
203364562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
203464562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
203564562Sgshapirodnl will only return user<@domain when "reversing" the args
203690792SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
203764562SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
203864562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
203990792Sgshapirodnl we may have to filter here because otherwise some RHSs
204090792Sgshapirodnl would be interpreted as generic error messages...
204190792Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
204290792Sgshapirodnl that would make a lot of things easier.
204364562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
204490792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
204590792SgshapiroR<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
204690792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
204790792Sgshapirodnl compatility with 8.11/8.10:
204864562Sgshapirodnl we have to filter these because otherwise they would be interpreted
204964562Sgshapirodnl as generic error message...
205064562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
205164562Sgshapirodnl that would make a lot of things easier.
205264562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
205364562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
205490792SgshapiroR<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
205564562SgshapiroR<DISCARD> $*		$#discard $: discard
2056132943SgshapiroR<QUARANTINE:$+> $*	$#error $@ quarantine $: $1
205764562Sgshapirodnl error tag
205864562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
205964562SgshapiroR<ERROR:$+> $*		$#error $: $1
206090792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
206164562Sgshapirodnl generic error from access map
206264562SgshapiroR<$+> $*		$#error $: $1		error from access db
206364562SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
206438032Speter
206590792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
206690792Sgshapiro# authenticated via TLS?
206790792SgshapiroR$*			$: $1 $| $>RelayTLS	client authenticated?
206890792SgshapiroR$* $| $# $+		$# $2			error/ok?
206990792SgshapiroR$* $| $*		$: $1			no
207064562Sgshapiro
207190792SgshapiroR$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
207290792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth
207390792SgshapiroR$* $| $# $*		$# $2
207490792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
207590792SgshapiroR$* $| NO		$: $1
207690792SgshapiroR$* $| $*		$: $1 $| $&{auth_type}
207790792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ]
207864562Sgshapirodnl empty ${auth_type}?
207964562SgshapiroR$* $|			$: $1
208064562Sgshapirodnl mechanism ${auth_type} accepted?
208164562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
208290792SgshapiroR$* $| $={TrustAuthMech}	$# RELAY
208390792Sgshapirodnl remove ${auth_type}
208464562SgshapiroR$* $| $*		$: $1
208571345Sgshapirodnl workspace: localpart<@domain> | localpart
208664562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
208771345Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
208871345SgshapiroR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
208938032Speter# anything terminating locally is ok
209038032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
209190792SgshapiroR$+ < @ $* $=m >	$@ RELAY', `dnl')
209290792SgshapiroR$+ < @ $=w >		$@ RELAY
209338032Speterifdef(`_RELAY_HOSTS_ONLY_',
209490792Sgshapiro`R$+ < @ $=R >		$@ RELAY
209564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
209664562SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
209764562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
209864562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
209990792Sgshapiro`R$+ < @ $* $=R >	$@ RELAY
210064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2101132943Sgshapiroifdef(`_RELAY_FULL_ADDR_', `dnl
2102132943SgshapiroR$+ < @ $+ >		$: $1 < @ $2 > $| $>SearchList <+ To> $| <F:$1@$2> <D:$2> <F:$1@> <>
2103132943SgshapiroR$+ < @ $+ > $| <$*>	$: <$3> <$1 <@ $2>>
2104132943SgshapiroR$+ < @ $+ > $| $*	$: <$3> <$1 <@ $2>>',
2105132943Sgshapiro`R$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>')')')
210664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
210764562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
210890792SgshapiroR<RELAY> $*		$@ RELAY
210990792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
211038032SpeterR<$*> <$*>		$: $2',`dnl')
211138032Speter
211264562Sgshapiro
211338032Speterifdef(`_RELAY_MX_SERVED_', `dnl
211438032Speter# allow relaying for hosts which we MX serve
211564562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
211664562Sgshapirodnl this must not necessarily happen if the client is checked first...
2117132943SgshapiroR< : $* <TEMP> : > $*	$#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1
211890792SgshapiroR<$* : $=w . : $*> $*	$@ RELAY
211942575SpeterR< : $* : > $*		$: $2',
212038032Speter`dnl')
212138032Speter
212238032Speter# check for local user (i.e. unqualified address)
212338032SpeterR$*			$: <?> $1
212442575SpeterR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
212538032Speter# local user is ok
212664562Sgshapirodnl is it really? the standard requires user@domain, not just user
212764562Sgshapirodnl but we should accept it anyway (maybe making it an option:
212864562Sgshapirodnl RequireFQDN ?)
212964562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
213064562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
213190792SgshapiroR<?> postmaster		$@ OK
213264562Sgshapiro# require qualified recipient?
213364562Sgshapirodnl prepend daemon_flags
213464562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
213564562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
213664562Sgshapirodnl do not allow these at all or only from local systems?
213764562Sgshapirodnl r flag? add client_name
213864562SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
213964562Sgshapirodnl no r flag: relay to local user (only local part)
214064562Sgshapiro# no qualified recipient required
214190792SgshapiroR$* $| <?> $+		$@ RELAY
214264562Sgshapirodnl client_name is empty
214390792SgshapiroR<?> <?> $+		$@ RELAY
214464562Sgshapirodnl client_name is local
214590792SgshapiroR<? $=w> <?> $+		$@ RELAY
214664562Sgshapirodnl client_name is not local
214764562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
214864562Sgshapirodnl no qualified recipient required
214990792SgshapiroR<?> $+			$@ RELAY')
215064562Sgshapirodnl it is a remote user: remove mark and then check client
215138032SpeterR<$+> $*		$: $2
215264562Sgshapirodnl currently the recipient address is not used below
215338032Speter
215490792Sgshapiro######################################################################
215590792Sgshapiro### Relay_ok: is the relay/sender ok?
215690792Sgshapirodnl input: ignored
215790792Sgshapirodnl output: see explanation at call
215890792Sgshapiro######################################################################
215990792SgshapiroSRelay_ok
216038032Speter# anything originating locally is ok
216164562Sgshapiro# check IP address
216264562SgshapiroR$*			$: $&{client_addr}
216390792SgshapiroR$@			$@ RELAY		originated locally
216490792SgshapiroR0			$@ RELAY		originated locally
2165110560SgshapiroR127.0.0.1		$@ RELAY		originated locally
2166110560SgshapiroRIPv6:::1		$@ RELAY		originated locally
216790792SgshapiroR$=R $*			$@ RELAY		relayable IP address
216864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
216990792SgshapiroR$*			$: $>A <$1> <?> <+ Connect> <$1>
217090792SgshapiroR<RELAY> $* 		$@ RELAY		relayable IP address
2171102528Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl
2172102528Sgshapirodnl this will cause rejections in cases like:
2173102528Sgshapirodnl Connect:My.Host.Domain	RELAY
2174102528Sgshapirodnl Connect:My.Net		REJECT
2175102528Sgshapirodnl since in check_relay client_name is checked before client_addr
2176102528SgshapiroR<REJECT> $* 		$@ REJECT		rejected IP address')
217790792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
217864562SgshapiroR<$*> <$*>		$: $2', `dnl')
217964562SgshapiroR$*			$: [ $1 ]		put brackets around it...
218090792SgshapiroR$=w			$@ RELAY		... and see if it is local
218164562Sgshapiro
218264562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
218364562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
218464562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
218564562Sgshapirodnl input: {client_addr} or something "broken"
218664562Sgshapirodnl just throw the input away; we do not need it.
218764562Sgshapiro# check whether FROM is allowed to use system as relay
218864562SgshapiroR$*			$: <?> $>CanonAddr $&f
218990792SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
219064562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
219164562Sgshapiro# check whether local FROM is ok
219290792SgshapiroR<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
219364562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
219494334SgshapiroR<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <>
219590792SgshapiroR<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
219690792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
219790792Sgshapiro', `dnl
219890792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_',
219990792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
220064562Sgshapiro')',
220164562Sgshapiro`dnl')
220264562Sgshapirodnl')', `dnl')
220390792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind.
220490792Sgshapirodnl it does not matter in this case because the following rule ignores
220590792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace.
220664562Sgshapiro
220764562Sgshapiro# check client name: first: did it resolve?
220864562Sgshapirodnl input: ignored
220964562SgshapiroR$*			$: < $&{client_resolve} >
2210132943SgshapiroR<TEMP>			$#TEMP $@ 4.4.0 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
221164562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
221264562SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
221364562Sgshapirodnl ${client_resolve} should be OK, so go ahead
221490792SgshapiroR$*			$: <@> $&{client_name}
221590792Sgshapirodnl should not be necessary since it has been done for client_addr already
2216110560Sgshapirodnl this rule actually may cause a problem if {client_name} resolves to ""
2217110560Sgshapirodnl however, this should not happen since the forward lookup should fail
2218110560Sgshapirodnl and {client_resolve} should be TEMP or FAIL.
2219110560Sgshapirodnl nevertheless, removing the rule doesn't hurt.
2220110560Sgshapirodnl R<@>			$@ RELAY
222190792Sgshapirodnl workspace: <@> ${client_name} (not empty)
222238032Speter# pass to name server to make hostname canonical
222390792SgshapiroR<@> $* $=P 		$:<?>  $1 $2
222490792SgshapiroR<@> $+			$:<?>  $[ $1 $]
222590792Sgshapirodnl workspace: <?> ${client_name} (canonified)
222664562SgshapiroR$* .			$1			strip trailing dots
222738032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
222890792SgshapiroR<?> $* $=m		$@ RELAY', `dnl')
222990792SgshapiroR<?> $=w		$@ RELAY
223038032Speterifdef(`_RELAY_HOSTS_ONLY_',
223190792Sgshapiro`R<?> $=R		$@ RELAY
223264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
223364562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
223464562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
223590792Sgshapiro`R<?> $* $=R			$@ RELAY
223664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
223790792SgshapiroR<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
223864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
223990792SgshapiroR<RELAY> $*		$@ RELAY
224090792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
224138032SpeterR<$*> <$*>		$: $2',`dnl')
224290792Sgshapirodnl end of _PROMISCUOUS_RELAY_
224364562Sgshapirodivert(0)
224464562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
224564562Sgshapiro# turn a canonical address in the form user<@domain>
224664562Sgshapiro# qualify unqual. addresses with $j
224764562Sgshapirodnl it might have been only user (without <@domain>)
224864562SgshapiroSFullAddr
224964562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
225064562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
225164562SgshapiroR$+			$@ $1 <@ $j >
225238032Speter
2253120256SgshapiroSDelay_TLS_Clt
2254110560Sgshapiro# authenticated?
2255110560Sgshapirodnl code repeated here from Basic_check_mail
2256110560Sgshapirodnl only called from check_rcpt in delay mode if checkrcpt returns $#
2257110560SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
2258110560SgshapiroR$* $| $#$+		$#$2
2259110560Sgshapirodnl return result from checkrcpt
2260120256SgshapiroR$* $| $*		$# $1
2261110560SgshapiroR$*			$# $1
2262110560Sgshapiro
2263120256SgshapiroSDelay_TLS_Clt2
2264110560Sgshapiro# authenticated?
2265110560Sgshapirodnl code repeated here from Basic_check_mail
2266110560Sgshapirodnl only called from check_rcpt in delay mode if stopping due to Friend/Hater
2267110560SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
2268110560SgshapiroR$* $| $#$+		$#$2
2269110560Sgshapirodnl return result from friend/hater check
2270120256SgshapiroR$* $| $*		$@ $1
2271110560SgshapiroR$*			$@ $1
2272110560Sgshapiro
227364562Sgshapiro# call all necessary rulesets
227464562SgshapiroScheck_rcpt
227564562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
227664562Sgshapirodnl which is the correct DSN code?
227764562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
2278110560Sgshapiro
227964562SgshapiroR$+			$: $1 $| $>checkrcpt $1
228064562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
2281110560Sgshapirodnl on error (or discard) stop now
2282110560SgshapiroR$+ $| $#error $*	$#error $2
2283110560SgshapiroR$+ $| $#discard $*	$#discard $2
2284110560Sgshapirodnl otherwise call tls_client; see above
2285120256SgshapiroR$+ $| $#$*		$@ $>"Delay_TLS_Clt" $2
228664562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
228764562Sgshapiroifdef(`_SPAM_FH_',
228864562Sgshapiro`dnl lookup user@ and user@address
228964562Sgshapiroifdef(`_ACCESS_TABLE_', `',
229064562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
229164562Sgshapiro')')dnl
229264562Sgshapirodnl one of the next two rules is supposed to match
229364562Sgshapirodnl this code has been copied from BLACKLIST... etc
229464562Sgshapirodnl and simplified by omitting some < >.
229590792SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
229690792SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
229764562Sgshapirodnl R<?>		$@ something_is_very_wrong_here
229890792Sgshapiro# lookup the addresses only with Spam tag
229990792SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
230064562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
230164562Sgshapirodnl', `dnl')
230264562Sgshapiroifdef(`_SPAM_FRIEND_',
230364562Sgshapiro`# is the recipient a spam friend?
230464562Sgshapiroifdef(`_SPAM_HATER_',
2305110560Sgshapiro	`errprint(`*** ERROR: define either Hater or Friend -- not both.
230664562Sgshapiro')', `dnl')
2307120256SgshapiroR<FRIEND> $+		$@ $>"Delay_TLS_Clt2" SPAMFRIEND
230864562SgshapiroR<$*> $+		$: $2',
230964562Sgshapiro`dnl')
231064562Sgshapiroifdef(`_SPAM_HATER_',
231164562Sgshapiro`# is the recipient no spam hater?
231290792SgshapiroR<HATER> $+		$: $1			spam hater: continue checks
2313120256SgshapiroR<$*> $+		$@ $>"Delay_TLS_Clt2" NOSPAMHATER	everyone else: stop
231464562Sgshapirodnl',`dnl')
231564562Sgshapirodnl run further checks: check_mail
231664562Sgshapirodnl should we "clean up" $&f?
231790792Sgshapiroifdef(`_FFR_MAIL_MACRO',
231890792Sgshapiro`R$*			$: $1 $| $>checkmail $&{mail_from}',
231990792Sgshapiro`R$*			$: $1 $| $>checkmail <$&f>')
232094334Sgshapirodnl recipient (canonical format) $| result of checkmail
232164562SgshapiroR$* $| $#$*		$#$2
232264562Sgshapirodnl run further checks: check_relay
232394334SgshapiroR$* $| $*		$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
232464562SgshapiroR$* $| $#$*		$#$2
232538032SpeterR$* $| $*		$: $1
232638032Speter', `dnl')
232790792Sgshapiro
232890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
232964562Sgshapiro######################################################################
233090792Sgshapiro###  F: LookUpFull -- search for an entry in access database
233190792Sgshapiro###
233290792Sgshapiro###	lookup of full key (which should be an address) and
233390792Sgshapiro###	variations if +detail exists: +* and without +detail
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
234790792SgshapiroSF
234890792Sgshapirodnl workspace: <key> <def> <o tag> <thru>
234990792Sgshapirodnl full lookup
235090792Sgshapirodnl    2    3  4    5
235190792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
235290792Sgshapirodnl no match, try without tag
235390792Sgshapirodnl   1    2      3    4
235490792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
235590792Sgshapirodnl no match, +detail: try +*
235690792Sgshapirodnl   1    2    3    4    5  6    7
235790792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
235890792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
235990792Sgshapirodnl no match, +detail: try +* without tag
236090792Sgshapirodnl   1    2    3    4      5    6
236190792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
236290792Sgshapiro			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
236390792Sgshapirodnl no match, +detail: try without +detail
236490792Sgshapirodnl   1    2    3    4    5  6    7
236590792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
236690792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
236790792Sgshapirodnl no match, +detail: try without +detail and without tag
236890792Sgshapirodnl   1    2    3    4      5    6
236990792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
237090792Sgshapiro			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
237190792Sgshapirodnl no match, return <default> <passthru>
237290792Sgshapirodnl   1    2    3  4    5
237390792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
237490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
237590792Sgshapirodnl            2    3  4    5
237690792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
237790792Sgshapirodnl match, return <match> <passthru>
237890792Sgshapirodnl    2    3  4    5
237990792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
238090792Sgshapiro
238190792Sgshapiro######################################################################
238290792Sgshapiro###  E: LookUpExact -- search for an entry in access database
238390792Sgshapiro###
238490792Sgshapiro###	Parameters:
238590792Sgshapiro###		<$1> -- key
238690792Sgshapiro###		<$2> -- default (what to return if not found in db)
238790792Sgshapirodnl			must not be empty
238890792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
238990792Sgshapiro###			! does lookup only with tag
239090792Sgshapiro###			+ does lookup with and without tag
239190792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
239290792Sgshapirodnl returns:		<default> <passthru>
239390792Sgshapirodnl 			<result> <passthru>
239490792Sgshapiro######################################################################
239590792Sgshapiro
239690792SgshapiroSE
239790792Sgshapirodnl    2    3  4    5
239890792SgshapiroR<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
239990792Sgshapirodnl no match, try without tag
240090792Sgshapirodnl   1    2      3    4
240190792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
240290792Sgshapirodnl no match, return default passthru
240390792Sgshapirodnl   1    2    3  4    5
240490792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
240590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
240690792Sgshapirodnl            2    3  4    5
240790792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
240890792Sgshapirodnl match, return <match> <passthru>
240990792Sgshapirodnl    2    3  4    5
241090792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
241190792Sgshapiro
241290792Sgshapiro######################################################################
241390792Sgshapiro###  U: LookUpUser -- search for an entry in access database
241490792Sgshapiro###
241590792Sgshapiro###	lookup of key (which should be a local part) and
241690792Sgshapiro###	variations if +detail exists: +* and without +detail
241790792Sgshapiro###
241890792Sgshapiro###	Parameters:
241990792Sgshapiro###		<$1> -- key (user@)
242090792Sgshapiro###		<$2> -- default (what to return if not found in db)
242190792Sgshapirodnl			must not be empty
242290792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
242390792Sgshapiro###			! does lookup only with tag
242490792Sgshapiro###			+ does lookup with and without tag
242590792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
242690792Sgshapirodnl returns:		<default> <passthru>
242790792Sgshapirodnl 			<result> <passthru>
242890792Sgshapiro######################################################################
242990792Sgshapiro
243090792SgshapiroSU
243190792Sgshapirodnl user lookups are always with trailing @
243290792Sgshapirodnl    2    3  4    5
243390792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
243490792Sgshapirodnl no match, try without tag
243590792Sgshapirodnl   1    2      3    4
243690792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
243790792Sgshapirodnl do not remove the @ from the lookup:
243890792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
243990792Sgshapirodnl no match, +detail: try +*
244090792Sgshapirodnl   1    2      3    4  5    6
244190792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
244290792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
244390792Sgshapirodnl no match, +detail: try +* without tag
244490792Sgshapirodnl   1    2      3      4    5
244590792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
244690792Sgshapiro			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
244790792Sgshapirodnl no match, +detail: try without +detail
244890792Sgshapirodnl   1    2      3    4  5    6
244990792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
245090792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
245190792Sgshapirodnl no match, +detail: try without +detail and without tag
245290792Sgshapirodnl   1    2      3      4    5
245390792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
245490792Sgshapiro			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
245590792Sgshapirodnl no match, return <default> <passthru>
245690792Sgshapirodnl   1    2    3  4    5
245790792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
245890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
245990792Sgshapirodnl            2    3  4    5
246090792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
246190792Sgshapirodnl match, return <match> <passthru>
246290792Sgshapirodnl    2    3  4    5
246390792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
246490792Sgshapiro
246590792Sgshapiro######################################################################
246664562Sgshapiro###  SearchList: search a list of items in the access map
246764562Sgshapiro###	Parameters:
246864562Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
246964562Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
247064562Sgshapirodnl	avoid errorneous matches (with error messages?)
247164562Sgshapirodnl	if we can make sure that tag is always a single token
247264562Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
247390792Sgshapirodnl	to avoid errorneous matchs (first rule: D: if there
247464562Sgshapirodnl	is that mark somewhere in the list, it will be taken).
247564562Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
247664562Sgshapirodnl	the tag only, e.g.:
247764562Sgshapiro###	where "exact" is either "+" or "!":
247864562Sgshapiro###	<+ TAG>	lookup with and w/o tag
247964562Sgshapiro###	<! TAG>	lookup with tag
248064562Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
248164562Sgshapirodnl		a blank between them and the tag.
248264562Sgshapiro###	possible values for "mark" are:
248390792Sgshapiro###		D: recursive host lookup (LookUpDomain)
248464562Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
248564562Sgshapiro###		E: exact lookup, no modifications
248664562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
248764562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
248864562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
248964562Sgshapiro######################################################################
249038032Speter
249164562Sgshapiro# class with valid marks for SearchList
249264562Sgshapirodnl if A is activated: add it
2493132943SgshapiroC{Src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
249464562SgshapiroSSearchList
249590792Sgshapiro# just call the ruleset with the name of the tag... nice trick...
249690792Sgshapirodnl       2       3    4
2497132943SgshapiroR<$+> $| <$={Src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
249890792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <>
249990792Sgshapirodnl no match and nothing left: return
250090792SgshapiroR<$+> $| <> $| <?> <>		$@ <?>
250190792Sgshapirodnl no match but something left: continue
250290792SgshapiroR<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
250390792Sgshapirodnl match: return
250490792SgshapiroR<$+> $| <$*> $| <$+> <>	$@ <$3>
250564562Sgshapirodnl return result from recursive invocation
250690792SgshapiroR<$+> $| <$+>			$@ <$2>
250790792Sgshapirodnl endif _ACCESS_TABLE_
250890792Sgshapirodivert(0)
250938032Speter
251090792Sgshapiro######################################################################
251190792Sgshapiro###  trust_auth: is user trusted to authenticate as someone else?
251290792Sgshapiro###
251390792Sgshapiro###	Parameters:
251490792Sgshapiro###		$1: AUTH= parameter from MAIL command
251590792Sgshapiro######################################################################
251690792Sgshapiro
251790792Sgshapirodnl empty ruleset definition so it can be called
251890792SgshapiroSLocal_trust_auth
251964562SgshapiroStrust_auth
252064562SgshapiroR$*			$: $&{auth_type} $| $1
252164562Sgshapiro# required by RFC 2554 section 4.
252264562SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
252364562Sgshapirodnl seems to be useful...
252464562SgshapiroR$* $| $&{auth_authen}		$@ identical
252564562SgshapiroR$* $| <$&{auth_authen}>	$@ identical
252664562Sgshapirodnl call user supplied code
2527120256SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $2
252864562SgshapiroR$* $| $#$*		$#$2
252964562Sgshapirodnl default: error
253064562SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
253164562Sgshapiro
253290792Sgshapiro######################################################################
253390792Sgshapiro###  Relay_Auth: allow relaying based on authentication?
253490792Sgshapiro###
253590792Sgshapiro###	Parameters:
253690792Sgshapiro###		$1: ${auth_type}
253790792Sgshapiro######################################################################
253890792SgshapiroSLocal_Relay_Auth
253964562Sgshapiro
254090792Sgshapiro######################################################################
254190792Sgshapiro###  srv_features: which features to offer to a client?
254290792Sgshapiro###	(done in server)
254390792Sgshapiro######################################################################
254490792SgshapiroSsrv_features
254590792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl
254690792SgshapiroR$*			$: $1 $| $>"Local_srv_features" $1
254790792SgshapiroR$* $| $#$*		$#$2
254890792SgshapiroR$* $| $*		$: $1', `dnl')
2549132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
255090792SgshapiroR$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
255190792SgshapiroR<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
255290792SgshapiroR<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
255364562SgshapiroR<?>$*		$@ OK
255490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
255590792SgshapiroR<$* _ATMPF_>$*	$#temp', `dnl')
2556132943SgshapiroR<$+>$*		$# $1')
255764562Sgshapiro
255890792Sgshapiro######################################################################
255990792Sgshapiro###  try_tls: try to use STARTTLS?
256090792Sgshapiro###	(done in client)
256190792Sgshapiro######################################################################
256264562SgshapiroStry_tls
256390792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl
256490792SgshapiroR$*			$: $1 $| $>"Local_try_tls" $1
256590792SgshapiroR$* $| $#$*		$#$2
256690792SgshapiroR$* $| $*		$: $1', `dnl')
2567132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
256890792SgshapiroR$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
256990792SgshapiroR<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
257090792SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
257164562SgshapiroR<?>$*		$@ OK
257290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
257390792SgshapiroR<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2574132943SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"')
2575132943Sgshapiro
257690792Sgshapiro######################################################################
257790792Sgshapiro###  tls_rcpt: is connection with server "good" enough?
257890792Sgshapiro###	(done in client, per recipient)
257990792Sgshapirodnl called from deliver() before RCPT command
258090792Sgshapiro###
258190792Sgshapiro###	Parameters:
258290792Sgshapiro###		$1: recipient
258390792Sgshapiro######################################################################
258490792SgshapiroStls_rcpt
258590792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl
258690792SgshapiroR$*			$: $1 $| $>"Local_tls_rcpt" $1
258790792SgshapiroR$* $| $#$*		$#$2
258890792SgshapiroR$* $| $*		$: $1', `dnl')
2589132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
259090792Sgshapirodnl store name of other side
259190792SgshapiroR$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
259290792Sgshapirodnl canonify recipient address
259390792SgshapiroR$+			$: <?> $>CanonAddr $1
259490792Sgshapirodnl strip trailing dots
259590792SgshapiroR<?> $+ < @ $+ . >	<?> $1 <@ $2 >
259690792Sgshapirodnl full address?
259790792SgshapiroR<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
259890792Sgshapirodnl only localpart?
259990792SgshapiroR<?> $+			$: $1 $| <U:$1@> <E:>
260090792Sgshapirodnl look it up
260190792Sgshapirodnl also look up a default value via E:
260290792SgshapiroR$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
260390792Sgshapirodnl found nothing: stop here
260490792SgshapiroR$* $| <?>	$@ OK
260590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
260690792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
260790792Sgshapirodnl use the generic routine (for now)
260890792SgshapiroR$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
260964562Sgshapiro
261090792Sgshapiro######################################################################
261190792Sgshapiro###  tls_client: is connection with client "good" enough?
261290792Sgshapiro###	(done in server)
261390792Sgshapiro###
261490792Sgshapiro###	Parameters:
261590792Sgshapiro###		${verify} $| (MAIL|STARTTLS)
261690792Sgshapiro######################################################################
261764562Sgshapirodnl MAIL: called from check_mail
261864562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
261964562SgshapiroStls_client
262090792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl
262190792SgshapiroR$*			$: $1 $| $>"Local_tls_client" $1
262290792SgshapiroR$* $| $#$*		$#$2
262390792SgshapiroR$* $| $*		$: $1', `dnl')
262464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
262590792Sgshapirodnl store name of other side
262690792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
262764562Sgshapirodnl ignore second arg for now
262864562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
262964562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
263064562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
263190792SgshapiroR$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
263290792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
263364562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
263464562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
263590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
263690792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
263790792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
263890792SgshapiroR$* $| $*	$@ $>"TLS_connection" $1')
263964562Sgshapiro
264090792Sgshapiro######################################################################
264190792Sgshapiro###  tls_server: is connection with server "good" enough?
264290792Sgshapiro###	(done in client)
264390792Sgshapiro###
264490792Sgshapiro###	Parameter:
264590792Sgshapiro###		${verify}
264690792Sgshapiro######################################################################
264764562Sgshapirodnl i.e. has the server been authenticated and is encryption active?
264864562Sgshapirodnl called from deliver() after STARTTLS command
264964562SgshapiroStls_server
265090792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl
265190792SgshapiroR$*			$: $1 $| $>"Local_tls_server" $1
265290792SgshapiroR$* $| $#$*		$#$2
265390792SgshapiroR$* $| $*		$: $1', `dnl')
265464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
265590792Sgshapirodnl store name of other side
265690792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
265790792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
265890792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
265964562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
266064562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
266190792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
266290792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
266390792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
266490792SgshapiroR$*		$@ $>"TLS_connection" $1')
266564562Sgshapiro
266690792Sgshapiro######################################################################
266790792Sgshapiro###  TLS_connection: is TLS connection "good" enough?
266890792Sgshapiro###
266990792Sgshapiro###	Parameters:
267064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
267190792Sgshapiro###		${verify} $| <Requirement> [<>]', `dnl
267290792Sgshapiro###		${verify}')
267390792Sgshapiro###		Requirement: RHS from access map, may be ? for none.
267490792Sgshapirodnl	syntax for Requirement:
267590792Sgshapirodnl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
267690792Sgshapirodnl	extensions: could be a list of further requirements
267790792Sgshapirodnl		for now: CN:string	{cn_subject} == string
267890792Sgshapiro######################################################################
267990792SgshapiroSTLS_connection
268090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
268190792Sgshapirodnl deal with TLS handshake failures: abort
268290792SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
268390792Sgshapirodivert(-1)')
268464562Sgshapirodnl common ruleset for tls_{client|server}
268590792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>]
268664562Sgshapirodnl remove optional <>
268764562SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
268890792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup>
268990792Sgshapiro# create the appropriate error codes
269064562Sgshapirodnl permanent or temporary error?
2691132943SgshapiroR$* $| <PERM + $={Tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
2692132943SgshapiroR$* $| <TEMP + $={Tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
269364562Sgshapirodnl default case depends on TLS_PERM_ERR
2694132943SgshapiroR$* $| <$={Tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
269590792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
269690792Sgshapiro# deal with TLS handshake failures: abort
269764562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
269864562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
269964562Sgshapirodnl use default error
270064562SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
2701157001Sgshapiro# deal with TLS protocol errors: abort
2702157001SgshapiroRPROTOCOL $| <$-:$+> $* 	$#error $@ $2 $: $1 " STARTTLS failed."
2703157001Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
2704157001Sgshapirodnl use default error
2705157001SgshapiroRPROTOCOL $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') STARTTLS failed."
270690792SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
270790792Sgshapirodnl separate optional requirements
270890792SgshapiroR$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
2709132943SgshapiroR$* $| <$*> <$={Tls}:$->$*	$: <$2> <$3:$4> <> $1
271090792Sgshapirodnl separate optional requirements
2711132943SgshapiroR$* $| <$*> <$={Tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
271264562Sgshapirodnl some other value in access map: accept
271364562Sgshapirodnl this also allows to override the default case (if used)
271464562SgshapiroR$* $| $*			$@ OK
271564562Sgshapiro# authentication required: give appropriate error
271664562Sgshapiro# other side did authenticate (via STARTTLS)
271790792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
271864562Sgshapirodnl only verification required and it succeeded
271990792SgshapiroR<$*><VERIFY> <> OK		$@ OK
272090792Sgshapirodnl verification required and it succeeded but extensions are given
272190792Sgshapirodnl change it to <SMTP:ESC> <REQ:0>  <extensions>
272290792SgshapiroR<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
272364562Sgshapirodnl verification required + some level of encryption
272490792SgshapiroR<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
272564562Sgshapirodnl just some level of encryption required
272690792SgshapiroR<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
272790792Sgshapirodnl workspace:
272890792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
272990792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
273090792Sgshapirodnl verification required but ${verify} is not set (case 1.)
273190792SgshapiroR<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
273290792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
273390792SgshapiroR<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
273490792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
273590792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
273664562Sgshapirodnl some other value for ${verify}
273790792SgshapiroR<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
273890792Sgshapirodnl some level of encryption required: get the maximum level (case 2.)
273990792SgshapiroR<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
274064562Sgshapirodnl compare required bits with actual bits
274190792SgshapiroR<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
274290792SgshapiroR<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
274390792Sgshapirodnl strength requirements fulfilled
274490792Sgshapirodnl TLS Additional Requirements Separator
274590792Sgshapirodnl this should be something which does not appear in the extensions itself
274690792Sgshapirodnl @ could be part of a CN, DN, etc...
274790792Sgshapirodnl use < > ? those are encoded in CN, DN, ...
274890792Sgshapirodefine(`_TLS_ARS_', `++')dnl
274990792Sgshapirodnl workspace:
275090792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
275190792SgshapiroR<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
275290792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
275390792Sgshapirodnl continue: check  extensions
275490792SgshapiroR<$-:$+ _TLS_ARS_ >			$@ OK
275590792Sgshapirodnl split extensions into own list
275690792SgshapiroR<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
275790792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
275890792SgshapiroR<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
275964562Sgshapiro
276090792Sgshapiro######################################################################
276190792Sgshapiro###  TLS_req: check additional TLS requirements
276290792Sgshapiro###
276390792Sgshapiro###	Parameters: [<list> <of> <req>] $| <$-:$+>
276490792Sgshapiro###		$-: SMTP reply code
276590792Sgshapiro###		$+: Enhanced Status Code
276690792Sgshapirodnl  further requirements for this ruleset:
276790792Sgshapirodnl	name of "other side" is stored is {TLS_name} (client/server_name)
276890792Sgshapirodnl
276990792Sgshapirodnl	currently only CN[:common_name] is implemented
277090792Sgshapirodnl	right now this is only a logical AND
277190792Sgshapirodnl	i.e. all requirements must be true
277290792Sgshapirodnl	how about an OR? CN must be X or CN must be Y or ..
277390792Sgshapirodnl	use a macro to compute this as a trivial sequential
277490792Sgshapirodnl	operations (no precedences etc)?
277590792Sgshapiro######################################################################
277690792SgshapiroSTLS_req
277790792Sgshapirodnl no additional requirements: ok
277890792SgshapiroR $| $+		$@ OK
277990792Sgshapirodnl require CN: but no CN specified: use name of other side
278090792SgshapiroR<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
278190792Sgshapirodnl match, check rest
278290792SgshapiroR<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
278390792Sgshapirodnl CN does not match
278490792Sgshapirodnl  1   2      3  4
278590792SgshapiroR<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
278690792Sgshapirodnl cert subject
278790792SgshapiroR<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
278890792Sgshapirodnl CS does not match
278990792Sgshapirodnl  1   2      3  4
2790110560SgshapiroR<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1
279190792Sgshapirodnl match, check rest
279290792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
279390792Sgshapirodnl CI does not match
279490792Sgshapirodnl  1   2      3  4
2795110560SgshapiroR<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1
279690792Sgshapirodnl return from recursive call
279790792SgshapiroROK			$@ OK
279890792Sgshapiro
279990792Sgshapiro######################################################################
280090792Sgshapiro###  max: return the maximum of two values separated by :
280190792Sgshapiro###
280290792Sgshapiro###	Parameters: [$-]:[$-]
280390792Sgshapiro######################################################################
280464562SgshapiroSmax
280564562SgshapiroR:		$: 0
280664562SgshapiroR:$-		$: $1
280764562SgshapiroR$-:		$: $1
280864562SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
280964562SgshapiroRTRUE:$-:$-	$: $2
281090792SgshapiroR$-:$-:$-	$: $2
281190792Sgshapirodnl endif _ACCESS_TABLE_
281290792Sgshapirodivert(0)
281364562Sgshapiro
281490792Sgshapiro######################################################################
281590792Sgshapiro###  RelayTLS: allow relaying based on TLS authentication
281690792Sgshapiro###
281790792Sgshapiro###	Parameters:
281890792Sgshapiro###		none
281990792Sgshapiro######################################################################
282090792SgshapiroSRelayTLS
282164562Sgshapiro# authenticated?
282264562Sgshapirodnl we do not allow relaying for anyone who can present a cert
282364562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
2824110560Sgshapirodnl CA in CertPath so we can authenticate users, we do not allow
282564562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
282664562Sgshapirodnl but anyway).
282764562Sgshapirodnl so here is the trick: if the verification succeeded
282864562Sgshapirodnl we look up the cert issuer in the access map
282964562Sgshapirodnl (maybe after extracting a part with a regular expression)
283064562Sgshapirodnl if this returns RELAY we relay without further questions
283164562Sgshapirodnl if it returns SUBJECT we perform a similar check on the
283264562Sgshapirodnl cert subject.
283364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
283490792SgshapiroR$*			$: <?> $&{verify}
283590792SgshapiroR<?> OK			$: OK		authenticated: continue
283690792SgshapiroR<?> $*			$@ NO		not authenticated
283764562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
283890792SgshapiroR$*			$: $(CERTIssuer $&{cert_issuer} $)',
283990792Sgshapiro`R$*			$: $&{cert_issuer}')
284090792SgshapiroR$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
284164562Sgshapirodnl use $# to stop further checks (delay_check)
284290792SgshapiroRRELAY			$# RELAY
284364562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
284490792SgshapiroRSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
284590792Sgshapiro`RSUBJECT		$: <@> $&{cert_subject}')
284690792SgshapiroR<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
284790792SgshapiroR<@> RELAY		$# RELAY
284890792SgshapiroR$*			$: NO', `dnl')
284964562Sgshapiro
285090792Sgshapiro######################################################################
285190792Sgshapiro###  authinfo: lookup authinfo in the access map
285290792Sgshapiro###
285390792Sgshapiro###	Parameters:
285490792Sgshapiro###		$1: {server_name}
285590792Sgshapiro###		$2: {server_addr}
285690792Sgshapirodnl	both are currently ignored
285790792Sgshapirodnl if it should be done via another map, we either need to restrict
285890792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another
285990792Sgshapirodnl parameter which I want to avoid, it's quite complex already)
286090792Sgshapiro######################################################################
286190792Sgshapirodnl omit this ruleset if neither is defined?
286290792Sgshapirodnl it causes DefaultAuthInfo to be ignored
286390792Sgshapirodnl (which may be considered a good thing).
286490792SgshapiroSauthinfo
286590792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl
286690792SgshapiroR$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
286790792SgshapiroR<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
286890792SgshapiroR<?>		$: <$(authinfo AuthInfo: $: ? $)>
286990792SgshapiroR<?>		$@ no				no authinfo available
287090792SgshapiroR<$*>		$# $1
287190792Sgshapirodnl', `dnl
287290792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
287390792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
287490792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
287590792SgshapiroR$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
287690792SgshapiroR$* $| <?>$*	$@ no				no authinfo available
287790792SgshapiroR$* $| <$*> <>	$# $2
287890792Sgshapirodnl', `dnl')')
287990792Sgshapiro
2880132943Sgshapiroifdef(`_RATE_CONTROL_',`dnl
2881132943Sgshapiro######################################################################
2882132943Sgshapiro###  RateControl: 
2883132943Sgshapiro###	Parameters:	ignored
2884132943Sgshapiro###	return: $#error or OK
2885132943Sgshapiro######################################################################
2886132943SgshapiroSRateControl
2887132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2888132943SgshapiroR$*		$: <A:$&{client_addr}> <E:>
2889132943Sgshapirodnl also look up a default value via E:
2890132943SgshapiroR$+		$: $>SearchList <! ClientRate> $| $1 <>
2891132943Sgshapirodnl found nothing: stop here
2892132943SgshapiroR<?>		$@ OK
2893132943Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
2894132943SgshapiroR<$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2895132943Sgshapirodnl use the generic routine (for now)
2896132943SgshapiroR<0>		$@ OK		no limit
2897132943SgshapiroR<$+>		$: <$1> $| $(arith l $@ $&{client_rate} $@ $1 $)
2898132943Sgshapirodnl log this? Connection rate $&{client_rate} exceeds limit $1.
2899132943SgshapiroR<$+> $| FALSE	$#error $@ 4.3.2 $: _RATE_CONTROL_REPLY Connection rate limit exceeded.
2900132943Sgshapiro')')
2901132943Sgshapiro
2902132943Sgshapiroifdef(`_CONN_CONTROL_',`dnl
2903132943Sgshapiro######################################################################
2904132943Sgshapiro###  ConnControl: 
2905132943Sgshapiro###	Parameters:	ignored
2906132943Sgshapiro###	return: $#error or OK
2907132943Sgshapiro######################################################################
2908132943SgshapiroSConnControl
2909132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2910132943SgshapiroR$*		$: <A:$&{client_addr}> <E:>
2911132943Sgshapirodnl also look up a default value via E:
2912132943SgshapiroR$+		$: $>SearchList <! ClientConn> $| $1 <>
2913132943Sgshapirodnl found nothing: stop here
2914132943SgshapiroR<?>		$@ OK
2915132943Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
2916132943SgshapiroR<$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2917132943Sgshapirodnl use the generic routine (for now)
2918132943SgshapiroR<0>		$@ OK		no limit
2919132943SgshapiroR<$+>		$: <$1> $| $(arith l $@ $&{client_connections} $@ $1 $)
2920132943Sgshapirodnl log this: Open connections $&{client_connections} exceeds limit $1.
2921132943SgshapiroR<$+> $| FALSE	$#error $@ 4.3.2 $: _CONN_CONTROL_REPLY Too many open connections.
2922132943Sgshapiro')')
2923132943Sgshapiro
292464562Sgshapiroundivert(9)dnl LOCAL_RULESETS
292538032Speter#
292638032Speter######################################################################
292738032Speter######################################################################
292838032Speter#####
292964562Sgshapiro`#####			MAIL FILTER DEFINITIONS'
293064562Sgshapiro#####
293164562Sgshapiro######################################################################
293264562Sgshapiro######################################################################
293390792Sgshapiro_MAIL_FILTERS_
293464562Sgshapiro#
293564562Sgshapiro######################################################################
293664562Sgshapiro######################################################################
293764562Sgshapiro#####
293838032Speter`#####			MAILER DEFINITIONS'
293938032Speter#####
294038032Speter######################################################################
294138032Speter######################################################################
294264562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
294366494Sgshapiro
2944