proto.m4 revision 168515
138032Speterdivert(-1)
238032Speter#
3168515Sgshapiro# Copyright (c) 1998-2007 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
16168515SgshapiroVERSIONID(`$Id: proto.m4,v 8.730 2007/02/01 18:50:03 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
399168515Sgshapiro# key for shared memory; 0 to turn off, -1 to auto-select
40090792Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
40190792Sgshapiro
402168515Sgshapiro# file to store auto-selected key for shared memory (SharedMemoryKey = -1)
403168515Sgshapiro_OPTION(SharedMemoryKeyFile, `confSHARED_MEMORY_KEY_FILE', `')
40494334Sgshapiro
40538032Speter# timeouts (many of these)
40664562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
40764562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
40890792Sgshapiro_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s')
40964562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
41064562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m')
41164562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m')
41264562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
41364562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
41464562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
41564562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
41664562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m')
41764562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m')
41864562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m')
41964562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h')
42064562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s')
42164562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
42264562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m')
42364562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
42464562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
42564562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
42664562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
427132943Sgshapiro_OPTION(Timeout.queuereturn.dsn, `confTO_QUEUERETURN_DSN', `5d')
42864562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
42964562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
43064562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
43164562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
432132943Sgshapiro_OPTION(Timeout.queuewarn.dsn, `confTO_QUEUEWARN_DSN', `4h')
43364562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
43464562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
43564562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
43664562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
43764562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
43864562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
43964562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
44090792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
44190792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m')
44290792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
44338032Speter
44490792Sgshapiro# time for DeliverBy; extension disabled if less than 0
44590792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
44690792Sgshapiro
44738032Speter# should we not prune routes in route-addr syntax addresses?
44864562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
44938032Speter
45038032Speter# queue up everything before forking?
45164562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
45238032Speter
45338032Speter# status file
454168515Sgshapiro_OPTION(StatusFile, `STATUS_FILE')
45538032Speter
45638032Speter# time zone handling:
45738032Speter#  if undefined, use system default
45838032Speter#  if defined but null, use TZ envariable passed in
45938032Speter#  if defined and non-null, use that info
46038032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
46138032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
46238032Speter	`O TimeZoneSpec=confTIME_ZONE')
46338032Speter
46438032Speter# default UID (can be username or userid:groupid)
46564562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
46638032Speter
46738032Speter# list of locations of user database file (null means no lookup)
46864562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
46938032Speter
47038032Speter# fallback MX host
47164562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
47238032Speter
473132943Sgshapiro# fallback smart host
474132943Sgshapiro_OPTION(FallbackSmartHost, `confFALLBACK_SMARTHOST', `fall.back.host.net')
475132943Sgshapiro
47638032Speter# if we are the best MX host for a site, try it directly instead of config err
47764562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
47838032Speter
47938032Speter# load average at which we just queue messages
48064562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8')
48138032Speter
48238032Speter# load average at which we refuse connections
48364562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
48438032Speter
485132943Sgshapiro# log interval when refusing connections for this long
486132943Sgshapiro_OPTION(RejectLogInterval, `confREJECT_LOG_INTERVAL', `3h')
487132943Sgshapiro
48890792Sgshapiro# load average at which we delay connections; 0 means no limit
48990792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0')
49090792Sgshapiro
49138032Speter# maximum number of children we allow at one time
49298841Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0')
49338032Speter
49438032Speter# maximum number of new connections per second
49571345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
49638032Speter
497132943Sgshapiro# Width of the window 
498132943Sgshapiro_OPTION(ConnectionRateWindowSize, `confCONNECTION_RATE_WINDOW_SIZE', `60s')
499132943Sgshapiro
50038032Speter# work recipient factor
50164562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
50238032Speter
50338032Speter# deliver each queued job in a separate process?
50464562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
50538032Speter
50638032Speter# work class factor
50764562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
50838032Speter
50938032Speter# work time factor
51064562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
51138032Speter
51238032Speter# default character set
513141858Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `unknown-8bit')
51438032Speter
51590792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
51664562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
51738032Speter
51838032Speter# hosts file (normally /etc/hosts)
51964562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
52038032Speter
52138032Speter# dialup line delay on connection failure
522157001Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `0s')
52338032Speter
52438032Speter# action to take if there are no recipients in the message
525157001Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `none')
52638032Speter
52738032Speter# chrooted environment for writing to files
528157001Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `')
52938032Speter
53038032Speter# are colons OK in addresses?
53164562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
53238032Speter
53338032Speter# shall I avoid expanding CNAMEs (violates protocols)?
53464562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
53538032Speter
53638032Speter# SMTP initial login message (old $e macro)
53764562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
53838032Speter
53938032Speter# UNIX initial From header format (old $l macro)
54064562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
54138032Speter
54238032Speter# From: lines that have embedded newlines are unwrapped onto one line
54364562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
54438032Speter
54538032Speter# Allow HELO SMTP command that does not `include' a host name
54664562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
54738032Speter
54838032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
54964562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
55038032Speter
55138032Speter# delimiter (operator) characters (old $o macro)
55264562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
55338032Speter
55438032Speter# shall I avoid calling initgroups(3) because of high NIS costs?
55564562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
55638032Speter
55738032Speter# are group-writable `:include:' and .forward files (un)trustworthy?
55890792Sgshapiro# True (the default) means they are not trustworthy.
55964562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
56090792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES',
56190792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
56290792Sgshapiro')')
56338032Speter
56438032Speter# where do errors that occur when sending errors get sent?
56564562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
56638032Speter
567168515Sgshapiro# issue temporary errors (4xy) instead of permanent errors (5xy)?
568168515Sgshapiro_OPTION(SoftBounce, `confSOFT_BOUNCE', `False')
569168515Sgshapiro
57064562Sgshapiro# where to save bounces if all else fails
57164562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
57264562Sgshapiro
57338032Speter# what user id do we assume for the majority of the processing?
57464562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
57538032Speter
57638032Speter# maximum number of recipients per SMTP envelope
577132943Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `0')
57838032Speter
57990792Sgshapiro# limit the rate recipients per SMTP envelope are accepted
58090792Sgshapiro# once the threshold number of recipients have been rejected
581132943Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `0')
58290792Sgshapiro
58338032Speter# shall we get local names from our installed interfaces?
58464562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
58538032Speter
58664562Sgshapiro# Return-Receipt-To: header implies DSN request
58764562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
58864562Sgshapiro
58964562Sgshapiro# override connection address (for testing)
59064562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
59164562Sgshapiro
59264562Sgshapiro# Trusted user for file ownership and starting the daemon
59364562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
59464562Sgshapiro
59564562Sgshapiro# Control socket for daemon management
59664562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
59764562Sgshapiro
59864562Sgshapiro# Maximum MIME header length to protect MUAs
599132943Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
60064562Sgshapiro
60164562Sgshapiro# Maximum length of the sum of all headers
60264562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
60364562Sgshapiro
60464562Sgshapiro# Maximum depth of alias recursion
60564562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
60664562Sgshapiro
60764562Sgshapiro# location of pid file
60864562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
60964562Sgshapiro
61064562Sgshapiro# Prefix string for the process title shown on 'ps' listings
61164562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
61264562Sgshapiro
61364562Sgshapiro# Data file (df) memory-buffer file maximum size
61464562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
61564562Sgshapiro
61664562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
61764562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
61864562Sgshapiro
61990792Sgshapiro# lookup type to find information about local mailboxes
62090792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
62190792Sgshapiro
622132943Sgshapiro# override compile time flag REQUIRES_DIR_FSYNC
623132943Sgshapiro_OPTION(RequiresDirfsync, `confREQUIRES_DIR_FSYNC', `true')
624132943Sgshapiro
62564562Sgshapiro# list of authentication mechanisms
62690792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
62764562Sgshapiro
628132943Sgshapiro# Authentication realm
629132943Sgshapiro_OPTION(AuthRealm, `confAUTH_REALM', `')
630132943Sgshapiro
63164562Sgshapiro# default authentication information for outgoing connections
63264562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
63364562Sgshapiro
63464562Sgshapiro# SMTP AUTH flags
63564562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
63664562Sgshapiro
63790792Sgshapiro# SMTP AUTH maximum encryption strength
63890792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
63990792Sgshapiro
64090792Sgshapiro# SMTP STARTTLS server options
64190792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
64290792Sgshapiro
64364562Sgshapiro# Input mail filters
64464562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
64564562Sgshapiro
64698841Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl
64764562Sgshapiro# Milter options
64890792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
64964562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
65064562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
65164562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
652125820Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')
653168515Sgshapiro_OPTION(Milter.macros.eom, `confMILTER_MACROS_EOM', `')
654168515Sgshapiro_OPTION(Milter.macros.eoh, `confMILTER_MACROS_EOH', `')
655168515Sgshapiro_OPTION(Milter.macros.data, `confMILTER_MACROS_DATA', `')')
65664562Sgshapiro
65764562Sgshapiro# CA directory
658110560Sgshapiro_OPTION(CACertPath, `confCACERT_PATH', `')
65964562Sgshapiro# CA file
660110560Sgshapiro_OPTION(CACertFile, `confCACERT', `')
66164562Sgshapiro# Server Cert
66264562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
66364562Sgshapiro# Server private key
66464562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
66564562Sgshapiro# Client Cert
66664562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
66764562Sgshapiro# Client private key
66864562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
669132943Sgshapiro# File containing certificate revocation lists 
670132943Sgshapiro_OPTION(CRLFile, `confCRL', `')
67164562Sgshapiro# DHParameters (only required if DSA/DH is used)
67264562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
67364562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
67464562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
67564562Sgshapiro
676168515Sgshapiro# Maximum number of "useless" commands before slowing down
677168515Sgshapiro_OPTION(MaxNOOPCommands, `confMAX_NOOP_COMMANDS', `20')
678168515Sgshapiro
679168515Sgshapiro# Name to use for EHLO (defaults to $j)
680168515Sgshapiro_OPTION(HeloName, `confHELO_NAME')
681168515Sgshapiro
68290792Sgshapiro############################
68390792Sgshapiro`# QUEUE GROUP DEFINITIONS  #'
68490792Sgshapiro############################
68590792Sgshapiro_QUEUE_GROUP_
68642575Speter
68738032Speter###########################
68838032Speter#   Message precedences   #
68938032Speter###########################
69038032Speter
69138032SpeterPfirst-class=0
69238032SpeterPspecial-delivery=100
69338032SpeterPlist=-30
69438032SpeterPbulk=-60
69538032SpeterPjunk=-100
69638032Speter
69738032Speter#####################
69838032Speter#   Trusted users   #
69938032Speter#####################
70038032Speter
70138032Speter# this is equivalent to setting class "t"
70264562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
70338032SpeterTroot
70438032SpeterTdaemon
70538032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp')
70638032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
70738032Speter
70838032Speter#########################
70938032Speter#   Format of headers   #
71038032Speter#########################
71138032Speter
71238032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
713132943Sgshapiroifdef(`confMESSAGEID_HEADER',, `define(`confMESSAGEID_HEADER', `<$t.$i@$j>')')dnl
71438032SpeterH?P?Return-Path: <$g>
71538032SpeterHReceived: confRECEIVED_HEADER
71638032SpeterH?D?Resent-Date: $a
71738032SpeterH?D?Date: $a
71838032SpeterH?F?Resent-From: confFROM_HEADER
71938032SpeterH?F?From: confFROM_HEADER
72038032SpeterH?x?Full-Name: $x
72138032Speter# HPosted-Date: $a
72238032Speter# H?l?Received-Date: $b
723132943SgshapiroH?M?Resent-Message-Id: confMESSAGEID_HEADER
724132943SgshapiroH?M?Message-Id: confMESSAGEID_HEADER
72564562Sgshapiro
72638032Speter#
72738032Speter######################################################################
72838032Speter######################################################################
72938032Speter#####
73038032Speter#####			REWRITING RULES
73138032Speter#####
73238032Speter######################################################################
73338032Speter######################################################################
73438032Speter
73538032Speter############################################
73638032Speter###  Ruleset 3 -- Name Canonicalization  ###
73738032Speter############################################
73864562SgshapiroScanonify=3
73938032Speter
74038032Speter# handle null input (translate to <@> special case)
74138032SpeterR$@			$@ <@>
74238032Speter
74338032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
74438032SpeterR$*			$: $1 <@>			mark addresses
74538032SpeterR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
74638032SpeterR@ $* <@>		$: @ $1				unmark @host:...
74790792SgshapiroR$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
74838032SpeterR$* :: $* <@>		$: $1 :: $2			unmark node::addr
74938032SpeterR:`include': $* <@>	$: :`include': $1			unmark :`include':...
75038032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
75138032SpeterR$* : $* <@>		$: $2				strip colon if marked
75238032SpeterR$* <@>			$: $1				unmark
75338032SpeterR$* ;			   $1				strip trailing semi
75471345SgshapiroR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
75538032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
75638032Speter
75738032Speter# null input now results from list:; syntax
75838032SpeterR$@			$@ :; <@>
75938032Speter
76038032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
76138032SpeterR$*			$: < $1 >			housekeeping <>
76238032SpeterR$+ < $* >		   < $2 >			strip excess on left
76338032SpeterR< $* > $+		   < $1 >			strip excess on right
76438032SpeterR<>			$@ < @ >			MAIL FROM:<> case
76538032SpeterR< $+ >			$: $1				remove housekeeping <>
76638032Speter
76764562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
76838032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
76938032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
77038032Speter
77138032Speter# localize and dispose of route-based addresses
77290792Sgshapirodnl XXX: IPv6 colon conflict
77390792Sgshapiroifdef(`NO_NETINET6', `dnl',
77490792Sgshapiro`R@ [$+] : $+		$@ $>Canonify2 < @ [$1] > : $2	handle <route-addr>')
77564562SgshapiroR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
77664562Sgshapirodnl',`dnl
77764562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d>
77864562SgshapiroR@ $+ , $+		$2
77990792Sgshapiroifdef(`NO_NETINET6', `dnl',
78090792Sgshapiro`R@ [ $* ] : $+		$2')
78164562SgshapiroR@ $+ : $+		$2
78264562Sgshapirodnl')
78338032Speter
78438032Speter# find focus for list syntax
78564562SgshapiroR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
78638032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
78738032Speter
78838032Speter# find focus for @ syntax addresses
78938032SpeterR$+ @ $+		$: $1 < @ $2 >			focus on domain
79038032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
79164562SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
79238032Speter
79390792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here.
79490792Sgshapirodnl # do some sanity checking
79590792Sgshapirodnl R$* < @ $~[ $* : $* > $*	$1 < @ $2 $3 > $4	nix colons in addrs
79638032Speter
79738032Speterifdef(`_NO_UUCP_', `dnl',
79838032Speter`# convert old-style addresses to a domain-based address
79964562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
80064562SgshapiroR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
80164562SgshapiroR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
80238032Speter')
80338032Speterifdef(`_USE_DECNET_SYNTAX_',
80438032Speter`# convert node::user addresses into a domain-based address
80564562SgshapiroR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
80664562SgshapiroR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
80738032Speter',
80838032Speter	`dnl')
80938032Speter# if we have % signs, take the rightmost one
81038032SpeterR$* % $*		$1 @ $2				First make them all @s.
81138032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
81264562SgshapiroR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
81338032Speter
81438032Speter# else we must be a local name
81564562SgshapiroR$*			$@ $>Canonify2 $1
81638032Speter
81738032Speter
81838032Speter################################################
81938032Speter###  Ruleset 96 -- bottom half of ruleset 3  ###
82038032Speter################################################
82138032Speter
82264562SgshapiroSCanonify2=96
82338032Speter
82438032Speter# handle special cases for local names
82538032SpeterR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
82638032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
82738032Speterifdef(`_NO_UUCP_', `dnl',
82838032Speter`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
82964562Sgshapiro
83090792Sgshapiro# check for IPv4/IPv6 domain literal
83190792SgshapiroR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [addr]
83238032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
83338032SpeterR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
83438032Speter
83564562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl
83638032Speter# look up domains in the domain table
83738032SpeterR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
83838032Speter
83964562Sgshapiroundivert(2)dnl LOCAL_RULE_3
84038032Speter
84164562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl
84238032Speter# handle BITNET mapping
84338032SpeterR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
84438032Speter
84564562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl
84638032Speter# handle UUCP mapping
84738032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
84838032Speter
84938032Speterifdef(`_NO_UUCP_', `dnl',
85038032Speter`ifdef(`UUCP_RELAY',
85138032Speter`# pass UUCP addresses straight through
85238032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
85338032Speter`# if really UUCP, handle it immediately
85438032Speterifdef(`_CLASS_U_',
85538032Speter`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
85638032Speterifdef(`_CLASS_V_',
85738032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
85838032Speterifdef(`_CLASS_W_',
85938032Speter`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
86038032Speterifdef(`_CLASS_X_',
86138032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
86238032Speterifdef(`_CLASS_Y_',
86338032Speter`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
86438032Speter
86538032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl
86638032Speter# try UUCP traffic as a local address
86738032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
86838032SpeterR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
86938032Speter')')
87064562Sgshapiro# hostnames ending in class P are always canonical
87164562SgshapiroR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
87264562Sgshapirodnl apply the next rule only for hostnames not in class P
87364562Sgshapirodnl this even works for phrases in class P since . is in class P
87464562Sgshapirodnl which daemon flags are set?
87564562SgshapiroR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
87664562Sgshapirodnl the other rules in this section only apply if the hostname
87764562Sgshapirodnl does not end in class P hence no further checks are done here
87864562Sgshapirodnl if this ever changes make sure the lookups are "protected" again!
87964562Sgshapiroifdef(`_NO_CANONIFY_', `dnl
88064562Sgshapirodnl do not canonify unless:
88164562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection
88264562Sgshapirodnl	with class P is non-empty)
88364562Sgshapirodnl or {daemon_flags} has c set
88464562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify}
88564562SgshapiroR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
88664562Sgshapiro# pass to name server to make hostname canonical if requested
88764562SgshapiroR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
88864562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_
88964562SgshapiroR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
89064562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work
89164562SgshapiroR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
89264562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl
89364562Sgshapirodnl this should only apply to unqualified hostnames
89464562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
89564562Sgshapirodnl then $- does not work.
89664562Sgshapiro# lookup unqualified hostnames
89790792SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
89864562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
89964562Sgshapirodnl {daemon_flags} contains CC (do not canonify)
90071345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work
90171345Sgshapirodnl should we do this for every hostname: even unqualified?
90271345SgshapiroR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
90364562SgshapiroR$* CC $* $| $*			$: $3
90490792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
90590792Sgshapiro# do not canonify header addresses
90690792SgshapiroR$* $| $* < @ $* $~P > $*	$: $&{addr_type} $| $2 < @ $3 $4 > $5
90790792SgshapiroR$* h $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
90890792SgshapiroR$* h $* $| $*			$: $3', `dnl')
90938032Speter# pass to name server to make hostname canonical
91064562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
91164562Sgshapirodnl remove {daemon_flags} for other cases
91264562SgshapiroR$* $| $*			$: $2
91338032Speter
91438032Speter# local host aliases and pseudo-domains are always canonical
91538032SpeterR$* < @ $=w > $*		$: $1 < @ $2 . > $3
91638032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
91738032Speter`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
91838032Speter`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
91964562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
92064562Sgshapirodnl virtual hosts are also canonical
92164562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
92264562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
92364562Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
92464562Sgshapiro`dnl')
92590792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
92690792Sgshapirodnl hosts for genericstable are also canonical
92790792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_',
92890792Sgshapiro`R$* < @ $* $=G > $* 	$: $1 < @ $2 $3 . > $4',
92990792Sgshapiro`R$* < @ $=G > $* 	$: $1 < @ $2 . > $3')',
93090792Sgshapiro`dnl')
93164562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added
93264562Sgshapirodnl by one of the rules before
93338032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
93438032Speter
93538032Speter
93638032Speter##################################################
93738032Speter###  Ruleset 4 -- Final Output Post-rewriting  ###
93838032Speter##################################################
93964562SgshapiroSfinal=4
94038032Speter
94171345SgshapiroR$+ :; <@>		$@ $1 :				handle <list:;>
94238032SpeterR$* <@>			$@				handle <> and list:;
94338032Speter
94438032Speter# strip trailing dot off possibly canonical name
94538032SpeterR$* < @ $+ . > $*	$1 < @ $2 > $3
94638032Speter
94764562Sgshapiro# eliminate internal code
94838032SpeterR$* < @ *LOCAL* > $*	$1 < @ $j > $2
94938032Speter
95038032Speter# externalize local domain info
95138032SpeterR$* < $+ > $*		$1 $2 $3			defocus
95238032SpeterR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
95338032SpeterR@ $*			$@ @ $1				... and exit
95438032Speter
95538032Speterifdef(`_NO_UUCP_', `dnl',
95638032Speter`# UUCP must always be presented in old form
95738032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
95838032Speter
95938032Speterifdef(`_USE_DECNET_SYNTAX_',
96038032Speter`# put DECnet back in :: form
96138032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
96238032Speter	`dnl')
96338032Speter# delete duplicate local names
96438032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
96538032Speter
96638032Speter
96738032Speter
96838032Speter##############################################################
96938032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
97038032Speter###		   (used for recursive calls)		   ###
97138032Speter##############################################################
97238032Speter
97364562SgshapiroSRecurse=97
97464562SgshapiroR$*			$: $>canonify $1
97564562SgshapiroR$*			$@ $>parse $1
97638032Speter
97738032Speter
97838032Speter######################################
97938032Speter###   Ruleset 0 -- Parse Address   ###
98038032Speter######################################
98138032Speter
98264562SgshapiroSparse=0
98338032Speter
98438032SpeterR$*			$: $>Parse0 $1		initial parsing
98538032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
98664562SgshapiroR$*			$: $>ParseLocal $1	handle local hacks
98738032SpeterR$*			$: $>Parse1 $1		final parsing
98838032Speter
98938032Speter#
99038032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
99138032Speter#	This should either return with the (possibly modified) input
99238032Speter#	or return with a #error mailer.  It should not return with a
99338032Speter#	#mailer other than the #error mailer.
99438032Speter#
99538032Speter
99638032SpeterSParse0
99738032SpeterR<@>			$@ <@>			special case error msgs
99890792SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
99964562SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
100090792SgshapiroR<@ $+>			$#error $@ 5.1.3 $: "_CODE553 User address required"
100190792SgshapiroR$+ <@>			$#error $@ 5.1.3 $: "_CODE553 Hostname required"
100238032SpeterR$*			$: <> $1
100390792Sgshapirodnl allow tricks like [host1]:[host2]
100490792SgshapiroR<> $* < @ [ $* ] : $+ > $*	$1 < @ [ $2 ] : $3 > $4
100590792SgshapiroR<> $* < @ [ $* ] , $+ > $*	$1 < @ [ $2 ] , $3 > $4
100690792Sgshapirodnl but no a@[b]c
100790792SgshapiroR<> $* < @ [ $* ] $+ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid address"
100890792SgshapiroR<> $* < @ [ $+ ] > $*		$1 < @ [ $2 ] > $3
100990792SgshapiroR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
101038032SpeterR<> $*			$1
101190792SgshapiroR$* < @ . $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
101290792SgshapiroR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
101390792Sgshapirodnl no a@b@
101490792SgshapiroR$* < @ $* @ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid route address"
101590792Sgshapirodnl no a@b@c
101690792SgshapiroR$* @ $* < @ $* > $*	$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
101764562Sgshapirodnl comma only allowed before @; this check is not complete
101890792SgshapiroR$* , $~O $*		$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
101938032Speter
102090792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks
102190792SgshapiroR$* . < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
102290792SgshapiroR. $* < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
102390792Sgshapirodnl', `dnl')
102490792Sgshapiro
102538032Speter# now delete the local info -- note $=O to find characters that cause forwarding
102664562SgshapiroR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
102764562SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
102838032SpeterR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
102990792SgshapiroR< @ $+ >		$#error $@ 5.1.3 $: "_CODE553 User address required"
103064562SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
103138032SpeterR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
103290792SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "_CODE553 User address required"
103338032SpeterR$* $=O $* < @ *LOCAL* >
103464562Sgshapiro			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
103538032SpeterR$* < @ *LOCAL* >	$: $1
103638032Speter
103738032Speter#
103838032Speter#  Parse1 -- the bottom half of ruleset 0.
103938032Speter#
104038032Speter
104138032SpeterSParse1
104264562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
104364562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute}
104490792SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
104590792SgshapiroR$+ < @ $={LDAPRouteEquiv} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
104664562Sgshapiro`dnl')
104764562Sgshapiro
104838032Speterifdef(`_MAILER_smtp_',
104938032Speter`# handle numeric address spec
105064562Sgshapirodnl there is no check whether this is really an IP number
105164562SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
1052112810SgshapiroR$* < @ [ $+ ] > $*	$: $1 < @ [ $2 ] : $S > $3	Add smart host to path
105390792SgshapiroR$* < @ [ $+ ] : > $*		$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
105464562SgshapiroR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
105564562SgshapiroR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
105638032Speter	`dnl')
105738032Speter
105864562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
105938032Speter# handle virtual users
106090792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
106190792Sgshapirodnl this is not a documented option
106290792Sgshapirodnl it stops looping in virtusertable mapping if input and output
106390792Sgshapirodnl are identical, i.e., if address A is mapped to A.
106490792Sgshapirodnl it does not deal with multi-level recursion
106590792Sgshapiro# handle full domains in RHS of virtusertable
106690792SgshapiroR$+ < @ $+ >			$: $(macro {RecipientAddress} $) $1 < @ $2 >
106790792SgshapiroR$+ < @ $+ > 			$: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
106890792SgshapiroR<?> $+ $| $+			$: $1 $(macro {RecipientAddress} $@ $2 $)
106990792SgshapiroR<?> $+ $| $*			$: $1',
107090792Sgshapiro`dnl')
107164562SgshapiroR$+			$: <!> $1		Mark for lookup
107290792Sgshapirodnl input: <!> local<@domain>
107364562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
107464562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
107564562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
107690792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
107764562SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
107890792Sgshapirodnl if <@> local<@domain>: no match but try lookup
107990792Sgshapirodnl user+detail: try user++@domain if detail not empty
108090792SgshapiroR<@> $+ + $+ < @ $* . >
108190792Sgshapiro			$: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
108290792Sgshapirodnl user+detail: try user+*@domain
108338032SpeterR<@> $+ + $* < @ $* . >
108490792Sgshapiro			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
108590792Sgshapirodnl user+detail: try user@domain
108638032SpeterR<@> $+ + $* < @ $* . >
108790792Sgshapiro			$: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
108864562Sgshapirodnl try default entry: @domain
108990792Sgshapirodnl ++@domain
109090792SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
109164562Sgshapirodnl +*@domain
109290792SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
109364562Sgshapirodnl @domain if +detail exists
109498121Sgshapirodnl if no match, change marker to prevent a second @domain lookup
109598121SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . >
109698121Sgshapirodnl without +detail
109738032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
109890792Sgshapirodnl no match
109938032SpeterR<@> $+			$: $1
110090792Sgshapirodnl remove mark
110164562SgshapiroR<!> $+			$: $1
110264562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
110338032SpeterR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
110490792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
110590792Sgshapiro# check virtuser input address against output address, if same, skip recursion
110690792SgshapiroR< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
110790792Sgshapiro# it is the same: stop now
110890792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
110990792SgshapiroR< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
111090792Sgshapirodnl', `dnl')
111180785Sgshapirodnl this is not a documented option
111280785Sgshapirodnl it performs no looping at all for virtusertable
111377349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_',
111477349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
111577349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
111677349Sgshapirodnl', `dnl')
111738032Speter
111838032Speter# short circuit local delivery so forwarded email works
111938032Speterifdef(`_MAILER_usenet_', `dnl
112064562SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
112166494Sgshapiro
112266494Sgshapiro
112338032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
112438032Speter`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
112564562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
112664562Sgshapirodnl $H empty (but @$=w.)
112738032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
112838032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
112964562Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
113038032SpeterR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
113138032Speter
113264562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
113338032Speter# not local -- try mailer table lookup
113438032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
113538032SpeterR< $+ . > $*		$: < $1 > $2			strip trailing dot
113638032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
113764562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
113864562SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
113964562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
114038032Speter`dnl')
114164562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)'
114238032Speter
114338032Speterifdef(`_NO_UUCP_', `dnl',
114438032Speter`# resolve remotely connected UUCP links (if any)
114538032Speterifdef(`_CLASS_V_',
114664562Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
114738032Speter	`dnl')
114838032Speterifdef(`_CLASS_W_',
114964562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
115038032Speter	`dnl')
115138032Speterifdef(`_CLASS_X_',
115264562Sgshapiro`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
115338032Speter	`dnl')')
115438032Speter
115538032Speter# resolve fake top level domains by forwarding to other hosts
115638032Speterifdef(`BITNET_RELAY',
115764562Sgshapiro`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
115838032Speter	`dnl')
115938032Speterifdef(`DECNET_RELAY',
116064562Sgshapiro`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
116138032Speter	`dnl')
116238032Speterifdef(`_MAILER_pop_',
116338032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
116438032Speter	`dnl')
116538032Speterifdef(`_MAILER_fax_',
116638032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
116738032Speter`ifdef(`FAX_RELAY',
116864562Sgshapiro`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
116938032Speter	`dnl')')
117038032Speter
117138032Speterifdef(`UUCP_RELAY',
117238032Speter`# forward non-local UUCP traffic to our UUCP relay
117364562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
117438032Speter`ifdef(`_MAILER_uucp_',
117538032Speter`# forward other UUCP traffic straight to UUCP
117638032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
117738032Speter	`dnl')')
117838032Speterifdef(`_MAILER_usenet_', `
117938032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
118064562SgshapiroR$+ . USENET		$#usenet $@ usenet $: $1',
118138032Speter	`dnl')
118238032Speter
118338032Speterifdef(`_LOCAL_RULES_',
118438032Speter`# figure out what should stay in our local mail system
118538032Speterundivert(1)', `dnl')
118638032Speter
118738032Speter# pass names that still have a host to a smarthost (if defined)
118864562SgshapiroR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
118938032Speter
119038032Speter# deal with other remote names
119138032Speterifdef(`_MAILER_smtp_',
119264562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
119390792Sgshapiro`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
119438032Speter
119538032Speter# handle locally delivered names
119664562SgshapiroR$=L			$#_LOCAL_ $: @ $1		special local names
119738032SpeterR$+			$#_LOCAL_ $: $1			regular local names
119838032Speter
119938032Speter###########################################################################
120038032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
120138032Speter###########################################################################
120238032Speter
120364562SgshapiroSLocal_localaddr
120464562SgshapiroSlocaladdr=5
120564562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
120690792SgshapiroR$+ $| $#ok		$@ $1			no change
120764562SgshapiroR$+ $| $#$*		$#$2
120864562SgshapiroR$+ $| $*		$: $1
120938032Speter
121090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
121190792Sgshapiro# Preserve rcpt_host in {Host}
121290792SgshapiroR$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
121390792SgshapiroR$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
121490792SgshapiroR$+ $| $| $+		$: $1			h not set, {Host} set
121590792SgshapiroR$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
121695154SgshapiroR$+ $| $* @ $+ $| $*	$: $(macro {Host} $@ @$3 $) $1	set {Host} to host in h
121790792SgshapiroR$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
121890792Sgshapiro')dnl
121990792Sgshapiro
122090792Sgshapiroifdef(`_FFR_5_', `dnl
122166494Sgshapiro# Preserve host in a macro
122266494SgshapiroR$+			$: $(macro {LocalAddrHost} $) $1
122366494SgshapiroR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
122466494Sgshapiro
122590792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
122638032Speter# deal with plussed users so aliases work nicely
122766494SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
122866494SgshapiroR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
122966494Sgshapiro')
123038032Speter# prepend an empty "forward host" on the front
123138032SpeterR$+			$: <> $1
123238032Speter
123338032Speterifdef(`LUSER_RELAY', `dnl
123438032Speter# send unrecognized local users to a relay host
123590792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
123666494SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
123766494SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
123866494SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
123966494SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
124064562SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
124190792SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')
124290792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
124390792SgshapiroR< $+ > $+		$: < $1 > $2 $&{Host}')
124490792Sgshapirodnl')
124538032Speter
124690792Sgshapiroifdef(`MAIL_HUB', `dnl
124790792SgshapiroR< > $+			$: < $H > $1			try hub', `dnl')
124890792Sgshapiroifdef(`LOCAL_RELAY', `dnl
124990792SgshapiroR< > $+			$: < $R > $1			try relay', `dnl')
125090792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
125190792SgshapiroR< > $+			$@ $1', `dnl
125264562SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
125390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
125490792SgshapiroR< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
125564562SgshapiroR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
125664562SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
125738032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
125866494SgshapiroR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
125938032SpeterR< > < $+ >		$@ $1				no +detail
126043730SpeterR$+			$: $1 <> $&h			add +detail back in
126190792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
126290792SgshapiroR$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
126343730SpeterR$+ <> + $*		$: $1 + $2			check whether +detail
126466494SgshapiroR$+ <> $*		$: $1				else discard')
126564562SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
126664562SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
126790792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
126890792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
126990792SgshapiroR< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
127090792SgshapiroR< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
127190792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
127290792SgshapiroR< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
127364562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
127438032Speter
127564562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
127690792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
127738032Speter###################################################################
127890792Sgshapiro###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
127990792Sgshapirodnl input: <Domain> FullAddress
128090792Sgshapiro###################################################################
128190792Sgshapiro
128290792SgshapiroSLDAPMailertable
128390792SgshapiroR< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
128490792SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
128590792SgshapiroR< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
128690792SgshapiroR< $+ > $#$*		$#$2					found
128790792SgshapiroR< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
128890792Sgshapiro`dnl')
128990792Sgshapiro
129090792Sgshapiro###################################################################
129138032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
129264562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
129338032Speter###################################################################
129438032Speter
129564562SgshapiroSMailertable=90
129664562Sgshapirodnl shift and check
129764562Sgshapirodnl %2 is not documented in cf/README
129838032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
129964562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
130064562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
130164562SgshapiroR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
130264562Sgshapirodnl is $2 always empty?
130338032SpeterR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
130464562SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
130564562Sgshapirodnl return full address
130638032SpeterR< $* > $*		$@ $2				no mailertable match',
130738032Speter`dnl')
130838032Speter
130938032Speter###################################################################
131038032Speter###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
131164562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
131264562Sgshapirodnl	<> address				-> address
131364562Sgshapirodnl	<error:d.s.n:text>			-> error
1314120256Sgshapirodnl	<error:keyword:text>			-> error
131564562Sgshapirodnl	<error:text>				-> error
131664562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
131764562Sgshapirodnl	<mailer:host> address			-> mailer host address
131864562Sgshapirodnl	<localdomain> address			-> address
131964562Sgshapirodnl	<host> address				-> relay host address
132038032Speter###################################################################
132138032Speter
132264562SgshapiroSMailerToTriple=95
132338032SpeterR< > $*				$@ $1			strip off null relay
132464562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
1325120256SgshapiroR< error : $- : $+ > $*		$#error $@ $(dequote $1 $) $: $2
1326120256SgshapiroR< error : $+ > $*		$#error $: $1
132738032SpeterR< local : $* > $*		$>CanonLocal < $1 > $2
132890792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
132990792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
133090792SgshapiroR< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
133138032SpeterR< $=w > $*			$@ $2			delete local host
133238032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
133338032Speter
133438032Speter###################################################################
133538032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
133664562Sgshapirodnl input: <user> address
133764562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
133864562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
133964562Sgshapirodnl <> user <@host> rest		-> local user@host user
134064562Sgshapirodnl <> user				-> local user user
134164562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
134264562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
134364562Sgshapirodnl <user> lp				-> local lp user
134438032Speter###################################################################
134538032Speter
134638032SpeterSCanonLocal
134743730Speter# strip local host from routed addresses
134864562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
134964562SgshapiroR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
135043730Speter
135138032Speter# strip trailing dot from any host name that may appear
135238032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
135338032Speter
135438032Speter# handle local: syntax -- use old user, either with or without host
135538032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
135638032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
135738032Speter
135838032Speter# handle local:user@host syntax -- ignore host part
135938032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
136038032Speter
136138032Speter# handle local:user syntax
136238032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
136338032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
136438032Speter
136538032Speter###################################################################
136638032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
136738032Speter###################################################################
136838032Speter
136964562SgshapiroSMasqHdr=93
137038032Speter
137164562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
137238032Speter# handle generics database
137338032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
137464562Sgshapirodnl if generics should be applied add a @ as mark
137538032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
137638032Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
137738032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
137864562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
137964562Sgshapirodnl ignore the first case for now
138064562Sgshapirodnl if it has the mark lookup full address
138190792Sgshapirodnl broken: %1 is full address not just detail
138264562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
138364562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
138464562Sgshapirodnl no match, try user+detail@domain
138564562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
138664562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
138764562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
138864562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
138964562Sgshapirodnl no match, remove mark
139064562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
139164562Sgshapirodnl no match, try @domain for exceptions
139264562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
139364562Sgshapirodnl workspace: ... or <match> user <@domain>
139464562Sgshapirodnl no match, try local part
139538032SpeterR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
139664562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
139764562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
139864562SgshapiroR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
139964562SgshapiroR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
140038032SpeterR< > $*			$: $1				not found',
140138032Speter`dnl')
140238032Speter
140364562Sgshapiro# do not masquerade anything in class N
140464562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
140564562Sgshapiro
140690792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
140738032Speter# special case the users that should be exposed
140838032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
140938032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
141038032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
141138032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
141238032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
141338032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
141438032Speter
141538032Speter# handle domain-specific masquerading
141638032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
141738032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
141838032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
141938032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
142038032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
142138032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
142238032SpeterR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
142338032SpeterR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
142490792Sgshapirodnl', `dnl no masquerading
142590792Sgshapirodnl just fix *LOCAL* leftovers
142690792SgshapiroR$* < @ *LOCAL* >	$@ $1 < @ $j . >')
142738032Speter
142838032Speter###################################################################
142938032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
143038032Speter###################################################################
143138032Speter
143264562SgshapiroSMasqEnv=94
143338032Speterifdef(`_MASQUERADE_ENVELOPE_',
143464562Sgshapiro`R$+			$@ $>MasqHdr $1',
143538032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
143638032Speter
143738032Speter###################################################################
143838032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
143938032Speter###################################################################
144038032Speter
144164562SgshapiroSParseLocal=98
144264562Sgshapiroundivert(3)dnl LOCAL_RULE_0
144338032Speter
144464562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
144590792Sgshapiro######################################################################
144690792Sgshapiro###  LDAPExpand: Expand address using LDAP routing
144790792Sgshapiro###
144890792Sgshapiro###	Parameters:
144990792Sgshapiro###		<$1> -- parsed address (user < @ domain . >) (pass through)
145090792Sgshapiro###		<$2> -- RFC822 address (user @ domain) (used for lookup)
145190792Sgshapiro###		<$3> -- +detail information
145290792Sgshapiro###
145390792Sgshapiro###	Returns:
145490792Sgshapiro###		Mailer triplet ($#mailer $@ host $: address)
145590792Sgshapiro###		Parsed address (user < @ domain . >)
145690792Sgshapiro######################################################################
145790792Sgshapiro
1458132943Sgshapiro# SMTP operation modes
1459132943SgshapiroC{SMTPOpModes} s d D
1460132943Sgshapiro
146164562SgshapiroSLDAPExpand
146264562Sgshapiro# do the LDAP lookups
146390792SgshapiroR<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
146464562Sgshapiro
1465132943Sgshapiro# look for temporary failures and...
1466132943SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*>	$: $&{opMode} $| TMPF <$&{addr_type}> $| $3
1467132943SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*>	$: $&{opMode} $| TMPF <$&{addr_type}> $| $3
1468132943Sgshapiroifelse(_LDAP_ROUTE_MAPTEMP_, `_TEMPFAIL_', `dnl
1469132943Sgshapiro# ... temp fail RCPT SMTP commands
1470132943SgshapiroR$={SMTPOpModes} $| TMPF <e r> $| $+	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."')
1471132943Sgshapiro# ... return original address for MTA to queue up
1472132943SgshapiroR$* $| TMPF <$*> $| $+			$@ $3
147394334Sgshapiro
147464562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
147564562Sgshapiro# return the new mailRoutingAddress
147690792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
147790792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
147890792SgshapiroR<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
147990792SgshapiroR<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
148090792SgshapiroR<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
148164562Sgshapiro
148298121Sgshapiro
148364562Sgshapiro# if mailRoutingAddress and non-local mailHost,
148464562Sgshapiro# relay to mailHost with new mailRoutingAddress
148590792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
148690792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
148790792Sgshapiro# check mailertable for host, relay from there
148890792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
148990792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
149090792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
149190792Sgshapiro# check mailertable for host, relay from there
149290792SgshapiroR<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
149390792Sgshapiro`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
149464562Sgshapiro
149564562Sgshapiro# if no mailRoutingAddress and local mailHost,
149664562Sgshapiro# return original address
149790792SgshapiroR<> <$=w> <$+> <$+> <$*>	$@ $2
149864562Sgshapiro
149998121Sgshapiro
150064562Sgshapiro# if no mailRoutingAddress and non-local mailHost,
150164562Sgshapiro# relay to mailHost with original address
150290792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
150390792Sgshapiro# check mailertable for host, relay from there
150490792SgshapiroR<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
150590792Sgshapiro`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
150664562Sgshapiro
150790792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_',
150890792Sgshapiro`# if no mailRoutingAddress and no mailHost,
150990792Sgshapiro# try without +detail
151090792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
151190792Sgshapiro
1512132943Sgshapiroifdef(`_LDAP_ROUTE_NODOMAIN_', `dnl', `
151390792Sgshapiro# if still no mailRoutingAddress and no mailHost,
151464562Sgshapiro# try @domain
151590792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
151690792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
1517132943SgshapiroR<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>')
151864562Sgshapiro
151964562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
152064562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
152164562Sgshapiro# user does not exist
152290792SgshapiroR<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
152390792Sgshapiro# only give error for envelope recipient
152490792SgshapiroR<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
1525132943Sgshapiroifdef(`_LDAP_SENDER_MUST_EXIST_', `dnl
1526132943Sgshapiro# and the sender too
1527132943SgshapiroR<?> <e s> <$+>			$#error $@ nouser $: "550 User unknown"')
152890792SgshapiroR<?> <$*> <$+>			$@ $2',
152964562Sgshapiro`dnl
153064562Sgshapiro# return the original address
153190792SgshapiroR<> <> <$+> <@ $+> <$*>		$@ $1')',
153264562Sgshapiro`dnl')
153364562Sgshapiro
153464562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
153564562Sgshapiro')')
153690792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
153738032Speter######################################################################
153890792Sgshapiro###  D: LookUpDomain -- search for domain in access database
153938032Speter###
154038032Speter###	Parameters:
154138032Speter###		<$1> -- key (domain name)
154238032Speter###		<$2> -- default (what to return if not found in db)
154364562Sgshapirodnl			must not be empty
154490792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
154564562Sgshapiro###			! does lookup only with tag
154664562Sgshapiro###			+ does lookup with and without tag
154790792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
154864562Sgshapirodnl returns:		<default> <passthru>
154964562Sgshapirodnl 			<result> <passthru>
155038032Speter######################################################################
155138032Speter
155290792SgshapiroSD
155364562Sgshapirodnl workspace <key> <default> <passthru> <mark>
155464562Sgshapirodnl lookup with tag (in front, no delimiter here)
155590792Sgshapirodnl    2    3  4    5
155690792SgshapiroR<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
155764562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
155864562Sgshapirodnl lookup without tag?
155990792Sgshapirodnl   1    2      3    4
156090792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
156190792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
156290792Sgshapirodnl XXX apply this also to IP addresses?
156390792Sgshapirodnl currently it works the wrong way round for [1.2.3.4]
156490792Sgshapirodnl   1  2    3    4  5    6
156590792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
156690792Sgshapirodnl   1  2    3      4    5
156790792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
156890792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
156990792Sgshapirodnl found SKIP: return <default> and <passthru>
157090792Sgshapirodnl      1    2    3  4    5
157190792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
157290792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!)
157390792Sgshapirodnl    1  2     3    4  5    6
157490792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
157590792Sgshapiroifdef(`NO_NETINET6', `dnl',
157690792Sgshapiro`dnl not found: IPv6 net
157790792Sgshapirodnl (could be merged with previous rule if we have a class containing .:)
157890792Sgshapirodnl    1   2     3    4  5    6
157990792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
158090792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
158164562Sgshapirodnl not found, but subdomain: try again
158290792Sgshapirodnl   1  2    3    4  5    6
158390792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
158490792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
158590792Sgshapirodnl   1    2      3    4
158690792SgshapiroR<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
158790792Sgshapirodnl not found, no subdomain: return <default> and <passthru>
158890792Sgshapirodnl   1    2    3  4    5
158990792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
159090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
159190792Sgshapirodnl            2    3    4  5    6
159290792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
159390792Sgshapirodnl return <result of lookup> and <passthru>
159490792Sgshapirodnl    2    3    4  5    6
159590792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
159638032Speter
159738032Speter######################################################################
159890792Sgshapiro###  A: LookUpAddress -- search for host address in access database
159938032Speter###
160038032Speter###	Parameters:
160138032Speter###		<$1> -- key (dot quadded host address)
160238032Speter###		<$2> -- default (what to return if not found in db)
160364562Sgshapirodnl			must not be empty
160490792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
160564562Sgshapiro###			! does lookup only with tag
160664562Sgshapiro###			+ does lookup with and without tag
160790792Sgshapiro###		<$4> -- passthru (additional data passed through)
160864562Sgshapirodnl	returns:	<default> <passthru>
160964562Sgshapirodnl			<result> <passthru>
161038032Speter######################################################################
161138032Speter
161290792SgshapiroSA
161364562Sgshapirodnl lookup with tag
161490792Sgshapirodnl    2    3  4    5
161590792SgshapiroR<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
161664562Sgshapirodnl lookup without tag
161790792Sgshapirodnl   1    2      3    4
161890792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
161990792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
162090792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
162190792Sgshapirodnl found SKIP: return <default> and <passthru>
162290792Sgshapirodnl      1    2    3  4    5
162390792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
162490792Sgshapiroifdef(`NO_NETINET6', `dnl',
162590792Sgshapiro`dnl no match; IPv6: remove last part
162690792Sgshapirodnl   1   2    3    4  5    6
162790792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
162890792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
162964562Sgshapirodnl no match; IPv4: remove last part
163090792Sgshapirodnl   1  2    3    4  5    6
163190792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
163264562Sgshapirodnl no match: return default
163390792Sgshapirodnl   1    2    3  4    5
163490792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
163590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
163690792Sgshapirodnl            2    3    4  5    6
163790792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
163864562Sgshapirodnl match: return result
163990792Sgshapirodnl    2    3    4  5    6
164090792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
164190792Sgshapirodnl endif _ACCESS_TABLE_
164290792Sgshapirodivert(0)
164338032Speter######################################################################
164442575Speter###  CanonAddr --	Convert an address into a standard form for
164542575Speter###			relay checking.  Route address syntax is
164642575Speter###			crudely converted into a %-hack address.
164742575Speter###
164842575Speter###	Parameters:
164942575Speter###		$1 -- full recipient address
165042575Speter###
165142575Speter###	Returns:
165242575Speter###		parsed address, not in source route form
165364562Sgshapirodnl		user%host%host<@domain>
165464562Sgshapirodnl		host!user<@domain>
165542575Speter######################################################################
165642575Speter
165742575SpeterSCanonAddr
165864562SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
165964562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
166042575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
166142575SpeterR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
166242575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
166364562Sgshapirodnl')
166442575Speter
166542575Speter######################################################################
166638032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
166738032Speter###			$* $=m or the access database.
166838032Speter###			Check user portion for host separators.
166938032Speter###
167038032Speter###	Parameters:
167138032Speter###		$1 -- full recipient address
167238032Speter###
167338032Speter###	Returns:
167438032Speter###		parsed, non-local-relaying address
167538032Speter######################################################################
167638032Speter
167738032SpeterSParseRecipient
167864562Sgshapirodnl mark and canonify address
167942575SpeterR$*				$: <?> $>CanonAddr $1
168064562Sgshapirodnl workspace: <?> localpart<@domain[.]>
168142575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
168264562Sgshapirodnl workspace: <?> localpart<@domain>
168342575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
168438032Speter
168538032Speter# if no $=O character, no host in the user portion, we are done
168642575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
168764562Sgshapirodnl no $=O in localpart: return
168842575SpeterR<?> $*				$@ $1
168938032Speter
169090792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O
169164562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
169238032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
169338032Speter# if we relay, check username portion for user%host so host can be checked also
169442575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
169564562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
169664562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
169790792Sgshapiro
169890792Sgshapirodnl what if access map returns something else than RELAY?
169990792Sgshapirodnl we are only interested in RELAY entries...
170090792Sgshapirodnl other To: entries: blacklist recipient; generic entries?
170190792Sgshapirodnl if it is an error we probably do not want to relay anyway
170238032Speterifdef(`_RELAY_HOSTS_ONLY_',
170342575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
170464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
170564562SgshapiroR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
170642575SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
170742575Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
170864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
170990792SgshapiroR<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
171042575SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
171138032Speter
171264562Sgshapiro
171390792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl
171490792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
171590792SgshapiroR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
1716132943SgshapiroR<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1
171790792Sgshapirodnl yes: mark it as <RELAY>
171890792SgshapiroR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
171990792Sgshapirodnl no: put old <NO> mark back
172090792SgshapiroR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
172190792Sgshapiro
172290792Sgshapirodnl do we relay to this recipient domain?
172342575SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
172490792Sgshapirodnl something else
172590792SgshapiroR<$+> $*			$@ $2
172642575Speter
172764562Sgshapiro
172838032Speter######################################################################
172938032Speter###  check_relay -- check hostname/address on SMTP startup
173038032Speter######################################################################
173138032Speter
1732132943Sgshapiroifdef(`_CONTROL_IMMEDIATE_',`dnl
1733132943SgshapiroScheck_relay
1734132943Sgshapiroifdef(`_RATE_CONTROL_IMMEDIATE_',`dnl
1735132943Sgshapirodnl workspace: ignored...
1736132943SgshapiroR$*		$: $>"RateControl" dummy', `dnl')
1737132943Sgshapiroifdef(`_CONN_CONTROL_IMMEDIATE_',`dnl
1738132943Sgshapirodnl workspace: ignored...
1739132943SgshapiroR$*		$: $>"ConnControl" dummy', `dnl')
1740132943Sgshapirodnl')
1741132943Sgshapiro
174238032SpeterSLocal_check_relay
174364562SgshapiroScheck`'_U_`'relay
1744132943Sgshapiroifdef(`_USE_CLIENT_PTR_',`dnl
1745132943SgshapiroR$* $| $*		$: $&{client_ptr} $| $2', `dnl')
174638032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
174738032SpeterR$* $| $* $| $#$*	$#$3
174838032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
174938032Speter
175038032SpeterSBasic_check_relay
175138032Speter# check for deferred delivery mode
175298121SgshapiroR$*			$: < $&{deliveryMode} > $1
175338032SpeterR< d > $*		$@ deferred
175438032SpeterR< $* > $*		$: $2
175538032Speter
175664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
175766494Sgshapirodnl workspace: {client_name} $| {client_addr}
175890792SgshapiroR$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
175966494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
1760110560Sgshapirodnl OR $| $+ if client_name is empty
1761110560SgshapiroR   $| $+		$: $>A < $1 > <?> <+ Connect> <>	empty client_name
1762110560Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
176390792SgshapiroR<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
176490792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>)
176590792SgshapiroR<?> <$*>		$: OK				found nothing
176690792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
176790792SgshapiroR<$={Accept}> <$*>	$@ $1				return value of lookup
1768132943SgshapiroR<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"')
176990792SgshapiroR<DISCARD> <$*>		$#discard $: discard
1770132943SgshapiroR<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1
177164562Sgshapirodnl error tag
177266494SgshapiroR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
177366494SgshapiroR<ERROR:$+> <$*>		$#error $: $1
177490792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
177564562Sgshapirodnl generic error from access map
177666494SgshapiroR<$+> <$*>		$#error $: $1', `dnl')
177738032Speter
177864562Sgshapiroifdef(`_RBL_',`dnl
177964562Sgshapiro# DNS based IP address spam list
178090792Sgshapirodnl workspace: ignored...
178138032SpeterR$*			$: $&{client_addr}
178264562SgshapiroR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
178364562SgshapiroR<?>OK			$: OKSOFAR
178498121SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"',
178538032Speter`dnl')
1786132943Sgshapiroifdef(`_RATE_CONTROL_',`dnl
1787132943Sgshapiroifdef(`_RATE_CONTROL_IMMEDIATE_',`', `dnl
1788132943Sgshapirodnl workspace: ignored...
1789132943SgshapiroR$*		$: $>"RateControl" dummy')', `dnl')
1790132943Sgshapiroifdef(`_CONN_CONTROL_',`dnl
1791132943Sgshapiroifdef(`_CONN_CONTROL_IMMEDIATE_',`',`dnl
1792132943Sgshapirodnl workspace: ignored...
1793132943SgshapiroR$*		$: $>"ConnControl" dummy')', `dnl')
179464562Sgshapiroundivert(8)
1795168515Sgshapiroifdef(`_REQUIRE_RDNS_', `dnl
1796168515SgshapiroR$*			$: $&{client_addr} $| $&{client_resolve}
1797168515SgshapiroR$=R $*			$@ RELAY		We relay for these
1798168515SgshapiroR$* $| OK		$@ OK			Resolves.
1799168515SgshapiroR$* $| FAIL		$#error $@ 5.7.1 $: 550 Fix reverse DNS for $1
1800168515SgshapiroR$* $| TEMP		$#error $@ 4.1.8 $: 451 Client IP address $1 does not resolve
1801168515SgshapiroR$* $| FORGED		$#error $@ 4.1.8 $: 451 Possibly forged hostname for $1
1802168515Sgshapiro', `dnl')
180338032Speter
180438032Speter######################################################################
180538032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
180638032Speter######################################################################
180738032Speter
180838032SpeterSLocal_check_mail
180964562SgshapiroScheck`'_U_`'mail
181038032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
181138032SpeterR$* $| $#$*		$#$2
181238032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
181338032Speter
181438032SpeterSBasic_check_mail
181538032Speter# check for deferred delivery mode
181698121SgshapiroR$*			$: < $&{deliveryMode} > $1
181738032SpeterR< d > $*		$@ deferred
181838032SpeterR< $* > $*		$: $2
181938032Speter
182064562Sgshapiro# authenticated?
182164562Sgshapirodnl done first: we can require authentication for every mail transaction
182264562Sgshapirodnl workspace: address as given by MAIL FROM: (sender)
182364562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
182464562SgshapiroR$* $| $#$+		$#$2
182564562Sgshapirodnl undo damage: remove result of tls_client call
182664562SgshapiroR$* $| $*		$: $1
182738032Speter
182864562Sgshapirodnl workspace: address as given by MAIL FROM:
182964562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
183038032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
183164562Sgshapirodnl do some additional checks
183264562Sgshapirodnl no user@host
183364562Sgshapirodnl no user@localhost (if nonlocal sender)
183464562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
183564562Sgshapirodnl just make sure the address has <> around it (which is required by
183664562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
183764562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
183864562Sgshapirodnl not be modified by host lookups.
183964562SgshapiroR$+			$: <?> $1
184064562SgshapiroR<?><$+>		$: <@> <$1>
184164562SgshapiroR<?>$+			$: <@> <$1>
184264562Sgshapirodnl workspace: <@> <address>
184364562Sgshapirodnl prepend daemon_flags
184464562SgshapiroR$*			$: $&{daemon_flags} $| $1
184564562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
184664562Sgshapirodnl do not allow these at all or only from local systems?
184764562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
184864562Sgshapirodnl accept unqualified sender: change mark to avoid test
184964562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
185064562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
185164562Sgshapirodnl        or:                    <? ${client_name} > <address>
185264562Sgshapirodnl        or:                    <?> <address>
185364562Sgshapirodnl remove daemon_flags
185464562SgshapiroR$* $| $*		$: $2
185538032Speter# handle case of @localhost on address
185664562SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
185764562SgshapiroR<@> < $* @ [127.0.0.1] >
185864562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
185964562SgshapiroR<@> < $* @ localhost.$m >
186064562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
186138032Speterifdef(`_NO_UUCP_', `dnl',
186264562Sgshapiro`R<@> < $* @ localhost.UUCP >
186364562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
186464562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
186564562Sgshapirodnl	or:    <@> <address>
186664562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
186764562SgshapiroR<@> $*			$: $1			no localhost as domain
186864562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
186964562Sgshapirodnl	or:    <address>
187064562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
187164562SgshapiroR<? $=w> $*		$: $2			local client: ok
187290792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
187364562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
187464562SgshapiroR<?> $*			$: $1')
187564562Sgshapirodnl workspace: address (or <address>)
187664562SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
187764562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
187864562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
187964562SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
188064562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
1881102528SgshapiroR<?> $* < @ $* $=P >	$: <_RES_OK_> $1 < @ $2 $3 >
188264562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
188398121Sgshapirodnl A sender address with my local host name ($j) is safe
1884102528SgshapiroR<?> $* < @ $j >	$: <_RES_OK_> $1 < @ $j >
188564562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
188690792Sgshapiro`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
188764562Sgshapiro`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
188864562SgshapiroR<? $* <$->> $* < @ $+ >
188964562Sgshapiro			$: <$2> $3 < @ $4 >')
189090792Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
189164562Sgshapirodnl mark is ? iff the address is user (wo @domain)
189238032Speter
189364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
189464562Sgshapiro# check sender address: user@address, user@, address
189564562Sgshapirodnl should we remove +ext from user?
189690792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
189790792SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
189864562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
189964562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
190064562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
190164562Sgshapirodnl will only return user<@domain when "reversing" the args
190290792SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
190364562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
190464562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
190564562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
190638032Speter# retransform for further use
190764562Sgshapirodnl required form:
190864562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
190964562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
191064562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
191164562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
191264562Sgshapirodnl mark is ? iff the address is user (wo @domain)
191338032Speter
191438032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
191538032Speter# handle case of no @domain on address
191664562Sgshapirodnl prepend daemon_flags
191764562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
191864562Sgshapirodnl accept unqualified sender: change mark to avoid test
191990792SgshapiroR$* u $* $| <?> $*	$: <_RES_OK_> $3
192064562Sgshapirodnl remove daemon_flags
192164562SgshapiroR$* $| $*		$: $2
1922110560SgshapiroR<?> $*			$: < ? $&{client_addr} > $1
1923102528SgshapiroR<?> $*			$@ <_RES_OK_>			...local unqualed ok
192490792SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
192538032Speter							...remote is not')
192638032Speter# check results
192764562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
1928168515SgshapiroR<$={ResOk}> $*		$: @ $2		domain ok
192964562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
193090792SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
193164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
193290792SgshapiroR<$={Accept}> $*	$# $1		accept from access map
193338032SpeterR<DISCARD> $*		$#discard $: discard
1934132943SgshapiroR<QUARANTINE:$+> $*	$#error $@ quarantine $: $1
1935132943SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"')
193664562Sgshapirodnl error tag
193764562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
193864562SgshapiroR<ERROR:$+> $*		$#error $: $1
193990792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
194064562Sgshapirodnl generic error from access map
194164562SgshapiroR<$+> $*		$#error $: $1		error from access db',
194238032Speter`dnl')
1943168515Sgshapirodnl workspace: @ CanonicalAddress (i.e. address in canonical form localpart<@host>)
194438032Speter
1945168515Sgshapiroifdef(`_BADMX_CHK_', `dnl
1946168515SgshapiroR@ $*<@$+>$*		$: $1<@$2>$3 $| $>BadMX $2
1947168515SgshapiroR$* $| $#$*		$#$2
1948168515Sgshapiro
1949168515SgshapiroSBadMX
1950168515Sgshapiro# Look up MX records and ferret away a copy of the original address.
1951168515Sgshapiro# input: domain part of address to check
1952168515SgshapiroR$+				$:<MX><$1><:$(mxlist $1$):><:>
1953168515Sgshapiro# workspace: <MX><domain><: mxlist-result $><:>
1954168515SgshapiroR<MX><$+><:$*<TEMP>:><$*>	$#error $@ 4.1.2 $: "450 MX lookup failure for "$1
1955168515Sgshapiro# workspace: <MX> <original destination> <unchecked mxlist> <checked mxlist>
1956168515Sgshapiro# Recursively run badmx check on each mx.
1957168515SgshapiroR<MX><$*><:$+:$*><:$*>		<MX><$1><:$3><: $4 $(badmx $2 $):>
1958168515Sgshapiro# See if any of them fail.
1959168515SgshapiroR<MX><$*><$*><$*<BADMX>:$*>	$#error $@ 5.1.2 $:"550 Illegal MX record for recipient host "$1
1960168515Sgshapiro# Reverse the mxlists so we can use the same argument order again.
1961168515SgshapiroR<MX><$*><$*><$*>		$:<MX><$1><$3><$2>
1962168515SgshapiroR<MX><$*><:$+:$*><:$*>		<MX><$1><:$3><:$4 $(dnsA $2 $) :>
1963168515Sgshapiro
1964168515Sgshapiro# Reverse the lists so we can use the same argument order again.
1965168515SgshapiroR<MX><$*><$*><$*>		$:<MX><$1><$3><$2>
1966168515SgshapiroR<MX><$*><:$+:$*><:$*>		<MX><$1><:$3><:$4 $(BadMXIP $2 $) :>
1967168515Sgshapiro
1968168515SgshapiroR<MX><$*><$*><$*<BADMXIP>:$*>	$#error $@ 5.1.2 $:"550 Invalid MX record for recipient host "$1',
1969168515Sgshapiro`dnl')
1970168515Sgshapiro
1971168515Sgshapiro
197238032Speter######################################################################
197338032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
197438032Speter######################################################################
197538032Speter
197638032SpeterSLocal_check_rcpt
197764562SgshapiroScheck`'_U_`'rcpt
197838032SpeterR$*			$: $1 $| $>"Local_check_rcpt" $1
197938032SpeterR$* $| $#$*		$#$2
198038032SpeterR$* $| $*		$@ $>"Basic_check_rcpt" $1
198138032Speter
198238032SpeterSBasic_check_rcpt
198390792Sgshapiro# empty address?
198490792SgshapiroR<>			$#error $@ nouser $: "553 User address required"
198590792SgshapiroR$@			$#error $@ nouser $: "553 User address required"
198638032Speter# check for deferred delivery mode
198798121SgshapiroR$*			$: < $&{deliveryMode} > $1
198838032SpeterR< d > $*		$@ deferred
198938032SpeterR< $* > $*		$: $2
199038032Speter
199164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
199290792Sgshapirodnl this code checks for user@host where host is not a FQHN.
199390792Sgshapirodnl it is not activated.
199490792Sgshapirodnl notice: code to check for a recipient without a domain name is
199590792Sgshapirodnl available down below; look for the same macro.
199690792Sgshapirodnl this check is done here because the name might be qualified by the
199790792Sgshapirodnl canonicalization.
199890792Sgshapiro# require fully qualified domain part?
199990792Sgshapirodnl very simple canonification: make sure the address is in < >
200064562SgshapiroR$+			$: <?> $1
200190792SgshapiroR<?> <$+>		$: <@> <$1>
200290792SgshapiroR<?> $+			$: <@> <$1>
200390792SgshapiroR<@> < postmaster >	$: postmaster
2004110560SgshapiroR<@> < $* @ $+ . $+ >	$: < $1 @ $2 . $3 >
200564562Sgshapirodnl prepend daemon_flags
200690792SgshapiroR<@> $*			$: $&{daemon_flags} $| <@> $1
200764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
2008159609Sgshapirodnl _r_equire qual.rcpt: ok
2009120256SgshapiroR$* r $* $| <@> < $+ @ $+ >	$: < $3 @ $4 >
201064562Sgshapirodnl do not allow these at all or only from local systems?
2011120256SgshapiroR$* r $* $| <@> < $* >	$: < ? $&{client_name} > < $3 >
201264562SgshapiroR<?> < $* >		$: <$1>
201364562SgshapiroR<? $=w> < $* >		$: <$1>
201490792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
201564562Sgshapirodnl remove daemon_flags for other cases
201664562SgshapiroR$* $| <@> $*		$: $2', `dnl')
201764562Sgshapiro
201890792Sgshapirodnl ##################################################################
201990792Sgshapirodnl call subroutines for recipient and relay
202090792Sgshapirodnl possible returns from subroutines:
202190792Sgshapirodnl $#TEMP	temporary failure
202290792Sgshapirodnl $#error	permanent failure (or temporary if from access map)
202390792Sgshapirodnl $#other	stop processing
202490792Sgshapirodnl RELAY	RELAYing allowed
202590792Sgshapirodnl other	otherwise
202690792Sgshapiro######################################################################
202790792SgshapiroR$*			$: $1 $| @ $>"Rcpt_ok" $1
202890792Sgshapirodnl temporary failure? remove mark @ and remember
202990792SgshapiroR$* $| @ $#TEMP $+	$: $1 $| T $2
203090792Sgshapirodnl error or ok (stop)
203190792SgshapiroR$* $| @ $#$*		$#$2
203290792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
203390792SgshapiroR$* $| @ RELAY		$@ RELAY
203490792Sgshapirodnl something else: call check sender (relay)
203590792SgshapiroR$* $| @ $*		$: O $| $>"Relay_ok" $1
203690792Sgshapirodnl temporary failure: call check sender (relay)
203790792SgshapiroR$* $| T $+		$: T $2 $| $>"Relay_ok" $1
203890792Sgshapirodnl temporary failure? return that
203990792SgshapiroR$* $| $#TEMP $+	$#error $2
204090792Sgshapirodnl error or ok (stop)
204190792SgshapiroR$* $| $#$*		$#$2
204290792SgshapiroR$* $| RELAY		$@ RELAY
204390792Sgshapirodnl something else: return previous temp failure
204490792SgshapiroR T $+ $| $*		$#error $1
204590792Sgshapiro# anything else is bogus
204690792SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
204790792Sgshapirodivert(0)
204890792Sgshapiro
204990792Sgshapiro######################################################################
205090792Sgshapiro### Rcpt_ok: is the recipient ok?
205190792Sgshapirodnl input: recipient address (RCPT TO)
205290792Sgshapirodnl output: see explanation at call
205390792Sgshapiro######################################################################
205490792SgshapiroSRcpt_ok
205538032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
205642575SpeterR$*			$: $>CanonAddr $1
205738032SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
205838032Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
205938032Speter
206042575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
206142575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
206242575Speter# unlimited bestmx
206342575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
206442575Speter`dnl
206542575Speter# limit bestmx to $=B
206643730SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
206790792SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
206842575SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
206942575SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
207042575Speter
207138032Speterifdef(`_BLACKLIST_RCPT_',`dnl
207264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
207338032Speter# blacklist local users or any host from receiving mail
207438032SpeterR$*			$: <?> $1
207564562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
207664562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
207790792SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
207890792SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
207964562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
208064562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
208164562Sgshapirodnl will only return user<@domain when "reversing" the args
208290792SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
208364562SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
208464562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
208590792Sgshapirodnl we may have to filter here because otherwise some RHSs
208690792Sgshapirodnl would be interpreted as generic error messages...
208790792Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
208890792Sgshapirodnl that would make a lot of things easier.
208964562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
209090792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
209190792SgshapiroR<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
209290792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
209390792Sgshapirodnl compatility with 8.11/8.10:
209464562Sgshapirodnl we have to filter these because otherwise they would be interpreted
209564562Sgshapirodnl as generic error message...
209664562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
209764562Sgshapirodnl that would make a lot of things easier.
209864562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
209964562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
210090792SgshapiroR<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
210164562SgshapiroR<DISCARD> $*		$#discard $: discard
2102132943SgshapiroR<QUARANTINE:$+> $*	$#error $@ quarantine $: $1
210364562Sgshapirodnl error tag
210464562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
210564562SgshapiroR<ERROR:$+> $*		$#error $: $1
210690792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
210764562Sgshapirodnl generic error from access map
210864562SgshapiroR<$+> $*		$#error $: $1		error from access db
210964562SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
211038032Speter
211190792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
211290792Sgshapiro# authenticated via TLS?
211390792SgshapiroR$*			$: $1 $| $>RelayTLS	client authenticated?
211490792SgshapiroR$* $| $# $+		$# $2			error/ok?
211590792SgshapiroR$* $| $*		$: $1			no
211664562Sgshapiro
211790792SgshapiroR$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
211890792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth
211990792SgshapiroR$* $| $# $*		$# $2
212090792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
212190792SgshapiroR$* $| NO		$: $1
212290792SgshapiroR$* $| $*		$: $1 $| $&{auth_type}
212390792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ]
212464562Sgshapirodnl empty ${auth_type}?
212564562SgshapiroR$* $|			$: $1
212664562Sgshapirodnl mechanism ${auth_type} accepted?
212764562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
212890792SgshapiroR$* $| $={TrustAuthMech}	$# RELAY
212990792Sgshapirodnl remove ${auth_type}
213064562SgshapiroR$* $| $*		$: $1
213171345Sgshapirodnl workspace: localpart<@domain> | localpart
213264562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
213371345Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
213471345SgshapiroR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
213538032Speter# anything terminating locally is ok
213638032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
213790792SgshapiroR$+ < @ $* $=m >	$@ RELAY', `dnl')
213890792SgshapiroR$+ < @ $=w >		$@ RELAY
213938032Speterifdef(`_RELAY_HOSTS_ONLY_',
214090792Sgshapiro`R$+ < @ $=R >		$@ RELAY
214164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
214264562SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
214364562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
214464562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
214590792Sgshapiro`R$+ < @ $* $=R >	$@ RELAY
214664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2147132943Sgshapiroifdef(`_RELAY_FULL_ADDR_', `dnl
2148132943SgshapiroR$+ < @ $+ >		$: $1 < @ $2 > $| $>SearchList <+ To> $| <F:$1@$2> <D:$2> <F:$1@> <>
2149132943SgshapiroR$+ < @ $+ > $| <$*>	$: <$3> <$1 <@ $2>>
2150132943SgshapiroR$+ < @ $+ > $| $*	$: <$3> <$1 <@ $2>>',
2151132943Sgshapiro`R$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>')')')
215264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
215364562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
215490792SgshapiroR<RELAY> $*		$@ RELAY
215590792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
215638032SpeterR<$*> <$*>		$: $2',`dnl')
215738032Speter
215864562Sgshapiro
215938032Speterifdef(`_RELAY_MX_SERVED_', `dnl
216038032Speter# allow relaying for hosts which we MX serve
216164562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
216264562Sgshapirodnl this must not necessarily happen if the client is checked first...
2163132943SgshapiroR< : $* <TEMP> : > $*	$#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1
216490792SgshapiroR<$* : $=w . : $*> $*	$@ RELAY
216542575SpeterR< : $* : > $*		$: $2',
216638032Speter`dnl')
216738032Speter
216838032Speter# check for local user (i.e. unqualified address)
216938032SpeterR$*			$: <?> $1
217042575SpeterR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
217138032Speter# local user is ok
217264562Sgshapirodnl is it really? the standard requires user@domain, not just user
217364562Sgshapirodnl but we should accept it anyway (maybe making it an option:
217464562Sgshapirodnl RequireFQDN ?)
217564562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
217664562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
217790792SgshapiroR<?> postmaster		$@ OK
217864562Sgshapiro# require qualified recipient?
217964562Sgshapirodnl prepend daemon_flags
218064562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
218164562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
218264562Sgshapirodnl do not allow these at all or only from local systems?
218364562Sgshapirodnl r flag? add client_name
218464562SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
218564562Sgshapirodnl no r flag: relay to local user (only local part)
218664562Sgshapiro# no qualified recipient required
218790792SgshapiroR$* $| <?> $+		$@ RELAY
218864562Sgshapirodnl client_name is empty
218990792SgshapiroR<?> <?> $+		$@ RELAY
219064562Sgshapirodnl client_name is local
219190792SgshapiroR<? $=w> <?> $+		$@ RELAY
219264562Sgshapirodnl client_name is not local
219364562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
219464562Sgshapirodnl no qualified recipient required
219590792SgshapiroR<?> $+			$@ RELAY')
219664562Sgshapirodnl it is a remote user: remove mark and then check client
219738032SpeterR<$+> $*		$: $2
219864562Sgshapirodnl currently the recipient address is not used below
219938032Speter
220090792Sgshapiro######################################################################
220190792Sgshapiro### Relay_ok: is the relay/sender ok?
220290792Sgshapirodnl input: ignored
220390792Sgshapirodnl output: see explanation at call
220490792Sgshapiro######################################################################
220590792SgshapiroSRelay_ok
220638032Speter# anything originating locally is ok
220764562Sgshapiro# check IP address
220864562SgshapiroR$*			$: $&{client_addr}
220990792SgshapiroR$@			$@ RELAY		originated locally
221090792SgshapiroR0			$@ RELAY		originated locally
2211110560SgshapiroR127.0.0.1		$@ RELAY		originated locally
2212110560SgshapiroRIPv6:::1		$@ RELAY		originated locally
221390792SgshapiroR$=R $*			$@ RELAY		relayable IP address
221464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
221590792SgshapiroR$*			$: $>A <$1> <?> <+ Connect> <$1>
221690792SgshapiroR<RELAY> $* 		$@ RELAY		relayable IP address
2217102528Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl
2218102528Sgshapirodnl this will cause rejections in cases like:
2219102528Sgshapirodnl Connect:My.Host.Domain	RELAY
2220102528Sgshapirodnl Connect:My.Net		REJECT
2221102528Sgshapirodnl since in check_relay client_name is checked before client_addr
2222102528SgshapiroR<REJECT> $* 		$@ REJECT		rejected IP address')
222390792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
222464562SgshapiroR<$*> <$*>		$: $2', `dnl')
222564562SgshapiroR$*			$: [ $1 ]		put brackets around it...
222690792SgshapiroR$=w			$@ RELAY		... and see if it is local
222764562Sgshapiro
222864562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
222964562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
223064562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
223164562Sgshapirodnl input: {client_addr} or something "broken"
223264562Sgshapirodnl just throw the input away; we do not need it.
223364562Sgshapiro# check whether FROM is allowed to use system as relay
223464562SgshapiroR$*			$: <?> $>CanonAddr $&f
223590792SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
223664562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
223764562Sgshapiro# check whether local FROM is ok
223890792SgshapiroR<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
223964562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
224094334SgshapiroR<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <>
224190792SgshapiroR<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
224290792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
224390792Sgshapiro', `dnl
224490792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_',
224590792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
224664562Sgshapiro')',
224764562Sgshapiro`dnl')
224864562Sgshapirodnl')', `dnl')
224990792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind.
225090792Sgshapirodnl it does not matter in this case because the following rule ignores
225190792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace.
225264562Sgshapiro
225364562Sgshapiro# check client name: first: did it resolve?
225464562Sgshapirodnl input: ignored
225564562SgshapiroR$*			$: < $&{client_resolve} >
2256132943SgshapiroR<TEMP>			$#TEMP $@ 4.4.0 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
225764562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
225864562SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
225964562Sgshapirodnl ${client_resolve} should be OK, so go ahead
226090792SgshapiroR$*			$: <@> $&{client_name}
226190792Sgshapirodnl should not be necessary since it has been done for client_addr already
2262110560Sgshapirodnl this rule actually may cause a problem if {client_name} resolves to ""
2263110560Sgshapirodnl however, this should not happen since the forward lookup should fail
2264110560Sgshapirodnl and {client_resolve} should be TEMP or FAIL.
2265110560Sgshapirodnl nevertheless, removing the rule doesn't hurt.
2266110560Sgshapirodnl R<@>			$@ RELAY
226790792Sgshapirodnl workspace: <@> ${client_name} (not empty)
226838032Speter# pass to name server to make hostname canonical
226990792SgshapiroR<@> $* $=P 		$:<?>  $1 $2
227090792SgshapiroR<@> $+			$:<?>  $[ $1 $]
227190792Sgshapirodnl workspace: <?> ${client_name} (canonified)
227264562SgshapiroR$* .			$1			strip trailing dots
227338032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
227490792SgshapiroR<?> $* $=m		$@ RELAY', `dnl')
227590792SgshapiroR<?> $=w		$@ RELAY
227638032Speterifdef(`_RELAY_HOSTS_ONLY_',
227790792Sgshapiro`R<?> $=R		$@ RELAY
227864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
227964562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
228064562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
228190792Sgshapiro`R<?> $* $=R			$@ RELAY
228264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
228390792SgshapiroR<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
228464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
228590792SgshapiroR<RELAY> $*		$@ RELAY
228690792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
228738032SpeterR<$*> <$*>		$: $2',`dnl')
228890792Sgshapirodnl end of _PROMISCUOUS_RELAY_
228964562Sgshapirodivert(0)
229064562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
229164562Sgshapiro# turn a canonical address in the form user<@domain>
229264562Sgshapiro# qualify unqual. addresses with $j
229364562Sgshapirodnl it might have been only user (without <@domain>)
229464562SgshapiroSFullAddr
229564562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
229664562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
229764562SgshapiroR$+			$@ $1 <@ $j >
229838032Speter
2299120256SgshapiroSDelay_TLS_Clt
2300110560Sgshapiro# authenticated?
2301110560Sgshapirodnl code repeated here from Basic_check_mail
2302110560Sgshapirodnl only called from check_rcpt in delay mode if checkrcpt returns $#
2303110560SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
2304110560SgshapiroR$* $| $#$+		$#$2
2305110560Sgshapirodnl return result from checkrcpt
2306120256SgshapiroR$* $| $*		$# $1
2307110560SgshapiroR$*			$# $1
2308110560Sgshapiro
2309120256SgshapiroSDelay_TLS_Clt2
2310110560Sgshapiro# authenticated?
2311110560Sgshapirodnl code repeated here from Basic_check_mail
2312110560Sgshapirodnl only called from check_rcpt in delay mode if stopping due to Friend/Hater
2313110560SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
2314110560SgshapiroR$* $| $#$+		$#$2
2315110560Sgshapirodnl return result from friend/hater check
2316120256SgshapiroR$* $| $*		$@ $1
2317110560SgshapiroR$*			$@ $1
2318110560Sgshapiro
231964562Sgshapiro# call all necessary rulesets
232064562SgshapiroScheck_rcpt
232164562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
232264562Sgshapirodnl which is the correct DSN code?
232364562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
2324110560Sgshapiro
232564562SgshapiroR$+			$: $1 $| $>checkrcpt $1
232664562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
2327110560Sgshapirodnl on error (or discard) stop now
2328110560SgshapiroR$+ $| $#error $*	$#error $2
2329110560SgshapiroR$+ $| $#discard $*	$#discard $2
2330110560Sgshapirodnl otherwise call tls_client; see above
2331120256SgshapiroR$+ $| $#$*		$@ $>"Delay_TLS_Clt" $2
233264562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
233364562Sgshapiroifdef(`_SPAM_FH_',
233464562Sgshapiro`dnl lookup user@ and user@address
233564562Sgshapiroifdef(`_ACCESS_TABLE_', `',
233664562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
233764562Sgshapiro')')dnl
233864562Sgshapirodnl one of the next two rules is supposed to match
233964562Sgshapirodnl this code has been copied from BLACKLIST... etc
234064562Sgshapirodnl and simplified by omitting some < >.
234190792SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
234290792SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
234364562Sgshapirodnl R<?>		$@ something_is_very_wrong_here
234490792Sgshapiro# lookup the addresses only with Spam tag
234590792SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
234664562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
234764562Sgshapirodnl', `dnl')
234864562Sgshapiroifdef(`_SPAM_FRIEND_',
234964562Sgshapiro`# is the recipient a spam friend?
235064562Sgshapiroifdef(`_SPAM_HATER_',
2351110560Sgshapiro	`errprint(`*** ERROR: define either Hater or Friend -- not both.
235264562Sgshapiro')', `dnl')
2353120256SgshapiroR<FRIEND> $+		$@ $>"Delay_TLS_Clt2" SPAMFRIEND
235464562SgshapiroR<$*> $+		$: $2',
235564562Sgshapiro`dnl')
235664562Sgshapiroifdef(`_SPAM_HATER_',
235764562Sgshapiro`# is the recipient no spam hater?
235890792SgshapiroR<HATER> $+		$: $1			spam hater: continue checks
2359120256SgshapiroR<$*> $+		$@ $>"Delay_TLS_Clt2" NOSPAMHATER	everyone else: stop
236064562Sgshapirodnl',`dnl')
2361168515Sgshapiro
236264562Sgshapirodnl run further checks: check_mail
236364562Sgshapirodnl should we "clean up" $&f?
236490792Sgshapiroifdef(`_FFR_MAIL_MACRO',
236590792Sgshapiro`R$*			$: $1 $| $>checkmail $&{mail_from}',
236690792Sgshapiro`R$*			$: $1 $| $>checkmail <$&f>')
236794334Sgshapirodnl recipient (canonical format) $| result of checkmail
236864562SgshapiroR$* $| $#$*		$#$2
236964562Sgshapirodnl run further checks: check_relay
237094334SgshapiroR$* $| $*		$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
237164562SgshapiroR$* $| $#$*		$#$2
237238032SpeterR$* $| $*		$: $1
237338032Speter', `dnl')
237490792Sgshapiro
2375168515Sgshapiroifdef(`_BLOCK_BAD_HELO_', `dnl
2376168515SgshapiroR$*			$: $1 $| <$&{auth_authen}>	Get auth info
2377168515Sgshapirodnl Bypass the test for users who have authenticated.
2378168515SgshapiroR$* $| <$+>		$: $1				skip if auth
2379168515SgshapiroR$* $| <$*>		$: $1 $| <$&{client_addr}> [$&s]	Get connection info
2380168515Sgshapirodnl Bypass for local clients -- IP address starts with $=R
2381168515SgshapiroR$* $| <$=R $*> [$*]	$: $1				skip if local client
2382168515Sgshapirodnl Bypass a "sendmail -bs" session, which use 0 for client ip address
2383168515SgshapiroR$* $| <0> [$*]		$: $1				skip if sendmail -bs
2384168515Sgshapirodnl Reject our IP - assumes "[ip]" is in class $=w
2385168515SgshapiroR$* $| <$*> $=w		$#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2386168515Sgshapirodnl Reject our hostname
2387168515SgshapiroR$* $| <$*> [$=w]	$#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2388168515Sgshapirodnl Pass anything else with a "." in the domain parameter
2389168515SgshapiroR$* $| <$*> [$+.$+]	$: $1				qualified domain ok
2390168515Sgshapirodnl Reject if there was no "." or only an initial or final "."
2391168515SgshapiroR$* $| <$*> [$*]	$#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2392168515Sgshapirodnl Clean up the workspace
2393168515SgshapiroR$* $| $*		$: $1
2394168515Sgshapiro', `dnl')
2395168515Sgshapiro
239690792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
239764562Sgshapiro######################################################################
239890792Sgshapiro###  F: LookUpFull -- search for an entry in access database
239990792Sgshapiro###
240090792Sgshapiro###	lookup of full key (which should be an address) and
240190792Sgshapiro###	variations if +detail exists: +* and without +detail
240290792Sgshapiro###
240390792Sgshapiro###	Parameters:
240490792Sgshapiro###		<$1> -- key
240590792Sgshapiro###		<$2> -- default (what to return if not found in db)
240690792Sgshapirodnl			must not be empty
240790792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
240890792Sgshapiro###			! does lookup only with tag
240990792Sgshapiro###			+ does lookup with and without tag
241090792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
241190792Sgshapirodnl returns:		<default> <passthru>
241290792Sgshapirodnl 			<result> <passthru>
241390792Sgshapiro######################################################################
241490792Sgshapiro
241590792SgshapiroSF
241690792Sgshapirodnl workspace: <key> <def> <o tag> <thru>
241790792Sgshapirodnl full lookup
241890792Sgshapirodnl    2    3  4    5
241990792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
242090792Sgshapirodnl no match, try without tag
242190792Sgshapirodnl   1    2      3    4
242290792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
242390792Sgshapirodnl no match, +detail: try +*
242490792Sgshapirodnl   1    2    3    4    5  6    7
242590792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
242690792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
242790792Sgshapirodnl no match, +detail: try +* without tag
242890792Sgshapirodnl   1    2    3    4      5    6
242990792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
243090792Sgshapiro			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
243190792Sgshapirodnl no match, +detail: try without +detail
243290792Sgshapirodnl   1    2    3    4    5  6    7
243390792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
243490792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
243590792Sgshapirodnl no match, +detail: try without +detail and without tag
243690792Sgshapirodnl   1    2    3    4      5    6
243790792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
243890792Sgshapiro			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
243990792Sgshapirodnl no match, return <default> <passthru>
244090792Sgshapirodnl   1    2    3  4    5
244190792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
244290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
244390792Sgshapirodnl            2    3  4    5
244490792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
244590792Sgshapirodnl match, return <match> <passthru>
244690792Sgshapirodnl    2    3  4    5
244790792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
244890792Sgshapiro
244990792Sgshapiro######################################################################
245090792Sgshapiro###  E: LookUpExact -- search for an entry in access database
245190792Sgshapiro###
245290792Sgshapiro###	Parameters:
245390792Sgshapiro###		<$1> -- key
245490792Sgshapiro###		<$2> -- default (what to return if not found in db)
245590792Sgshapirodnl			must not be empty
245690792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
245790792Sgshapiro###			! does lookup only with tag
245890792Sgshapiro###			+ does lookup with and without tag
245990792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
246090792Sgshapirodnl returns:		<default> <passthru>
246190792Sgshapirodnl 			<result> <passthru>
246290792Sgshapiro######################################################################
246390792Sgshapiro
246490792SgshapiroSE
246590792Sgshapirodnl    2    3  4    5
246690792SgshapiroR<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
246790792Sgshapirodnl no match, try without tag
246890792Sgshapirodnl   1    2      3    4
246990792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
247090792Sgshapirodnl no match, return default passthru
247190792Sgshapirodnl   1    2    3  4    5
247290792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
247390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
247490792Sgshapirodnl            2    3  4    5
247590792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
247690792Sgshapirodnl match, return <match> <passthru>
247790792Sgshapirodnl    2    3  4    5
247890792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
247990792Sgshapiro
248090792Sgshapiro######################################################################
248190792Sgshapiro###  U: LookUpUser -- search for an entry in access database
248290792Sgshapiro###
248390792Sgshapiro###	lookup of key (which should be a local part) and
248490792Sgshapiro###	variations if +detail exists: +* and without +detail
248590792Sgshapiro###
248690792Sgshapiro###	Parameters:
248790792Sgshapiro###		<$1> -- key (user@)
248890792Sgshapiro###		<$2> -- default (what to return if not found in db)
248990792Sgshapirodnl			must not be empty
249090792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
249190792Sgshapiro###			! does lookup only with tag
249290792Sgshapiro###			+ does lookup with and without tag
249390792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
249490792Sgshapirodnl returns:		<default> <passthru>
249590792Sgshapirodnl 			<result> <passthru>
249690792Sgshapiro######################################################################
249790792Sgshapiro
249890792SgshapiroSU
249990792Sgshapirodnl user lookups are always with trailing @
250090792Sgshapirodnl    2    3  4    5
250190792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
250290792Sgshapirodnl no match, try without tag
250390792Sgshapirodnl   1    2      3    4
250490792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
250590792Sgshapirodnl do not remove the @ from the lookup:
250690792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
250790792Sgshapirodnl no match, +detail: try +*
250890792Sgshapirodnl   1    2      3    4  5    6
250990792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
251090792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
251190792Sgshapirodnl no match, +detail: try +* without tag
251290792Sgshapirodnl   1    2      3      4    5
251390792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
251490792Sgshapiro			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
251590792Sgshapirodnl no match, +detail: try without +detail
251690792Sgshapirodnl   1    2      3    4  5    6
251790792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
251890792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
251990792Sgshapirodnl no match, +detail: try without +detail and without tag
252090792Sgshapirodnl   1    2      3      4    5
252190792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
252290792Sgshapiro			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
252390792Sgshapirodnl no match, return <default> <passthru>
252490792Sgshapirodnl   1    2    3  4    5
252590792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
252690792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
252790792Sgshapirodnl            2    3  4    5
252890792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
252990792Sgshapirodnl match, return <match> <passthru>
253090792Sgshapirodnl    2    3  4    5
253190792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
253290792Sgshapiro
253390792Sgshapiro######################################################################
253464562Sgshapiro###  SearchList: search a list of items in the access map
253564562Sgshapiro###	Parameters:
253664562Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
253764562Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
253864562Sgshapirodnl	avoid errorneous matches (with error messages?)
253964562Sgshapirodnl	if we can make sure that tag is always a single token
254064562Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
254190792Sgshapirodnl	to avoid errorneous matchs (first rule: D: if there
254264562Sgshapirodnl	is that mark somewhere in the list, it will be taken).
254364562Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
254464562Sgshapirodnl	the tag only, e.g.:
254564562Sgshapiro###	where "exact" is either "+" or "!":
254664562Sgshapiro###	<+ TAG>	lookup with and w/o tag
254764562Sgshapiro###	<! TAG>	lookup with tag
254864562Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
254964562Sgshapirodnl		a blank between them and the tag.
255064562Sgshapiro###	possible values for "mark" are:
255190792Sgshapiro###		D: recursive host lookup (LookUpDomain)
255264562Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
255364562Sgshapiro###		E: exact lookup, no modifications
255464562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
255564562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
255664562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
255764562Sgshapiro######################################################################
255838032Speter
255964562Sgshapiro# class with valid marks for SearchList
256064562Sgshapirodnl if A is activated: add it
2561132943SgshapiroC{Src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
256264562SgshapiroSSearchList
256390792Sgshapiro# just call the ruleset with the name of the tag... nice trick...
256490792Sgshapirodnl       2       3    4
2565132943SgshapiroR<$+> $| <$={Src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
256690792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <>
256790792Sgshapirodnl no match and nothing left: return
256890792SgshapiroR<$+> $| <> $| <?> <>		$@ <?>
256990792Sgshapirodnl no match but something left: continue
257090792SgshapiroR<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
257190792Sgshapirodnl match: return
257290792SgshapiroR<$+> $| <$*> $| <$+> <>	$@ <$3>
257364562Sgshapirodnl return result from recursive invocation
257490792SgshapiroR<$+> $| <$+>			$@ <$2>
257590792Sgshapirodnl endif _ACCESS_TABLE_
257690792Sgshapirodivert(0)
257738032Speter
257890792Sgshapiro######################################################################
257990792Sgshapiro###  trust_auth: is user trusted to authenticate as someone else?
258090792Sgshapiro###
258190792Sgshapiro###	Parameters:
258290792Sgshapiro###		$1: AUTH= parameter from MAIL command
258390792Sgshapiro######################################################################
258490792Sgshapiro
258590792Sgshapirodnl empty ruleset definition so it can be called
258690792SgshapiroSLocal_trust_auth
258764562SgshapiroStrust_auth
258864562SgshapiroR$*			$: $&{auth_type} $| $1
258964562Sgshapiro# required by RFC 2554 section 4.
259064562SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
259164562Sgshapirodnl seems to be useful...
259264562SgshapiroR$* $| $&{auth_authen}		$@ identical
259364562SgshapiroR$* $| <$&{auth_authen}>	$@ identical
259464562Sgshapirodnl call user supplied code
2595120256SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $2
259664562SgshapiroR$* $| $#$*		$#$2
259764562Sgshapirodnl default: error
259864562SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
259964562Sgshapiro
260090792Sgshapiro######################################################################
260190792Sgshapiro###  Relay_Auth: allow relaying based on authentication?
260290792Sgshapiro###
260390792Sgshapiro###	Parameters:
260490792Sgshapiro###		$1: ${auth_type}
260590792Sgshapiro######################################################################
260690792SgshapiroSLocal_Relay_Auth
260764562Sgshapiro
260890792Sgshapiro######################################################################
260990792Sgshapiro###  srv_features: which features to offer to a client?
261090792Sgshapiro###	(done in server)
261190792Sgshapiro######################################################################
261290792SgshapiroSsrv_features
261390792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl
261490792SgshapiroR$*			$: $1 $| $>"Local_srv_features" $1
261590792SgshapiroR$* $| $#$*		$#$2
261690792SgshapiroR$* $| $*		$: $1', `dnl')
2617132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
261890792SgshapiroR$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
261990792SgshapiroR<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
262090792SgshapiroR<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
262164562SgshapiroR<?>$*		$@ OK
262290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
262390792SgshapiroR<$* _ATMPF_>$*	$#temp', `dnl')
2624132943SgshapiroR<$+>$*		$# $1')
262564562Sgshapiro
262690792Sgshapiro######################################################################
262790792Sgshapiro###  try_tls: try to use STARTTLS?
262890792Sgshapiro###	(done in client)
262990792Sgshapiro######################################################################
263064562SgshapiroStry_tls
263190792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl
263290792SgshapiroR$*			$: $1 $| $>"Local_try_tls" $1
263390792SgshapiroR$* $| $#$*		$#$2
263490792SgshapiroR$* $| $*		$: $1', `dnl')
2635132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
263690792SgshapiroR$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
263790792SgshapiroR<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
263890792SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
263964562SgshapiroR<?>$*		$@ OK
264090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
264190792SgshapiroR<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2642132943SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"')
2643132943Sgshapiro
264490792Sgshapiro######################################################################
264590792Sgshapiro###  tls_rcpt: is connection with server "good" enough?
264690792Sgshapiro###	(done in client, per recipient)
264790792Sgshapirodnl called from deliver() before RCPT command
264890792Sgshapiro###
264990792Sgshapiro###	Parameters:
265090792Sgshapiro###		$1: recipient
265190792Sgshapiro######################################################################
265290792SgshapiroStls_rcpt
265390792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl
265490792SgshapiroR$*			$: $1 $| $>"Local_tls_rcpt" $1
265590792SgshapiroR$* $| $#$*		$#$2
265690792SgshapiroR$* $| $*		$: $1', `dnl')
2657132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
265890792Sgshapirodnl store name of other side
265990792SgshapiroR$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
266090792Sgshapirodnl canonify recipient address
266190792SgshapiroR$+			$: <?> $>CanonAddr $1
266290792Sgshapirodnl strip trailing dots
266390792SgshapiroR<?> $+ < @ $+ . >	<?> $1 <@ $2 >
266490792Sgshapirodnl full address?
266590792SgshapiroR<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
266690792Sgshapirodnl only localpart?
266790792SgshapiroR<?> $+			$: $1 $| <U:$1@> <E:>
266890792Sgshapirodnl look it up
266990792Sgshapirodnl also look up a default value via E:
267090792SgshapiroR$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
267190792Sgshapirodnl found nothing: stop here
267290792SgshapiroR$* $| <?>	$@ OK
267390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
267490792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
267590792Sgshapirodnl use the generic routine (for now)
267690792SgshapiroR$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
267764562Sgshapiro
267890792Sgshapiro######################################################################
267990792Sgshapiro###  tls_client: is connection with client "good" enough?
268090792Sgshapiro###	(done in server)
268190792Sgshapiro###
268290792Sgshapiro###	Parameters:
268390792Sgshapiro###		${verify} $| (MAIL|STARTTLS)
268490792Sgshapiro######################################################################
268564562Sgshapirodnl MAIL: called from check_mail
268664562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
268764562SgshapiroStls_client
268890792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl
268990792SgshapiroR$*			$: $1 $| $>"Local_tls_client" $1
269090792SgshapiroR$* $| $#$*		$#$2
269190792SgshapiroR$* $| $*		$: $1', `dnl')
269264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
269390792Sgshapirodnl store name of other side
269490792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
269564562Sgshapirodnl ignore second arg for now
269664562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
269764562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
269864562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
269990792SgshapiroR$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
270090792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
270164562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
270264562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
270390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
270490792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
270590792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
270690792SgshapiroR$* $| $*	$@ $>"TLS_connection" $1')
270764562Sgshapiro
270890792Sgshapiro######################################################################
270990792Sgshapiro###  tls_server: is connection with server "good" enough?
271090792Sgshapiro###	(done in client)
271190792Sgshapiro###
271290792Sgshapiro###	Parameter:
271390792Sgshapiro###		${verify}
271490792Sgshapiro######################################################################
271564562Sgshapirodnl i.e. has the server been authenticated and is encryption active?
271664562Sgshapirodnl called from deliver() after STARTTLS command
271764562SgshapiroStls_server
271890792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl
271990792SgshapiroR$*			$: $1 $| $>"Local_tls_server" $1
272090792SgshapiroR$* $| $#$*		$#$2
272190792SgshapiroR$* $| $*		$: $1', `dnl')
272264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
272390792Sgshapirodnl store name of other side
272490792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
272590792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
272690792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
272764562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
272864562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
272990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
273090792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
273190792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
273290792SgshapiroR$*		$@ $>"TLS_connection" $1')
273364562Sgshapiro
273490792Sgshapiro######################################################################
273590792Sgshapiro###  TLS_connection: is TLS connection "good" enough?
273690792Sgshapiro###
273790792Sgshapiro###	Parameters:
273864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
273990792Sgshapiro###		${verify} $| <Requirement> [<>]', `dnl
274090792Sgshapiro###		${verify}')
274190792Sgshapiro###		Requirement: RHS from access map, may be ? for none.
274290792Sgshapirodnl	syntax for Requirement:
274390792Sgshapirodnl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
274490792Sgshapirodnl	extensions: could be a list of further requirements
274590792Sgshapirodnl		for now: CN:string	{cn_subject} == string
274690792Sgshapiro######################################################################
274790792SgshapiroSTLS_connection
274890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
274990792Sgshapirodnl deal with TLS handshake failures: abort
275090792SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
275190792Sgshapirodivert(-1)')
275264562Sgshapirodnl common ruleset for tls_{client|server}
275390792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>]
275464562Sgshapirodnl remove optional <>
275564562SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
275690792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup>
275790792Sgshapiro# create the appropriate error codes
275864562Sgshapirodnl permanent or temporary error?
2759132943SgshapiroR$* $| <PERM + $={Tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
2760132943SgshapiroR$* $| <TEMP + $={Tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
276164562Sgshapirodnl default case depends on TLS_PERM_ERR
2762132943SgshapiroR$* $| <$={Tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
276390792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
276490792Sgshapiro# deal with TLS handshake failures: abort
276564562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
276664562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
276764562Sgshapirodnl use default error
276864562SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
2769157001Sgshapiro# deal with TLS protocol errors: abort
2770157001SgshapiroRPROTOCOL $| <$-:$+> $* 	$#error $@ $2 $: $1 " STARTTLS failed."
2771157001Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
2772157001Sgshapirodnl use default error
2773157001SgshapiroRPROTOCOL $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') STARTTLS failed."
277490792SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
277590792Sgshapirodnl separate optional requirements
277690792SgshapiroR$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
2777132943SgshapiroR$* $| <$*> <$={Tls}:$->$*	$: <$2> <$3:$4> <> $1
277890792Sgshapirodnl separate optional requirements
2779132943SgshapiroR$* $| <$*> <$={Tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
278064562Sgshapirodnl some other value in access map: accept
278164562Sgshapirodnl this also allows to override the default case (if used)
278264562SgshapiroR$* $| $*			$@ OK
278364562Sgshapiro# authentication required: give appropriate error
278464562Sgshapiro# other side did authenticate (via STARTTLS)
278590792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
278664562Sgshapirodnl only verification required and it succeeded
278790792SgshapiroR<$*><VERIFY> <> OK		$@ OK
278890792Sgshapirodnl verification required and it succeeded but extensions are given
278990792Sgshapirodnl change it to <SMTP:ESC> <REQ:0>  <extensions>
279090792SgshapiroR<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
279164562Sgshapirodnl verification required + some level of encryption
279290792SgshapiroR<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
279364562Sgshapirodnl just some level of encryption required
279490792SgshapiroR<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
279590792Sgshapirodnl workspace:
279690792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
279790792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
279890792Sgshapirodnl verification required but ${verify} is not set (case 1.)
279990792SgshapiroR<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
280090792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
280190792SgshapiroR<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
280290792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
280390792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
280464562Sgshapirodnl some other value for ${verify}
280590792SgshapiroR<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
280690792Sgshapirodnl some level of encryption required: get the maximum level (case 2.)
280790792SgshapiroR<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
280864562Sgshapirodnl compare required bits with actual bits
280990792SgshapiroR<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
281090792SgshapiroR<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
281190792Sgshapirodnl strength requirements fulfilled
281290792Sgshapirodnl TLS Additional Requirements Separator
281390792Sgshapirodnl this should be something which does not appear in the extensions itself
281490792Sgshapirodnl @ could be part of a CN, DN, etc...
281590792Sgshapirodnl use < > ? those are encoded in CN, DN, ...
281690792Sgshapirodefine(`_TLS_ARS_', `++')dnl
281790792Sgshapirodnl workspace:
281890792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
281990792SgshapiroR<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
282090792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
282190792Sgshapirodnl continue: check  extensions
282290792SgshapiroR<$-:$+ _TLS_ARS_ >			$@ OK
282390792Sgshapirodnl split extensions into own list
282490792SgshapiroR<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
282590792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
282690792SgshapiroR<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
282764562Sgshapiro
282890792Sgshapiro######################################################################
282990792Sgshapiro###  TLS_req: check additional TLS requirements
283090792Sgshapiro###
283190792Sgshapiro###	Parameters: [<list> <of> <req>] $| <$-:$+>
283290792Sgshapiro###		$-: SMTP reply code
283390792Sgshapiro###		$+: Enhanced Status Code
283490792Sgshapirodnl  further requirements for this ruleset:
283590792Sgshapirodnl	name of "other side" is stored is {TLS_name} (client/server_name)
283690792Sgshapirodnl
283790792Sgshapirodnl	currently only CN[:common_name] is implemented
283890792Sgshapirodnl	right now this is only a logical AND
283990792Sgshapirodnl	i.e. all requirements must be true
284090792Sgshapirodnl	how about an OR? CN must be X or CN must be Y or ..
284190792Sgshapirodnl	use a macro to compute this as a trivial sequential
284290792Sgshapirodnl	operations (no precedences etc)?
284390792Sgshapiro######################################################################
284490792SgshapiroSTLS_req
284590792Sgshapirodnl no additional requirements: ok
284690792SgshapiroR $| $+		$@ OK
284790792Sgshapirodnl require CN: but no CN specified: use name of other side
284890792SgshapiroR<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
284990792Sgshapirodnl match, check rest
285090792SgshapiroR<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
285190792Sgshapirodnl CN does not match
285290792Sgshapirodnl  1   2      3  4
285390792SgshapiroR<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
285490792Sgshapirodnl cert subject
285590792SgshapiroR<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
285690792Sgshapirodnl CS does not match
285790792Sgshapirodnl  1   2      3  4
2858110560SgshapiroR<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1
285990792Sgshapirodnl match, check rest
286090792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
286190792Sgshapirodnl CI does not match
286290792Sgshapirodnl  1   2      3  4
2863110560SgshapiroR<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1
286490792Sgshapirodnl return from recursive call
286590792SgshapiroROK			$@ OK
286690792Sgshapiro
286790792Sgshapiro######################################################################
286890792Sgshapiro###  max: return the maximum of two values separated by :
286990792Sgshapiro###
287090792Sgshapiro###	Parameters: [$-]:[$-]
287190792Sgshapiro######################################################################
287264562SgshapiroSmax
287364562SgshapiroR:		$: 0
287464562SgshapiroR:$-		$: $1
287564562SgshapiroR$-:		$: $1
287664562SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
287764562SgshapiroRTRUE:$-:$-	$: $2
287890792SgshapiroR$-:$-:$-	$: $2
287990792Sgshapirodnl endif _ACCESS_TABLE_
288090792Sgshapirodivert(0)
288164562Sgshapiro
288290792Sgshapiro######################################################################
288390792Sgshapiro###  RelayTLS: allow relaying based on TLS authentication
288490792Sgshapiro###
288590792Sgshapiro###	Parameters:
288690792Sgshapiro###		none
288790792Sgshapiro######################################################################
288890792SgshapiroSRelayTLS
288964562Sgshapiro# authenticated?
289064562Sgshapirodnl we do not allow relaying for anyone who can present a cert
289164562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
2892110560Sgshapirodnl CA in CertPath so we can authenticate users, we do not allow
289364562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
289464562Sgshapirodnl but anyway).
289564562Sgshapirodnl so here is the trick: if the verification succeeded
289664562Sgshapirodnl we look up the cert issuer in the access map
289764562Sgshapirodnl (maybe after extracting a part with a regular expression)
289864562Sgshapirodnl if this returns RELAY we relay without further questions
289964562Sgshapirodnl if it returns SUBJECT we perform a similar check on the
290064562Sgshapirodnl cert subject.
290164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
290290792SgshapiroR$*			$: <?> $&{verify}
290390792SgshapiroR<?> OK			$: OK		authenticated: continue
290490792SgshapiroR<?> $*			$@ NO		not authenticated
290564562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
290690792SgshapiroR$*			$: $(CERTIssuer $&{cert_issuer} $)',
290790792Sgshapiro`R$*			$: $&{cert_issuer}')
290890792SgshapiroR$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
290964562Sgshapirodnl use $# to stop further checks (delay_check)
291090792SgshapiroRRELAY			$# RELAY
291164562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
291290792SgshapiroRSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
291390792Sgshapiro`RSUBJECT		$: <@> $&{cert_subject}')
291490792SgshapiroR<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
291590792SgshapiroR<@> RELAY		$# RELAY
291690792SgshapiroR$*			$: NO', `dnl')
291764562Sgshapiro
291890792Sgshapiro######################################################################
291990792Sgshapiro###  authinfo: lookup authinfo in the access map
292090792Sgshapiro###
292190792Sgshapiro###	Parameters:
292290792Sgshapiro###		$1: {server_name}
292390792Sgshapiro###		$2: {server_addr}
292490792Sgshapirodnl	both are currently ignored
292590792Sgshapirodnl if it should be done via another map, we either need to restrict
292690792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another
292790792Sgshapirodnl parameter which I want to avoid, it's quite complex already)
292890792Sgshapiro######################################################################
292990792Sgshapirodnl omit this ruleset if neither is defined?
293090792Sgshapirodnl it causes DefaultAuthInfo to be ignored
293190792Sgshapirodnl (which may be considered a good thing).
293290792SgshapiroSauthinfo
293390792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl
293490792SgshapiroR$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
293590792SgshapiroR<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
293690792SgshapiroR<?>		$: <$(authinfo AuthInfo: $: ? $)>
293790792SgshapiroR<?>		$@ no				no authinfo available
293890792SgshapiroR<$*>		$# $1
293990792Sgshapirodnl', `dnl
294090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
294190792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
294290792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
294390792SgshapiroR$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
294490792SgshapiroR$* $| <?>$*	$@ no				no authinfo available
294590792SgshapiroR$* $| <$*> <>	$# $2
294690792Sgshapirodnl', `dnl')')
294790792Sgshapiro
2948132943Sgshapiroifdef(`_RATE_CONTROL_',`dnl
2949132943Sgshapiro######################################################################
2950132943Sgshapiro###  RateControl: 
2951132943Sgshapiro###	Parameters:	ignored
2952132943Sgshapiro###	return: $#error or OK
2953132943Sgshapiro######################################################################
2954132943SgshapiroSRateControl
2955132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2956132943SgshapiroR$*		$: <A:$&{client_addr}> <E:>
2957132943Sgshapirodnl also look up a default value via E:
2958132943SgshapiroR$+		$: $>SearchList <! ClientRate> $| $1 <>
2959132943Sgshapirodnl found nothing: stop here
2960132943SgshapiroR<?>		$@ OK
2961132943Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
2962132943SgshapiroR<$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2963132943Sgshapirodnl use the generic routine (for now)
2964132943SgshapiroR<0>		$@ OK		no limit
2965132943SgshapiroR<$+>		$: <$1> $| $(arith l $@ $&{client_rate} $@ $1 $)
2966132943Sgshapirodnl log this? Connection rate $&{client_rate} exceeds limit $1.
2967132943SgshapiroR<$+> $| FALSE	$#error $@ 4.3.2 $: _RATE_CONTROL_REPLY Connection rate limit exceeded.
2968132943Sgshapiro')')
2969132943Sgshapiro
2970132943Sgshapiroifdef(`_CONN_CONTROL_',`dnl
2971132943Sgshapiro######################################################################
2972132943Sgshapiro###  ConnControl: 
2973132943Sgshapiro###	Parameters:	ignored
2974132943Sgshapiro###	return: $#error or OK
2975132943Sgshapiro######################################################################
2976132943SgshapiroSConnControl
2977132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2978132943SgshapiroR$*		$: <A:$&{client_addr}> <E:>
2979132943Sgshapirodnl also look up a default value via E:
2980132943SgshapiroR$+		$: $>SearchList <! ClientConn> $| $1 <>
2981132943Sgshapirodnl found nothing: stop here
2982132943SgshapiroR<?>		$@ OK
2983132943Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
2984132943SgshapiroR<$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2985132943Sgshapirodnl use the generic routine (for now)
2986132943SgshapiroR<0>		$@ OK		no limit
2987132943SgshapiroR<$+>		$: <$1> $| $(arith l $@ $&{client_connections} $@ $1 $)
2988132943Sgshapirodnl log this: Open connections $&{client_connections} exceeds limit $1.
2989132943SgshapiroR<$+> $| FALSE	$#error $@ 4.3.2 $: _CONN_CONTROL_REPLY Too many open connections.
2990132943Sgshapiro')')
2991132943Sgshapiro
299264562Sgshapiroundivert(9)dnl LOCAL_RULESETS
299338032Speter#
299438032Speter######################################################################
299538032Speter######################################################################
299638032Speter#####
299764562Sgshapiro`#####			MAIL FILTER DEFINITIONS'
299864562Sgshapiro#####
299964562Sgshapiro######################################################################
300064562Sgshapiro######################################################################
300190792Sgshapiro_MAIL_FILTERS_
300264562Sgshapiro#
300364562Sgshapiro######################################################################
300464562Sgshapiro######################################################################
300564562Sgshapiro#####
300638032Speter`#####			MAILER DEFINITIONS'
300738032Speter#####
300838032Speter######################################################################
300938032Speter######################################################################
301064562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
301166494Sgshapiro
3012