proto.m4 revision 110560
138032Speterdivert(-1)
238032Speter#
394334Sgshapiro# Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
464562Sgshapiro#	All rights reserved.
538032Speter# Copyright (c) 1983, 1995 Eric P. Allman.  All rights reserved.
638032Speter# Copyright (c) 1988, 1993
738032Speter#	The Regents of the University of California.  All rights reserved.
838032Speter#
938032Speter# By using this file, you agree to the terms and conditions set
1038032Speter# forth in the LICENSE file which can be found at the top level of
1138032Speter# the sendmail distribution.
1238032Speter#
1338032Speter#
1438032Speterdivert(0)
1538032Speter
16102528SgshapiroVERSIONID(`$Id: proto.m4,v 8.649.2.13 2002/12/04 00:12:18 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
20838032Speter# who I send unqualified names to if FEATURE(stickyhost) is used
20990792Sgshapiro# (null means deliver locally)
21038032SpeterDR`'LOCAL_RELAY')
21190792Sgshapiro
21238032Speterifdef(`MAIL_HUB', `dnl
21390792Sgshapiro# who gets all local email traffic
21438032Speter# ($R has precedence for unqualified names if FEATURE(stickyhost) is used)
21538032SpeterDH`'MAIL_HUB')
21690792Sgshapiro
21738032Speter# dequoting map
21838032SpeterKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `')
21938032Speter
22064562Sgshapirodivert(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
22438032Speter# class N: domains that should not be converted to $M
22564562Sgshapiro#CL root
22638032Speterundivert(5)dnl
22790792Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
22838032Speter
22990792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
23038032Speter# who I masquerade as (null for no masquerading) (see also $=M)
23138032SpeterDM`'MASQUERADE_NAME')
23238032Speter
23338032Speter# my name for error messages
23464562Sgshapiroifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
23538032Speter
23638032Speterundivert(6)dnl LOCAL_CONFIG
23738032Speterinclude(_CF_DIR_`m4/version.m4')
23838032Speter
23938032Speter###############
24090792Sgshapiro#   Options   #
24190792Sgshapiro###############
24290792Sgshapiroifdef(`confAUTO_REBUILD',
24390792Sgshapiro`errprint(WARNING: `confAUTO_REBUILD' is no longer valid.
24438032Speter	There was a potential for a denial of service attack if this is set.
24538032Speter)')dnl
24664562Sgshapiro
24738032Speter# strip message body to 7 bits on input?
24838032Speter_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
24977349Sgshapiro
25038032Speter# 8-bit data handling
25138032Speter_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8')
25264562Sgshapiro
25338032Speter# wait for alias file rebuild (default units: minutes)
25438032Speter_OPTION(AliasWait, `confALIAS_WAIT', `5m')
25564562Sgshapiro
25664562Sgshapiro# location of alias file
25738032Speter_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
25864562Sgshapiro
25938032Speter# minimum number of free blocks on filesystem
26038032Speter_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
26164562Sgshapiro
26238032Speter# maximum message size
26338032Speter_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000')
26464562Sgshapiro
26538032Speter# substitution for space (blank) characters
26638032Speter_OPTION(BlankSub, `confBLANK_SUB', `_')
26764562Sgshapiro
26838032Speter# avoid connecting to "expensive" mailers on initial submission?
26938032Speter_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
27064562Sgshapiro
27138032Speter# checkpoint queue runs after every N successful deliveries
27238032Speter_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
27364562Sgshapiro
27438032Speter# default delivery mode
27538032Speter_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
27664562Sgshapiro
27738032Speter# error message header/file
27838032Speter_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
27964562Sgshapiro
28038032Speter# error mode
28138032Speter_OPTION(ErrorMode, `confERROR_MODE', `print')
28264562Sgshapiro
28338032Speter# save Unix-style "From_" lines at top of header?
28490792Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
28590792Sgshapiro
28690792Sgshapiro# queue file mode (qf files)
28738032Speter_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600')
28864562Sgshapiro
28938032Speter# temporary file mode
29038032Speter_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
29164562Sgshapiro
29238032Speter# match recipients against GECOS field?
29338032Speter_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
29490792Sgshapiro
29538032Speter# maximum hop count
29638032Speter_OPTION(MaxHopCount, `confMAX_HOP', `25')
29764562Sgshapiro
29838032Speter# location of help file
29938032SpeterO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
30064562Sgshapiro
30138032Speter# ignore dots as terminators in incoming messages?
30238032Speter_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
30364562Sgshapiro
30438032Speter# name resolver options
30538032Speter_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
30664562Sgshapiro
30738032Speter# deliver MIME-encapsulated error messages?
30838032Speter_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
30964562Sgshapiro
31038032Speter# Forward file search path
31138032Speter_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
31264562Sgshapiro
31338032Speter# open connection cache size
31438032Speter_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
31564562Sgshapiro
31638032Speter# open connection cache timeout
31738032Speter_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
31864562Sgshapiro
31938032Speter# persistent host status directory
32038032Speter_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
32164562Sgshapiro
32238032Speter# single thread deliveries (requires HostStatusDirectory)?
32338032Speter_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
32464562Sgshapiro
32538032Speter# use Errors-To: header?
32638032Speter_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
32764562Sgshapiro
32838032Speter# log level
32938032Speter_OPTION(LogLevel, `confLOG_LEVEL', `10')
33064562Sgshapiro
33138032Speter# send to me too, even in an alias expansion?
33238032Speter_OPTION(MeToo, `confME_TOO', `True')
33364562Sgshapiro
33438032Speter# verify RHS in newaliases?
33538032Speter_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
33664562Sgshapiro
33738032Speter# default messages to old style headers if no special punctuation?
33838032Speter_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
33964562Sgshapiro
34094334Sgshapiro# SMTP daemon options
34194334Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
34264562Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.
34364562Sgshapiro	Use `DAEMON_OPTIONS()'; see cf/README.
34466494Sgshapiro)'dnl
34590792Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
34690792Sgshapiroifelse(defn(`_DPO_'), `',
34764562Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet
34838032SpeterO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
34964562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
35090792Sgshapiro
35190792Sgshapiro# 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')')
35664562Sgshapiroifelse(defn(`_CPO_'), `',
35790792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_')
35890792Sgshapiro
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
36338032Speter_OPTION(UseMSP, `confUSE_MSP', `')
36464562Sgshapiro
36538032Speter# privacy flags
36638032Speter_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
36764562Sgshapiro
36838032Speter# who (if anyone) should get extra copies of error messages
36938032Speter_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
37064562Sgshapiro
37138032Speter# slope of queue-only function
37290792Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
37390792Sgshapiro
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
39338032Speter_OPTION(FastSplit, `confFAST_SPLIT', `1')
39464562Sgshapiro
39538032Speter# queue directory
39690792SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
39790792Sgshapiro
39890792Sgshapiro# key for shared memory; 0 to turn off
39994334Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
40094334Sgshapiro
40194334Sgshapiroifdef(`confSHARED_MEMORY_KEY_FILE', `dnl
40294334Sgshapiro# file to store key for shared memory (if SharedMemoryKey = -1)
40338032SpeterO SharedMemoryKeyFile=confSHARED_MEMORY_KEY_FILE')
40464562Sgshapiro
40564562Sgshapiro# timeouts (many of these)
40690792Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
40764562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
40864562Sgshapiro_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')
42764562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
42864562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
42964562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
43064562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
43164562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
43264562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
43364562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
43464562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
43564562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
43690792Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
43790792Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
43890792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
43938032Speter_OPTION(Timeout.auth, `confTO_AUTH', `10m')
44090792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
44190792Sgshapiro
44290792Sgshapiro# time for DeliverBy; extension disabled if less than 0
44338032Speter_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
44464562Sgshapiro
44538032Speter# should we not prune routes in route-addr syntax addresses?
44638032Speter_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
44764562Sgshapiro
44838032Speter# queue up everything before forking?
44938032Speter_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
45064562Sgshapiro
45138032Speter# status file
45238032SpeterO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
45338032Speter
45438032Speter# time zone handling:
45538032Speter#  if undefined, use system default
45638032Speter#  if defined but null, use TZ envariable passed in
45738032Speter#  if defined and non-null, use that info
45838032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
45938032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
46038032Speter	`O TimeZoneSpec=confTIME_ZONE')
46164562Sgshapiro
46238032Speter# default UID (can be username or userid:groupid)
46338032Speter_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
46464562Sgshapiro
46538032Speter# list of locations of user database file (null means no lookup)
46638032Speter_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
46764562Sgshapiro
46838032Speter# fallback MX host
46938032Speter_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
47064562Sgshapiro
47138032Speter# if we are the best MX host for a site, try it directly instead of config err
47238032Speter_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
47364562Sgshapiro
47438032Speter# load average at which we just queue messages
47538032Speter_OPTION(QueueLA, `confQUEUE_LA', `8')
47664562Sgshapiro
47738032Speter# load average at which we refuse connections
47890792Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
47990792Sgshapiro
48090792Sgshapiro# load average at which we delay connections; 0 means no limit
48138032Speter_OPTION(DelayLA, `confDELAY_LA', `0')
48298841Sgshapiro
48338032Speter# maximum number of children we allow at one time
48438032Speter_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0')
48571345Sgshapiro
48638032Speter# maximum number of new connections per second
48738032Speter_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
48864562Sgshapiro
48938032Speter# work recipient factor
49038032Speter_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
49164562Sgshapiro
49238032Speter# deliver each queued job in a separate process?
49338032Speter_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
49464562Sgshapiro
49538032Speter# work class factor
49638032Speter_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
49764562Sgshapiro
49838032Speter# work time factor
49938032Speter_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
50064562Sgshapiro
50138032Speter# default character set
50290792Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
50364562Sgshapiro
50438032Speter# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
50538032Speter_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
50664562Sgshapiro
50738032Speter# hosts file (normally /etc/hosts)
50838032Speter_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
50964562Sgshapiro
51038032Speter# dialup line delay on connection failure
51138032Speter_OPTION(DialDelay, `confDIAL_DELAY', `10s')
51264562Sgshapiro
51338032Speter# action to take if there are no recipients in the message
51438032Speter_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed')
51564562Sgshapiro
51638032Speter# chrooted environment for writing to files
51738032Speter_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
51864562Sgshapiro
51938032Speter# are colons OK in addresses?
52038032Speter_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
52164562Sgshapiro
52238032Speter# shall I avoid expanding CNAMEs (violates protocols)?
52338032Speter_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
52464562Sgshapiro
52538032Speter# SMTP initial login message (old $e macro)
52638032Speter_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
52764562Sgshapiro
52838032Speter# UNIX initial From header format (old $l macro)
52938032Speter_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
53064562Sgshapiro
53138032Speter# From: lines that have embedded newlines are unwrapped onto one line
53238032Speter_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
53364562Sgshapiro
53438032Speter# Allow HELO SMTP command that does not `include' a host name
53538032Speter_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
53664562Sgshapiro
53738032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
53838032Speter_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
53964562Sgshapiro
54038032Speter# delimiter (operator) characters (old $o macro)
54138032Speter_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
54264562Sgshapiro
54338032Speter# shall I avoid calling initgroups(3) because of high NIS costs?
54438032Speter_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
54590792Sgshapiro
54664562Sgshapiro# are group-writable `:include:' and .forward files (un)trustworthy?
54790792Sgshapiro# True (the default) means they are not trustworthy.
54890792Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
54990792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES',
55038032Speter`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
55138032Speter')')
55264562Sgshapiro
55338032Speter# where do errors that occur when sending errors get sent?
55464562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
55564562Sgshapiro
55664562Sgshapiro# where to save bounces if all else fails
55738032Speter_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
55864562Sgshapiro
55938032Speter# what user id do we assume for the majority of the processing?
56038032Speter_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
56164562Sgshapiro
56238032Speter# maximum number of recipients per SMTP envelope
56390792Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
56490792Sgshapiro
56590792Sgshapiro# limit the rate recipients per SMTP envelope are accepted
56690792Sgshapiro# once the threshold number of recipients have been rejected
56738032Speter_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20')
56864562Sgshapiro
56938032Speter# shall we get local names from our installed interfaces?
57064562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
57164562Sgshapiro
57264562Sgshapiro# Return-Receipt-To: header implies DSN request
57364562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
57464562Sgshapiro
57564562Sgshapiro# override connection address (for testing)
57664562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
57764562Sgshapiro
57864562Sgshapiro# Trusted user for file ownership and starting the daemon
57964562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
58064562Sgshapiro
58164562Sgshapiro# Control socket for daemon management
58264562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
58364562Sgshapiro
58464562Sgshapiro# Maximum MIME header length to protect MUAs
58564562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
58664562Sgshapiro
58764562Sgshapiro# Maximum length of the sum of all headers
58864562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
58964562Sgshapiro
59064562Sgshapiro# Maximum depth of alias recursion
59164562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
59264562Sgshapiro
59364562Sgshapiro# location of pid file
59464562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
59564562Sgshapiro
59664562Sgshapiro# Prefix string for the process title shown on 'ps' listings
59764562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
59864562Sgshapiro
59964562Sgshapiro# Data file (df) memory-buffer file maximum size
60064562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
60164562Sgshapiro
60264562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
60390792Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
60490792Sgshapiro
60590792Sgshapiro# lookup type to find information about local mailboxes
60664562Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
60790792Sgshapiro
60864562Sgshapiro# list of authentication mechanisms
60964562Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
61064562Sgshapiro
61164562Sgshapiro# default authentication information for outgoing connections
61264562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
61364562Sgshapiro
61464562Sgshapiro# SMTP AUTH flags
61590792Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
61690792Sgshapiro
61790792Sgshapiro# SMTP AUTH maximum encryption strength
61890792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
61990792Sgshapiro
62090792Sgshapiro# SMTP STARTTLS server options
62164562Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
62264562Sgshapiro
62364562Sgshapiro# Input mail filters
62498841Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
62564562Sgshapiro
62690792Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl
62764562Sgshapiro# Milter options
62864562Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
62964562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
63064562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
63164562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
63264562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')')
63364562Sgshapiro
63464562Sgshapiro# CA directory
63564562Sgshapiro_OPTION(CACertPath, `confCACERT_PATH', `')
63664562Sgshapiro# CA file
63764562Sgshapiro_OPTION(CACertFile, `confCACERT', `')
63864562Sgshapiro# Server Cert
63964562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
64064562Sgshapiro# Server private key
64164562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
64264562Sgshapiro# Client Cert
64364562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
64464562Sgshapiro# Client private key
64564562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
64664562Sgshapiro# DHParameters (only required if DSA/DH is used)
64764562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
64864562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
64990792Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
65090792Sgshapiro
65190792Sgshapiro############################
65290792Sgshapiro`# QUEUE GROUP DEFINITIONS  #'
65342575Speter############################
65438032Speter_QUEUE_GROUP_
65538032Speter
65638032Speter###########################
65738032Speter#   Message precedences   #
65838032Speter###########################
65938032Speter
66038032SpeterPfirst-class=0
66138032SpeterPspecial-delivery=100
66238032SpeterPlist=-30
66338032SpeterPbulk=-60
66438032SpeterPjunk=-100
66538032Speter
66638032Speter#####################
66738032Speter#   Trusted users   #
66838032Speter#####################
66964562Sgshapiro
67038032Speter# this is equivalent to setting class "t"
67138032Speterifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
67238032SpeterTroot
67338032SpeterTdaemon
67438032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp')
67538032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
67638032Speter
67738032Speter#########################
67838032Speter#   Format of headers   #
67938032Speter#########################
68038032Speter
68138032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
68238032SpeterH?P?Return-Path: <$g>
68338032SpeterHReceived: confRECEIVED_HEADER
68438032SpeterH?D?Resent-Date: $a
68538032SpeterH?D?Date: $a
68638032SpeterH?F?Resent-From: confFROM_HEADER
68738032SpeterH?F?From: confFROM_HEADER
68838032SpeterH?x?Full-Name: $x
68938032Speter# HPosted-Date: $a
69038032Speter# H?l?Received-Date: $b
69164562SgshapiroH?M?Resent-Message-Id: <$t.$i@$j>
69238032SpeterH?M?Message-Id: <$t.$i@$j>
69338032Speter
69438032Speter#
69538032Speter######################################################################
69638032Speter######################################################################
69738032Speter#####
69838032Speter#####			REWRITING RULES
69938032Speter#####
70038032Speter######################################################################
70138032Speter######################################################################
70238032Speter
70338032Speter############################################
70464562Sgshapiro###  Ruleset 3 -- Name Canonicalization  ###
70538032Speter############################################
70638032SpeterScanonify=3
70738032Speter
70838032Speter# handle null input (translate to <@> special case)
70938032SpeterR$@			$@ <@>
71038032Speter
71138032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
71238032SpeterR$*			$: $1 <@>			mark addresses
71390792SgshapiroR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
71438032SpeterR@ $* <@>		$: @ $1				unmark @host:...
71538032SpeterR$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
71638032SpeterR$* :: $* <@>		$: $1 :: $2			unmark node::addr
71738032SpeterR:`include': $* <@>	$: :`include': $1			unmark :`include':...
71838032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
71938032SpeterR$* : $* <@>		$: $2				strip colon if marked
72071345SgshapiroR$* <@>			$: $1				unmark
72138032SpeterR$* ;			   $1				strip trailing semi
72238032SpeterR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
72338032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
72438032Speter
72538032Speter# null input now results from list:; syntax
72638032SpeterR$@			$@ :; <@>
72738032Speter
72838032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
72938032SpeterR$*			$: < $1 >			housekeeping <>
73038032SpeterR$+ < $* >		   < $2 >			strip excess on left
73138032SpeterR< $* > $+		   < $1 >			strip excess on right
73238032SpeterR<>			$@ < @ >			MAIL FROM:<> case
73364562SgshapiroR< $+ >			$: $1				remove housekeeping <>
73438032Speter
73538032Speterifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
73638032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
73738032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
73890792Sgshapiro
73990792Sgshapiro# localize and dispose of route-based addresses
74090792Sgshapirodnl XXX: IPv6 colon conflict
74164562Sgshapiroifdef(`NO_NETINET6', `dnl',
74264562Sgshapiro`R@ [$+] : $+		$@ $>Canonify2 < @ [$1] > : $2	handle <route-addr>')
74364562SgshapiroR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
74464562Sgshapirodnl',`dnl
74590792Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d>
74690792SgshapiroR@ $+ , $+		$2
74764562Sgshapiroifdef(`NO_NETINET6', `dnl',
74864562Sgshapiro`R@ [ $* ] : $+		$2')
74938032SpeterR@ $+ : $+		$2
75038032Speterdnl')
75164562Sgshapiro
75238032Speter# find focus for list syntax
75338032SpeterR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
75438032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
75538032Speter
75638032Speter# find focus for @ syntax addresses
75764562SgshapiroR$+ @ $+		$: $1 < @ $2 >			focus on domain
75838032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
75990792SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
76090792Sgshapiro
76190792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here.
76238032Speterdnl # do some sanity checking
76338032Speterdnl R$* < @ $~[ $* : $* > $*	$1 < @ $2 $3 > $4	nix colons in addrs
76438032Speter
76564562Sgshapiroifdef(`_NO_UUCP_', `dnl',
76664562Sgshapiro`# convert old-style addresses to a domain-based address
76764562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
76838032SpeterR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
76938032SpeterR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
77038032Speter')
77164562Sgshapiroifdef(`_USE_DECNET_SYNTAX_',
77264562Sgshapiro`# convert node::user addresses into a domain-based address
77338032SpeterR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
77438032SpeterR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
77538032Speter',
77638032Speter	`dnl')
77738032Speter# if we have % signs, take the rightmost one
77864562SgshapiroR$* % $*		$1 @ $2				First make them all @s.
77938032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
78038032SpeterR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
78164562Sgshapiro
78238032Speter# else we must be a local name
78338032SpeterR$*			$@ $>Canonify2 $1
78438032Speter
78538032Speter
78638032Speter################################################
78738032Speter###  Ruleset 96 -- bottom half of ruleset 3  ###
78864562Sgshapiro################################################
78938032Speter
79038032SpeterSCanonify2=96
79138032Speter
79238032Speter# handle special cases for local names
79338032SpeterR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
79438032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
79564562Sgshapiroifdef(`_NO_UUCP_', `dnl',
79690792Sgshapiro`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
79790792Sgshapiro
79838032Speter# check for IPv4/IPv6 domain literal
79938032SpeterR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [addr]
80038032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
80164562SgshapiroR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
80238032Speter
80338032Speterifdef(`_DOMAIN_TABLE_', `dnl
80438032Speter# look up domains in the domain table
80564562SgshapiroR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
80638032Speter
80764562Sgshapiroundivert(2)dnl LOCAL_RULE_3
80838032Speter
80938032Speterifdef(`_BITDOMAIN_TABLE_', `dnl
81038032Speter# handle BITNET mapping
81164562SgshapiroR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
81238032Speter
81338032Speterifdef(`_UUDOMAIN_TABLE_', `dnl
81438032Speter# handle UUCP mapping
81538032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
81638032Speter
81738032Speterifdef(`_NO_UUCP_', `dnl',
81838032Speter`ifdef(`UUCP_RELAY',
81938032Speter`# pass UUCP addresses straight through
82038032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
82138032Speter`# if really UUCP, handle it immediately
82238032Speterifdef(`_CLASS_U_',
82338032Speter`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82438032Speterifdef(`_CLASS_V_',
82538032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82638032Speterifdef(`_CLASS_W_',
82738032Speter`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82838032Speterifdef(`_CLASS_X_',
82938032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83038032Speterifdef(`_CLASS_Y_',
83138032Speter`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83238032Speter
83338032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl
83438032Speter# try UUCP traffic as a local address
83538032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
83664562SgshapiroR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
83764562Sgshapiro')')
83864562Sgshapiro# hostnames ending in class P are always canonical
83964562SgshapiroR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
84064562Sgshapirodnl apply the next rule only for hostnames not in class P
84164562Sgshapirodnl this even works for phrases in class P since . is in class P
84264562Sgshapirodnl which daemon flags are set?
84364562SgshapiroR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
84464562Sgshapirodnl the other rules in this section only apply if the hostname
84564562Sgshapirodnl does not end in class P hence no further checks are done here
84664562Sgshapirodnl if this ever changes make sure the lookups are "protected" again!
84764562Sgshapiroifdef(`_NO_CANONIFY_', `dnl
84864562Sgshapirodnl do not canonify unless:
84964562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection
85064562Sgshapirodnl	with class P is non-empty)
85164562Sgshapirodnl or {daemon_flags} has c set
85264562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify}
85364562SgshapiroR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
85464562Sgshapiro# pass to name server to make hostname canonical if requested
85564562SgshapiroR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
85664562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_
85764562SgshapiroR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
85864562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work
85964562SgshapiroR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
86064562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl
86164562Sgshapirodnl this should only apply to unqualified hostnames
86264562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
86390792Sgshapirodnl then $- does not work.
86464562Sgshapiro# lookup unqualified hostnames
86564562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
86671345Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
86771345Sgshapirodnl {daemon_flags} contains CC (do not canonify)
86871345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work
86964562Sgshapirodnl should we do this for every hostname: even unqualified?
87090792SgshapiroR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
87190792SgshapiroR$* CC $* $| $*			$: $3
87290792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
87390792Sgshapiro# do not canonify header addresses
87490792SgshapiroR$* $| $* < @ $* $~P > $*	$: $&{addr_type} $| $2 < @ $3 $4 > $5
87538032SpeterR$* h $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
87664562SgshapiroR$* h $* $| $*			$: $3', `dnl')
87764562Sgshapiro# pass to name server to make hostname canonical
87864562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
87938032Speterdnl remove {daemon_flags} for other cases
88038032SpeterR$* $| $*			$: $2
88138032Speter
88238032Speter# local host aliases and pseudo-domains are always canonical
88338032SpeterR$* < @ $=w > $*		$: $1 < @ $2 . > $3
88438032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
88564562Sgshapiro`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
88664562Sgshapiro`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
88764562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
88864562Sgshapirodnl virtual hosts are also canonical
88964562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
89064562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
89190792Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
89290792Sgshapiro`dnl')
89390792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
89490792Sgshapirodnl hosts for genericstable are also canonical
89590792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_',
89690792Sgshapiro`R$* < @ $* $=G > $* 	$: $1 < @ $2 $3 . > $4',
89764562Sgshapiro`R$* < @ $=G > $* 	$: $1 < @ $2 . > $3')',
89864562Sgshapiro`dnl')
89938032Speterdnl remove superfluous dots (maybe repeatedly) which may have been added
90038032Speterdnl by one of the rules before
90138032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
90238032Speter
90338032Speter
90438032Speter##################################################
90564562Sgshapiro###  Ruleset 4 -- Final Output Post-rewriting  ###
90638032Speter##################################################
90771345SgshapiroSfinal=4
90838032Speter
90938032SpeterR$+ :; <@>		$@ $1 :				handle <list:;>
91038032SpeterR$* <@>			$@				handle <> and list:;
91138032Speter
91238032Speter# strip trailing dot off possibly canonical name
91364562SgshapiroR$* < @ $+ . > $*	$1 < @ $2 > $3
91438032Speter
91538032Speter# eliminate internal code
91638032SpeterR$* < @ *LOCAL* > $*	$1 < @ $j > $2
91738032Speter
91838032Speter# externalize local domain info
91938032SpeterR$* < $+ > $*		$1 $2 $3			defocus
92038032SpeterR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
92138032SpeterR@ $*			$@ @ $1				... and exit
92238032Speter
92338032Speterifdef(`_NO_UUCP_', `dnl',
92438032Speter`# UUCP must always be presented in old form
92538032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
92638032Speter
92738032Speterifdef(`_USE_DECNET_SYNTAX_',
92838032Speter`# put DECnet back in :: form
92938032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
93038032Speter	`dnl')
93138032Speter# delete duplicate local names
93238032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
93338032Speter
93438032Speter
93538032Speter
93638032Speter##############################################################
93738032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
93838032Speter###		   (used for recursive calls)		   ###
93964562Sgshapiro##############################################################
94064562Sgshapiro
94164562SgshapiroSRecurse=97
94238032SpeterR$*			$: $>canonify $1
94338032SpeterR$*			$@ $>parse $1
94438032Speter
94538032Speter
94638032Speter######################################
94738032Speter###   Ruleset 0 -- Parse Address   ###
94864562Sgshapiro######################################
94938032Speter
95038032SpeterSparse=0
95138032Speter
95264562SgshapiroR$*			$: $>Parse0 $1		initial parsing
95338032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
95438032SpeterR$*			$: $>ParseLocal $1	handle local hacks
95538032SpeterR$*			$: $>Parse1 $1		final parsing
95638032Speter
95738032Speter#
95838032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
95938032Speter#	This should either return with the (possibly modified) input
96038032Speter#	or return with a #error mailer.  It should not return with a
96138032Speter#	#mailer other than the #error mailer.
96238032Speter#
96338032Speter
96490792SgshapiroSParse0
96564562SgshapiroR<@>			$@ <@>			special case error msgs
96690792SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
96790792SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
96838032SpeterR<@ $+>			$#error $@ 5.1.3 $: "_CODE553 User address required"
96990792SgshapiroR$+ <@>			$#error $@ 5.1.3 $: "_CODE553 Hostname required"
97090792SgshapiroR$*			$: <> $1
97190792Sgshapirodnl allow tricks like [host1]:[host2]
97290792SgshapiroR<> $* < @ [ $* ] : $+ > $*	$1 < @ [ $2 ] : $3 > $4
97390792SgshapiroR<> $* < @ [ $* ] , $+ > $*	$1 < @ [ $2 ] , $3 > $4
97490792Sgshapirodnl but no a@[b]c
97590792SgshapiroR<> $* < @ [ $* ] $+ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid address"
97638032SpeterR<> $* < @ [ $+ ] > $*		$1 < @ [ $2 ] > $3
97790792SgshapiroR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
97890792SgshapiroR<> $*			$1
97990792SgshapiroR$* < @ . $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
98090792SgshapiroR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
98190792Sgshapirodnl no a@b@
98290792SgshapiroR$* < @ $* @ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid route address"
98364562Sgshapirodnl no a@b@c
98490792SgshapiroR$* @ $* < @ $* > $*	$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
98538032Speterdnl comma only allowed before @; this check is not complete
98690792SgshapiroR$* , $~O $*		$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
98790792Sgshapiro
98890792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks
98990792SgshapiroR$* . < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
99090792SgshapiroR. $* < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
99138032Speterdnl', `dnl')
99264562Sgshapiro
99364562Sgshapiro# now delete the local info -- note $=O to find characters that cause forwarding
99438032SpeterR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
99590792SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
99664562SgshapiroR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
99738032SpeterR< @ $+ >		$#error $@ 5.1.3 $: "_CODE553 User address required"
99890792SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
99938032SpeterR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
100064562SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "_CODE553 User address required"
100138032SpeterR$* $=O $* < @ *LOCAL* >
100238032Speter			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
100338032SpeterR$* < @ *LOCAL* >	$: $1
100438032Speter
100538032Speter#
100638032Speter#  Parse1 -- the bottom half of ruleset 0.
100738032Speter#
100864562Sgshapiro
100964562SgshapiroSParse1
101090792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
101190792Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute}
101264562SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
101364562SgshapiroR$+ < @ $={LDAPRouteEquiv} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
101438032Speter`dnl')
101538032Speter
101664562Sgshapiroifdef(`_MAILER_smtp_',
101764562Sgshapiro`# handle numeric address spec
101864562Sgshapirodnl there is no check whether this is really an IP number
101990792SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
102064562SgshapiroR$* < @ [ $+ ] > $*	$1 < @ [ $2 ] : $S > $3		Add smart host to path
102164562SgshapiroR$* < @ [ $+ ] : > $*		$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
102238032SpeterR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
102338032SpeterR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
102464562Sgshapiro	`dnl')
102538032Speter
102690792Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
102790792Sgshapiro# handle virtual users
102890792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
102990792Sgshapirodnl this is not a documented option
103090792Sgshapirodnl it stops looping in virtusertable mapping if input and output
103190792Sgshapirodnl are identical, i.e., if address A is mapped to A.
103290792Sgshapirodnl it does not deal with multi-level recursion
103390792Sgshapiro# handle full domains in RHS of virtusertable
103490792SgshapiroR$+ < @ $+ >			$: $(macro {RecipientAddress} $) $1 < @ $2 >
103590792SgshapiroR$+ < @ $+ > 			$: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
103690792SgshapiroR<?> $+ $| $+			$: $1 $(macro {RecipientAddress} $@ $2 $)
103764562SgshapiroR<?> $+ $| $*			$: $1',
103890792Sgshapiro`dnl')
103964562SgshapiroR$+			$: <!> $1		Mark for lookup
104064562Sgshapirodnl input: <!> local<@domain>
104164562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
104290792Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
104364562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
104490792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
104590792SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
104690792Sgshapirodnl if <@> local<@domain>: no match but try lookup
104790792Sgshapirodnl user+detail: try user++@domain if detail not empty
104890792SgshapiroR<@> $+ + $+ < @ $* . >
104938032Speter			$: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105090792Sgshapirodnl user+detail: try user+*@domain
105190792SgshapiroR<@> $+ + $* < @ $* . >
105238032Speter			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105390792Sgshapirodnl user+detail: try user@domain
105464562SgshapiroR<@> $+ + $* < @ $* . >
105590792Sgshapiro			$: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105690792Sgshapirodnl try default entry: @domain
105764562Sgshapirodnl ++@domain
105890792SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105964562Sgshapirodnl +*@domain
106098121SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
106198121Sgshapirodnl @domain if +detail exists
106298121Sgshapirodnl if no match, change marker to prevent a second @domain lookup
106338032SpeterR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . >
106490792Sgshapirodnl without +detail
106538032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
106690792Sgshapirodnl no match
106764562SgshapiroR<@> $+			$: $1
106864562Sgshapirodnl remove mark
106938032SpeterR<!> $+			$: $1
107090792SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
107190792SgshapiroR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
107290792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
107390792Sgshapiro# check virtuser input address against output address, if same, skip recursion
107490792SgshapiroR< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
107590792Sgshapiro# it is the same: stop now
107690792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
107780785SgshapiroR< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
107880785Sgshapirodnl', `dnl')
107977349Sgshapirodnl this is not a documented option
108077349Sgshapirodnl it performs no looping at all for virtusertable
108177349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_',
108277349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
108338032Speter`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
108438032Speterdnl', `dnl')
108538032Speter
108664562Sgshapiro# short circuit local delivery so forwarded email works
108766494Sgshapiroifdef(`_MAILER_usenet_', `dnl
108866494SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
108938032Speter
109038032Speter
109164562Sgshapiroifdef(`_STICKY_LOCAL_DOMAIN_',
109264562Sgshapiro`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
109338032SpeterR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
109438032Speterdnl $H empty (but @$=w.)
109564562SgshapiroR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
109638032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
109738032Speter`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
109864562SgshapiroR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
109938032Speter
110038032Speterifdef(`_MAILER_TABLE_', `dnl
110138032Speter# not local -- try mailer table lookup
110238032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
110364562SgshapiroR< $+ . > $*		$: < $1 > $2			strip trailing dot
110464562SgshapiroR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
110564562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
110638032SpeterR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
110764562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
110838032Speter`dnl')
110938032Speterundivert(4)dnl UUCP rules from `MAILER(uucp)'
111038032Speter
111138032Speterifdef(`_NO_UUCP_', `dnl',
111264562Sgshapiro`# resolve remotely connected UUCP links (if any)
111338032Speterifdef(`_CLASS_V_',
111438032Speter`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
111564562Sgshapiro	`dnl')
111638032Speterifdef(`_CLASS_W_',
111738032Speter`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
111864562Sgshapiro	`dnl')
111938032Speterifdef(`_CLASS_X_',
112038032Speter`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
112138032Speter	`dnl')')
112238032Speter
112364562Sgshapiro# resolve fake top level domains by forwarding to other hosts
112438032Speterifdef(`BITNET_RELAY',
112538032Speter`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
112664562Sgshapiro	`dnl')
112738032Speterifdef(`DECNET_RELAY',
112838032Speter`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
112938032Speter	`dnl')
113038032Speterifdef(`_MAILER_pop_',
113138032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
113238032Speter	`dnl')
113338032Speterifdef(`_MAILER_fax_',
113464562Sgshapiro`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
113538032Speter`ifdef(`FAX_RELAY',
113638032Speter`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
113738032Speter	`dnl')')
113838032Speter
113964562Sgshapiroifdef(`UUCP_RELAY',
114038032Speter`# forward non-local UUCP traffic to our UUCP relay
114138032SpeterR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
114238032Speter`ifdef(`_MAILER_uucp_',
114338032Speter`# forward other UUCP traffic straight to UUCP
114438032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
114538032Speter	`dnl')')
114664562Sgshapiroifdef(`_MAILER_usenet_', `
114738032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
114838032SpeterR$+ . USENET		$#usenet $@ usenet $: $1',
114938032Speter	`dnl')
115038032Speter
115138032Speterifdef(`_LOCAL_RULES_',
115238032Speter`# figure out what should stay in our local mail system
115338032Speterundivert(1)', `dnl')
115464562Sgshapiro
115538032Speter# pass names that still have a host to a smarthost (if defined)
115638032SpeterR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
115738032Speter
115864562Sgshapiro# deal with other remote names
115990792Sgshapiroifdef(`_MAILER_smtp_',
116038032Speter`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
116138032Speter`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
116264562Sgshapiro
116338032Speter# handle locally delivered names
116438032SpeterR$=L			$#_LOCAL_ $: @ $1		special local names
116538032SpeterR$+			$#_LOCAL_ $: $1			regular local names
116638032Speter
116738032Speter###########################################################################
116838032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
116964562Sgshapiro###########################################################################
117064562Sgshapiro
117164562SgshapiroSLocal_localaddr
117290792SgshapiroSlocaladdr=5
117364562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
117464562SgshapiroR$+ $| $#ok		$@ $1			no change
117538032SpeterR$+ $| $#$*		$#$2
117690792SgshapiroR$+ $| $*		$: $1
117790792Sgshapiro
117890792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
117990792Sgshapiro# Preserve rcpt_host in {Host}
118090792SgshapiroR$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
118190792SgshapiroR$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
118295154SgshapiroR$+ $| $| $+		$: $1			h not set, {Host} set
118390792SgshapiroR$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
118490792SgshapiroR$+ $| $* @ $+ $| $*	$: $(macro {Host} $@ @$3 $) $1	set {Host} to host in h
118590792SgshapiroR$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
118690792Sgshapiro')dnl
118766494Sgshapiro
118866494Sgshapiroifdef(`_FFR_5_', `dnl
118966494Sgshapiro# Preserve host in a macro
119066494SgshapiroR$+			$: $(macro {LocalAddrHost} $) $1
119190792SgshapiroR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
119238032Speter
119366494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
119466494Sgshapiro# deal with plussed users so aliases work nicely
119566494SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
119638032SpeterR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
119738032Speter')
119838032Speter# prepend an empty "forward host" on the front
119938032SpeterR$+			$: <> $1
120038032Speter
120190792Sgshapiroifdef(`LUSER_RELAY', `dnl
120266494Sgshapiro# send unrecognized local users to a relay host
120366494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
120466494SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
120566494SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
120664562SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
120790792SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
120890792SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
120990792SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')
121090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
121138032SpeterR< $+ > $+		$: < $1 > $2 $&{Host}')
121290792Sgshapirodnl')
121390792Sgshapiro
121490792Sgshapiroifdef(`MAIL_HUB', `dnl
121590792SgshapiroR< > $+			$: < $H > $1			try hub', `dnl')
121690792Sgshapiroifdef(`LOCAL_RELAY', `dnl
121790792SgshapiroR< > $+			$: < $R > $1			try relay', `dnl')
121864562Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
121990792SgshapiroR< > $+			$@ $1', `dnl
122090792SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
122164562Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
122264562SgshapiroR< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
122338032SpeterR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
122466494SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
122538032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
122643730SpeterR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
122790792SgshapiroR< > < $+ >		$@ $1				no +detail
122890792SgshapiroR$+			$: $1 <> $&h			add +detail back in
122943730Speterifdef(`_PRESERVE_LUSER_HOST_', `dnl
123066494SgshapiroR$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
123164562SgshapiroR$+ <> + $*		$: $1 + $2			check whether +detail
123264562SgshapiroR$+ <> $*		$: $1				else discard')
123390792SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
123490792SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
123590792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
123690792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
123790792SgshapiroR< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
123890792SgshapiroR< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
123964562Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
124038032SpeterR< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
124164562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
124290792Sgshapiro
124338032Speterifdef(`_MAILER_TABLE_', `dnl
124490792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
124590792Sgshapiro###################################################################
124690792Sgshapiro###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
124790792Sgshapirodnl input: <Domain> FullAddress
124890792Sgshapiro###################################################################
124990792Sgshapiro
125090792SgshapiroSLDAPMailertable
125190792SgshapiroR< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
125290792SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
125390792SgshapiroR< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
125490792SgshapiroR< $+ > $#$*		$#$2					found
125590792SgshapiroR< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
125690792Sgshapiro`dnl')
125738032Speter
125864562Sgshapiro###################################################################
125938032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
126038032Speterdnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
126164562Sgshapiro###################################################################
126264562Sgshapiro
126364562SgshapiroSMailertable=90
126438032Speterdnl shift and check
126564562Sgshapirodnl %2 is not documented in cf/README
126664562SgshapiroR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
126764562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
126864562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
126938032SpeterR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
127064562Sgshapirodnl is $2 always empty?
127164562SgshapiroR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
127238032SpeterR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
127338032Speterdnl return full address
127438032SpeterR< $* > $*		$@ $2				no mailertable match',
127538032Speter`dnl')
127638032Speter
127764562Sgshapiro###################################################################
127864562Sgshapiro###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
127964562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
128064562Sgshapirodnl	<> address				-> address
128164562Sgshapirodnl	<error:d.s.n:text>			-> error
128264562Sgshapirodnl	<error:text>				-> error
128364562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
128464562Sgshapirodnl	<mailer:host> address			-> mailer host address
128538032Speterdnl	<localdomain> address			-> address
128638032Speterdnl	<host> address				-> relay host address
128764562Sgshapiro###################################################################
128838032Speter
128964562SgshapiroSMailerToTriple=95
129038032SpeterR< > $*				$@ $1			strip off null relay
129138032SpeterR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
129290792SgshapiroR< error : $- $+ > $*		$#error $@ $(dequote $1 $) $: $2
129390792SgshapiroR< local : $* > $*		$>CanonLocal < $1 > $2
129490792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
129538032SpeterR< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
129638032SpeterR< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
129738032SpeterR< $=w > $*			$@ $2			delete local host
129838032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
129938032Speter
130064562Sgshapiro###################################################################
130164562Sgshapiro###  Ruleset CanonLocal -- canonify local: syntax		###
130264562Sgshapirodnl input: <user> address
130364562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
130464562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
130564562Sgshapirodnl <> user <@host> rest		-> local user@host user
130664562Sgshapirodnl <> user				-> local user user
130764562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
130838032Speterdnl <user> lp <@host> rest		-> local lp@host user
130938032Speterdnl <user> lp				-> local lp user
131038032Speter###################################################################
131143730Speter
131264562SgshapiroSCanonLocal
131364562Sgshapiro# strip local host from routed addresses
131443730SpeterR< $* > < @ $+ > : $+		$@ $>Recurse $3
131538032SpeterR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
131638032Speter
131738032Speter# strip trailing dot from any host name that may appear
131838032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
131938032Speter
132038032Speter# handle local: syntax -- use old user, either with or without host
132138032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
132238032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
132338032Speter
132438032Speter# handle local:user@host syntax -- ignore host part
132538032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
132638032Speter
132738032Speter# handle local:user syntax
132838032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
132938032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
133038032Speter
133138032Speter###################################################################
133238032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
133364562Sgshapiro###################################################################
133438032Speter
133564562SgshapiroSMasqHdr=93
133638032Speter
133738032Speterifdef(`_GENERICS_TABLE_', `dnl
133864562Sgshapiro# handle generics database
133938032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
134038032Speterdnl if generics should be applied add a @ as mark
134138032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
134264562Sgshapiro`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
134364562SgshapiroR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
134464562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
134590792Sgshapirodnl ignore the first case for now
134664562Sgshapirodnl if it has the mark lookup full address
134764562Sgshapirodnl broken: %1 is full address not just detail
134864562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
134964562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
135064562Sgshapirodnl no match, try user+detail@domain
135164562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
135264562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
135364562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
135464562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
135564562Sgshapirodnl no match, remove mark
135664562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
135764562Sgshapirodnl no match, try @domain for exceptions
135864562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
135938032Speterdnl workspace: ... or <match> user <@domain>
136064562Sgshapirodnl no match, try local part
136164562SgshapiroR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
136264562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
136364562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
136438032SpeterR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
136538032SpeterR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
136638032SpeterR< > $*			$: $1				not found',
136764562Sgshapiro`dnl')
136864562Sgshapiro
136964562Sgshapiro# do not masquerade anything in class N
137090792SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
137138032Speter
137238032Speterifdef(`MASQUERADE_NAME', `dnl
137338032Speter# special case the users that should be exposed
137438032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
137538032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
137638032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
137738032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
137838032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
137938032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
138038032Speter
138138032Speter# handle domain-specific masquerading
138238032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
138338032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
138438032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
138538032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
138638032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
138738032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
138890792SgshapiroR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
138990792SgshapiroR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
139090792Sgshapirodnl', `dnl no masquerading
139138032Speterdnl just fix *LOCAL* leftovers
139238032SpeterR$* < @ *LOCAL* >	$@ $1 < @ $j . >')
139338032Speter
139438032Speter###################################################################
139538032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
139664562Sgshapiro###################################################################
139738032Speter
139864562SgshapiroSMasqEnv=94
139938032Speterifdef(`_MASQUERADE_ENVELOPE_',
140038032Speter`R$+			$@ $>MasqHdr $1',
140138032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
140238032Speter
140338032Speter###################################################################
140438032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
140564562Sgshapiro###################################################################
140664562Sgshapiro
140738032SpeterSParseLocal=98
140864562Sgshapiroundivert(3)dnl LOCAL_RULE_0
140990792Sgshapiro
141090792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
141190792Sgshapiro######################################################################
141290792Sgshapiro###  LDAPExpand: Expand address using LDAP routing
141390792Sgshapiro###
141490792Sgshapiro###	Parameters:
141590792Sgshapiro###		<$1> -- parsed address (user < @ domain . >) (pass through)
141690792Sgshapiro###		<$2> -- RFC822 address (user @ domain) (used for lookup)
141790792Sgshapiro###		<$3> -- +detail information
141890792Sgshapiro###
141990792Sgshapiro###	Returns:
142090792Sgshapiro###		Mailer triplet ($#mailer $@ host $: address)
142190792Sgshapiro###		Parsed address (user < @ domain . >)
142264562Sgshapiro######################################################################
142364562Sgshapiro
142490792SgshapiroSLDAPExpand
142564562Sgshapiro# do the LDAP lookups
142694334SgshapiroR<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
1427102528Sgshapiro
1428102528Sgshapiro# look for temporary failures (return original address, MTA will queue up)
142994334SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*>	$@ $3
143064562SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*>	$@ $3
143164562Sgshapiro
143290792Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
143390792Sgshapiro# return the new mailRoutingAddress
143490792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
143590792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
143690792SgshapiroR<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
143764562SgshapiroR<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
143898121SgshapiroR<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
143964562Sgshapiro
144064562Sgshapiro
144190792Sgshapiro# if mailRoutingAddress and non-local mailHost,
144290792Sgshapiro# relay to mailHost with new mailRoutingAddress
144390792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
144490792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
144590792Sgshapiro# check mailertable for host, relay from there
144690792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
144790792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
144890792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
144990792Sgshapiro# check mailertable for host, relay from there
145064562SgshapiroR<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
145164562Sgshapiro`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
145264562Sgshapiro
145390792Sgshapiro# if no mailRoutingAddress and local mailHost,
145464562Sgshapiro# return original address
145598121SgshapiroR<> <$=w> <$+> <$+> <$*>	$@ $2
145664562Sgshapiro
145764562Sgshapiro
145890792Sgshapiro# if no mailRoutingAddress and non-local mailHost,
145990792Sgshapiro# relay to mailHost with original address
146090792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
146190792Sgshapiro# check mailertable for host, relay from there
146264562SgshapiroR<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
146390792Sgshapiro`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
146490792Sgshapiro
146590792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_',
146690792Sgshapiro`# if no mailRoutingAddress and no mailHost,
146790792Sgshapiro# try without +detail
146890792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
146964562Sgshapiro
147090792Sgshapiro# if still no mailRoutingAddress and no mailHost,
147190792Sgshapiro# try @domain
147290792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
147364562SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
147464562SgshapiroR<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>
147564562Sgshapiro
147664562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
147790792Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
147890792Sgshapiro# user does not exist
147990792SgshapiroR<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
148090792Sgshapiro# only give error for envelope recipient
148164562SgshapiroR<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
148264562SgshapiroR<?> <$*> <$+>			$@ $2',
148390792Sgshapiro`dnl
148464562Sgshapiro# return the original address
148564562SgshapiroR<> <> <$+> <@ $+> <$*>		$@ $1')',
148664562Sgshapiro`dnl')
148764562Sgshapiro
148890792Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
148938032Speter')')
149090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
149138032Speter######################################################################
149238032Speter###  D: LookUpDomain -- search for domain in access database
149338032Speter###
149438032Speter###	Parameters:
149564562Sgshapiro###		<$1> -- key (domain name)
149690792Sgshapiro###		<$2> -- default (what to return if not found in db)
149764562Sgshapirodnl			must not be empty
149864562Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
149990792Sgshapiro###			! does lookup only with tag
150064562Sgshapiro###			+ does lookup with and without tag
150164562Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
150238032Speterdnl returns:		<default> <passthru>
150338032Speterdnl 			<result> <passthru>
150490792Sgshapiro######################################################################
150564562Sgshapiro
150664562SgshapiroSD
150790792Sgshapirodnl workspace <key> <default> <passthru> <mark>
150890792Sgshapirodnl lookup with tag (in front, no delimiter here)
150964562Sgshapirodnl    2    3  4    5
151064562SgshapiroR<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
151190792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
151290792Sgshapirodnl lookup without tag?
151390792Sgshapirodnl   1    2      3    4
151490792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
151590792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
151690792Sgshapirodnl XXX apply this also to IP addresses?
151790792Sgshapirodnl currently it works the wrong way round for [1.2.3.4]
151890792Sgshapirodnl   1  2    3    4  5    6
151990792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
152090792Sgshapirodnl   1  2    3      4    5
152190792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
152290792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
152390792Sgshapirodnl found SKIP: return <default> and <passthru>
152490792Sgshapirodnl      1    2    3  4    5
152590792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
152690792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!)
152790792Sgshapirodnl    1  2     3    4  5    6
152890792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
152990792Sgshapiroifdef(`NO_NETINET6', `dnl',
153090792Sgshapiro`dnl not found: IPv6 net
153190792Sgshapirodnl (could be merged with previous rule if we have a class containing .:)
153290792Sgshapirodnl    1   2     3    4  5    6
153364562SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
153490792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
153590792Sgshapirodnl not found, but subdomain: try again
153690792Sgshapirodnl   1  2    3    4  5    6
153790792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
153890792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
153990792Sgshapirodnl   1    2      3    4
154090792SgshapiroR<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
154190792Sgshapirodnl not found, no subdomain: return <default> and <passthru>
154290792Sgshapirodnl   1    2    3  4    5
154390792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
154490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
154590792Sgshapirodnl            2    3    4  5    6
154690792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
154790792Sgshapirodnl return <result of lookup> and <passthru>
154838032Speterdnl    2    3    4  5    6
154938032SpeterR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
155090792Sgshapiro
155138032Speter######################################################################
155238032Speter###  A: LookUpAddress -- search for host address in access database
155338032Speter###
155438032Speter###	Parameters:
155564562Sgshapiro###		<$1> -- key (dot quadded host address)
155690792Sgshapiro###		<$2> -- default (what to return if not found in db)
155764562Sgshapirodnl			must not be empty
155864562Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
155990792Sgshapiro###			! does lookup only with tag
156064562Sgshapiro###			+ does lookup with and without tag
156164562Sgshapiro###		<$4> -- passthru (additional data passed through)
156238032Speterdnl	returns:	<default> <passthru>
156338032Speterdnl			<result> <passthru>
156490792Sgshapiro######################################################################
156564562Sgshapiro
156690792SgshapiroSA
156790792Sgshapirodnl lookup with tag
156864562Sgshapirodnl    2    3  4    5
156990792SgshapiroR<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
157090792Sgshapirodnl lookup without tag
157190792Sgshapirodnl   1    2      3    4
157290792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
157390792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
157490792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
157590792Sgshapirodnl found SKIP: return <default> and <passthru>
157690792Sgshapirodnl      1    2    3  4    5
157790792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
157890792Sgshapiroifdef(`NO_NETINET6', `dnl',
157990792Sgshapiro`dnl no match; IPv6: remove last part
158090792Sgshapirodnl   1   2    3    4  5    6
158164562SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
158290792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
158390792Sgshapirodnl no match; IPv4: remove last part
158464562Sgshapirodnl   1  2    3    4  5    6
158590792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
158690792Sgshapirodnl no match: return default
158790792Sgshapirodnl   1    2    3  4    5
158890792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
158990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
159064562Sgshapirodnl            2    3    4  5    6
159190792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
159290792Sgshapirodnl match: return result
159390792Sgshapirodnl    2    3    4  5    6
159490792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
159538032Speterdnl endif _ACCESS_TABLE_
159642575Speterdivert(0)
159742575Speter######################################################################
159842575Speter###  CanonAddr --	Convert an address into a standard form for
159942575Speter###			relay checking.  Route address syntax is
160042575Speter###			crudely converted into a %-hack address.
160142575Speter###
160242575Speter###	Parameters:
160342575Speter###		$1 -- full recipient address
160442575Speter###
160564562Sgshapiro###	Returns:
160664562Sgshapiro###		parsed address, not in source route form
160742575Speterdnl		user%host%host<@domain>
160842575Speterdnl		host!user<@domain>
160942575Speter######################################################################
161064562Sgshapiro
161164562SgshapiroSCanonAddr
161242575SpeterR$*			$: $>Parse0 $>canonify $1	make domain canonical
161342575Speterifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
161442575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
161564562SgshapiroR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
161642575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
161742575Speterdnl')
161838032Speter
161938032Speter######################################################################
162038032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
162138032Speter###			$* $=m or the access database.
162238032Speter###			Check user portion for host separators.
162338032Speter###
162438032Speter###	Parameters:
162538032Speter###		$1 -- full recipient address
162638032Speter###
162738032Speter###	Returns:
162838032Speter###		parsed, non-local-relaying address
162938032Speter######################################################################
163064562Sgshapiro
163142575SpeterSParseRecipient
163264562Sgshapirodnl mark and canonify address
163342575SpeterR$*				$: <?> $>CanonAddr $1
163464562Sgshapirodnl workspace: <?> localpart<@domain[.]>
163542575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
163638032Speterdnl workspace: <?> localpart<@domain>
163738032SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
163842575Speter
163964562Sgshapiro# if no $=O character, no host in the user portion, we are done
164042575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
164138032Speterdnl no $=O in localpart: return
164290792SgshapiroR<?> $*				$@ $1
164364562Sgshapiro
164438032Speterdnl workspace: <NO> localpart<@domain>, where localpart contains $=O
164538032Speterdnl mark everything which has an "authorized" domain with <RELAY>
164642575Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
164764562Sgshapiro# if we relay, check username portion for user%host so host can be checked also
164864562SgshapiroR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
164990792Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
165090792Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
165190792Sgshapiro
165290792Sgshapirodnl what if access map returns something else than RELAY?
165390792Sgshapirodnl we are only interested in RELAY entries...
165438032Speterdnl other To: entries: blacklist recipient; generic entries?
165542575Speterdnl if it is an error we probably do not want to relay anyway
165664562Sgshapiroifdef(`_RELAY_HOSTS_ONLY_',
165764562Sgshapiro`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
165842575Speterifdef(`_ACCESS_TABLE_', `dnl
165942575SpeterR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
166064562SgshapiroR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
166190792Sgshapiro`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
166242575Speterifdef(`_ACCESS_TABLE_', `dnl
166338032SpeterR<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
166464562SgshapiroR<$+> <$+>			$: <$1> $2',`dnl')')
166590792Sgshapiro
166690792Sgshapiro
166790792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl
166890792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
166990792SgshapiroR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
167090792SgshapiroR<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
167190792Sgshapirodnl yes: mark it as <RELAY>
167290792SgshapiroR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
167390792Sgshapirodnl no: put old <NO> mark back
167490792SgshapiroR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
167542575Speter
167690792Sgshapirodnl do we relay to this recipient domain?
167790792SgshapiroR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
167842575Speterdnl something else
167964562SgshapiroR<$+> $*			$@ $2
168038032Speter
168138032Speter
168238032Speter######################################################################
168338032Speter###  check_relay -- check hostname/address on SMTP startup
168438032Speter######################################################################
168564562Sgshapiro
168638032SpeterSLocal_check_relay
168738032SpeterScheck`'_U_`'relay
168838032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
168938032SpeterR$* $| $* $| $#$*	$#$3
169038032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
169138032Speter
169298121SgshapiroSBasic_check_relay
169338032Speter# check for deferred delivery mode
169438032SpeterR$*			$: < $&{deliveryMode} > $1
169538032SpeterR< d > $*		$@ deferred
169664562SgshapiroR< $* > $*		$: $2
169766494Sgshapiro
169890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
169966494Sgshapirodnl workspace: {client_name} $| {client_addr}
170090792SgshapiroR$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
170190792Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
170290792Sgshapirodnl OR $| $+ if client_name is empty
170390792SgshapiroR   $| $+		$: $>A < $1 > <?> <+ Connect> <>	empty client_name
170490792Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
170590792SgshapiroR<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
170690792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>)
170790792SgshapiroR<?> <$*>		$: OK				found nothing
170890792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
170964562SgshapiroR<$={Accept}> <$*>	$@ $1				return value of lookup
171066494SgshapiroR<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
171166494SgshapiroR<DISCARD> <$*>		$#discard $: discard
171290792Sgshapiroifdef(`_FFR_QUARANTINE',
171364562Sgshapiro`R<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1', `dnl')
171466494Sgshapirodnl error tag
171538032SpeterR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
171664562SgshapiroR<ERROR:$+> <$*>		$#error $: $1
171764562Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
171890792Sgshapirodnl generic error from access map
171938032SpeterR<$+> <$*>		$#error $: $1', `dnl')
172064562Sgshapiro
172164562Sgshapiroifdef(`_RBL_',`dnl
172298121Sgshapiro# DNS based IP address spam list
172338032Speterdnl workspace: ignored...
172464562SgshapiroR$*			$: $&{client_addr}
172538032SpeterR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
172638032SpeterR<?>OK			$: OKSOFAR
172738032SpeterR<?>$+			$#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"',
172838032Speter`dnl')
172938032Speterundivert(8)
173038032Speter
173164562Sgshapiro######################################################################
173238032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
173338032Speter######################################################################
173438032Speter
173538032SpeterSLocal_check_mail
173638032SpeterScheck`'_U_`'mail
173738032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
173898121SgshapiroR$* $| $#$*		$#$2
173938032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
174038032Speter
174138032SpeterSBasic_check_mail
174264562Sgshapiro# check for deferred delivery mode
174364562SgshapiroR$*			$: < $&{deliveryMode} > $1
174464562SgshapiroR< d > $*		$@ deferred
174564562SgshapiroR< $* > $*		$: $2
174664562Sgshapiro
174764562Sgshapiro# authenticated?
174864562Sgshapirodnl done first: we can require authentication for every mail transaction
174938032Speterdnl workspace: address as given by MAIL FROM: (sender)
175064562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
175164562SgshapiroR$* $| $#$+		$#$2
175238032Speterdnl undo damage: remove result of tls_client call
175364562SgshapiroR$* $| $*		$: $1
175464562Sgshapiro
175564562Sgshapirodnl workspace: address as given by MAIL FROM:
175664562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
175764562Sgshapiroifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
175864562Sgshapirodnl do some additional checks
175964562Sgshapirodnl no user@host
176064562Sgshapirodnl no user@localhost (if nonlocal sender)
176164562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
176264562Sgshapirodnl just make sure the address has <> around it (which is required by
176364562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
176464562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
176564562Sgshapirodnl not be modified by host lookups.
176664562SgshapiroR$+			$: <?> $1
176764562SgshapiroR<?><$+>		$: <@> <$1>
176864562SgshapiroR<?>$+			$: <@> <$1>
176964562Sgshapirodnl workspace: <@> <address>
177064562Sgshapirodnl prepend daemon_flags
177164562SgshapiroR$*			$: $&{daemon_flags} $| $1
177264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
177364562Sgshapirodnl do not allow these at all or only from local systems?
177464562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
177564562Sgshapirodnl accept unqualified sender: change mark to avoid test
177664562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
177738032Speterdnl workspace: ${daemon_flags} $| <@> <address>
177864562Sgshapirodnl        or:                    <? ${client_name} > <address>
177964562Sgshapirodnl        or:                    <?> <address>
178064562Sgshapirodnl remove daemon_flags
178164562SgshapiroR$* $| $*		$: $2
178264562Sgshapiro# handle case of @localhost on address
178338032SpeterR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
178464562SgshapiroR<@> < $* @ [127.0.0.1] >
178564562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
178664562SgshapiroR<@> < $* @ localhost.$m >
178764562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
178864562Sgshapiroifdef(`_NO_UUCP_', `dnl',
178964562Sgshapiro`R<@> < $* @ localhost.UUCP >
179064562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
179164562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
179264562Sgshapirodnl	or:    <@> <address>
179364562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
179490792SgshapiroR<@> $*			$: $1			no localhost as domain
179564562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
179664562Sgshapirodnl	or:    <address>
179764562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
179864562SgshapiroR<? $=w> $*		$: $2			local client: ok
179964562SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
180064562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
180164562SgshapiroR<?> $*			$: $1')
180264562Sgshapirodnl workspace: address (or <address>)
1803102528SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
180464562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
180598121Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
1806102528SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
180764562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
180890792SgshapiroR<?> $* < @ $* $=P >	$: <_RES_OK_> $1 < @ $2 $3 >
180964562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
181064562Sgshapirodnl A sender address with my local host name ($j) is safe
181164562SgshapiroR<?> $* < @ $j >	$: <_RES_OK_> $1 < @ $j >
181290792Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
181364562Sgshapiro`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
181438032Speter`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
181564562SgshapiroR<? $* <$->> $* < @ $+ >
181664562Sgshapiro			$: <$2> $3 < @ $4 >')
181764562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
181890792Sgshapirodnl mark is ? iff the address is user (wo @domain)
181990792Sgshapiro
182064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
182164562Sgshapiro# check sender address: user@address, user@, address
182264562Sgshapirodnl should we remove +ext from user?
182364562Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
182490792SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
182564562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
182664562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
182764562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
182838032Speterdnl will only return user<@domain when "reversing" the args
182964562SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
183064562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
183164562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
183264562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
183364562Sgshapiro# retransform for further use
183464562Sgshapirodnl required form:
183538032Speterdnl <ResultOfLookup|mark> CanonicalAddress
183638032SpeterR<?> <$+> <$*>		$: <$1> $2	no match
183738032SpeterR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
183864562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
183964562Sgshapirodnl mark is ? iff the address is user (wo @domain)
184064562Sgshapiro
184190792Sgshapiroifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
184264562Sgshapiro# handle case of no @domain on address
184364562Sgshapirodnl prepend daemon_flags
184438032SpeterR<?> $*			$: $&{daemon_flags} $| <?> $1
1845102528Sgshapirodnl accept unqualified sender: change mark to avoid test
184690792SgshapiroR$* u $* $| <?> $*	$: <_RES_OK_> $3
184738032Speterdnl remove daemon_flags
184838032SpeterR$* $| $*		$: $2
184964562SgshapiroR<?> $*			$: < ? $&{client_addr} > $1
185090792SgshapiroR<?> $*			$@ <_RES_OK_>			...local unqualed ok
185164562SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
185290792Sgshapiro							...remote is not')
185364562Sgshapiro# check results
185490792SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
185538032SpeterR<$={ResOk}> $*		$@ <_RES_OK_>	domain ok: stop
185690792SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
185790792SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
185864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
185964562SgshapiroR<$={Accept}> $*	$# $1		accept from access map
186064562SgshapiroR<DISCARD> $*		$#discard $: discard
186164562Sgshapiroifdef(`_FFR_QUARANTINE',
186290792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
186364562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
186464562Sgshapirodnl error tag
186538032SpeterR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
186638032SpeterR<ERROR:$+> $*		$#error $: $1
186738032Speterifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
186838032Speterdnl generic error from access map
186938032SpeterR<$+> $*		$#error $: $1		error from access db',
187038032Speter`dnl')
187138032Speter
187264562Sgshapiro######################################################################
187338032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
187438032Speter######################################################################
187538032Speter
187638032SpeterSLocal_check_rcpt
187738032SpeterScheck`'_U_`'rcpt
187890792SgshapiroR$*			$: $1 $| $>"Local_check_rcpt" $1
187990792SgshapiroR$* $| $#$*		$#$2
188090792SgshapiroR$* $| $*		$@ $>"Basic_check_rcpt" $1
188138032Speter
188298121SgshapiroSBasic_check_rcpt
188338032Speter# empty address?
188438032SpeterR<>			$#error $@ nouser $: "553 User address required"
188538032SpeterR$@			$#error $@ nouser $: "553 User address required"
188664562Sgshapiro# check for deferred delivery mode
188790792SgshapiroR$*			$: < $&{deliveryMode} > $1
188890792SgshapiroR< d > $*		$@ deferred
188990792SgshapiroR< $* > $*		$: $2
189090792Sgshapiro
189190792Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
189290792Sgshapirodnl this code checks for user@host where host is not a FQHN.
189390792Sgshapirodnl it is not activated.
189490792Sgshapirodnl notice: code to check for a recipient without a domain name is
189564562Sgshapirodnl available down below; look for the same macro.
189690792Sgshapirodnl this check is done here because the name might be qualified by the
189790792Sgshapirodnl canonicalization.
189890792Sgshapiro# require fully qualified domain part?
189990792Sgshapirodnl very simple canonification: make sure the address is in < >
190064562SgshapiroR$+			$: <?> $1
190190792SgshapiroR<?> <$+>		$: <@> <$1>
190264562SgshapiroR<?> $+			$: <@> <$1>
190364562SgshapiroR<@> < postmaster >	$: postmaster
190490792SgshapiroR<@> < $* @ $+ . $+ >	$: < $1 @ $2 . $3 >
190564562Sgshapirodnl prepend daemon_flags
190664562SgshapiroR<@> $*			$: $&{daemon_flags} $| <@> $1
190790792Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
190864562Sgshapirodnl do not allow these at all or only from local systems?
190964562SgshapiroR$* r $* $| <@> < $* @ $* >	$: < ? $&{client_name} > < $3 @ $4 >
191064562SgshapiroR<?> < $* >		$: <$1>
191190792SgshapiroR<? $=w> < $* >		$: <$1>
191290792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
191390792Sgshapirodnl remove daemon_flags for other cases
191490792SgshapiroR$* $| <@> $*		$: $2', `dnl')
191590792Sgshapiro
191690792Sgshapirodnl ##################################################################
191790792Sgshapirodnl call subroutines for recipient and relay
191890792Sgshapirodnl possible returns from subroutines:
191990792Sgshapirodnl $#TEMP	temporary failure
192090792Sgshapirodnl $#error	permanent failure (or temporary if from access map)
192190792Sgshapirodnl $#other	stop processing
192290792Sgshapirodnl RELAY	RELAYing allowed
192390792Sgshapirodnl other	otherwise
192490792Sgshapiro######################################################################
192590792SgshapiroR$*			$: $1 $| @ $>"Rcpt_ok" $1
192690792Sgshapirodnl temporary failure? remove mark @ and remember
192790792SgshapiroR$* $| @ $#TEMP $+	$: $1 $| T $2
192890792Sgshapirodnl error or ok (stop)
192990792SgshapiroR$* $| @ $#$*		$#$2
193090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
193190792SgshapiroR$* $| @ RELAY		$@ RELAY
193290792Sgshapirodnl something else: call check sender (relay)
193390792SgshapiroR$* $| @ $*		$: O $| $>"Relay_ok" $1
193490792Sgshapirodnl temporary failure: call check sender (relay)
193590792SgshapiroR$* $| T $+		$: T $2 $| $>"Relay_ok" $1
193690792Sgshapirodnl temporary failure? return that
193790792SgshapiroR$* $| $#TEMP $+	$#error $2
193890792Sgshapirodnl error or ok (stop)
193990792SgshapiroR$* $| $#$*		$#$2
194090792SgshapiroR$* $| RELAY		$@ RELAY
194190792Sgshapirodnl something else: return previous temp failure
194290792SgshapiroR T $+ $| $*		$#error $1
194390792Sgshapiro# anything else is bogus
194490792SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
194590792Sgshapirodivert(0)
194690792Sgshapiro
194790792Sgshapiro######################################################################
194838032Speter### Rcpt_ok: is the recipient ok?
194942575Speterdnl input: recipient address (RCPT TO)
195038032Speterdnl output: see explanation at call
195138032Speter######################################################################
195238032SpeterSRcpt_ok
195342575Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
195442575SpeterR$*			$: $>CanonAddr $1
195542575SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
195642575Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
195742575Speter
195842575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
195943730Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
196090792Sgshapiro# unlimited bestmx
196142575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
196242575Speter`dnl
196342575Speter# limit bestmx to $=B
196438032SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
196564562SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
196638032SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
196738032SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
196864562Sgshapiro
196964562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl
197090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
197190792Sgshapiro# blacklist local users or any host from receiving mail
197264562SgshapiroR$*			$: <?> $1
197364562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
197464562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
197590792SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
197664562SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
197764562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
197890792Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
197990792Sgshapirodnl will only return user<@domain when "reversing" the args
198090792SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
198190792SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
198264562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
198390792Sgshapirodnl we may have to filter here because otherwise some RHSs
198490792Sgshapirodnl would be interpreted as generic error messages...
198590792Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
198690792Sgshapirodnl that would make a lot of things easier.
198764562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
198864562Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
198964562SgshapiroR<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
199064562Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
199164562Sgshapirodnl compatility with 8.11/8.10:
199264562Sgshapirodnl we have to filter these because otherwise they would be interpreted
199390792Sgshapirodnl as generic error message...
199464562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
199590792Sgshapirodnl that would make a lot of things easier.
199690792Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
199764562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
199864562SgshapiroR<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
199964562SgshapiroR<DISCARD> $*		$#discard $: discard
200090792Sgshapiroifdef(`_FFR_QUARANTINE',
200164562Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
200264562Sgshapirodnl error tag
200364562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
200438032SpeterR<ERROR:$+> $*		$#error $: $1
200590792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
200690792Sgshapirodnl generic error from access map
200790792SgshapiroR<$+> $*		$#error $: $1		error from access db
200890792SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
200990792Sgshapiro
201064562Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
201190792Sgshapiro# authenticated via TLS?
201290792SgshapiroR$*			$: $1 $| $>RelayTLS	client authenticated?
201390792SgshapiroR$* $| $# $+		$# $2			error/ok?
201490792SgshapiroR$* $| $*		$: $1			no
201590792Sgshapiro
201690792SgshapiroR$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
201790792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth
201864562SgshapiroR$* $| $# $*		$# $2
201964562Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
202064562SgshapiroR$* $| NO		$: $1
202164562SgshapiroR$* $| $*		$: $1 $| $&{auth_type}
202290792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ]
202390792Sgshapirodnl empty ${auth_type}?
202464562SgshapiroR$* $|			$: $1
202571345Sgshapirodnl mechanism ${auth_type} accepted?
202664562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
202771345SgshapiroR$* $| $={TrustAuthMech}	$# RELAY
202871345Sgshapirodnl remove ${auth_type}
202938032SpeterR$* $| $*		$: $1
203038032Speterdnl workspace: localpart<@domain> | localpart
203190792Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
203290792Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
203338032SpeterR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
203490792Sgshapiro# anything terminating locally is ok
203564562Sgshapiroifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
203664562SgshapiroR$+ < @ $* $=m >	$@ RELAY', `dnl')
203764562SgshapiroR$+ < @ $=w >		$@ RELAY
203864562Sgshapiroifdef(`_RELAY_HOSTS_ONLY_',
203990792Sgshapiro`R$+ < @ $=R >		$@ RELAY
204064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
204190792SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
204264562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
204364562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
204490792Sgshapiro`R$+ < @ $* $=R >	$@ RELAY
204590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
204638032SpeterR$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')')
204738032Speterifdef(`_ACCESS_TABLE_', `dnl
204864562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
204938032SpeterR<RELAY> $*		$@ RELAY
205038032Speterifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
205164562SgshapiroR<$*> <$*>		$: $2',`dnl')
205264562Sgshapiro
205390792Sgshapiro
205490792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl
205542575Speter# allow relaying for hosts which we MX serve
205638032SpeterR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
205738032Speterdnl this must not necessarily happen if the client is checked first...
205838032SpeterR< : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
205938032SpeterR<$* : $=w . : $*> $*	$@ RELAY
206042575SpeterR< : $* : > $*		$: $2',
206138032Speter`dnl')
206264562Sgshapiro
206364562Sgshapiro# check for local user (i.e. unqualified address)
206464562SgshapiroR$*			$: <?> $1
206564562SgshapiroR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
206664562Sgshapiro# local user is ok
206790792Sgshapirodnl is it really? the standard requires user@domain, not just user
206864562Sgshapirodnl but we should accept it anyway (maybe making it an option:
206964562Sgshapirodnl RequireFQDN ?)
207064562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
207164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
207264562SgshapiroR<?> postmaster		$@ OK
207364562Sgshapiro# require qualified recipient?
207464562Sgshapirodnl prepend daemon_flags
207564562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
207664562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
207790792Sgshapirodnl do not allow these at all or only from local systems?
207864562Sgshapirodnl r flag? add client_name
207990792SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
208064562Sgshapirodnl no r flag: relay to local user (only local part)
208190792Sgshapiro# no qualified recipient required
208264562SgshapiroR$* $| <?> $+		$@ RELAY
208364562Sgshapirodnl client_name is empty
208464562SgshapiroR<?> <?> $+		$@ RELAY
208590792Sgshapirodnl client_name is local
208664562SgshapiroR<? $=w> <?> $+		$@ RELAY
208738032Speterdnl client_name is not local
208864562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
208938032Speterdnl no qualified recipient required
209090792SgshapiroR<?> $+			$@ RELAY')
209190792Sgshapirodnl it is a remote user: remove mark and then check client
209290792SgshapiroR<$+> $*		$: $2
209390792Sgshapirodnl currently the recipient address is not used below
209490792Sgshapiro
209590792Sgshapiro######################################################################
209638032Speter### Relay_ok: is the relay/sender ok?
209764562Sgshapirodnl input: ignored
209864562Sgshapirodnl output: see explanation at call
209990792Sgshapiro######################################################################
210090792SgshapiroSRelay_ok
210190792Sgshapiro# anything originating locally is ok
210264562Sgshapiro# check IP address
210390792SgshapiroR$*			$: $&{client_addr}
210490792SgshapiroR$@			$@ RELAY		originated locally
2105102528SgshapiroR0			$@ RELAY		originated locally
2106102528SgshapiroR127.0.0.1		$@ RELAY		originated locally
2107102528SgshapiroRIPv6:::1		$@ RELAY		originated locally
2108102528SgshapiroR$=R $*			$@ RELAY		relayable IP address
2109102528Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2110102528SgshapiroR$*			$: $>A <$1> <?> <+ Connect> <$1>
211190792SgshapiroR<RELAY> $* 		$@ RELAY		relayable IP address
211264562Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl
211364562Sgshapirodnl this will cause rejections in cases like:
211490792Sgshapirodnl Connect:My.Host.Domain	RELAY
211564562Sgshapirodnl Connect:My.Net		REJECT
211664562Sgshapirodnl since in check_relay client_name is checked before client_addr
211764562SgshapiroR<REJECT> $* 		$@ REJECT		rejected IP address')
211864562Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
211964562SgshapiroR<$*> <$*>		$: $2', `dnl')
212064562SgshapiroR$*			$: [ $1 ]		put brackets around it...
212164562SgshapiroR$=w			$@ RELAY		... and see if it is local
212264562Sgshapiro
212390792Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
212464562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
212564562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
212690792Sgshapirodnl input: {client_addr} or something "broken"
212764562Sgshapirodnl just throw the input away; we do not need it.
212894334Sgshapiro# check whether FROM is allowed to use system as relay
212990792SgshapiroR$*			$: <?> $>CanonAddr $&f
213090792SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
213190792Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
213290792Sgshapiro# check whether local FROM is ok
213390792SgshapiroR<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
213464562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
213564562SgshapiroR<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <>
213664562SgshapiroR<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
213790792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
213890792Sgshapiro', `dnl
213990792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_',
214064562Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
214164562Sgshapiro')',
214264562Sgshapiro`dnl')
214364562Sgshapirodnl')', `dnl')
214490792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind.
214564562Sgshapirodnl it does not matter in this case because the following rule ignores
214664562Sgshapirodnl the input. otherwise these rules must "clean up" the workspace.
214764562Sgshapiro
214890792Sgshapiro# check client name: first: did it resolve?
214990792Sgshapirodnl input: ignored
215090792SgshapiroR$*			$: < $&{client_resolve} >
215190792SgshapiroR<TEMP>			$#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
215238032SpeterR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
215390792SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
215490792Sgshapirodnl ${client_resolve} should be OK, so go ahead
215590792SgshapiroR$*			$: <@> $&{client_name}
215664562Sgshapirodnl should not be necessary since it has been done for client_addr already
215738032Speterdnl this rule actually may cause a problem if {client_name} resolves to ""
215890792Sgshapirodnl however, this should not happen since the forward lookup should fail
215990792Sgshapirodnl and {client_resolve} should be TEMP or FAIL.
216038032Speterdnl nevertheless, removing the rule doesn't hurt.
216190792Sgshapirodnl R<@>			$@ RELAY
216264562Sgshapirodnl workspace: <@> ${client_name} (not empty)
216364562Sgshapiro# pass to name server to make hostname canonical
216464562SgshapiroR<@> $* $=P 		$:<?>  $1 $2
216590792SgshapiroR<@> $+			$:<?>  $[ $1 $]
216664562Sgshapirodnl workspace: <?> ${client_name} (canonified)
216790792SgshapiroR$* .			$1			strip trailing dots
216864562Sgshapiroifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
216990792SgshapiroR<?> $* $=m		$@ RELAY', `dnl')
217090792SgshapiroR<?> $=w		$@ RELAY
217138032Speterifdef(`_RELAY_HOSTS_ONLY_',
217290792Sgshapiro`R<?> $=R		$@ RELAY
217364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
217464562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
217564562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
217664562Sgshapiro`R<?> $* $=R			$@ RELAY
217764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
217864562SgshapiroR<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
217964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
218064562SgshapiroR<RELAY> $*		$@ RELAY
218164562Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
218238032SpeterR<$*> <$*>		$: $2',`dnl')
218364562Sgshapirodnl end of _PROMISCUOUS_RELAY_
218464562Sgshapirodivert(0)
218564562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
218664562Sgshapiro# turn a canonical address in the form user<@domain>
218764562Sgshapiro# qualify unqual. addresses with $j
218864562Sgshapirodnl it might have been only user (without <@domain>)
218964562SgshapiroSFullAddr
219064562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
219164562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
219264562SgshapiroR$+			$@ $1 <@ $j >
219364562Sgshapiro
219464562SgshapiroSDelay_TLS_Client
219564562Sgshapiro# authenticated?
219664562Sgshapirodnl code repeated here from Basic_check_mail
219764562Sgshapirodnl only called from check_rcpt in delay mode if checkrcpt returns $#
219864562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
219964562SgshapiroR$* $| $#$+		$#$2
220090792Sgshapirodnl return result from checkrcpt
220190792SgshapiroR$*			$# $1
220264562Sgshapiro
220390792SgshapiroSDelay_TLS_Client2
220490792Sgshapiro# authenticated?
220564562Sgshapirodnl code repeated here from Basic_check_mail
220664562Sgshapirodnl only called from check_rcpt in delay mode if stopping due to Friend/Hater
220764562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
220864562SgshapiroR$* $| $#$+		$#$2
220964562Sgshapirodnl return result from friend/hater check
221064562SgshapiroR$*			$@ $1
221164562Sgshapiro
221290792Sgshapiro# call all necessary rulesets
221364562SgshapiroScheck_rcpt
221464562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
221564562Sgshapirodnl which is the correct DSN code?
221664562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
221790792Sgshapiro
221864562SgshapiroR$+			$: $1 $| $>checkrcpt $1
221964562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
222064562Sgshapirodnl on error (or discard) stop now
222164562SgshapiroR$+ $| $#error $*	$#error $2
222290792SgshapiroR$+ $| $#discard $*	$#discard $2
222390792Sgshapirodnl otherwise call tls_client; see above
222490792SgshapiroR$+ $| $#$*		$@ $>"Delay_TLS_Client" $2
222594334SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
222664562Sgshapiroifdef(`_SPAM_FH_',
222764562Sgshapiro`dnl lookup user@ and user@address
222894334Sgshapiroifdef(`_ACCESS_TABLE_', `',
222964562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
223038032Speter')')dnl
223138032Speterdnl one of the next two rules is supposed to match
223290792Sgshapirodnl this code has been copied from BLACKLIST... etc
223390792Sgshapirodnl and simplified by omitting some < >.
223464562SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
223590792SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
223690792Sgshapirodnl R<?>		$@ something_is_very_wrong_here
223790792Sgshapiro# lookup the addresses only with Spam tag
223890792SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
223990792SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
224090792Sgshapirodnl', `dnl')
224190792Sgshapiroifdef(`_SPAM_FRIEND_',
224290792Sgshapiro`# is the recipient a spam friend?
224390792Sgshapiroifdef(`_SPAM_HATER_',
224490792Sgshapiro	`errprint(`*** ERROR: define either Hater or Friend -- not both.
224590792Sgshapiro')', `dnl')
224690792SgshapiroR<FRIEND> $+		$@ $>"Delay_TLS_Client2" SPAMFRIEND
224790792SgshapiroR<$*> $+		$: $2',
224890792Sgshapiro`dnl')
224990792Sgshapiroifdef(`_SPAM_HATER_',
225090792Sgshapiro`# is the recipient no spam hater?
225190792SgshapiroR<HATER> $+		$: $1			spam hater: continue checks
225290792SgshapiroR<$*> $+		$@ $>"Delay_TLS_Client2" NOSPAMHATER	everyone else: stop
225390792Sgshapirodnl',`dnl')
225490792Sgshapirodnl run further checks: check_mail
225590792Sgshapirodnl should we "clean up" $&f?
225690792Sgshapiroifdef(`_FFR_MAIL_MACRO',
225790792Sgshapiro`R$*			$: $1 $| $>checkmail $&{mail_from}',
225890792Sgshapiro`R$*			$: $1 $| $>checkmail <$&f>')
225990792Sgshapirodnl recipient (canonical format) $| result of checkmail
226090792SgshapiroR$* $| $#$*		$#$2
226190792Sgshapirodnl run further checks: check_relay
226290792SgshapiroR$* $| $*		$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
226390792SgshapiroR$* $| $#$*		$#$2
226490792SgshapiroR$* $| $*		$: $1
226590792Sgshapiro', `dnl')
226690792Sgshapiro
226790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
226890792Sgshapiro######################################################################
226990792Sgshapiro###  F: LookUpFull -- search for an entry in access database
227090792Sgshapiro###
227190792Sgshapiro###	lookup of full key (which should be an address) and
227290792Sgshapiro###	variations if +detail exists: +* and without +detail
227390792Sgshapiro###
227490792Sgshapiro###	Parameters:
227590792Sgshapiro###		<$1> -- key
227690792Sgshapiro###		<$2> -- default (what to return if not found in db)
227790792Sgshapirodnl			must not be empty
227890792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
227990792Sgshapiro###			! does lookup only with tag
228090792Sgshapiro###			+ does lookup with and without tag
228190792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
228290792Sgshapirodnl returns:		<default> <passthru>
228390792Sgshapirodnl 			<result> <passthru>
228490792Sgshapiro######################################################################
228590792Sgshapiro
228690792SgshapiroSF
228790792Sgshapirodnl workspace: <key> <def> <o tag> <thru>
228890792Sgshapirodnl full lookup
228990792Sgshapirodnl    2    3  4    5
229090792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
229190792Sgshapirodnl no match, try without tag
229290792Sgshapirodnl   1    2      3    4
229390792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
229490792Sgshapirodnl no match, +detail: try +*
229590792Sgshapirodnl   1    2    3    4    5  6    7
229690792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
229790792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
229890792Sgshapirodnl no match, +detail: try +* without tag
229990792Sgshapirodnl   1    2    3    4      5    6
230090792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
230190792Sgshapiro			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
230290792Sgshapirodnl no match, +detail: try without +detail
230390792Sgshapirodnl   1    2    3    4    5  6    7
230490792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
230590792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
230690792Sgshapirodnl no match, +detail: try without +detail and without tag
230790792Sgshapirodnl   1    2    3    4      5    6
230890792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
230990792Sgshapiro			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
231090792Sgshapirodnl no match, return <default> <passthru>
231190792Sgshapirodnl   1    2    3  4    5
231290792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
231390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
231490792Sgshapirodnl            2    3  4    5
231590792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
231690792Sgshapirodnl match, return <match> <passthru>
231790792Sgshapirodnl    2    3  4    5
231890792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
231990792Sgshapiro
232090792Sgshapiro######################################################################
232190792Sgshapiro###  E: LookUpExact -- search for an entry in access database
232290792Sgshapiro###
232390792Sgshapiro###	Parameters:
232490792Sgshapiro###		<$1> -- key
232590792Sgshapiro###		<$2> -- default (what to return if not found in db)
232690792Sgshapirodnl			must not be empty
232790792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
232890792Sgshapiro###			! does lookup only with tag
232990792Sgshapiro###			+ does lookup with and without tag
233090792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
233190792Sgshapirodnl returns:		<default> <passthru>
233290792Sgshapirodnl 			<result> <passthru>
233390792Sgshapiro######################################################################
233490792Sgshapiro
233590792SgshapiroSE
233690792Sgshapirodnl    2    3  4    5
233790792SgshapiroR<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
233890792Sgshapirodnl no match, try without tag
233990792Sgshapirodnl   1    2      3    4
234090792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
234190792Sgshapirodnl no match, return default passthru
234290792Sgshapirodnl   1    2    3  4    5
234390792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
234490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
234590792Sgshapirodnl            2    3  4    5
234690792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
234790792Sgshapirodnl match, return <match> <passthru>
234890792Sgshapirodnl    2    3  4    5
234990792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
235090792Sgshapiro
235190792Sgshapiro######################################################################
235290792Sgshapiro###  U: LookUpUser -- search for an entry in access database
235390792Sgshapiro###
235490792Sgshapiro###	lookup of key (which should be a local part) and
235590792Sgshapiro###	variations if +detail exists: +* and without +detail
235690792Sgshapiro###
235790792Sgshapiro###	Parameters:
235890792Sgshapiro###		<$1> -- key (user@)
235990792Sgshapiro###		<$2> -- default (what to return if not found in db)
236090792Sgshapirodnl			must not be empty
236190792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
236290792Sgshapiro###			! does lookup only with tag
236390792Sgshapiro###			+ does lookup with and without tag
236490792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
236590792Sgshapirodnl returns:		<default> <passthru>
236690792Sgshapirodnl 			<result> <passthru>
236790792Sgshapiro######################################################################
236890792Sgshapiro
236990792SgshapiroSU
237090792Sgshapirodnl user lookups are always with trailing @
237164562Sgshapirodnl    2    3  4    5
237264562SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
237364562Sgshapirodnl no match, try without tag
237464562Sgshapirodnl   1    2      3    4
237564562SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
237664562Sgshapirodnl do not remove the @ from the lookup:
237764562Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
237890792Sgshapirodnl no match, +detail: try +*
237964562Sgshapirodnl   1    2      3    4  5    6
238064562SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
238164562Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
238264562Sgshapirodnl no match, +detail: try +* without tag
238364562Sgshapirodnl   1    2      3      4    5
238464562SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
238564562Sgshapiro			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
238664562Sgshapirodnl no match, +detail: try without +detail
238764562Sgshapirodnl   1    2      3    4  5    6
238890792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
238964562Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
239064562Sgshapirodnl no match, +detail: try without +detail and without tag
239164562Sgshapirodnl   1    2      3      4    5
239264562SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
239364562Sgshapiro			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
239464562Sgshapirodnl no match, return <default> <passthru>
239538032Speterdnl   1    2    3  4    5
239664562SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
239764562Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
239890792Sgshapirodnl            2    3  4    5
239964562SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
240090792Sgshapirodnl match, return <match> <passthru>
240190792Sgshapirodnl    2    3  4    5
240290792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
240390792Sgshapiro
240490792Sgshapiro######################################################################
240590792Sgshapiro###  SearchList: search a list of items in the access map
240690792Sgshapiro###	Parameters:
240790792Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
240890792Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
240990792Sgshapirodnl	avoid errorneous matches (with error messages?)
241064562Sgshapirodnl	if we can make sure that tag is always a single token
241190792Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
241290792Sgshapirodnl	to avoid errorneous matchs (first rule: D: if there
241390792Sgshapirodnl	is that mark somewhere in the list, it will be taken).
241438032Speterdnl	moreover, we can do some tricks to enforce lookup with
241590792Sgshapirodnl	the tag only, e.g.:
241690792Sgshapiro###	where "exact" is either "+" or "!":
241790792Sgshapiro###	<+ TAG>	lookup with and w/o tag
241890792Sgshapiro###	<! TAG>	lookup with tag
241990792Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
242090792Sgshapirodnl		a blank between them and the tag.
242190792Sgshapiro###	possible values for "mark" are:
242290792Sgshapiro###		D: recursive host lookup (LookUpDomain)
242390792Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
242464562Sgshapiro###		E: exact lookup, no modifications
242564562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
242664562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
242764562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
242864562Sgshapiro######################################################################
242964562Sgshapiro
243064562Sgshapiro# class with valid marks for SearchList
243164562Sgshapirodnl if A is activated: add it
243264562SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
243364562SgshapiroSSearchList
243464562Sgshapiro# just call the ruleset with the name of the tag... nice trick...
243564562Sgshapirodnl       2       3    4
243664562SgshapiroR<$+> $| <$={src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
243790792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <>
243890792Sgshapirodnl no match and nothing left: return
243990792SgshapiroR<$+> $| <> $| <?> <>		$@ <?>
244090792Sgshapirodnl no match but something left: continue
244190792SgshapiroR<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
244290792Sgshapirodnl match: return
244390792SgshapiroR<$+> $| <$*> $| <$+> <>	$@ <$3>
244464562Sgshapirodnl return result from recursive invocation
244590792SgshapiroR<$+> $| <$+>			$@ <$2>
244690792Sgshapirodnl endif _ACCESS_TABLE_
244790792Sgshapirodivert(0)
244890792Sgshapiro
244990792Sgshapiro######################################################################
245090792Sgshapiro###  trust_auth: is user trusted to authenticate as someone else?
245190792Sgshapiro###
245290792Sgshapiro###	Parameters:
245390792Sgshapiro###		$1: AUTH= parameter from MAIL command
245490792Sgshapiro######################################################################
245590792Sgshapiro
245690792Sgshapirodnl empty ruleset definition so it can be called
245790792SgshapiroSLocal_trust_auth
245864562SgshapiroStrust_auth
245990792SgshapiroR$*			$: $&{auth_type} $| $1
246090792Sgshapiro# required by RFC 2554 section 4.
246190792SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
246264562Sgshapirodnl seems to be useful...
246390792SgshapiroR$* $| $&{auth_authen}		$@ identical
246490792SgshapiroR$* $| <$&{auth_authen}>	$@ identical
246590792Sgshapirodnl call user supplied code
246690792SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $1
246764562SgshapiroR$* $| $#$*		$#$2
246890792Sgshapirodnl default: error
246990792SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
247090792Sgshapiro
247190792Sgshapiro######################################################################
247290792Sgshapiro###  Relay_Auth: allow relaying based on authentication?
247390792Sgshapiro###
247490792Sgshapiro###	Parameters:
247564562Sgshapiro###		$1: ${auth_type}
247690792Sgshapiro######################################################################
247790792SgshapiroSLocal_Relay_Auth
247871345Sgshapiro
2479102528Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
248090792Sgshapiro######################################################################
248190792Sgshapiro###  srv_features: which features to offer to a client?
248290792Sgshapiro###	(done in server)
248390792Sgshapiro######################################################################
248490792SgshapiroSsrv_features
248590792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl
248690792SgshapiroR$*			$: $1 $| $>"Local_srv_features" $1
248790792SgshapiroR$* $| $#$*		$#$2
248890792SgshapiroR$* $| $*		$: $1', `dnl')
248990792SgshapiroR$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
249090792SgshapiroR<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
249190792SgshapiroR<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
249290792SgshapiroR<?>$*		$@ OK
249390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
249490792SgshapiroR<$* _ATMPF_>$*	$#temp', `dnl')
249590792SgshapiroR<$+>$*		$# $1
249690792Sgshapiro
249790792Sgshapiro######################################################################
249890792Sgshapiro###  try_tls: try to use STARTTLS?
249990792Sgshapiro###	(done in client)
250090792Sgshapiro######################################################################
250190792SgshapiroStry_tls
250290792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl
250390792SgshapiroR$*			$: $1 $| $>"Local_try_tls" $1
250490792SgshapiroR$* $| $#$*		$#$2
250590792SgshapiroR$* $| $*		$: $1', `dnl')
250690792SgshapiroR$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
250790792SgshapiroR<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
250890792SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
250990792SgshapiroR<?>$*		$@ OK
251090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
251190792SgshapiroR<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
251264562SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
251390792Sgshapiro 
251490792Sgshapiro######################################################################
251590792Sgshapiro###  tls_rcpt: is connection with server "good" enough?
251690792Sgshapiro###	(done in client, per recipient)
251790792Sgshapirodnl called from deliver() before RCPT command
251890792Sgshapiro###
251990792Sgshapiro###	Parameters:
252064562Sgshapiro###		$1: recipient
252164562Sgshapiro######################################################################
252264562SgshapiroStls_rcpt
252390792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl
252490792SgshapiroR$*			$: $1 $| $>"Local_tls_rcpt" $1
252590792SgshapiroR$* $| $#$*		$#$2
252690792SgshapiroR$* $| $*		$: $1', `dnl')
252764562Sgshapirodnl store name of other side
252890792SgshapiroR$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
252990792Sgshapirodnl canonify recipient address
253064562SgshapiroR$+			$: <?> $>CanonAddr $1
253164562Sgshapirodnl strip trailing dots
253264562SgshapiroR<?> $+ < @ $+ . >	<?> $1 <@ $2 >
253364562Sgshapirodnl full address?
253490792SgshapiroR<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
253590792Sgshapirodnl only localpart?
253664562SgshapiroR<?> $+			$: $1 $| <U:$1@> <E:>
253764562Sgshapirodnl look it up
253890792Sgshapirodnl also look up a default value via E:
253990792SgshapiroR$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
254090792Sgshapirodnl found nothing: stop here
254190792SgshapiroR$* $| <?>	$@ OK
254264562Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
254390792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
254490792Sgshapirodnl use the generic routine (for now)
254590792SgshapiroR$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
254690792Sgshapiro
254790792Sgshapiro######################################################################
254890792Sgshapiro###  tls_client: is connection with client "good" enough?
254990792Sgshapiro###	(done in server)
255064562Sgshapiro###
255164562Sgshapiro###	Parameters:
255264562Sgshapiro###		${verify} $| (MAIL|STARTTLS)
255390792Sgshapiro######################################################################
255490792Sgshapirodnl MAIL: called from check_mail
255590792Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
255690792SgshapiroStls_client
255764562Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl
255890792SgshapiroR$*			$: $1 $| $>"Local_tls_client" $1
255990792SgshapiroR$* $| $#$*		$#$2
256090792SgshapiroR$* $| $*		$: $1', `dnl')
256190792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
256264562Sgshapirodnl store name of other side
256364562SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
256490792Sgshapirodnl ignore second arg for now
256590792Sgshapirodnl maybe use it to distinguish permanent/temporary error?
256690792Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
256790792Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
256864562SgshapiroR$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
256990792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
257090792Sgshapirodnl do a default lookup: just TLS_CLT_TAG
257190792SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
257290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
257364562SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
257490792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
257590792SgshapiroR$* $| $*	$@ $>"TLS_connection" $1')
257690792Sgshapiro
257790792Sgshapiro######################################################################
257890792Sgshapiro###  tls_server: is connection with server "good" enough?
257990792Sgshapiro###	(done in client)
258090792Sgshapiro###
258190792Sgshapiro###	Parameter:
258290792Sgshapiro###		${verify}
258390792Sgshapiro######################################################################
258490792Sgshapirodnl i.e. has the server been authenticated and is encryption active?
258590792Sgshapirodnl called from deliver() after STARTTLS command
258690792SgshapiroStls_server
258764562Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl
258890792SgshapiroR$*			$: $1 $| $>"Local_tls_server" $1
258964562SgshapiroR$* $| $#$*		$#$2
259064562SgshapiroR$* $| $*		$: $1', `dnl')
259190792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
259290792Sgshapirodnl store name of other side
259364562SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
259464562SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
259564562SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
259664562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
259764562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
259890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
259990792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
260064562SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
260164562SgshapiroR$*		$@ $>"TLS_connection" $1')
260264562Sgshapiro
260364562Sgshapiro######################################################################
260490792Sgshapiro###  TLS_connection: is TLS connection "good" enough?
260590792Sgshapiro###
260690792Sgshapiro###	Parameters:
260790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
260890792Sgshapiro###		${verify} $| <Requirement> [<>]', `dnl
260990792Sgshapiro###		${verify}')
261064562Sgshapiro###		Requirement: RHS from access map, may be ? for none.
261164562Sgshapirodnl	syntax for Requirement:
261264562Sgshapirodnl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
261364562Sgshapirodnl	extensions: could be a list of further requirements
261464562Sgshapirodnl		for now: CN:string	{cn_subject} == string
261590792Sgshapiro######################################################################
261664562SgshapiroSTLS_connection
261790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
261890792Sgshapirodnl deal with TLS handshake failures: abort
261990792SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
262090792Sgshapirodivert(-1)')
262164562Sgshapirodnl common ruleset for tls_{client|server}
262290792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>]
262364562Sgshapirodnl remove optional <>
262490792SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
262590792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup>
262690792Sgshapiro# create the appropriate error codes
262790792Sgshapirodnl permanent or temporary error?
262890792SgshapiroR$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
262990792SgshapiroR$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
263090792Sgshapirodnl default case depends on TLS_PERM_ERR
263190792SgshapiroR$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
263290792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
263390792Sgshapiro# deal with TLS handshake failures: abort
263464562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
263590792Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
263690792Sgshapirodnl use default error
263790792SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
263864562SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
263990792Sgshapirodnl separate optional requirements
264090792SgshapiroR$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
264190792SgshapiroR$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> <> $1
264290792Sgshapirodnl separate optional requirements
264390792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
264490792Sgshapirodnl some other value in access map: accept
264590792Sgshapirodnl this also allows to override the default case (if used)
264690792SgshapiroR$* $| $*			$@ OK
264790792Sgshapiro# authentication required: give appropriate error
264890792Sgshapiro# other side did authenticate (via STARTTLS)
264990792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
265090792Sgshapirodnl only verification required and it succeeded
265190792SgshapiroR<$*><VERIFY> <> OK		$@ OK
265290792Sgshapirodnl verification required and it succeeded but extensions are given
265390792Sgshapirodnl change it to <SMTP:ESC> <REQ:0>  <extensions>
265490792SgshapiroR<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
265590792Sgshapirodnl verification required + some level of encryption
265690792SgshapiroR<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
265764562Sgshapirodnl just some level of encryption required
265890792SgshapiroR<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
265990792Sgshapirodnl workspace:
266090792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
266190792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
266290792Sgshapirodnl verification required but ${verify} is not set (case 1.)
266390792SgshapiroR<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
266490792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
266590792SgshapiroR<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
266690792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
266790792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
266890792Sgshapirodnl some other value for ${verify}
266990792SgshapiroR<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
267090792Sgshapirodnl some level of encryption required: get the maximum level (case 2.)
267190792SgshapiroR<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
267290792Sgshapirodnl compare required bits with actual bits
267390792SgshapiroR<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
267490792SgshapiroR<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
267590792Sgshapirodnl strength requirements fulfilled
267690792Sgshapirodnl TLS Additional Requirements Separator
267790792Sgshapirodnl this should be something which does not appear in the extensions itself
267890792Sgshapirodnl @ could be part of a CN, DN, etc...
267990792Sgshapirodnl use < > ? those are encoded in CN, DN, ...
268090792Sgshapirodefine(`_TLS_ARS_', `++')dnl
268190792Sgshapirodnl workspace:
268290792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
268390792SgshapiroR<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
268490792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
268590792Sgshapirodnl continue: check  extensions
268690792SgshapiroR<$-:$+ _TLS_ARS_ >			$@ OK
268790792Sgshapirodnl split extensions into own list
268890792SgshapiroR<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
268990792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
269090792SgshapiroR<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
269190792Sgshapiro
269290792Sgshapiro######################################################################
269390792Sgshapiro###  TLS_req: check additional TLS requirements
269490792Sgshapiro###
269590792Sgshapiro###	Parameters: [<list> <of> <req>] $| <$-:$+>
269690792Sgshapiro###		$-: SMTP reply code
269790792Sgshapiro###		$+: Enhanced Status Code
269890792Sgshapirodnl  further requirements for this ruleset:
269990792Sgshapirodnl	name of "other side" is stored is {TLS_name} (client/server_name)
270090792Sgshapirodnl
270190792Sgshapirodnl	currently only CN[:common_name] is implemented
270264562Sgshapirodnl	right now this is only a logical AND
270364562Sgshapirodnl	i.e. all requirements must be true
270464562Sgshapirodnl	how about an OR? CN must be X or CN must be Y or ..
270564562Sgshapirodnl	use a macro to compute this as a trivial sequential
270664562Sgshapirodnl	operations (no precedences etc)?
270764562Sgshapiro######################################################################
270890792SgshapiroSTLS_req
270990792Sgshapirodnl no additional requirements: ok
271090792SgshapiroR $| $+		$@ OK
271164562Sgshapirodnl require CN: but no CN specified: use name of other side
271290792SgshapiroR<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
271390792Sgshapirodnl match, check rest
271490792SgshapiroR<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
271590792Sgshapirodnl CN does not match
271690792Sgshapirodnl  1   2      3  4
271790792SgshapiroR<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
271890792Sgshapirodnl cert subject
271964562SgshapiroR<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
272064562Sgshapirodnl CS does not match
272164562Sgshapirodnl  1   2      3  4
272264562SgshapiroR<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1
272364562Sgshapirodnl match, check rest
272464562SgshapiroR<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
272564562Sgshapirodnl CI does not match
272664562Sgshapirodnl  1   2      3  4
272764562SgshapiroR<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1
272864562Sgshapirodnl return from recursive call
272964562SgshapiroROK			$@ OK
273064562Sgshapiro
273164562Sgshapiro######################################################################
273290792Sgshapiro###  max: return the maximum of two values separated by :
273390792Sgshapiro###
273490792Sgshapiro###	Parameters: [$-]:[$-]
273564562Sgshapiro######################################################################
273690792SgshapiroSmax
273790792SgshapiroR:		$: 0
273890792SgshapiroR:$-		$: $1
273964562SgshapiroR$-:		$: $1
274090792SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
274164562SgshapiroRTRUE:$-:$-	$: $2
274290792SgshapiroR$-:$-:$-	$: $2
274390792Sgshapirodnl endif _ACCESS_TABLE_
274490792Sgshapirodivert(0)
274590792Sgshapiro
274690792Sgshapiro######################################################################
274764562Sgshapiro###  RelayTLS: allow relaying based on TLS authentication
274890792Sgshapiro###
274990792Sgshapiro###	Parameters:
275090792Sgshapiro###		none
275190792Sgshapiro######################################################################
275290792SgshapiroSRelayTLS
275390792Sgshapiro# authenticated?
275490792Sgshapirodnl we do not allow relaying for anyone who can present a cert
275590792Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
275690792Sgshapirodnl CA in CertPath so we can authenticate users, we do not allow
275790792Sgshapirodnl them to abuse our server (they might be easier to get hold of,
275890792Sgshapirodnl but anyway).
275990792Sgshapirodnl so here is the trick: if the verification succeeded
276090792Sgshapirodnl we look up the cert issuer in the access map
276190792Sgshapirodnl (maybe after extracting a part with a regular expression)
276290792Sgshapirodnl if this returns RELAY we relay without further questions
276390792Sgshapirodnl if it returns SUBJECT we perform a similar check on the
276490792Sgshapirodnl cert subject.
276590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
276690792SgshapiroR$*			$: <?> $&{verify}
276790792SgshapiroR<?> OK			$: OK		authenticated: continue
276890792SgshapiroR<?> $*			$@ NO		not authenticated
276990792Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
277090792SgshapiroR$*			$: $(CERTIssuer $&{cert_issuer} $)',
277190792Sgshapiro`R$*			$: $&{cert_issuer}')
277290792SgshapiroR$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
277390792Sgshapirodnl use $# to stop further checks (delay_check)
277490792SgshapiroRRELAY			$# RELAY
277590792Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
277690792SgshapiroRSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
277790792Sgshapiro`RSUBJECT		$: <@> $&{cert_subject}')
277864562SgshapiroR<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
277938032SpeterR<@> RELAY		$# RELAY
278038032SpeterR$*			$: NO', `dnl')
278138032Speter
278238032Speter######################################################################
278364562Sgshapiro###  authinfo: lookup authinfo in the access map
278464562Sgshapiro###
278564562Sgshapiro###	Parameters:
278664562Sgshapiro###		$1: {server_name}
278790792Sgshapiro###		$2: {server_addr}
278864562Sgshapirodnl	both are currently ignored
278964562Sgshapirodnl if it should be done via another map, we either need to restrict
279064562Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another
279164562Sgshapirodnl parameter which I want to avoid, it's quite complex already)
279238032Speter######################################################################
279338032Speterdnl omit this ruleset if neither is defined?
279438032Speterdnl it causes DefaultAuthInfo to be ignored
279538032Speterdnl (which may be considered a good thing).
279664562SgshapiroSauthinfo
279766494Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl
2798R$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
2799R<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
2800R<?>		$: <$(authinfo AuthInfo: $: ? $)>
2801R<?>		$@ no				no authinfo available
2802R<$*>		$# $1
2803dnl', `dnl
2804ifdef(`_ACCESS_TABLE_', `dnl
2805R$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
2806R$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
2807R$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
2808R$* $| <?>$*	$@ no				no authinfo available
2809R$* $| <$*> <>	$# $2
2810dnl', `dnl')')
2811
2812undivert(9)dnl LOCAL_RULESETS
2813#
2814######################################################################
2815######################################################################
2816#####
2817`#####			MAIL FILTER DEFINITIONS'
2818#####
2819######################################################################
2820######################################################################
2821_MAIL_FILTERS_
2822#
2823######################################################################
2824######################################################################
2825#####
2826`#####			MAILER DEFINITIONS'
2827#####
2828######################################################################
2829######################################################################
2830undivert(7)dnl MAILER_DEFINITIONS
2831
2832