proto.m4 revision 120256
138032Speterdivert(-1)
238032Speter#
3120256Sgshapiro# Copyright (c) 1998-2003 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
16120256SgshapiroVERSIONID(`$Id: proto.m4,v 8.649.2.24 2003/08/04 21:14:26 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
11438032SpeterCP.
11538032Speter
11638032Speterifdef(`UUCP_RELAY',
11738032Speter`# UUCP relay host
11838032SpeterDY`'UUCP_RELAY
11938032SpeterCPUUCP
12038032Speter
12138032Speter')dnl
12238032Speterifdef(`BITNET_RELAY',
12338032Speter`#  BITNET relay host
12438032SpeterDB`'BITNET_RELAY
12538032SpeterCPBITNET
12638032Speter
12738032Speter')dnl
12838032Speterifdef(`DECNET_RELAY',
12938032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl
13038032Speter# DECnet relay host
13138032SpeterDC`'DECNET_RELAY
13238032SpeterCPDECNET
13338032Speter
13438032Speter')dnl
13538032Speterifdef(`FAX_RELAY',
13638032Speter`# FAX relay host
13738032SpeterDF`'FAX_RELAY
13838032SpeterCPFAX
13938032Speter
14038032Speter')dnl
14138032Speter# "Smart" relay host (may be null)
14290792SgshapiroDS`'ifdef(`SMART_HOST', `SMART_HOST')
14338032Speter
14438032Speterifdef(`LUSER_RELAY', `dnl
14538032Speter# place to which unknown users should be forwarded
14638032SpeterKuser user -m -a<>
14738032SpeterDL`'LUSER_RELAY',
14838032Speter`dnl')
14938032Speter
15038032Speter# operators that cannot be in local usernames (i.e., network indicators)
15138032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!')
15238032Speter
15338032Speter# a class with just dot (for identifying canonical names)
15438032SpeterC..
15538032Speter
15638032Speter# a class with just a left bracket (for identifying domain literals)
15738032SpeterC[[
15838032Speter
15964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
16064562Sgshapiro# access_db acceptance class
16164562SgshapiroC{Accept}OK RELAY
16290792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
16364562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl
16464562Sgshapiro# possible access_db RHS for spam friends/haters
16564562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')',
16638032Speter`dnl')
16738032Speter
16890792Sgshapirodnl mark for "domain is ok" (resolved or accepted anyway)
16990792Sgshapirodefine(`_RES_OK_', `OKR')dnl
17038032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
17138032Speter# Resolve map (to check if a host exists in check_mail)
17290792SgshapiroKresolve host -a<_RES_OK_> -T<TEMP>')
17390792SgshapiroC{ResOk}_RES_OK_
17438032Speter
17580785Sgshapiroifdef(`_NEED_MACRO_MAP_', `dnl
17680785Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map
17780785Sgshapirodefine(`_MACRO_MAP_', `1')dnl
17880785SgshapiroKmacro macro')', `dnl')
17966494Sgshapiro
18038032Speterifdef(`confCR_FILE', `dnl
18166494Sgshapiro# Hosts for which relaying is permitted ($=R)
18238032SpeterFR`'confCR_FILE',
18338032Speter`dnl')
18438032Speter
18590792Sgshapirodefine(`TLS_SRV_TAG', `"TLS_Srv"')dnl
18690792Sgshapirodefine(`TLS_CLT_TAG', `"TLS_Clt"')dnl
18790792Sgshapirodefine(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl
18890792Sgshapirodefine(`TLS_TRY_TAG', `"Try_TLS"')dnl
18990792Sgshapirodefine(`SRV_FEAT_TAG', `"Srv_Features"')dnl
19064562Sgshapirodnl this may be useful in other contexts too
19164562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map
19264562Sgshapirodefine(`_ARITH_MAP_', `1')dnl
19364562SgshapiroKarith arith')
19464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
19590792Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map
19690792Sgshapirodefine(`_MACRO_MAP_', `1')dnl
19790792SgshapiroKmacro macro')
19890792Sgshapiro# possible values for TLS_connection in access map
19964562SgshapiroC{tls}VERIFY ENCR', `dnl')
20064562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
20164562Sgshapiro# extract relevant part from cert issuer
20264562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
20364562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
20464562Sgshapiro# extract relevant part from cert subject
20564562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
20664562Sgshapiro
20790792Sgshapiroifdef(`LOCAL_RELAY', `dnl
208110647Sgshapiro# who I send unqualified names to if `FEATURE(stickyhost)' is used
209110560Sgshapiro# (null means deliver locally)
21090792SgshapiroDR`'LOCAL_RELAY')
21138032Speter
21290792Sgshapiroifdef(`MAIL_HUB', `dnl
213110560Sgshapiro# who gets all local email traffic
214110647Sgshapiro# ($R has precedence for unqualified names if `FEATURE(stickyhost)' is used)
21590792SgshapiroDH`'MAIL_HUB')
21638032Speter
21738032Speter# dequoting map
21890792SgshapiroKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `')
21938032Speter
22038032Speterdivert(0)dnl	# end of nullclient diversion
22138032Speter# class E: names that should be exposed as from this host, even if we masquerade
22264562Sgshapiro# class L: names that should be delivered locally, even if we have a relay
22338032Speter# class M: domains that should be converted to $M
22464562Sgshapiro# class N: domains that should not be converted to $M
22538032Speter#CL root
22638032Speterundivert(5)dnl
22764562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
22838032Speter
22990792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
23038032Speter# who I masquerade as (null for no masquerading) (see also $=M)
23190792SgshapiroDM`'MASQUERADE_NAME')
23238032Speter
23338032Speter# my name for error messages
23438032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
23538032Speter
23664562Sgshapiroundivert(6)dnl LOCAL_CONFIG
23738032Speterinclude(_CF_DIR_`m4/version.m4')
23838032Speter
23938032Speter###############
24038032Speter#   Options   #
24138032Speter###############
24290792Sgshapiroifdef(`confAUTO_REBUILD',
24390792Sgshapiro`errprint(WARNING: `confAUTO_REBUILD' is no longer valid.
24490792Sgshapiro	There was a potential for a denial of service attack if this is set.
24590792Sgshapiro)')dnl
24638032Speter
24738032Speter# strip message body to 7 bits on input?
24864562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
24938032Speter
25038032Speter# 8-bit data handling
25177349Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8')
25238032Speter
25338032Speter# wait for alias file rebuild (default units: minutes)
25464562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m')
25538032Speter
25638032Speter# location of alias file
25764562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
25864562Sgshapiro
25938032Speter# minimum number of free blocks on filesystem
26064562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
26138032Speter
26238032Speter# maximum message size
26364562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000')
26438032Speter
26538032Speter# substitution for space (blank) characters
26664562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_')
26738032Speter
26838032Speter# avoid connecting to "expensive" mailers on initial submission?
26964562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
27038032Speter
27138032Speter# checkpoint queue runs after every N successful deliveries
27264562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
27338032Speter
27438032Speter# default delivery mode
27564562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
27638032Speter
27738032Speter# error message header/file
27864562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
27938032Speter
28038032Speter# error mode
28164562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print')
28238032Speter
28338032Speter# save Unix-style "From_" lines at top of header?
28464562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
28538032Speter
28690792Sgshapiro# queue file mode (qf files)
28790792Sgshapiro_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600')
28890792Sgshapiro
28938032Speter# temporary file mode
29064562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
29138032Speter
29238032Speter# match recipients against GECOS field?
29364562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
29438032Speter
29538032Speter# maximum hop count
29690792Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `25')
29738032Speter
29838032Speter# location of help file
29964562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
30038032Speter
30138032Speter# ignore dots as terminators in incoming messages?
30264562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
30338032Speter
30438032Speter# name resolver options
30564562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
30638032Speter
30738032Speter# deliver MIME-encapsulated error messages?
30864562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
30938032Speter
31038032Speter# Forward file search path
31164562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
31238032Speter
31338032Speter# open connection cache size
31464562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
31538032Speter
31638032Speter# open connection cache timeout
31764562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
31838032Speter
31938032Speter# persistent host status directory
32064562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
32138032Speter
32238032Speter# single thread deliveries (requires HostStatusDirectory)?
32364562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
32438032Speter
32538032Speter# use Errors-To: header?
32664562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
32738032Speter
32838032Speter# log level
32964562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10')
33038032Speter
33138032Speter# send to me too, even in an alias expansion?
33264562Sgshapiro_OPTION(MeToo, `confME_TOO', `True')
33338032Speter
33438032Speter# verify RHS in newaliases?
33564562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
33638032Speter
33738032Speter# default messages to old style headers if no special punctuation?
33864562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
33938032Speter
34038032Speter# SMTP daemon options
34164562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
34294334Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.
34394334Sgshapiro	Use `DAEMON_OPTIONS()'; see cf/README.
34464562Sgshapiro)'dnl
34564562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
34666494Sgshapiroifelse(defn(`_DPO_'), `',
34790792Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet
34890792SgshapiroO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
34964562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
35038032Speter
35164562Sgshapiro# SMTP client options
35290792Sgshapiroifelse(defn(`confCLIENT_OPTIONS'), `', `dnl',
35390792Sgshapiro`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid.  See cf/README for more information.
35490792Sgshapiro)'dnl
35590792Sgshapiro`CLIENT_OPTIONS(`confCLIENT_OPTIONS')')
35690792Sgshapiroifelse(defn(`_CPO_'), `',
35790792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_')
35864562Sgshapiro
35990792Sgshapiro# Modifiers to `define' {daemon_flags} for direct submissions
36090792Sgshapiro_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `')
36190792Sgshapiro
36290792Sgshapiro# Use as mail submission program? See sendmail/SECURITY
36390792Sgshapiro_OPTION(UseMSP, `confUSE_MSP', `')
36490792Sgshapiro
36538032Speter# privacy flags
36664562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
36738032Speter
36838032Speter# who (if anyone) should get extra copies of error messages
36964562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
37038032Speter
37138032Speter# slope of queue-only function
37264562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
37338032Speter
37490792Sgshapiro# limit on number of concurrent queue runners
37590792Sgshapiro_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `')
37690792Sgshapiro
37790792Sgshapiro# maximum number of queue-runners per queue-grouping with multiple queues
37890792Sgshapiro_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1')
37990792Sgshapiro
38090792Sgshapiro# priority of queue runners (nice(3))
38190792Sgshapiro_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `')
38290792Sgshapiro
38390792Sgshapiro# shall we sort the queue by hostname first?
38490792Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
38590792Sgshapiro
38690792Sgshapiro# minimum time in queue before retry
38790792Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
38890792Sgshapiro
38990792Sgshapiro# how many jobs can you process in the queue?
39090792Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
39190792Sgshapiro
39290792Sgshapiro# perform initial split of envelope without checking MX records
39390792Sgshapiro_OPTION(FastSplit, `confFAST_SPLIT', `1')
39490792Sgshapiro
39538032Speter# queue directory
39664562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
39738032Speter
39890792Sgshapiro# key for shared memory; 0 to turn off
39990792Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
40090792Sgshapiro
40194334Sgshapiroifdef(`confSHARED_MEMORY_KEY_FILE', `dnl
40294334Sgshapiro# file to store key for shared memory (if SharedMemoryKey = -1)
40394334SgshapiroO 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')
427112810Sgshapiroifdef(`confTO_QUEUERETURN_DSN', `dnl
428112810SgshapiroO Timeout.queuereturn.dsn=confTO_QUEUERETURN_DSN')
42964562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
43064562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
43164562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
43264562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
433112810Sgshapiroifdef(`confTO_QUEUEWARN_DSN', `dnl
434112810SgshapiroO Timeout.queuewarn.dsn=confTO_QUEUEWARN_DSN')
43564562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
43664562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
43764562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
43864562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
43964562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
44064562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
44164562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
44290792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
44390792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m')
44490792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
44538032Speter
44690792Sgshapiro# time for DeliverBy; extension disabled if less than 0
44790792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
44890792Sgshapiro
44938032Speter# should we not prune routes in route-addr syntax addresses?
45064562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
45138032Speter
45238032Speter# queue up everything before forking?
45364562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
45438032Speter
45538032Speter# status file
45664562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
45738032Speter
45838032Speter# time zone handling:
45938032Speter#  if undefined, use system default
46038032Speter#  if defined but null, use TZ envariable passed in
46138032Speter#  if defined and non-null, use that info
46238032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
46338032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
46438032Speter	`O TimeZoneSpec=confTIME_ZONE')
46538032Speter
46638032Speter# default UID (can be username or userid:groupid)
46764562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
46838032Speter
46938032Speter# list of locations of user database file (null means no lookup)
47064562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
47138032Speter
47238032Speter# fallback MX host
47364562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
47438032Speter
47538032Speter# if we are the best MX host for a site, try it directly instead of config err
47664562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
47738032Speter
47838032Speter# load average at which we just queue messages
47964562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8')
48038032Speter
48138032Speter# load average at which we refuse connections
48264562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
48338032Speter
48490792Sgshapiro# load average at which we delay connections; 0 means no limit
48590792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0')
48690792Sgshapiro
48738032Speter# maximum number of children we allow at one time
48898841Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0')
48938032Speter
49038032Speter# maximum number of new connections per second
49171345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
49238032Speter
49338032Speter# work recipient factor
49464562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
49538032Speter
49638032Speter# deliver each queued job in a separate process?
49764562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
49838032Speter
49938032Speter# work class factor
50064562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
50138032Speter
50238032Speter# work time factor
50364562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
50438032Speter
50538032Speter# default character set
50664562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
50738032Speter
50890792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
50964562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
51038032Speter
51138032Speter# hosts file (normally /etc/hosts)
51264562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
51338032Speter
51438032Speter# dialup line delay on connection failure
51564562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s')
51638032Speter
51738032Speter# action to take if there are no recipients in the message
51864562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed')
51938032Speter
52038032Speter# chrooted environment for writing to files
52164562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
52238032Speter
52338032Speter# are colons OK in addresses?
52464562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
52538032Speter
52638032Speter# shall I avoid expanding CNAMEs (violates protocols)?
52764562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
52838032Speter
52938032Speter# SMTP initial login message (old $e macro)
53064562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
53138032Speter
53238032Speter# UNIX initial From header format (old $l macro)
53364562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
53438032Speter
53538032Speter# From: lines that have embedded newlines are unwrapped onto one line
53664562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
53738032Speter
53838032Speter# Allow HELO SMTP command that does not `include' a host name
53964562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
54038032Speter
54138032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
54264562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
54338032Speter
54438032Speter# delimiter (operator) characters (old $o macro)
54564562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
54638032Speter
54738032Speter# shall I avoid calling initgroups(3) because of high NIS costs?
54864562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
54938032Speter
55038032Speter# are group-writable `:include:' and .forward files (un)trustworthy?
55190792Sgshapiro# True (the default) means they are not trustworthy.
55264562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
55390792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES',
55490792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
55590792Sgshapiro')')
55638032Speter
55738032Speter# where do errors that occur when sending errors get sent?
55864562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
55938032Speter
56064562Sgshapiro# where to save bounces if all else fails
56164562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
56264562Sgshapiro
56338032Speter# what user id do we assume for the majority of the processing?
56464562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
56538032Speter
56638032Speter# maximum number of recipients per SMTP envelope
56764562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
56838032Speter
56990792Sgshapiro# limit the rate recipients per SMTP envelope are accepted
57090792Sgshapiro# once the threshold number of recipients have been rejected
57190792Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20')
57290792Sgshapiro
57338032Speter# shall we get local names from our installed interfaces?
57464562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
57538032Speter
57664562Sgshapiro# Return-Receipt-To: header implies DSN request
57764562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
57864562Sgshapiro
57964562Sgshapiro# override connection address (for testing)
58064562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
58164562Sgshapiro
58264562Sgshapiro# Trusted user for file ownership and starting the daemon
58364562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
58464562Sgshapiro
58564562Sgshapiro# Control socket for daemon management
58664562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
58764562Sgshapiro
58864562Sgshapiro# Maximum MIME header length to protect MUAs
589112810Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `2048/1024')
59064562Sgshapiro
59164562Sgshapiro# Maximum length of the sum of all headers
59264562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
59364562Sgshapiro
59464562Sgshapiro# Maximum depth of alias recursion
59564562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
59664562Sgshapiro
59764562Sgshapiro# location of pid file
59864562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
59964562Sgshapiro
60064562Sgshapiro# Prefix string for the process title shown on 'ps' listings
60164562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
60264562Sgshapiro
60364562Sgshapiro# Data file (df) memory-buffer file maximum size
60464562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
60564562Sgshapiro
60664562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
60764562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
60864562Sgshapiro
60990792Sgshapiro# lookup type to find information about local mailboxes
61090792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
61190792Sgshapiro
61264562Sgshapiro# list of authentication mechanisms
61390792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
61464562Sgshapiro
61564562Sgshapiro# default authentication information for outgoing connections
61664562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
61764562Sgshapiro
61864562Sgshapiro# SMTP AUTH flags
61964562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
62064562Sgshapiro
62190792Sgshapiro# SMTP AUTH maximum encryption strength
62290792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
62390792Sgshapiro
62490792Sgshapiro# SMTP STARTTLS server options
62590792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
62690792Sgshapiro
62764562Sgshapiro# Input mail filters
62864562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
62964562Sgshapiro
63098841Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl
63164562Sgshapiro# Milter options
63290792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
63364562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
63464562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
63564562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
63664562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')')
63764562Sgshapiro
63864562Sgshapiro# CA directory
639110560Sgshapiro_OPTION(CACertPath, `confCACERT_PATH', `')
64064562Sgshapiro# CA file
641110560Sgshapiro_OPTION(CACertFile, `confCACERT', `')
64264562Sgshapiro# Server Cert
64364562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
64464562Sgshapiro# Server private key
64564562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
64664562Sgshapiro# Client Cert
64764562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
64864562Sgshapiro# Client private key
64964562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
65064562Sgshapiro# DHParameters (only required if DSA/DH is used)
65164562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
65264562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
65364562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
65464562Sgshapiro
65590792Sgshapiro############################
65690792Sgshapiro`# QUEUE GROUP DEFINITIONS  #'
65790792Sgshapiro############################
65890792Sgshapiro_QUEUE_GROUP_
65942575Speter
66038032Speter###########################
66138032Speter#   Message precedences   #
66238032Speter###########################
66338032Speter
66438032SpeterPfirst-class=0
66538032SpeterPspecial-delivery=100
66638032SpeterPlist=-30
66738032SpeterPbulk=-60
66838032SpeterPjunk=-100
66938032Speter
67038032Speter#####################
67138032Speter#   Trusted users   #
67238032Speter#####################
67338032Speter
67438032Speter# this is equivalent to setting class "t"
67564562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
67638032SpeterTroot
67738032SpeterTdaemon
67838032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp')
67938032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
68038032Speter
68138032Speter#########################
68238032Speter#   Format of headers   #
68338032Speter#########################
68438032Speter
68538032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
68638032SpeterH?P?Return-Path: <$g>
68738032SpeterHReceived: confRECEIVED_HEADER
68838032SpeterH?D?Resent-Date: $a
68938032SpeterH?D?Date: $a
69038032SpeterH?F?Resent-From: confFROM_HEADER
69138032SpeterH?F?From: confFROM_HEADER
69238032SpeterH?x?Full-Name: $x
69338032Speter# HPosted-Date: $a
69438032Speter# H?l?Received-Date: $b
69538032SpeterH?M?Resent-Message-Id: <$t.$i@$j>
69638032SpeterH?M?Message-Id: <$t.$i@$j>
69764562Sgshapiro
69838032Speter#
69938032Speter######################################################################
70038032Speter######################################################################
70138032Speter#####
70238032Speter#####			REWRITING RULES
70338032Speter#####
70438032Speter######################################################################
70538032Speter######################################################################
70638032Speter
70738032Speter############################################
70838032Speter###  Ruleset 3 -- Name Canonicalization  ###
70938032Speter############################################
71064562SgshapiroScanonify=3
71138032Speter
71238032Speter# handle null input (translate to <@> special case)
71338032SpeterR$@			$@ <@>
71438032Speter
71538032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
71638032SpeterR$*			$: $1 <@>			mark addresses
71738032SpeterR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
71838032SpeterR@ $* <@>		$: @ $1				unmark @host:...
71990792SgshapiroR$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
72038032SpeterR$* :: $* <@>		$: $1 :: $2			unmark node::addr
72138032SpeterR:`include': $* <@>	$: :`include': $1			unmark :`include':...
72238032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
72338032SpeterR$* : $* <@>		$: $2				strip colon if marked
72438032SpeterR$* <@>			$: $1				unmark
72538032SpeterR$* ;			   $1				strip trailing semi
72671345SgshapiroR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
72738032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
72838032Speter
72938032Speter# null input now results from list:; syntax
73038032SpeterR$@			$@ :; <@>
73138032Speter
73238032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
73338032SpeterR$*			$: < $1 >			housekeeping <>
73438032SpeterR$+ < $* >		   < $2 >			strip excess on left
73538032SpeterR< $* > $+		   < $1 >			strip excess on right
73638032SpeterR<>			$@ < @ >			MAIL FROM:<> case
73738032SpeterR< $+ >			$: $1				remove housekeeping <>
73838032Speter
73964562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
74038032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
74138032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
74238032Speter
74338032Speter# localize and dispose of route-based addresses
74490792Sgshapirodnl XXX: IPv6 colon conflict
74590792Sgshapiroifdef(`NO_NETINET6', `dnl',
74690792Sgshapiro`R@ [$+] : $+		$@ $>Canonify2 < @ [$1] > : $2	handle <route-addr>')
74764562SgshapiroR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
74864562Sgshapirodnl',`dnl
74964562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d>
75064562SgshapiroR@ $+ , $+		$2
75190792Sgshapiroifdef(`NO_NETINET6', `dnl',
75290792Sgshapiro`R@ [ $* ] : $+		$2')
75364562SgshapiroR@ $+ : $+		$2
75464562Sgshapirodnl')
75538032Speter
75638032Speter# find focus for list syntax
75764562SgshapiroR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
75838032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
75938032Speter
76038032Speter# find focus for @ syntax addresses
76138032SpeterR$+ @ $+		$: $1 < @ $2 >			focus on domain
76238032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
76364562SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
76438032Speter
76590792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here.
76690792Sgshapirodnl # do some sanity checking
76790792Sgshapirodnl R$* < @ $~[ $* : $* > $*	$1 < @ $2 $3 > $4	nix colons in addrs
76838032Speter
76938032Speterifdef(`_NO_UUCP_', `dnl',
77038032Speter`# convert old-style addresses to a domain-based address
77164562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
77264562SgshapiroR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
77364562SgshapiroR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
77438032Speter')
77538032Speterifdef(`_USE_DECNET_SYNTAX_',
77638032Speter`# convert node::user addresses into a domain-based address
77764562SgshapiroR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
77864562SgshapiroR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
77938032Speter',
78038032Speter	`dnl')
78138032Speter# if we have % signs, take the rightmost one
78238032SpeterR$* % $*		$1 @ $2				First make them all @s.
78338032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
78464562SgshapiroR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
78538032Speter
78638032Speter# else we must be a local name
78764562SgshapiroR$*			$@ $>Canonify2 $1
78838032Speter
78938032Speter
79038032Speter################################################
79138032Speter###  Ruleset 96 -- bottom half of ruleset 3  ###
79238032Speter################################################
79338032Speter
79464562SgshapiroSCanonify2=96
79538032Speter
79638032Speter# handle special cases for local names
79738032SpeterR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
79838032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
79938032Speterifdef(`_NO_UUCP_', `dnl',
80038032Speter`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
80164562Sgshapiro
80290792Sgshapiro# check for IPv4/IPv6 domain literal
80390792SgshapiroR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [addr]
80438032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
80538032SpeterR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
80638032Speter
80764562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl
80838032Speter# look up domains in the domain table
80938032SpeterR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
81038032Speter
81164562Sgshapiroundivert(2)dnl LOCAL_RULE_3
81238032Speter
81364562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl
81438032Speter# handle BITNET mapping
81538032SpeterR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
81638032Speter
81764562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl
81838032Speter# handle UUCP mapping
81938032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
82038032Speter
82138032Speterifdef(`_NO_UUCP_', `dnl',
82238032Speter`ifdef(`UUCP_RELAY',
82338032Speter`# pass UUCP addresses straight through
82438032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
82538032Speter`# if really UUCP, handle it immediately
82638032Speterifdef(`_CLASS_U_',
82738032Speter`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82838032Speterifdef(`_CLASS_V_',
82938032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83038032Speterifdef(`_CLASS_W_',
83138032Speter`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83238032Speterifdef(`_CLASS_X_',
83338032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83438032Speterifdef(`_CLASS_Y_',
83538032Speter`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83638032Speter
83738032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl
83838032Speter# try UUCP traffic as a local address
83938032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
84038032SpeterR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
84138032Speter')')
84264562Sgshapiro# hostnames ending in class P are always canonical
84364562SgshapiroR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
84464562Sgshapirodnl apply the next rule only for hostnames not in class P
84564562Sgshapirodnl this even works for phrases in class P since . is in class P
84664562Sgshapirodnl which daemon flags are set?
84764562SgshapiroR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
84864562Sgshapirodnl the other rules in this section only apply if the hostname
84964562Sgshapirodnl does not end in class P hence no further checks are done here
85064562Sgshapirodnl if this ever changes make sure the lookups are "protected" again!
85164562Sgshapiroifdef(`_NO_CANONIFY_', `dnl
85264562Sgshapirodnl do not canonify unless:
85364562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection
85464562Sgshapirodnl	with class P is non-empty)
85564562Sgshapirodnl or {daemon_flags} has c set
85664562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify}
85764562SgshapiroR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
85864562Sgshapiro# pass to name server to make hostname canonical if requested
85964562SgshapiroR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
86064562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_
86164562SgshapiroR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
86264562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work
86364562SgshapiroR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
86464562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl
86564562Sgshapirodnl this should only apply to unqualified hostnames
86664562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
86764562Sgshapirodnl then $- does not work.
86864562Sgshapiro# lookup unqualified hostnames
86990792SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
87064562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
87164562Sgshapirodnl {daemon_flags} contains CC (do not canonify)
87271345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work
87371345Sgshapirodnl should we do this for every hostname: even unqualified?
87471345SgshapiroR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
87564562SgshapiroR$* CC $* $| $*			$: $3
87690792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
87790792Sgshapiro# do not canonify header addresses
87890792SgshapiroR$* $| $* < @ $* $~P > $*	$: $&{addr_type} $| $2 < @ $3 $4 > $5
87990792SgshapiroR$* h $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
88090792SgshapiroR$* h $* $| $*			$: $3', `dnl')
88138032Speter# pass to name server to make hostname canonical
88264562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
88364562Sgshapirodnl remove {daemon_flags} for other cases
88464562SgshapiroR$* $| $*			$: $2
88538032Speter
88638032Speter# local host aliases and pseudo-domains are always canonical
88738032SpeterR$* < @ $=w > $*		$: $1 < @ $2 . > $3
88838032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
88938032Speter`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
89038032Speter`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
89164562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
89264562Sgshapirodnl virtual hosts are also canonical
89364562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
89464562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
89564562Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
89664562Sgshapiro`dnl')
89790792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
89890792Sgshapirodnl hosts for genericstable are also canonical
89990792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_',
90090792Sgshapiro`R$* < @ $* $=G > $* 	$: $1 < @ $2 $3 . > $4',
90190792Sgshapiro`R$* < @ $=G > $* 	$: $1 < @ $2 . > $3')',
90290792Sgshapiro`dnl')
90364562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added
90464562Sgshapirodnl by one of the rules before
90538032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
90638032Speter
90738032Speter
90838032Speter##################################################
90938032Speter###  Ruleset 4 -- Final Output Post-rewriting  ###
91038032Speter##################################################
91164562SgshapiroSfinal=4
91238032Speter
91371345SgshapiroR$+ :; <@>		$@ $1 :				handle <list:;>
91438032SpeterR$* <@>			$@				handle <> and list:;
91538032Speter
91638032Speter# strip trailing dot off possibly canonical name
91738032SpeterR$* < @ $+ . > $*	$1 < @ $2 > $3
91838032Speter
91964562Sgshapiro# eliminate internal code
92038032SpeterR$* < @ *LOCAL* > $*	$1 < @ $j > $2
92138032Speter
92238032Speter# externalize local domain info
92338032SpeterR$* < $+ > $*		$1 $2 $3			defocus
92438032SpeterR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
92538032SpeterR@ $*			$@ @ $1				... and exit
92638032Speter
92738032Speterifdef(`_NO_UUCP_', `dnl',
92838032Speter`# UUCP must always be presented in old form
92938032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
93038032Speter
93138032Speterifdef(`_USE_DECNET_SYNTAX_',
93238032Speter`# put DECnet back in :: form
93338032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
93438032Speter	`dnl')
93538032Speter# delete duplicate local names
93638032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
93738032Speter
93838032Speter
93938032Speter
94038032Speter##############################################################
94138032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
94238032Speter###		   (used for recursive calls)		   ###
94338032Speter##############################################################
94438032Speter
94564562SgshapiroSRecurse=97
94664562SgshapiroR$*			$: $>canonify $1
94764562SgshapiroR$*			$@ $>parse $1
94838032Speter
94938032Speter
95038032Speter######################################
95138032Speter###   Ruleset 0 -- Parse Address   ###
95238032Speter######################################
95338032Speter
95464562SgshapiroSparse=0
95538032Speter
95638032SpeterR$*			$: $>Parse0 $1		initial parsing
95738032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
95864562SgshapiroR$*			$: $>ParseLocal $1	handle local hacks
95938032SpeterR$*			$: $>Parse1 $1		final parsing
96038032Speter
96138032Speter#
96238032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
96338032Speter#	This should either return with the (possibly modified) input
96438032Speter#	or return with a #error mailer.  It should not return with a
96538032Speter#	#mailer other than the #error mailer.
96638032Speter#
96738032Speter
96838032SpeterSParse0
96938032SpeterR<@>			$@ <@>			special case error msgs
97090792SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
97164562SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
97290792SgshapiroR<@ $+>			$#error $@ 5.1.3 $: "_CODE553 User address required"
97390792SgshapiroR$+ <@>			$#error $@ 5.1.3 $: "_CODE553 Hostname required"
97438032SpeterR$*			$: <> $1
97590792Sgshapirodnl allow tricks like [host1]:[host2]
97690792SgshapiroR<> $* < @ [ $* ] : $+ > $*	$1 < @ [ $2 ] : $3 > $4
97790792SgshapiroR<> $* < @ [ $* ] , $+ > $*	$1 < @ [ $2 ] , $3 > $4
97890792Sgshapirodnl but no a@[b]c
97990792SgshapiroR<> $* < @ [ $* ] $+ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid address"
98090792SgshapiroR<> $* < @ [ $+ ] > $*		$1 < @ [ $2 ] > $3
98190792SgshapiroR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
98238032SpeterR<> $*			$1
98390792SgshapiroR$* < @ . $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
98490792SgshapiroR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
98590792Sgshapirodnl no a@b@
98690792SgshapiroR$* < @ $* @ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid route address"
98790792Sgshapirodnl no a@b@c
98890792SgshapiroR$* @ $* < @ $* > $*	$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
98964562Sgshapirodnl comma only allowed before @; this check is not complete
99090792SgshapiroR$* , $~O $*		$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
99138032Speter
99290792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks
99390792SgshapiroR$* . < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
99490792SgshapiroR. $* < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
99590792Sgshapirodnl', `dnl')
99690792Sgshapiro
99738032Speter# now delete the local info -- note $=O to find characters that cause forwarding
99864562SgshapiroR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
99964562SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
100038032SpeterR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
100190792SgshapiroR< @ $+ >		$#error $@ 5.1.3 $: "_CODE553 User address required"
100264562SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
100338032SpeterR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
100490792SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "_CODE553 User address required"
100538032SpeterR$* $=O $* < @ *LOCAL* >
100664562Sgshapiro			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
100738032SpeterR$* < @ *LOCAL* >	$: $1
100838032Speter
100938032Speter#
101038032Speter#  Parse1 -- the bottom half of ruleset 0.
101138032Speter#
101238032Speter
101338032SpeterSParse1
101464562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
101564562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute}
101690792SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
101790792SgshapiroR$+ < @ $={LDAPRouteEquiv} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
101864562Sgshapiro`dnl')
101964562Sgshapiro
102038032Speterifdef(`_MAILER_smtp_',
102138032Speter`# handle numeric address spec
102264562Sgshapirodnl there is no check whether this is really an IP number
102364562SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
1024112810SgshapiroR$* < @ [ $+ ] > $*	$: $1 < @ [ $2 ] : $S > $3	Add smart host to path
102590792SgshapiroR$* < @ [ $+ ] : > $*		$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
102664562SgshapiroR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
102764562SgshapiroR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
102838032Speter	`dnl')
102938032Speter
103064562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
103138032Speter# handle virtual users
103290792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
103390792Sgshapirodnl this is not a documented option
103490792Sgshapirodnl it stops looping in virtusertable mapping if input and output
103590792Sgshapirodnl are identical, i.e., if address A is mapped to A.
103690792Sgshapirodnl it does not deal with multi-level recursion
103790792Sgshapiro# handle full domains in RHS of virtusertable
103890792SgshapiroR$+ < @ $+ >			$: $(macro {RecipientAddress} $) $1 < @ $2 >
103990792SgshapiroR$+ < @ $+ > 			$: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
104090792SgshapiroR<?> $+ $| $+			$: $1 $(macro {RecipientAddress} $@ $2 $)
104190792SgshapiroR<?> $+ $| $*			$: $1',
104290792Sgshapiro`dnl')
104364562SgshapiroR$+			$: <!> $1		Mark for lookup
104490792Sgshapirodnl input: <!> local<@domain>
104564562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
104664562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
104764562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
104890792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
104964562SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
105090792Sgshapirodnl if <@> local<@domain>: no match but try lookup
105190792Sgshapirodnl user+detail: try user++@domain if detail not empty
105290792SgshapiroR<@> $+ + $+ < @ $* . >
105390792Sgshapiro			$: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105490792Sgshapirodnl user+detail: try user+*@domain
105538032SpeterR<@> $+ + $* < @ $* . >
105690792Sgshapiro			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105790792Sgshapirodnl user+detail: try user@domain
105838032SpeterR<@> $+ + $* < @ $* . >
105990792Sgshapiro			$: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
106064562Sgshapirodnl try default entry: @domain
106190792Sgshapirodnl ++@domain
106290792SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
106364562Sgshapirodnl +*@domain
106490792SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
106564562Sgshapirodnl @domain if +detail exists
106698121Sgshapirodnl if no match, change marker to prevent a second @domain lookup
106798121SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . >
106898121Sgshapirodnl without +detail
106938032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
107090792Sgshapirodnl no match
107138032SpeterR<@> $+			$: $1
107290792Sgshapirodnl remove mark
107364562SgshapiroR<!> $+			$: $1
107464562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
107538032SpeterR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
107690792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
107790792Sgshapiro# check virtuser input address against output address, if same, skip recursion
107890792SgshapiroR< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
107990792Sgshapiro# it is the same: stop now
108090792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
108190792SgshapiroR< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
108290792Sgshapirodnl', `dnl')
108380785Sgshapirodnl this is not a documented option
108480785Sgshapirodnl it performs no looping at all for virtusertable
108577349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_',
108677349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
108777349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
108877349Sgshapirodnl', `dnl')
108938032Speter
109038032Speter# short circuit local delivery so forwarded email works
109138032Speterifdef(`_MAILER_usenet_', `dnl
109264562SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
109366494Sgshapiro
109466494Sgshapiro
109538032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
109638032Speter`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
109764562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
109864562Sgshapirodnl $H empty (but @$=w.)
109938032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
110038032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
110164562Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
110238032SpeterR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
110338032Speter
110464562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
110538032Speter# not local -- try mailer table lookup
110638032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
110738032SpeterR< $+ . > $*		$: < $1 > $2			strip trailing dot
110838032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
110964562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
111064562SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
111164562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
111238032Speter`dnl')
111364562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)'
111438032Speter
111538032Speterifdef(`_NO_UUCP_', `dnl',
111638032Speter`# resolve remotely connected UUCP links (if any)
111738032Speterifdef(`_CLASS_V_',
111864562Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
111938032Speter	`dnl')
112038032Speterifdef(`_CLASS_W_',
112164562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
112238032Speter	`dnl')
112338032Speterifdef(`_CLASS_X_',
112464562Sgshapiro`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
112538032Speter	`dnl')')
112638032Speter
112738032Speter# resolve fake top level domains by forwarding to other hosts
112838032Speterifdef(`BITNET_RELAY',
112964562Sgshapiro`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
113038032Speter	`dnl')
113138032Speterifdef(`DECNET_RELAY',
113264562Sgshapiro`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
113338032Speter	`dnl')
113438032Speterifdef(`_MAILER_pop_',
113538032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
113638032Speter	`dnl')
113738032Speterifdef(`_MAILER_fax_',
113838032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
113938032Speter`ifdef(`FAX_RELAY',
114064562Sgshapiro`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
114138032Speter	`dnl')')
114238032Speter
114338032Speterifdef(`UUCP_RELAY',
114438032Speter`# forward non-local UUCP traffic to our UUCP relay
114564562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
114638032Speter`ifdef(`_MAILER_uucp_',
114738032Speter`# forward other UUCP traffic straight to UUCP
114838032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
114938032Speter	`dnl')')
115038032Speterifdef(`_MAILER_usenet_', `
115138032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
115264562SgshapiroR$+ . USENET		$#usenet $@ usenet $: $1',
115338032Speter	`dnl')
115438032Speter
115538032Speterifdef(`_LOCAL_RULES_',
115638032Speter`# figure out what should stay in our local mail system
115738032Speterundivert(1)', `dnl')
115838032Speter
115938032Speter# pass names that still have a host to a smarthost (if defined)
116064562SgshapiroR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
116138032Speter
116238032Speter# deal with other remote names
116338032Speterifdef(`_MAILER_smtp_',
116464562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
116590792Sgshapiro`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
116638032Speter
116738032Speter# handle locally delivered names
116864562SgshapiroR$=L			$#_LOCAL_ $: @ $1		special local names
116938032SpeterR$+			$#_LOCAL_ $: $1			regular local names
117038032Speter
117138032Speter###########################################################################
117238032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
117338032Speter###########################################################################
117438032Speter
117564562SgshapiroSLocal_localaddr
117664562SgshapiroSlocaladdr=5
117764562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
117890792SgshapiroR$+ $| $#ok		$@ $1			no change
117964562SgshapiroR$+ $| $#$*		$#$2
118064562SgshapiroR$+ $| $*		$: $1
118138032Speter
118290792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
118390792Sgshapiro# Preserve rcpt_host in {Host}
118490792SgshapiroR$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
118590792SgshapiroR$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
118690792SgshapiroR$+ $| $| $+		$: $1			h not set, {Host} set
118790792SgshapiroR$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
118895154SgshapiroR$+ $| $* @ $+ $| $*	$: $(macro {Host} $@ @$3 $) $1	set {Host} to host in h
118990792SgshapiroR$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
119090792Sgshapiro')dnl
119190792Sgshapiro
119290792Sgshapiroifdef(`_FFR_5_', `dnl
119366494Sgshapiro# Preserve host in a macro
119466494SgshapiroR$+			$: $(macro {LocalAddrHost} $) $1
119566494SgshapiroR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
119666494Sgshapiro
119790792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
119838032Speter# deal with plussed users so aliases work nicely
119966494SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
120066494SgshapiroR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
120166494Sgshapiro')
120238032Speter# prepend an empty "forward host" on the front
120338032SpeterR$+			$: <> $1
120438032Speter
120538032Speterifdef(`LUSER_RELAY', `dnl
120638032Speter# send unrecognized local users to a relay host
120790792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
120866494SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
120966494SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
121066494SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
121166494SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
121264562SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
121390792SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')
121490792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
121590792SgshapiroR< $+ > $+		$: < $1 > $2 $&{Host}')
121690792Sgshapirodnl')
121738032Speter
121890792Sgshapiroifdef(`MAIL_HUB', `dnl
121990792SgshapiroR< > $+			$: < $H > $1			try hub', `dnl')
122090792Sgshapiroifdef(`LOCAL_RELAY', `dnl
122190792SgshapiroR< > $+			$: < $R > $1			try relay', `dnl')
122290792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
122390792SgshapiroR< > $+			$@ $1', `dnl
122464562SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
122590792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
122690792SgshapiroR< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
122764562SgshapiroR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
122864562SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
122938032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
123066494SgshapiroR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
123138032SpeterR< > < $+ >		$@ $1				no +detail
123243730SpeterR$+			$: $1 <> $&h			add +detail back in
123390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
123490792SgshapiroR$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
123543730SpeterR$+ <> + $*		$: $1 + $2			check whether +detail
123666494SgshapiroR$+ <> $*		$: $1				else discard')
123764562SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
123864562SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
123990792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
124090792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
124190792SgshapiroR< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
124290792SgshapiroR< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
124390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
124490792SgshapiroR< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
124564562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
124638032Speter
124764562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
124890792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
124938032Speter###################################################################
125090792Sgshapiro###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
125190792Sgshapirodnl input: <Domain> FullAddress
125290792Sgshapiro###################################################################
125390792Sgshapiro
125490792SgshapiroSLDAPMailertable
125590792SgshapiroR< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
125690792SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
125790792SgshapiroR< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
125890792SgshapiroR< $+ > $#$*		$#$2					found
125990792SgshapiroR< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
126090792Sgshapiro`dnl')
126190792Sgshapiro
126290792Sgshapiro###################################################################
126338032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
126464562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
126538032Speter###################################################################
126638032Speter
126764562SgshapiroSMailertable=90
126864562Sgshapirodnl shift and check
126964562Sgshapirodnl %2 is not documented in cf/README
127038032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
127164562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
127264562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
127364562SgshapiroR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
127464562Sgshapirodnl is $2 always empty?
127538032SpeterR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
127664562SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
127764562Sgshapirodnl return full address
127838032SpeterR< $* > $*		$@ $2				no mailertable match',
127938032Speter`dnl')
128038032Speter
128138032Speter###################################################################
128238032Speter###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
128364562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
128464562Sgshapirodnl	<> address				-> address
128564562Sgshapirodnl	<error:d.s.n:text>			-> error
1286120256Sgshapirodnl	<error:keyword:text>			-> error
128764562Sgshapirodnl	<error:text>				-> error
128864562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
128964562Sgshapirodnl	<mailer:host> address			-> mailer host address
129064562Sgshapirodnl	<localdomain> address			-> address
129164562Sgshapirodnl	<host> address				-> relay host address
129238032Speter###################################################################
129338032Speter
129464562SgshapiroSMailerToTriple=95
129538032SpeterR< > $*				$@ $1			strip off null relay
129664562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
1297120256SgshapiroR< error : $- : $+ > $*		$#error $@ $(dequote $1 $) $: $2
1298120256SgshapiroR< error : $+ > $*		$#error $: $1
129938032SpeterR< local : $* > $*		$>CanonLocal < $1 > $2
130090792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
130190792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
130290792SgshapiroR< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
130338032SpeterR< $=w > $*			$@ $2			delete local host
130438032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
130538032Speter
130638032Speter###################################################################
130738032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
130864562Sgshapirodnl input: <user> address
130964562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
131064562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
131164562Sgshapirodnl <> user <@host> rest		-> local user@host user
131264562Sgshapirodnl <> user				-> local user user
131364562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
131464562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
131564562Sgshapirodnl <user> lp				-> local lp user
131638032Speter###################################################################
131738032Speter
131838032SpeterSCanonLocal
131943730Speter# strip local host from routed addresses
132064562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
132164562SgshapiroR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
132243730Speter
132338032Speter# strip trailing dot from any host name that may appear
132438032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
132538032Speter
132638032Speter# handle local: syntax -- use old user, either with or without host
132738032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
132838032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
132938032Speter
133038032Speter# handle local:user@host syntax -- ignore host part
133138032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
133238032Speter
133338032Speter# handle local:user syntax
133438032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
133538032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
133638032Speter
133738032Speter###################################################################
133838032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
133938032Speter###################################################################
134038032Speter
134164562SgshapiroSMasqHdr=93
134238032Speter
134364562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
134438032Speter# handle generics database
134538032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
134664562Sgshapirodnl if generics should be applied add a @ as mark
134738032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
134838032Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
134938032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
135064562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
135164562Sgshapirodnl ignore the first case for now
135264562Sgshapirodnl if it has the mark lookup full address
135390792Sgshapirodnl broken: %1 is full address not just detail
135464562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
135564562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
135664562Sgshapirodnl no match, try user+detail@domain
135764562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
135864562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
135964562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
136064562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
136164562Sgshapirodnl no match, remove mark
136264562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
136364562Sgshapirodnl no match, try @domain for exceptions
136464562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
136564562Sgshapirodnl workspace: ... or <match> user <@domain>
136664562Sgshapirodnl no match, try local part
136738032SpeterR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
136864562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
136964562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
137064562SgshapiroR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
137164562SgshapiroR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
137238032SpeterR< > $*			$: $1				not found',
137338032Speter`dnl')
137438032Speter
137564562Sgshapiro# do not masquerade anything in class N
137664562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
137764562Sgshapiro
137890792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
137938032Speter# special case the users that should be exposed
138038032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
138138032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
138238032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
138338032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
138438032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
138538032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
138638032Speter
138738032Speter# handle domain-specific masquerading
138838032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
138938032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
139038032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
139138032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
139238032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
139338032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
139438032SpeterR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
139538032SpeterR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
139690792Sgshapirodnl', `dnl no masquerading
139790792Sgshapirodnl just fix *LOCAL* leftovers
139890792SgshapiroR$* < @ *LOCAL* >	$@ $1 < @ $j . >')
139938032Speter
140038032Speter###################################################################
140138032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
140238032Speter###################################################################
140338032Speter
140464562SgshapiroSMasqEnv=94
140538032Speterifdef(`_MASQUERADE_ENVELOPE_',
140664562Sgshapiro`R$+			$@ $>MasqHdr $1',
140738032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
140838032Speter
140938032Speter###################################################################
141038032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
141138032Speter###################################################################
141238032Speter
141364562SgshapiroSParseLocal=98
141464562Sgshapiroundivert(3)dnl LOCAL_RULE_0
141538032Speter
141664562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
141790792Sgshapiro######################################################################
141890792Sgshapiro###  LDAPExpand: Expand address using LDAP routing
141990792Sgshapiro###
142090792Sgshapiro###	Parameters:
142190792Sgshapiro###		<$1> -- parsed address (user < @ domain . >) (pass through)
142290792Sgshapiro###		<$2> -- RFC822 address (user @ domain) (used for lookup)
142390792Sgshapiro###		<$3> -- +detail information
142490792Sgshapiro###
142590792Sgshapiro###	Returns:
142690792Sgshapiro###		Mailer triplet ($#mailer $@ host $: address)
142790792Sgshapiro###		Parsed address (user < @ domain . >)
142890792Sgshapiro######################################################################
142990792Sgshapiro
143064562SgshapiroSLDAPExpand
143164562Sgshapiro# do the LDAP lookups
143290792SgshapiroR<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
143364562Sgshapiro
143494334Sgshapiro# look for temporary failures (return original address, MTA will queue up)
1435102528SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*>	$@ $3
1436102528SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*>	$@ $3
143794334Sgshapiro
143864562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
143964562Sgshapiro# return the new mailRoutingAddress
144090792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
144190792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
144290792SgshapiroR<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
144390792SgshapiroR<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
144490792SgshapiroR<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
144564562Sgshapiro
144698121Sgshapiro
144764562Sgshapiro# if mailRoutingAddress and non-local mailHost,
144864562Sgshapiro# relay to mailHost with new mailRoutingAddress
144990792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
145090792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
145190792Sgshapiro# check mailertable for host, relay from there
145290792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
145390792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
145490792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
145590792Sgshapiro# check mailertable for host, relay from there
145690792SgshapiroR<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
145790792Sgshapiro`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
145864562Sgshapiro
145964562Sgshapiro# if no mailRoutingAddress and local mailHost,
146064562Sgshapiro# return original address
146190792SgshapiroR<> <$=w> <$+> <$+> <$*>	$@ $2
146264562Sgshapiro
146398121Sgshapiro
146464562Sgshapiro# if no mailRoutingAddress and non-local mailHost,
146564562Sgshapiro# relay to mailHost with original address
146690792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
146790792Sgshapiro# check mailertable for host, relay from there
146890792SgshapiroR<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
146990792Sgshapiro`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
147064562Sgshapiro
147190792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_',
147290792Sgshapiro`# if no mailRoutingAddress and no mailHost,
147390792Sgshapiro# try without +detail
147490792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
147590792Sgshapiro
147690792Sgshapiro# if still no mailRoutingAddress and no mailHost,
147764562Sgshapiro# try @domain
147890792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
147990792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
148090792SgshapiroR<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>
148164562Sgshapiro
148264562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
148364562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
148464562Sgshapiro# user does not exist
148590792SgshapiroR<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
148690792Sgshapiro# only give error for envelope recipient
148790792SgshapiroR<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
148890792SgshapiroR<?> <$*> <$+>			$@ $2',
148964562Sgshapiro`dnl
149064562Sgshapiro# return the original address
149190792SgshapiroR<> <> <$+> <@ $+> <$*>		$@ $1')',
149264562Sgshapiro`dnl')
149364562Sgshapiro
149464562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
149564562Sgshapiro')')
149690792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
149738032Speter######################################################################
149890792Sgshapiro###  D: LookUpDomain -- search for domain in access database
149938032Speter###
150038032Speter###	Parameters:
150138032Speter###		<$1> -- key (domain name)
150238032Speter###		<$2> -- default (what to return if not found in db)
150364562Sgshapirodnl			must not be empty
150490792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
150564562Sgshapiro###			! does lookup only with tag
150664562Sgshapiro###			+ does lookup with and without tag
150790792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
150864562Sgshapirodnl returns:		<default> <passthru>
150964562Sgshapirodnl 			<result> <passthru>
151038032Speter######################################################################
151138032Speter
151290792SgshapiroSD
151364562Sgshapirodnl workspace <key> <default> <passthru> <mark>
151464562Sgshapirodnl lookup with tag (in front, no delimiter here)
151590792Sgshapirodnl    2    3  4    5
151690792SgshapiroR<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
151764562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
151864562Sgshapirodnl lookup without tag?
151990792Sgshapirodnl   1    2      3    4
152090792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
152190792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
152290792Sgshapirodnl XXX apply this also to IP addresses?
152390792Sgshapirodnl currently it works the wrong way round for [1.2.3.4]
152490792Sgshapirodnl   1  2    3    4  5    6
152590792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
152690792Sgshapirodnl   1  2    3      4    5
152790792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
152890792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
152990792Sgshapirodnl found SKIP: return <default> and <passthru>
153090792Sgshapirodnl      1    2    3  4    5
153190792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
153290792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!)
153390792Sgshapirodnl    1  2     3    4  5    6
153490792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
153590792Sgshapiroifdef(`NO_NETINET6', `dnl',
153690792Sgshapiro`dnl not found: IPv6 net
153790792Sgshapirodnl (could be merged with previous rule if we have a class containing .:)
153890792Sgshapirodnl    1   2     3    4  5    6
153990792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
154090792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
154164562Sgshapirodnl not found, but subdomain: try again
154290792Sgshapirodnl   1  2    3    4  5    6
154390792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
154490792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
154590792Sgshapirodnl   1    2      3    4
154690792SgshapiroR<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
154790792Sgshapirodnl not found, no subdomain: return <default> and <passthru>
154890792Sgshapirodnl   1    2    3  4    5
154990792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
155090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
155190792Sgshapirodnl            2    3    4  5    6
155290792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
155390792Sgshapirodnl return <result of lookup> and <passthru>
155490792Sgshapirodnl    2    3    4  5    6
155590792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
155638032Speter
155738032Speter######################################################################
155890792Sgshapiro###  A: LookUpAddress -- search for host address in access database
155938032Speter###
156038032Speter###	Parameters:
156138032Speter###		<$1> -- key (dot quadded host address)
156238032Speter###		<$2> -- default (what to return if not found in db)
156364562Sgshapirodnl			must not be empty
156490792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
156564562Sgshapiro###			! does lookup only with tag
156664562Sgshapiro###			+ does lookup with and without tag
156790792Sgshapiro###		<$4> -- passthru (additional data passed through)
156864562Sgshapirodnl	returns:	<default> <passthru>
156964562Sgshapirodnl			<result> <passthru>
157038032Speter######################################################################
157138032Speter
157290792SgshapiroSA
157364562Sgshapirodnl lookup with tag
157490792Sgshapirodnl    2    3  4    5
157590792SgshapiroR<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
157664562Sgshapirodnl lookup without tag
157790792Sgshapirodnl   1    2      3    4
157890792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
157990792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
158090792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
158190792Sgshapirodnl found SKIP: return <default> and <passthru>
158290792Sgshapirodnl      1    2    3  4    5
158390792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
158490792Sgshapiroifdef(`NO_NETINET6', `dnl',
158590792Sgshapiro`dnl no match; IPv6: remove last part
158690792Sgshapirodnl   1   2    3    4  5    6
158790792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
158890792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
158964562Sgshapirodnl no match; IPv4: remove last part
159090792Sgshapirodnl   1  2    3    4  5    6
159190792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
159264562Sgshapirodnl no match: return default
159390792Sgshapirodnl   1    2    3  4    5
159490792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
159590792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
159690792Sgshapirodnl            2    3    4  5    6
159790792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
159864562Sgshapirodnl match: return result
159990792Sgshapirodnl    2    3    4  5    6
160090792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
160190792Sgshapirodnl endif _ACCESS_TABLE_
160290792Sgshapirodivert(0)
160338032Speter######################################################################
160442575Speter###  CanonAddr --	Convert an address into a standard form for
160542575Speter###			relay checking.  Route address syntax is
160642575Speter###			crudely converted into a %-hack address.
160742575Speter###
160842575Speter###	Parameters:
160942575Speter###		$1 -- full recipient address
161042575Speter###
161142575Speter###	Returns:
161242575Speter###		parsed address, not in source route form
161364562Sgshapirodnl		user%host%host<@domain>
161464562Sgshapirodnl		host!user<@domain>
161542575Speter######################################################################
161642575Speter
161742575SpeterSCanonAddr
161864562SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
161964562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
162042575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
162142575SpeterR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
162242575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
162364562Sgshapirodnl')
162442575Speter
162542575Speter######################################################################
162638032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
162738032Speter###			$* $=m or the access database.
162838032Speter###			Check user portion for host separators.
162938032Speter###
163038032Speter###	Parameters:
163138032Speter###		$1 -- full recipient address
163238032Speter###
163338032Speter###	Returns:
163438032Speter###		parsed, non-local-relaying address
163538032Speter######################################################################
163638032Speter
163738032SpeterSParseRecipient
163864562Sgshapirodnl mark and canonify address
163942575SpeterR$*				$: <?> $>CanonAddr $1
164064562Sgshapirodnl workspace: <?> localpart<@domain[.]>
164142575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
164264562Sgshapirodnl workspace: <?> localpart<@domain>
164342575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
164438032Speter
164538032Speter# if no $=O character, no host in the user portion, we are done
164642575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
164764562Sgshapirodnl no $=O in localpart: return
164842575SpeterR<?> $*				$@ $1
164938032Speter
165090792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O
165164562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
165238032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
165338032Speter# if we relay, check username portion for user%host so host can be checked also
165442575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
165564562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
165664562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
165790792Sgshapiro
165890792Sgshapirodnl what if access map returns something else than RELAY?
165990792Sgshapirodnl we are only interested in RELAY entries...
166090792Sgshapirodnl other To: entries: blacklist recipient; generic entries?
166190792Sgshapirodnl if it is an error we probably do not want to relay anyway
166238032Speterifdef(`_RELAY_HOSTS_ONLY_',
166342575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
166464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
166564562SgshapiroR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
166642575SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
166742575Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
166864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
166990792SgshapiroR<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
167042575SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
167138032Speter
167264562Sgshapiro
167390792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl
167490792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
167590792SgshapiroR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
167690792SgshapiroR<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
167790792Sgshapirodnl yes: mark it as <RELAY>
167890792SgshapiroR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
167990792Sgshapirodnl no: put old <NO> mark back
168090792SgshapiroR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
168190792Sgshapiro
168290792Sgshapirodnl do we relay to this recipient domain?
168342575SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
168490792Sgshapirodnl something else
168590792SgshapiroR<$+> $*			$@ $2
168642575Speter
168764562Sgshapiro
168838032Speter######################################################################
168938032Speter###  check_relay -- check hostname/address on SMTP startup
169038032Speter######################################################################
169138032Speter
169238032SpeterSLocal_check_relay
169364562SgshapiroScheck`'_U_`'relay
169438032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
169538032SpeterR$* $| $* $| $#$*	$#$3
169638032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
169738032Speter
169838032SpeterSBasic_check_relay
169938032Speter# check for deferred delivery mode
170098121SgshapiroR$*			$: < $&{deliveryMode} > $1
170138032SpeterR< d > $*		$@ deferred
170238032SpeterR< $* > $*		$: $2
170338032Speter
170464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
170566494Sgshapirodnl workspace: {client_name} $| {client_addr}
170690792SgshapiroR$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
170766494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
1708110560Sgshapirodnl OR $| $+ if client_name is empty
1709110560SgshapiroR   $| $+		$: $>A < $1 > <?> <+ Connect> <>	empty client_name
1710110560Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
171190792SgshapiroR<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
171290792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>)
171390792SgshapiroR<?> <$*>		$: OK				found nothing
171490792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
171590792SgshapiroR<$={Accept}> <$*>	$@ $1				return value of lookup
171690792SgshapiroR<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
171790792SgshapiroR<DISCARD> <$*>		$#discard $: discard
171890792Sgshapiroifdef(`_FFR_QUARANTINE',
171990792Sgshapiro`R<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1', `dnl')
172064562Sgshapirodnl error tag
172166494SgshapiroR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
172266494SgshapiroR<ERROR:$+> <$*>		$#error $: $1
172390792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
172464562Sgshapirodnl generic error from access map
172566494SgshapiroR<$+> <$*>		$#error $: $1', `dnl')
172638032Speter
172764562Sgshapiroifdef(`_RBL_',`dnl
172864562Sgshapiro# DNS based IP address spam list
172990792Sgshapirodnl workspace: ignored...
173038032SpeterR$*			$: $&{client_addr}
173164562SgshapiroR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
173264562SgshapiroR<?>OK			$: OKSOFAR
173398121SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"',
173438032Speter`dnl')
173564562Sgshapiroundivert(8)
173638032Speter
173738032Speter######################################################################
173838032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
173938032Speter######################################################################
174038032Speter
174138032SpeterSLocal_check_mail
174264562SgshapiroScheck`'_U_`'mail
174338032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
174438032SpeterR$* $| $#$*		$#$2
174538032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
174638032Speter
174738032SpeterSBasic_check_mail
174838032Speter# check for deferred delivery mode
174998121SgshapiroR$*			$: < $&{deliveryMode} > $1
175038032SpeterR< d > $*		$@ deferred
175138032SpeterR< $* > $*		$: $2
175238032Speter
175364562Sgshapiro# authenticated?
175464562Sgshapirodnl done first: we can require authentication for every mail transaction
175564562Sgshapirodnl workspace: address as given by MAIL FROM: (sender)
175664562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
175764562SgshapiroR$* $| $#$+		$#$2
175864562Sgshapirodnl undo damage: remove result of tls_client call
175964562SgshapiroR$* $| $*		$: $1
176038032Speter
176164562Sgshapirodnl workspace: address as given by MAIL FROM:
176264562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
176338032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
176464562Sgshapirodnl do some additional checks
176564562Sgshapirodnl no user@host
176664562Sgshapirodnl no user@localhost (if nonlocal sender)
176764562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
176864562Sgshapirodnl just make sure the address has <> around it (which is required by
176964562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
177064562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
177164562Sgshapirodnl not be modified by host lookups.
177264562SgshapiroR$+			$: <?> $1
177364562SgshapiroR<?><$+>		$: <@> <$1>
177464562SgshapiroR<?>$+			$: <@> <$1>
177564562Sgshapirodnl workspace: <@> <address>
177664562Sgshapirodnl prepend daemon_flags
177764562SgshapiroR$*			$: $&{daemon_flags} $| $1
177864562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
177964562Sgshapirodnl do not allow these at all or only from local systems?
178064562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
178164562Sgshapirodnl accept unqualified sender: change mark to avoid test
178264562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
178364562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
178464562Sgshapirodnl        or:                    <? ${client_name} > <address>
178564562Sgshapirodnl        or:                    <?> <address>
178664562Sgshapirodnl remove daemon_flags
178764562SgshapiroR$* $| $*		$: $2
178838032Speter# handle case of @localhost on address
178964562SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
179064562SgshapiroR<@> < $* @ [127.0.0.1] >
179164562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
179264562SgshapiroR<@> < $* @ localhost.$m >
179364562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
179438032Speterifdef(`_NO_UUCP_', `dnl',
179564562Sgshapiro`R<@> < $* @ localhost.UUCP >
179664562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
179764562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
179864562Sgshapirodnl	or:    <@> <address>
179964562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
180064562SgshapiroR<@> $*			$: $1			no localhost as domain
180164562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
180264562Sgshapirodnl	or:    <address>
180364562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
180464562SgshapiroR<? $=w> $*		$: $2			local client: ok
180590792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
180664562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
180764562SgshapiroR<?> $*			$: $1')
180864562Sgshapirodnl workspace: address (or <address>)
180964562SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
181064562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
181164562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
181264562SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
181364562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
1814102528SgshapiroR<?> $* < @ $* $=P >	$: <_RES_OK_> $1 < @ $2 $3 >
181564562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
181698121Sgshapirodnl A sender address with my local host name ($j) is safe
1817102528SgshapiroR<?> $* < @ $j >	$: <_RES_OK_> $1 < @ $j >
181864562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
181990792Sgshapiro`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
182064562Sgshapiro`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
182164562SgshapiroR<? $* <$->> $* < @ $+ >
182264562Sgshapiro			$: <$2> $3 < @ $4 >')
182390792Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
182464562Sgshapirodnl mark is ? iff the address is user (wo @domain)
182538032Speter
182664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
182764562Sgshapiro# check sender address: user@address, user@, address
182864562Sgshapirodnl should we remove +ext from user?
182990792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
183090792SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
183164562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
183264562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
183364562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
183464562Sgshapirodnl will only return user<@domain when "reversing" the args
183590792SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
183664562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
183764562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
183864562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
183938032Speter# retransform for further use
184064562Sgshapirodnl required form:
184164562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
184264562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
184364562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
184464562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
184564562Sgshapirodnl mark is ? iff the address is user (wo @domain)
184638032Speter
184738032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
184838032Speter# handle case of no @domain on address
184964562Sgshapirodnl prepend daemon_flags
185064562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
185164562Sgshapirodnl accept unqualified sender: change mark to avoid test
185290792SgshapiroR$* u $* $| <?> $*	$: <_RES_OK_> $3
185364562Sgshapirodnl remove daemon_flags
185464562SgshapiroR$* $| $*		$: $2
1855110560SgshapiroR<?> $*			$: < ? $&{client_addr} > $1
1856102528SgshapiroR<?> $*			$@ <_RES_OK_>			...local unqualed ok
185790792SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
185838032Speter							...remote is not')
185938032Speter# check results
186064562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
186190792SgshapiroR<$={ResOk}> $*		$@ <_RES_OK_>	domain ok: stop
186264562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
186390792SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
186464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
186590792SgshapiroR<$={Accept}> $*	$# $1		accept from access map
186638032SpeterR<DISCARD> $*		$#discard $: discard
186790792Sgshapiroifdef(`_FFR_QUARANTINE',
186890792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
186964562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
187064562Sgshapirodnl error tag
187164562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
187264562SgshapiroR<ERROR:$+> $*		$#error $: $1
187390792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
187464562Sgshapirodnl generic error from access map
187564562SgshapiroR<$+> $*		$#error $: $1		error from access db',
187638032Speter`dnl')
187738032Speter
187838032Speter######################################################################
187938032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
188038032Speter######################################################################
188138032Speter
188238032SpeterSLocal_check_rcpt
188364562SgshapiroScheck`'_U_`'rcpt
188438032SpeterR$*			$: $1 $| $>"Local_check_rcpt" $1
188538032SpeterR$* $| $#$*		$#$2
188638032SpeterR$* $| $*		$@ $>"Basic_check_rcpt" $1
188738032Speter
188838032SpeterSBasic_check_rcpt
188990792Sgshapiro# empty address?
189090792SgshapiroR<>			$#error $@ nouser $: "553 User address required"
189190792SgshapiroR$@			$#error $@ nouser $: "553 User address required"
189238032Speter# check for deferred delivery mode
189398121SgshapiroR$*			$: < $&{deliveryMode} > $1
189438032SpeterR< d > $*		$@ deferred
189538032SpeterR< $* > $*		$: $2
189638032Speter
189764562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
189890792Sgshapirodnl this code checks for user@host where host is not a FQHN.
189990792Sgshapirodnl it is not activated.
190090792Sgshapirodnl notice: code to check for a recipient without a domain name is
190190792Sgshapirodnl available down below; look for the same macro.
190290792Sgshapirodnl this check is done here because the name might be qualified by the
190390792Sgshapirodnl canonicalization.
190490792Sgshapiro# require fully qualified domain part?
190590792Sgshapirodnl very simple canonification: make sure the address is in < >
190664562SgshapiroR$+			$: <?> $1
190790792SgshapiroR<?> <$+>		$: <@> <$1>
190890792SgshapiroR<?> $+			$: <@> <$1>
190990792SgshapiroR<@> < postmaster >	$: postmaster
1910110560SgshapiroR<@> < $* @ $+ . $+ >	$: < $1 @ $2 . $3 >
191164562Sgshapirodnl prepend daemon_flags
191290792SgshapiroR<@> $*			$: $&{daemon_flags} $| <@> $1
191364562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
1914120256Sgshapirodnl 'r'equire qual.rcpt: ok
1915120256SgshapiroR$* r $* $| <@> < $+ @ $+ >	$: < $3 @ $4 >
191664562Sgshapirodnl do not allow these at all or only from local systems?
1917120256SgshapiroR$* r $* $| <@> < $* >	$: < ? $&{client_name} > < $3 >
191864562SgshapiroR<?> < $* >		$: <$1>
191964562SgshapiroR<? $=w> < $* >		$: <$1>
192090792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
192164562Sgshapirodnl remove daemon_flags for other cases
192264562SgshapiroR$* $| <@> $*		$: $2', `dnl')
192364562Sgshapiro
192490792Sgshapirodnl ##################################################################
192590792Sgshapirodnl call subroutines for recipient and relay
192690792Sgshapirodnl possible returns from subroutines:
192790792Sgshapirodnl $#TEMP	temporary failure
192890792Sgshapirodnl $#error	permanent failure (or temporary if from access map)
192990792Sgshapirodnl $#other	stop processing
193090792Sgshapirodnl RELAY	RELAYing allowed
193190792Sgshapirodnl other	otherwise
193290792Sgshapiro######################################################################
193390792SgshapiroR$*			$: $1 $| @ $>"Rcpt_ok" $1
193490792Sgshapirodnl temporary failure? remove mark @ and remember
193590792SgshapiroR$* $| @ $#TEMP $+	$: $1 $| T $2
193690792Sgshapirodnl error or ok (stop)
193790792SgshapiroR$* $| @ $#$*		$#$2
193890792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
193990792SgshapiroR$* $| @ RELAY		$@ RELAY
194090792Sgshapirodnl something else: call check sender (relay)
194190792SgshapiroR$* $| @ $*		$: O $| $>"Relay_ok" $1
194290792Sgshapirodnl temporary failure: call check sender (relay)
194390792SgshapiroR$* $| T $+		$: T $2 $| $>"Relay_ok" $1
194490792Sgshapirodnl temporary failure? return that
194590792SgshapiroR$* $| $#TEMP $+	$#error $2
194690792Sgshapirodnl error or ok (stop)
194790792SgshapiroR$* $| $#$*		$#$2
194890792SgshapiroR$* $| RELAY		$@ RELAY
194990792Sgshapirodnl something else: return previous temp failure
195090792SgshapiroR T $+ $| $*		$#error $1
195190792Sgshapiro# anything else is bogus
195290792SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
195390792Sgshapirodivert(0)
195490792Sgshapiro
195590792Sgshapiro######################################################################
195690792Sgshapiro### Rcpt_ok: is the recipient ok?
195790792Sgshapirodnl input: recipient address (RCPT TO)
195890792Sgshapirodnl output: see explanation at call
195990792Sgshapiro######################################################################
196090792SgshapiroSRcpt_ok
196138032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
196242575SpeterR$*			$: $>CanonAddr $1
196338032SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
196438032Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
196538032Speter
196642575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
196742575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
196842575Speter# unlimited bestmx
196942575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
197042575Speter`dnl
197142575Speter# limit bestmx to $=B
197243730SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
197390792SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
197442575SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
197542575SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
197642575Speter
197738032Speterifdef(`_BLACKLIST_RCPT_',`dnl
197864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
197938032Speter# blacklist local users or any host from receiving mail
198038032SpeterR$*			$: <?> $1
198164562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
198264562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
198390792SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
198490792SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
198564562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
198664562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
198764562Sgshapirodnl will only return user<@domain when "reversing" the args
198890792SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
198964562SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
199064562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
199190792Sgshapirodnl we may have to filter here because otherwise some RHSs
199290792Sgshapirodnl would be interpreted as generic error messages...
199390792Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
199490792Sgshapirodnl that would make a lot of things easier.
199564562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
199690792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
199790792SgshapiroR<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
199890792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
199990792Sgshapirodnl compatility with 8.11/8.10:
200064562Sgshapirodnl we have to filter these because otherwise they would be interpreted
200164562Sgshapirodnl as generic error message...
200264562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
200364562Sgshapirodnl that would make a lot of things easier.
200464562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
200564562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
200690792SgshapiroR<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
200764562SgshapiroR<DISCARD> $*		$#discard $: discard
200890792Sgshapiroifdef(`_FFR_QUARANTINE',
200990792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
201064562Sgshapirodnl error tag
201164562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
201264562SgshapiroR<ERROR:$+> $*		$#error $: $1
201390792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
201464562Sgshapirodnl generic error from access map
201564562SgshapiroR<$+> $*		$#error $: $1		error from access db
201664562SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
201738032Speter
201890792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
201990792Sgshapiro# authenticated via TLS?
202090792SgshapiroR$*			$: $1 $| $>RelayTLS	client authenticated?
202190792SgshapiroR$* $| $# $+		$# $2			error/ok?
202290792SgshapiroR$* $| $*		$: $1			no
202364562Sgshapiro
202490792SgshapiroR$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
202590792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth
202690792SgshapiroR$* $| $# $*		$# $2
202790792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
202890792SgshapiroR$* $| NO		$: $1
202990792SgshapiroR$* $| $*		$: $1 $| $&{auth_type}
203090792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ]
203164562Sgshapirodnl empty ${auth_type}?
203264562SgshapiroR$* $|			$: $1
203364562Sgshapirodnl mechanism ${auth_type} accepted?
203464562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
203590792SgshapiroR$* $| $={TrustAuthMech}	$# RELAY
203690792Sgshapirodnl remove ${auth_type}
203764562SgshapiroR$* $| $*		$: $1
203871345Sgshapirodnl workspace: localpart<@domain> | localpart
203964562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
204071345Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
204171345SgshapiroR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
204238032Speter# anything terminating locally is ok
204338032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
204490792SgshapiroR$+ < @ $* $=m >	$@ RELAY', `dnl')
204590792SgshapiroR$+ < @ $=w >		$@ RELAY
204638032Speterifdef(`_RELAY_HOSTS_ONLY_',
204790792Sgshapiro`R$+ < @ $=R >		$@ RELAY
204864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
204964562SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
205064562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
205164562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
205290792Sgshapiro`R$+ < @ $* $=R >	$@ RELAY
205364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
205490792SgshapiroR$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')')
205564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
205664562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
205790792SgshapiroR<RELAY> $*		$@ RELAY
205890792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
205938032SpeterR<$*> <$*>		$: $2',`dnl')
206038032Speter
206164562Sgshapiro
206238032Speterifdef(`_RELAY_MX_SERVED_', `dnl
206338032Speter# allow relaying for hosts which we MX serve
206464562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
206564562Sgshapirodnl this must not necessarily happen if the client is checked first...
206690792SgshapiroR< : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
206790792SgshapiroR<$* : $=w . : $*> $*	$@ RELAY
206842575SpeterR< : $* : > $*		$: $2',
206938032Speter`dnl')
207038032Speter
207138032Speter# check for local user (i.e. unqualified address)
207238032SpeterR$*			$: <?> $1
207342575SpeterR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
207438032Speter# local user is ok
207564562Sgshapirodnl is it really? the standard requires user@domain, not just user
207664562Sgshapirodnl but we should accept it anyway (maybe making it an option:
207764562Sgshapirodnl RequireFQDN ?)
207864562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
207964562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
208090792SgshapiroR<?> postmaster		$@ OK
208164562Sgshapiro# require qualified recipient?
208264562Sgshapirodnl prepend daemon_flags
208364562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
208464562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
208564562Sgshapirodnl do not allow these at all or only from local systems?
208664562Sgshapirodnl r flag? add client_name
208764562SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
208864562Sgshapirodnl no r flag: relay to local user (only local part)
208964562Sgshapiro# no qualified recipient required
209090792SgshapiroR$* $| <?> $+		$@ RELAY
209164562Sgshapirodnl client_name is empty
209290792SgshapiroR<?> <?> $+		$@ RELAY
209364562Sgshapirodnl client_name is local
209490792SgshapiroR<? $=w> <?> $+		$@ RELAY
209564562Sgshapirodnl client_name is not local
209664562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
209764562Sgshapirodnl no qualified recipient required
209890792SgshapiroR<?> $+			$@ RELAY')
209964562Sgshapirodnl it is a remote user: remove mark and then check client
210038032SpeterR<$+> $*		$: $2
210164562Sgshapirodnl currently the recipient address is not used below
210238032Speter
210390792Sgshapiro######################################################################
210490792Sgshapiro### Relay_ok: is the relay/sender ok?
210590792Sgshapirodnl input: ignored
210690792Sgshapirodnl output: see explanation at call
210790792Sgshapiro######################################################################
210890792SgshapiroSRelay_ok
210938032Speter# anything originating locally is ok
211064562Sgshapiro# check IP address
211164562SgshapiroR$*			$: $&{client_addr}
211290792SgshapiroR$@			$@ RELAY		originated locally
211390792SgshapiroR0			$@ RELAY		originated locally
2114110560SgshapiroR127.0.0.1		$@ RELAY		originated locally
2115110560SgshapiroRIPv6:::1		$@ RELAY		originated locally
211690792SgshapiroR$=R $*			$@ RELAY		relayable IP address
211764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
211890792SgshapiroR$*			$: $>A <$1> <?> <+ Connect> <$1>
211990792SgshapiroR<RELAY> $* 		$@ RELAY		relayable IP address
2120102528Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl
2121102528Sgshapirodnl this will cause rejections in cases like:
2122102528Sgshapirodnl Connect:My.Host.Domain	RELAY
2123102528Sgshapirodnl Connect:My.Net		REJECT
2124102528Sgshapirodnl since in check_relay client_name is checked before client_addr
2125102528SgshapiroR<REJECT> $* 		$@ REJECT		rejected IP address')
212690792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
212764562SgshapiroR<$*> <$*>		$: $2', `dnl')
212864562SgshapiroR$*			$: [ $1 ]		put brackets around it...
212990792SgshapiroR$=w			$@ RELAY		... and see if it is local
213064562Sgshapiro
213164562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
213264562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
213364562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
213464562Sgshapirodnl input: {client_addr} or something "broken"
213564562Sgshapirodnl just throw the input away; we do not need it.
213664562Sgshapiro# check whether FROM is allowed to use system as relay
213764562SgshapiroR$*			$: <?> $>CanonAddr $&f
213890792SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
213964562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
214064562Sgshapiro# check whether local FROM is ok
214190792SgshapiroR<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
214264562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
214394334SgshapiroR<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <>
214490792SgshapiroR<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
214590792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
214690792Sgshapiro', `dnl
214790792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_',
214890792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
214964562Sgshapiro')',
215064562Sgshapiro`dnl')
215164562Sgshapirodnl')', `dnl')
215290792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind.
215390792Sgshapirodnl it does not matter in this case because the following rule ignores
215490792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace.
215564562Sgshapiro
215664562Sgshapiro# check client name: first: did it resolve?
215764562Sgshapirodnl input: ignored
215864562SgshapiroR$*			$: < $&{client_resolve} >
215990792SgshapiroR<TEMP>			$#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
216064562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
216164562SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
216264562Sgshapirodnl ${client_resolve} should be OK, so go ahead
216390792SgshapiroR$*			$: <@> $&{client_name}
216490792Sgshapirodnl should not be necessary since it has been done for client_addr already
2165110560Sgshapirodnl this rule actually may cause a problem if {client_name} resolves to ""
2166110560Sgshapirodnl however, this should not happen since the forward lookup should fail
2167110560Sgshapirodnl and {client_resolve} should be TEMP or FAIL.
2168110560Sgshapirodnl nevertheless, removing the rule doesn't hurt.
2169110560Sgshapirodnl R<@>			$@ RELAY
217090792Sgshapirodnl workspace: <@> ${client_name} (not empty)
217138032Speter# pass to name server to make hostname canonical
217290792SgshapiroR<@> $* $=P 		$:<?>  $1 $2
217390792SgshapiroR<@> $+			$:<?>  $[ $1 $]
217490792Sgshapirodnl workspace: <?> ${client_name} (canonified)
217564562SgshapiroR$* .			$1			strip trailing dots
217638032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
217790792SgshapiroR<?> $* $=m		$@ RELAY', `dnl')
217890792SgshapiroR<?> $=w		$@ RELAY
217938032Speterifdef(`_RELAY_HOSTS_ONLY_',
218090792Sgshapiro`R<?> $=R		$@ RELAY
218164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
218264562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
218364562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
218490792Sgshapiro`R<?> $* $=R			$@ RELAY
218564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
218690792SgshapiroR<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
218764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
218890792SgshapiroR<RELAY> $*		$@ RELAY
218990792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
219038032SpeterR<$*> <$*>		$: $2',`dnl')
219190792Sgshapirodnl end of _PROMISCUOUS_RELAY_
219264562Sgshapirodivert(0)
219364562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
219464562Sgshapiro# turn a canonical address in the form user<@domain>
219564562Sgshapiro# qualify unqual. addresses with $j
219664562Sgshapirodnl it might have been only user (without <@domain>)
219764562SgshapiroSFullAddr
219864562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
219964562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
220064562SgshapiroR$+			$@ $1 <@ $j >
220138032Speter
2202120256SgshapiroSDelay_TLS_Clt
2203110560Sgshapiro# authenticated?
2204110560Sgshapirodnl code repeated here from Basic_check_mail
2205110560Sgshapirodnl only called from check_rcpt in delay mode if checkrcpt returns $#
2206110560SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
2207110560SgshapiroR$* $| $#$+		$#$2
2208110560Sgshapirodnl return result from checkrcpt
2209120256SgshapiroR$* $| $*		$# $1
2210110560SgshapiroR$*			$# $1
2211110560Sgshapiro
2212120256SgshapiroSDelay_TLS_Clt2
2213110560Sgshapiro# authenticated?
2214110560Sgshapirodnl code repeated here from Basic_check_mail
2215110560Sgshapirodnl only called from check_rcpt in delay mode if stopping due to Friend/Hater
2216110560SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
2217110560SgshapiroR$* $| $#$+		$#$2
2218110560Sgshapirodnl return result from friend/hater check
2219120256SgshapiroR$* $| $*		$@ $1
2220110560SgshapiroR$*			$@ $1
2221110560Sgshapiro
222264562Sgshapiro# call all necessary rulesets
222364562SgshapiroScheck_rcpt
222464562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
222564562Sgshapirodnl which is the correct DSN code?
222664562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
2227110560Sgshapiro
222864562SgshapiroR$+			$: $1 $| $>checkrcpt $1
222964562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
2230110560Sgshapirodnl on error (or discard) stop now
2231110560SgshapiroR$+ $| $#error $*	$#error $2
2232110560SgshapiroR$+ $| $#discard $*	$#discard $2
2233110560Sgshapirodnl otherwise call tls_client; see above
2234120256SgshapiroR$+ $| $#$*		$@ $>"Delay_TLS_Clt" $2
223564562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
223664562Sgshapiroifdef(`_SPAM_FH_',
223764562Sgshapiro`dnl lookup user@ and user@address
223864562Sgshapiroifdef(`_ACCESS_TABLE_', `',
223964562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
224064562Sgshapiro')')dnl
224164562Sgshapirodnl one of the next two rules is supposed to match
224264562Sgshapirodnl this code has been copied from BLACKLIST... etc
224364562Sgshapirodnl and simplified by omitting some < >.
224490792SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
224590792SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
224664562Sgshapirodnl R<?>		$@ something_is_very_wrong_here
224790792Sgshapiro# lookup the addresses only with Spam tag
224890792SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
224964562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
225064562Sgshapirodnl', `dnl')
225164562Sgshapiroifdef(`_SPAM_FRIEND_',
225264562Sgshapiro`# is the recipient a spam friend?
225364562Sgshapiroifdef(`_SPAM_HATER_',
2254110560Sgshapiro	`errprint(`*** ERROR: define either Hater or Friend -- not both.
225564562Sgshapiro')', `dnl')
2256120256SgshapiroR<FRIEND> $+		$@ $>"Delay_TLS_Clt2" SPAMFRIEND
225764562SgshapiroR<$*> $+		$: $2',
225864562Sgshapiro`dnl')
225964562Sgshapiroifdef(`_SPAM_HATER_',
226064562Sgshapiro`# is the recipient no spam hater?
226190792SgshapiroR<HATER> $+		$: $1			spam hater: continue checks
2262120256SgshapiroR<$*> $+		$@ $>"Delay_TLS_Clt2" NOSPAMHATER	everyone else: stop
226364562Sgshapirodnl',`dnl')
226464562Sgshapirodnl run further checks: check_mail
226564562Sgshapirodnl should we "clean up" $&f?
226690792Sgshapiroifdef(`_FFR_MAIL_MACRO',
226790792Sgshapiro`R$*			$: $1 $| $>checkmail $&{mail_from}',
226890792Sgshapiro`R$*			$: $1 $| $>checkmail <$&f>')
226994334Sgshapirodnl recipient (canonical format) $| result of checkmail
227064562SgshapiroR$* $| $#$*		$#$2
227164562Sgshapirodnl run further checks: check_relay
227294334SgshapiroR$* $| $*		$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
227364562SgshapiroR$* $| $#$*		$#$2
227438032SpeterR$* $| $*		$: $1
227538032Speter', `dnl')
227690792Sgshapiro
227790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
227864562Sgshapiro######################################################################
227990792Sgshapiro###  F: LookUpFull -- search for an entry in access database
228090792Sgshapiro###
228190792Sgshapiro###	lookup of full key (which should be an address) and
228290792Sgshapiro###	variations if +detail exists: +* and without +detail
228390792Sgshapiro###
228490792Sgshapiro###	Parameters:
228590792Sgshapiro###		<$1> -- key
228690792Sgshapiro###		<$2> -- default (what to return if not found in db)
228790792Sgshapirodnl			must not be empty
228890792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
228990792Sgshapiro###			! does lookup only with tag
229090792Sgshapiro###			+ does lookup with and without tag
229190792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
229290792Sgshapirodnl returns:		<default> <passthru>
229390792Sgshapirodnl 			<result> <passthru>
229490792Sgshapiro######################################################################
229590792Sgshapiro
229690792SgshapiroSF
229790792Sgshapirodnl workspace: <key> <def> <o tag> <thru>
229890792Sgshapirodnl full lookup
229990792Sgshapirodnl    2    3  4    5
230090792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
230190792Sgshapirodnl no match, try without tag
230290792Sgshapirodnl   1    2      3    4
230390792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
230490792Sgshapirodnl no match, +detail: try +*
230590792Sgshapirodnl   1    2    3    4    5  6    7
230690792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
230790792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
230890792Sgshapirodnl no match, +detail: try +* without tag
230990792Sgshapirodnl   1    2    3    4      5    6
231090792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
231190792Sgshapiro			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
231290792Sgshapirodnl no match, +detail: try without +detail
231390792Sgshapirodnl   1    2    3    4    5  6    7
231490792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
231590792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
231690792Sgshapirodnl no match, +detail: try without +detail and without tag
231790792Sgshapirodnl   1    2    3    4      5    6
231890792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
231990792Sgshapiro			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
232090792Sgshapirodnl no match, return <default> <passthru>
232190792Sgshapirodnl   1    2    3  4    5
232290792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
232390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
232490792Sgshapirodnl            2    3  4    5
232590792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
232690792Sgshapirodnl match, return <match> <passthru>
232790792Sgshapirodnl    2    3  4    5
232890792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
232990792Sgshapiro
233090792Sgshapiro######################################################################
233190792Sgshapiro###  E: LookUpExact -- search for an entry in access database
233290792Sgshapiro###
233390792Sgshapiro###	Parameters:
233490792Sgshapiro###		<$1> -- key
233590792Sgshapiro###		<$2> -- default (what to return if not found in db)
233690792Sgshapirodnl			must not be empty
233790792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
233890792Sgshapiro###			! does lookup only with tag
233990792Sgshapiro###			+ does lookup with and without tag
234090792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
234190792Sgshapirodnl returns:		<default> <passthru>
234290792Sgshapirodnl 			<result> <passthru>
234390792Sgshapiro######################################################################
234490792Sgshapiro
234590792SgshapiroSE
234690792Sgshapirodnl    2    3  4    5
234790792SgshapiroR<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
234890792Sgshapirodnl no match, try without tag
234990792Sgshapirodnl   1    2      3    4
235090792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
235190792Sgshapirodnl no match, return default passthru
235290792Sgshapirodnl   1    2    3  4    5
235390792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
235490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
235590792Sgshapirodnl            2    3  4    5
235690792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
235790792Sgshapirodnl match, return <match> <passthru>
235890792Sgshapirodnl    2    3  4    5
235990792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
236090792Sgshapiro
236190792Sgshapiro######################################################################
236290792Sgshapiro###  U: LookUpUser -- search for an entry in access database
236390792Sgshapiro###
236490792Sgshapiro###	lookup of key (which should be a local part) and
236590792Sgshapiro###	variations if +detail exists: +* and without +detail
236690792Sgshapiro###
236790792Sgshapiro###	Parameters:
236890792Sgshapiro###		<$1> -- key (user@)
236990792Sgshapiro###		<$2> -- default (what to return if not found in db)
237090792Sgshapirodnl			must not be empty
237190792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
237290792Sgshapiro###			! does lookup only with tag
237390792Sgshapiro###			+ does lookup with and without tag
237490792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
237590792Sgshapirodnl returns:		<default> <passthru>
237690792Sgshapirodnl 			<result> <passthru>
237790792Sgshapiro######################################################################
237890792Sgshapiro
237990792SgshapiroSU
238090792Sgshapirodnl user lookups are always with trailing @
238190792Sgshapirodnl    2    3  4    5
238290792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
238390792Sgshapirodnl no match, try without tag
238490792Sgshapirodnl   1    2      3    4
238590792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
238690792Sgshapirodnl do not remove the @ from the lookup:
238790792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
238890792Sgshapirodnl no match, +detail: try +*
238990792Sgshapirodnl   1    2      3    4  5    6
239090792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
239190792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
239290792Sgshapirodnl no match, +detail: try +* without tag
239390792Sgshapirodnl   1    2      3      4    5
239490792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
239590792Sgshapiro			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
239690792Sgshapirodnl no match, +detail: try without +detail
239790792Sgshapirodnl   1    2      3    4  5    6
239890792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
239990792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
240090792Sgshapirodnl no match, +detail: try without +detail and without tag
240190792Sgshapirodnl   1    2      3      4    5
240290792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
240390792Sgshapiro			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
240490792Sgshapirodnl no match, return <default> <passthru>
240590792Sgshapirodnl   1    2    3  4    5
240690792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
240790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
240890792Sgshapirodnl            2    3  4    5
240990792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
241090792Sgshapirodnl match, return <match> <passthru>
241190792Sgshapirodnl    2    3  4    5
241290792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
241390792Sgshapiro
241490792Sgshapiro######################################################################
241564562Sgshapiro###  SearchList: search a list of items in the access map
241664562Sgshapiro###	Parameters:
241764562Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
241864562Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
241964562Sgshapirodnl	avoid errorneous matches (with error messages?)
242064562Sgshapirodnl	if we can make sure that tag is always a single token
242164562Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
242290792Sgshapirodnl	to avoid errorneous matchs (first rule: D: if there
242364562Sgshapirodnl	is that mark somewhere in the list, it will be taken).
242464562Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
242564562Sgshapirodnl	the tag only, e.g.:
242664562Sgshapiro###	where "exact" is either "+" or "!":
242764562Sgshapiro###	<+ TAG>	lookup with and w/o tag
242864562Sgshapiro###	<! TAG>	lookup with tag
242964562Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
243064562Sgshapirodnl		a blank between them and the tag.
243164562Sgshapiro###	possible values for "mark" are:
243290792Sgshapiro###		D: recursive host lookup (LookUpDomain)
243364562Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
243464562Sgshapiro###		E: exact lookup, no modifications
243564562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
243664562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
243764562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
243864562Sgshapiro######################################################################
243938032Speter
244064562Sgshapiro# class with valid marks for SearchList
244164562Sgshapirodnl if A is activated: add it
244290792SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
244364562SgshapiroSSearchList
244490792Sgshapiro# just call the ruleset with the name of the tag... nice trick...
244590792Sgshapirodnl       2       3    4
244690792SgshapiroR<$+> $| <$={src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
244790792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <>
244890792Sgshapirodnl no match and nothing left: return
244990792SgshapiroR<$+> $| <> $| <?> <>		$@ <?>
245090792Sgshapirodnl no match but something left: continue
245190792SgshapiroR<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
245290792Sgshapirodnl match: return
245390792SgshapiroR<$+> $| <$*> $| <$+> <>	$@ <$3>
245464562Sgshapirodnl return result from recursive invocation
245590792SgshapiroR<$+> $| <$+>			$@ <$2>
245690792Sgshapirodnl endif _ACCESS_TABLE_
245790792Sgshapirodivert(0)
245838032Speter
245990792Sgshapiro######################################################################
246090792Sgshapiro###  trust_auth: is user trusted to authenticate as someone else?
246190792Sgshapiro###
246290792Sgshapiro###	Parameters:
246390792Sgshapiro###		$1: AUTH= parameter from MAIL command
246490792Sgshapiro######################################################################
246590792Sgshapiro
246690792Sgshapirodnl empty ruleset definition so it can be called
246790792SgshapiroSLocal_trust_auth
246864562SgshapiroStrust_auth
246964562SgshapiroR$*			$: $&{auth_type} $| $1
247064562Sgshapiro# required by RFC 2554 section 4.
247164562SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
247264562Sgshapirodnl seems to be useful...
247364562SgshapiroR$* $| $&{auth_authen}		$@ identical
247464562SgshapiroR$* $| <$&{auth_authen}>	$@ identical
247564562Sgshapirodnl call user supplied code
2476120256SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $2
247764562SgshapiroR$* $| $#$*		$#$2
247864562Sgshapirodnl default: error
247964562SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
248064562Sgshapiro
248190792Sgshapiro######################################################################
248290792Sgshapiro###  Relay_Auth: allow relaying based on authentication?
248390792Sgshapiro###
248490792Sgshapiro###	Parameters:
248590792Sgshapiro###		$1: ${auth_type}
248690792Sgshapiro######################################################################
248790792SgshapiroSLocal_Relay_Auth
248864562Sgshapiro
248990792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
249090792Sgshapiro######################################################################
249190792Sgshapiro###  srv_features: which features to offer to a client?
249290792Sgshapiro###	(done in server)
249390792Sgshapiro######################################################################
249490792SgshapiroSsrv_features
249590792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl
249690792SgshapiroR$*			$: $1 $| $>"Local_srv_features" $1
249790792SgshapiroR$* $| $#$*		$#$2
249890792SgshapiroR$* $| $*		$: $1', `dnl')
249990792SgshapiroR$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
250090792SgshapiroR<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
250190792SgshapiroR<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
250264562SgshapiroR<?>$*		$@ OK
250390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
250490792SgshapiroR<$* _ATMPF_>$*	$#temp', `dnl')
250590792SgshapiroR<$+>$*		$# $1
250664562Sgshapiro
250790792Sgshapiro######################################################################
250890792Sgshapiro###  try_tls: try to use STARTTLS?
250990792Sgshapiro###	(done in client)
251090792Sgshapiro######################################################################
251164562SgshapiroStry_tls
251290792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl
251390792SgshapiroR$*			$: $1 $| $>"Local_try_tls" $1
251490792SgshapiroR$* $| $#$*		$#$2
251590792SgshapiroR$* $| $*		$: $1', `dnl')
251690792SgshapiroR$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
251790792SgshapiroR<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
251890792SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
251964562SgshapiroR<?>$*		$@ OK
252090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
252190792SgshapiroR<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
252271345SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
2523102528Sgshapiro 
252490792Sgshapiro######################################################################
252590792Sgshapiro###  tls_rcpt: is connection with server "good" enough?
252690792Sgshapiro###	(done in client, per recipient)
252790792Sgshapirodnl called from deliver() before RCPT command
252890792Sgshapiro###
252990792Sgshapiro###	Parameters:
253090792Sgshapiro###		$1: recipient
253190792Sgshapiro######################################################################
253290792SgshapiroStls_rcpt
253390792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl
253490792SgshapiroR$*			$: $1 $| $>"Local_tls_rcpt" $1
253590792SgshapiroR$* $| $#$*		$#$2
253690792SgshapiroR$* $| $*		$: $1', `dnl')
253790792Sgshapirodnl store name of other side
253890792SgshapiroR$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
253990792Sgshapirodnl canonify recipient address
254090792SgshapiroR$+			$: <?> $>CanonAddr $1
254190792Sgshapirodnl strip trailing dots
254290792SgshapiroR<?> $+ < @ $+ . >	<?> $1 <@ $2 >
254390792Sgshapirodnl full address?
254490792SgshapiroR<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
254590792Sgshapirodnl only localpart?
254690792SgshapiroR<?> $+			$: $1 $| <U:$1@> <E:>
254790792Sgshapirodnl look it up
254890792Sgshapirodnl also look up a default value via E:
254990792SgshapiroR$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
255090792Sgshapirodnl found nothing: stop here
255190792SgshapiroR$* $| <?>	$@ OK
255290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
255390792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
255490792Sgshapirodnl use the generic routine (for now)
255590792SgshapiroR$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
255664562Sgshapiro
255790792Sgshapiro######################################################################
255890792Sgshapiro###  tls_client: is connection with client "good" enough?
255990792Sgshapiro###	(done in server)
256090792Sgshapiro###
256190792Sgshapiro###	Parameters:
256290792Sgshapiro###		${verify} $| (MAIL|STARTTLS)
256390792Sgshapiro######################################################################
256464562Sgshapirodnl MAIL: called from check_mail
256564562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
256664562SgshapiroStls_client
256790792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl
256890792SgshapiroR$*			$: $1 $| $>"Local_tls_client" $1
256990792SgshapiroR$* $| $#$*		$#$2
257090792SgshapiroR$* $| $*		$: $1', `dnl')
257164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
257290792Sgshapirodnl store name of other side
257390792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
257464562Sgshapirodnl ignore second arg for now
257564562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
257664562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
257764562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
257890792SgshapiroR$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
257990792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
258064562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
258164562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
258290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
258390792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
258490792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
258590792SgshapiroR$* $| $*	$@ $>"TLS_connection" $1')
258664562Sgshapiro
258790792Sgshapiro######################################################################
258890792Sgshapiro###  tls_server: is connection with server "good" enough?
258990792Sgshapiro###	(done in client)
259090792Sgshapiro###
259190792Sgshapiro###	Parameter:
259290792Sgshapiro###		${verify}
259390792Sgshapiro######################################################################
259464562Sgshapirodnl i.e. has the server been authenticated and is encryption active?
259564562Sgshapirodnl called from deliver() after STARTTLS command
259664562SgshapiroStls_server
259790792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl
259890792SgshapiroR$*			$: $1 $| $>"Local_tls_server" $1
259990792SgshapiroR$* $| $#$*		$#$2
260090792SgshapiroR$* $| $*		$: $1', `dnl')
260164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
260290792Sgshapirodnl store name of other side
260390792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
260490792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
260590792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
260664562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
260764562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
260890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
260990792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
261090792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
261190792SgshapiroR$*		$@ $>"TLS_connection" $1')
261264562Sgshapiro
261390792Sgshapiro######################################################################
261490792Sgshapiro###  TLS_connection: is TLS connection "good" enough?
261590792Sgshapiro###
261690792Sgshapiro###	Parameters:
261764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
261890792Sgshapiro###		${verify} $| <Requirement> [<>]', `dnl
261990792Sgshapiro###		${verify}')
262090792Sgshapiro###		Requirement: RHS from access map, may be ? for none.
262190792Sgshapirodnl	syntax for Requirement:
262290792Sgshapirodnl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
262390792Sgshapirodnl	extensions: could be a list of further requirements
262490792Sgshapirodnl		for now: CN:string	{cn_subject} == string
262590792Sgshapiro######################################################################
262690792SgshapiroSTLS_connection
262790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
262890792Sgshapirodnl deal with TLS handshake failures: abort
262990792SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
263090792Sgshapirodivert(-1)')
263164562Sgshapirodnl common ruleset for tls_{client|server}
263290792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>]
263364562Sgshapirodnl remove optional <>
263464562SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
263590792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup>
263690792Sgshapiro# create the appropriate error codes
263764562Sgshapirodnl permanent or temporary error?
263864562SgshapiroR$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
263964562SgshapiroR$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
264064562Sgshapirodnl default case depends on TLS_PERM_ERR
264164562SgshapiroR$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
264290792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
264390792Sgshapiro# deal with TLS handshake failures: abort
264464562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
264564562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
264664562Sgshapirodnl use default error
264764562SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
264890792SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
264990792Sgshapirodnl separate optional requirements
265090792SgshapiroR$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
265190792SgshapiroR$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> <> $1
265290792Sgshapirodnl separate optional requirements
265390792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
265464562Sgshapirodnl some other value in access map: accept
265564562Sgshapirodnl this also allows to override the default case (if used)
265664562SgshapiroR$* $| $*			$@ OK
265764562Sgshapiro# authentication required: give appropriate error
265864562Sgshapiro# other side did authenticate (via STARTTLS)
265990792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
266064562Sgshapirodnl only verification required and it succeeded
266190792SgshapiroR<$*><VERIFY> <> OK		$@ OK
266290792Sgshapirodnl verification required and it succeeded but extensions are given
266390792Sgshapirodnl change it to <SMTP:ESC> <REQ:0>  <extensions>
266490792SgshapiroR<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
266564562Sgshapirodnl verification required + some level of encryption
266690792SgshapiroR<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
266764562Sgshapirodnl just some level of encryption required
266890792SgshapiroR<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
266990792Sgshapirodnl workspace:
267090792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
267190792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
267290792Sgshapirodnl verification required but ${verify} is not set (case 1.)
267390792SgshapiroR<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
267490792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
267590792SgshapiroR<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
267690792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
267790792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
267864562Sgshapirodnl some other value for ${verify}
267990792SgshapiroR<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
268090792Sgshapirodnl some level of encryption required: get the maximum level (case 2.)
268190792SgshapiroR<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
268264562Sgshapirodnl compare required bits with actual bits
268390792SgshapiroR<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
268490792SgshapiroR<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
268590792Sgshapirodnl strength requirements fulfilled
268690792Sgshapirodnl TLS Additional Requirements Separator
268790792Sgshapirodnl this should be something which does not appear in the extensions itself
268890792Sgshapirodnl @ could be part of a CN, DN, etc...
268990792Sgshapirodnl use < > ? those are encoded in CN, DN, ...
269090792Sgshapirodefine(`_TLS_ARS_', `++')dnl
269190792Sgshapirodnl workspace:
269290792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
269390792SgshapiroR<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
269490792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
269590792Sgshapirodnl continue: check  extensions
269690792SgshapiroR<$-:$+ _TLS_ARS_ >			$@ OK
269790792Sgshapirodnl split extensions into own list
269890792SgshapiroR<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
269990792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
270090792SgshapiroR<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
270164562Sgshapiro
270290792Sgshapiro######################################################################
270390792Sgshapiro###  TLS_req: check additional TLS requirements
270490792Sgshapiro###
270590792Sgshapiro###	Parameters: [<list> <of> <req>] $| <$-:$+>
270690792Sgshapiro###		$-: SMTP reply code
270790792Sgshapiro###		$+: Enhanced Status Code
270890792Sgshapirodnl  further requirements for this ruleset:
270990792Sgshapirodnl	name of "other side" is stored is {TLS_name} (client/server_name)
271090792Sgshapirodnl
271190792Sgshapirodnl	currently only CN[:common_name] is implemented
271290792Sgshapirodnl	right now this is only a logical AND
271390792Sgshapirodnl	i.e. all requirements must be true
271490792Sgshapirodnl	how about an OR? CN must be X or CN must be Y or ..
271590792Sgshapirodnl	use a macro to compute this as a trivial sequential
271690792Sgshapirodnl	operations (no precedences etc)?
271790792Sgshapiro######################################################################
271890792SgshapiroSTLS_req
271990792Sgshapirodnl no additional requirements: ok
272090792SgshapiroR $| $+		$@ OK
272190792Sgshapirodnl require CN: but no CN specified: use name of other side
272290792SgshapiroR<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
272390792Sgshapirodnl match, check rest
272490792SgshapiroR<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
272590792Sgshapirodnl CN does not match
272690792Sgshapirodnl  1   2      3  4
272790792SgshapiroR<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
272890792Sgshapirodnl cert subject
272990792SgshapiroR<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
273090792Sgshapirodnl CS does not match
273190792Sgshapirodnl  1   2      3  4
2732110560SgshapiroR<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1
273390792Sgshapirodnl match, check rest
273490792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
273590792Sgshapirodnl CI does not match
273690792Sgshapirodnl  1   2      3  4
2737110560SgshapiroR<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1
273890792Sgshapirodnl return from recursive call
273990792SgshapiroROK			$@ OK
274090792Sgshapiro
274190792Sgshapiro######################################################################
274290792Sgshapiro###  max: return the maximum of two values separated by :
274390792Sgshapiro###
274490792Sgshapiro###	Parameters: [$-]:[$-]
274590792Sgshapiro######################################################################
274664562SgshapiroSmax
274764562SgshapiroR:		$: 0
274864562SgshapiroR:$-		$: $1
274964562SgshapiroR$-:		$: $1
275064562SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
275164562SgshapiroRTRUE:$-:$-	$: $2
275290792SgshapiroR$-:$-:$-	$: $2
275390792Sgshapirodnl endif _ACCESS_TABLE_
275490792Sgshapirodivert(0)
275564562Sgshapiro
275690792Sgshapiro######################################################################
275790792Sgshapiro###  RelayTLS: allow relaying based on TLS authentication
275890792Sgshapiro###
275990792Sgshapiro###	Parameters:
276090792Sgshapiro###		none
276190792Sgshapiro######################################################################
276290792SgshapiroSRelayTLS
276364562Sgshapiro# authenticated?
276464562Sgshapirodnl we do not allow relaying for anyone who can present a cert
276564562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
2766110560Sgshapirodnl CA in CertPath so we can authenticate users, we do not allow
276764562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
276864562Sgshapirodnl but anyway).
276964562Sgshapirodnl so here is the trick: if the verification succeeded
277064562Sgshapirodnl we look up the cert issuer in the access map
277164562Sgshapirodnl (maybe after extracting a part with a regular expression)
277264562Sgshapirodnl if this returns RELAY we relay without further questions
277364562Sgshapirodnl if it returns SUBJECT we perform a similar check on the
277464562Sgshapirodnl cert subject.
277564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
277690792SgshapiroR$*			$: <?> $&{verify}
277790792SgshapiroR<?> OK			$: OK		authenticated: continue
277890792SgshapiroR<?> $*			$@ NO		not authenticated
277964562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
278090792SgshapiroR$*			$: $(CERTIssuer $&{cert_issuer} $)',
278190792Sgshapiro`R$*			$: $&{cert_issuer}')
278290792SgshapiroR$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
278364562Sgshapirodnl use $# to stop further checks (delay_check)
278490792SgshapiroRRELAY			$# RELAY
278564562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
278690792SgshapiroRSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
278790792Sgshapiro`RSUBJECT		$: <@> $&{cert_subject}')
278890792SgshapiroR<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
278990792SgshapiroR<@> RELAY		$# RELAY
279090792SgshapiroR$*			$: NO', `dnl')
279164562Sgshapiro
279290792Sgshapiro######################################################################
279390792Sgshapiro###  authinfo: lookup authinfo in the access map
279490792Sgshapiro###
279590792Sgshapiro###	Parameters:
279690792Sgshapiro###		$1: {server_name}
279790792Sgshapiro###		$2: {server_addr}
279890792Sgshapirodnl	both are currently ignored
279990792Sgshapirodnl if it should be done via another map, we either need to restrict
280090792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another
280190792Sgshapirodnl parameter which I want to avoid, it's quite complex already)
280290792Sgshapiro######################################################################
280390792Sgshapirodnl omit this ruleset if neither is defined?
280490792Sgshapirodnl it causes DefaultAuthInfo to be ignored
280590792Sgshapirodnl (which may be considered a good thing).
280690792SgshapiroSauthinfo
280790792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl
280890792SgshapiroR$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
280990792SgshapiroR<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
281090792SgshapiroR<?>		$: <$(authinfo AuthInfo: $: ? $)>
281190792SgshapiroR<?>		$@ no				no authinfo available
281290792SgshapiroR<$*>		$# $1
281390792Sgshapirodnl', `dnl
281490792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
281590792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
281690792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
281790792SgshapiroR$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
281890792SgshapiroR$* $| <?>$*	$@ no				no authinfo available
281990792SgshapiroR$* $| <$*> <>	$# $2
282090792Sgshapirodnl', `dnl')')
282190792Sgshapiro
282264562Sgshapiroundivert(9)dnl LOCAL_RULESETS
282338032Speter#
282438032Speter######################################################################
282538032Speter######################################################################
282638032Speter#####
282764562Sgshapiro`#####			MAIL FILTER DEFINITIONS'
282864562Sgshapiro#####
282964562Sgshapiro######################################################################
283064562Sgshapiro######################################################################
283190792Sgshapiro_MAIL_FILTERS_
283264562Sgshapiro#
283364562Sgshapiro######################################################################
283464562Sgshapiro######################################################################
283564562Sgshapiro#####
283638032Speter`#####			MAILER DEFINITIONS'
283738032Speter#####
283838032Speter######################################################################
283938032Speter######################################################################
284064562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
284166494Sgshapiro
2842