proto.m4 revision 90792
138032Speterdivert(-1)
238032Speter#
390792Sgshapiro# Copyright (c) 1998-2001 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
1690792SgshapiroVERSIONID(`$Id: proto.m4,v 8.628 2001/12/28 19:02:40 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 (null means deliver locally)
20990792SgshapiroDR`'LOCAL_RELAY')
21038032Speter
21190792Sgshapiroifdef(`MAIL_HUB', `dnl
21238032Speter# who gets all local email traffic ($R has precedence for unqualified names)
21390792SgshapiroDH`'MAIL_HUB')
21438032Speter
21538032Speter# dequoting map
21690792SgshapiroKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `')
21738032Speter
21838032Speterdivert(0)dnl	# end of nullclient diversion
21938032Speter# class E: names that should be exposed as from this host, even if we masquerade
22064562Sgshapiro# class L: names that should be delivered locally, even if we have a relay
22138032Speter# class M: domains that should be converted to $M
22264562Sgshapiro# class N: domains that should not be converted to $M
22338032Speter#CL root
22438032Speterundivert(5)dnl
22564562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
22638032Speter
22790792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
22838032Speter# who I masquerade as (null for no masquerading) (see also $=M)
22990792SgshapiroDM`'MASQUERADE_NAME')
23038032Speter
23138032Speter# my name for error messages
23238032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
23338032Speter
23464562Sgshapiroundivert(6)dnl LOCAL_CONFIG
23538032Speterinclude(_CF_DIR_`m4/version.m4')
23638032Speter
23738032Speter###############
23838032Speter#   Options   #
23938032Speter###############
24090792Sgshapiroifdef(`confAUTO_REBUILD',
24190792Sgshapiro`errprint(WARNING: `confAUTO_REBUILD' is no longer valid.
24290792Sgshapiro	There was a potential for a denial of service attack if this is set.
24390792Sgshapiro)')dnl
24438032Speter
24538032Speter# strip message body to 7 bits on input?
24664562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
24738032Speter
24838032Speter# 8-bit data handling
24977349Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8')
25038032Speter
25138032Speter# wait for alias file rebuild (default units: minutes)
25264562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m')
25338032Speter
25438032Speter# location of alias file
25564562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
25664562Sgshapiro
25738032Speter# minimum number of free blocks on filesystem
25864562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
25938032Speter
26038032Speter# maximum message size
26164562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000')
26238032Speter
26338032Speter# substitution for space (blank) characters
26464562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_')
26538032Speter
26638032Speter# avoid connecting to "expensive" mailers on initial submission?
26764562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
26838032Speter
26938032Speter# checkpoint queue runs after every N successful deliveries
27064562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
27138032Speter
27238032Speter# default delivery mode
27364562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
27438032Speter
27538032Speter# error message header/file
27664562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
27738032Speter
27838032Speter# error mode
27964562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print')
28038032Speter
28138032Speter# save Unix-style "From_" lines at top of header?
28264562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
28338032Speter
28490792Sgshapiro# queue file mode (qf files)
28590792Sgshapiro_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600')
28690792Sgshapiro
28738032Speter# temporary file mode
28864562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
28938032Speter
29038032Speter# match recipients against GECOS field?
29164562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
29238032Speter
29338032Speter# maximum hop count
29490792Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `25')
29538032Speter
29638032Speter# location of help file
29764562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
29838032Speter
29938032Speter# ignore dots as terminators in incoming messages?
30064562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
30138032Speter
30238032Speter# name resolver options
30364562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
30438032Speter
30538032Speter# deliver MIME-encapsulated error messages?
30664562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
30738032Speter
30838032Speter# Forward file search path
30964562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
31038032Speter
31138032Speter# open connection cache size
31264562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
31338032Speter
31438032Speter# open connection cache timeout
31564562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
31638032Speter
31738032Speter# persistent host status directory
31864562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
31938032Speter
32038032Speter# single thread deliveries (requires HostStatusDirectory)?
32164562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
32238032Speter
32338032Speter# use Errors-To: header?
32464562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
32538032Speter
32638032Speter# log level
32764562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10')
32838032Speter
32938032Speter# send to me too, even in an alias expansion?
33064562Sgshapiro_OPTION(MeToo, `confME_TOO', `True')
33138032Speter
33238032Speter# verify RHS in newaliases?
33364562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
33438032Speter
33538032Speter# default messages to old style headers if no special punctuation?
33664562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
33738032Speter
33838032Speter# SMTP daemon options
33964562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
34064562Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.  See cf/README for more information.
34164562Sgshapiro)'dnl
34264562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
34366494Sgshapiroifelse(defn(`_DPO_'), `',
34490792Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet
34590792SgshapiroO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
34664562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
34738032Speter
34864562Sgshapiro# SMTP client options
34990792Sgshapiroifelse(defn(`confCLIENT_OPTIONS'), `', `dnl',
35090792Sgshapiro`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid.  See cf/README for more information.
35190792Sgshapiro)'dnl
35290792Sgshapiro`CLIENT_OPTIONS(`confCLIENT_OPTIONS')')
35390792Sgshapiroifelse(defn(`_CPO_'), `',
35490792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_')
35564562Sgshapiro
35690792Sgshapiro# Modifiers to `define' {daemon_flags} for direct submissions
35790792Sgshapiro_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `')
35890792Sgshapiro
35990792Sgshapiro# Use as mail submission program? See sendmail/SECURITY
36090792Sgshapiro_OPTION(UseMSP, `confUSE_MSP', `')
36190792Sgshapiro
36238032Speter# privacy flags
36364562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
36438032Speter
36538032Speter# who (if anyone) should get extra copies of error messages
36664562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
36738032Speter
36838032Speter# slope of queue-only function
36964562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
37038032Speter
37190792Sgshapiro# limit on number of concurrent queue runners
37290792Sgshapiro_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `')
37390792Sgshapiro
37490792Sgshapiro# maximum number of queue-runners per queue-grouping with multiple queues
37590792Sgshapiro_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1')
37690792Sgshapiro
37790792Sgshapiro# priority of queue runners (nice(3))
37890792Sgshapiro_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `')
37990792Sgshapiro
38090792Sgshapiro# shall we sort the queue by hostname first?
38190792Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
38290792Sgshapiro
38390792Sgshapiro# minimum time in queue before retry
38490792Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
38590792Sgshapiro
38690792Sgshapiro# how many jobs can you process in the queue?
38790792Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
38890792Sgshapiro
38990792Sgshapiro# perform initial split of envelope without checking MX records
39090792Sgshapiro_OPTION(FastSplit, `confFAST_SPLIT', `1')
39190792Sgshapiro
39238032Speter# queue directory
39364562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
39438032Speter
39590792Sgshapiro# key for shared memory; 0 to turn off
39690792Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
39790792Sgshapiro
39838032Speter# timeouts (many of these)
39964562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
40064562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
40190792Sgshapiro_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s')
40264562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
40364562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m')
40464562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m')
40564562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
40664562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
40764562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
40864562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
40964562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m')
41064562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m')
41164562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m')
41264562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h')
41364562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s')
41464562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
41564562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m')
41664562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
41764562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
41864562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
41964562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
42064562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
42164562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
42264562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
42364562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
42464562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
42564562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
42664562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
42764562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
42864562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
42964562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
43064562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
43190792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
43290792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m')
43390792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
43438032Speter
43590792Sgshapiro# time for DeliverBy; extension disabled if less than 0
43690792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
43790792Sgshapiro
43838032Speter# should we not prune routes in route-addr syntax addresses?
43964562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
44038032Speter
44138032Speter# queue up everything before forking?
44264562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
44338032Speter
44438032Speter# status file
44564562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
44638032Speter
44738032Speter# time zone handling:
44838032Speter#  if undefined, use system default
44938032Speter#  if defined but null, use TZ envariable passed in
45038032Speter#  if defined and non-null, use that info
45138032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
45238032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
45338032Speter	`O TimeZoneSpec=confTIME_ZONE')
45438032Speter
45538032Speter# default UID (can be username or userid:groupid)
45664562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
45738032Speter
45838032Speter# list of locations of user database file (null means no lookup)
45964562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
46038032Speter
46138032Speter# fallback MX host
46264562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
46338032Speter
46438032Speter# if we are the best MX host for a site, try it directly instead of config err
46564562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
46638032Speter
46738032Speter# load average at which we just queue messages
46864562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8')
46938032Speter
47038032Speter# load average at which we refuse connections
47164562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
47238032Speter
47390792Sgshapiro# load average at which we delay connections; 0 means no limit
47490792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0')
47590792Sgshapiro
47638032Speter# maximum number of children we allow at one time
47764562Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12')
47838032Speter
47938032Speter# maximum number of new connections per second
48071345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
48138032Speter
48238032Speter# work recipient factor
48364562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
48438032Speter
48538032Speter# deliver each queued job in a separate process?
48664562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
48738032Speter
48838032Speter# work class factor
48964562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
49038032Speter
49138032Speter# work time factor
49264562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
49338032Speter
49438032Speter# default character set
49564562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
49638032Speter
49790792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
49864562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
49938032Speter
50038032Speter# hosts file (normally /etc/hosts)
50164562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
50238032Speter
50338032Speter# dialup line delay on connection failure
50464562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s')
50538032Speter
50638032Speter# action to take if there are no recipients in the message
50764562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed')
50838032Speter
50938032Speter# chrooted environment for writing to files
51064562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
51138032Speter
51238032Speter# are colons OK in addresses?
51364562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
51438032Speter
51538032Speter# shall I avoid expanding CNAMEs (violates protocols)?
51664562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
51738032Speter
51838032Speter# SMTP initial login message (old $e macro)
51964562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
52038032Speter
52138032Speter# UNIX initial From header format (old $l macro)
52264562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
52338032Speter
52438032Speter# From: lines that have embedded newlines are unwrapped onto one line
52564562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
52638032Speter
52738032Speter# Allow HELO SMTP command that does not `include' a host name
52864562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
52938032Speter
53038032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
53164562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
53238032Speter
53338032Speter# delimiter (operator) characters (old $o macro)
53464562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
53538032Speter
53638032Speter# shall I avoid calling initgroups(3) because of high NIS costs?
53764562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
53838032Speter
53938032Speter# are group-writable `:include:' and .forward files (un)trustworthy?
54090792Sgshapiro# True (the default) means they are not trustworthy.
54164562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
54290792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES',
54390792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
54490792Sgshapiro')')
54538032Speter
54638032Speter# where do errors that occur when sending errors get sent?
54764562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
54838032Speter
54964562Sgshapiro# where to save bounces if all else fails
55064562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
55164562Sgshapiro
55238032Speter# what user id do we assume for the majority of the processing?
55364562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
55438032Speter
55538032Speter# maximum number of recipients per SMTP envelope
55664562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
55738032Speter
55890792Sgshapiro# limit the rate recipients per SMTP envelope are accepted
55990792Sgshapiro# once the threshold number of recipients have been rejected
56090792Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20')
56190792Sgshapiro
56238032Speter# shall we get local names from our installed interfaces?
56364562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
56438032Speter
56564562Sgshapiro# Return-Receipt-To: header implies DSN request
56664562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
56764562Sgshapiro
56864562Sgshapiro# override connection address (for testing)
56964562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
57064562Sgshapiro
57164562Sgshapiro# Trusted user for file ownership and starting the daemon
57264562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
57364562Sgshapiro
57464562Sgshapiro# Control socket for daemon management
57564562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
57664562Sgshapiro
57764562Sgshapiro# Maximum MIME header length to protect MUAs
57864562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
57964562Sgshapiro
58064562Sgshapiro# Maximum length of the sum of all headers
58164562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
58264562Sgshapiro
58364562Sgshapiro# Maximum depth of alias recursion
58464562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
58564562Sgshapiro
58664562Sgshapiro# location of pid file
58764562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
58864562Sgshapiro
58964562Sgshapiro# Prefix string for the process title shown on 'ps' listings
59064562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
59164562Sgshapiro
59264562Sgshapiro# Data file (df) memory-buffer file maximum size
59364562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
59464562Sgshapiro
59564562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
59664562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
59764562Sgshapiro
59890792Sgshapiro# lookup type to find information about local mailboxes
59990792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
60090792Sgshapiro
60164562Sgshapiro# list of authentication mechanisms
60290792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
60364562Sgshapiro
60464562Sgshapiro# default authentication information for outgoing connections
60564562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
60664562Sgshapiro
60764562Sgshapiro# SMTP AUTH flags
60864562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
60964562Sgshapiro
61090792Sgshapiro# SMTP AUTH maximum encryption strength
61190792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
61290792Sgshapiro
61390792Sgshapiro# SMTP STARTTLS server options
61490792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
61590792Sgshapiro
61664562Sgshapiro# Input mail filters
61764562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
61864562Sgshapiro
61990792Sgshapiroifdef(`confINPUT_MAIL_FILTERS', `dnl
62064562Sgshapiro# Milter options
62190792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
62264562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
62364562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
62464562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
62564562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')')
62664562Sgshapiro
62764562Sgshapiro# CA directory
62864562Sgshapiro_OPTION(CACERTPath, `confCACERT_PATH', `')
62964562Sgshapiro# CA file
63064562Sgshapiro_OPTION(CACERTFile, `confCACERT', `')
63164562Sgshapiro# Server Cert
63264562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
63364562Sgshapiro# Server private key
63464562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
63564562Sgshapiro# Client Cert
63664562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
63764562Sgshapiro# Client private key
63864562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
63964562Sgshapiro# DHParameters (only required if DSA/DH is used)
64064562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
64164562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
64264562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
64364562Sgshapiro
64490792Sgshapiro############################
64590792Sgshapiro`# QUEUE GROUP DEFINITIONS  #'
64690792Sgshapiro############################
64790792Sgshapiro_QUEUE_GROUP_
64842575Speter
64938032Speter###########################
65038032Speter#   Message precedences   #
65138032Speter###########################
65238032Speter
65338032SpeterPfirst-class=0
65438032SpeterPspecial-delivery=100
65538032SpeterPlist=-30
65638032SpeterPbulk=-60
65738032SpeterPjunk=-100
65838032Speter
65938032Speter#####################
66038032Speter#   Trusted users   #
66138032Speter#####################
66238032Speter
66338032Speter# this is equivalent to setting class "t"
66464562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
66538032SpeterTroot
66638032SpeterTdaemon
66738032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp')
66838032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
66938032Speter
67038032Speter#########################
67138032Speter#   Format of headers   #
67238032Speter#########################
67338032Speter
67438032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
67538032SpeterH?P?Return-Path: <$g>
67638032SpeterHReceived: confRECEIVED_HEADER
67738032SpeterH?D?Resent-Date: $a
67838032SpeterH?D?Date: $a
67938032SpeterH?F?Resent-From: confFROM_HEADER
68038032SpeterH?F?From: confFROM_HEADER
68138032SpeterH?x?Full-Name: $x
68238032Speter# HPosted-Date: $a
68338032Speter# H?l?Received-Date: $b
68438032SpeterH?M?Resent-Message-Id: <$t.$i@$j>
68538032SpeterH?M?Message-Id: <$t.$i@$j>
68664562Sgshapiro
68738032Speter#
68838032Speter######################################################################
68938032Speter######################################################################
69038032Speter#####
69138032Speter#####			REWRITING RULES
69238032Speter#####
69338032Speter######################################################################
69438032Speter######################################################################
69538032Speter
69638032Speter############################################
69738032Speter###  Ruleset 3 -- Name Canonicalization  ###
69838032Speter############################################
69964562SgshapiroScanonify=3
70038032Speter
70138032Speter# handle null input (translate to <@> special case)
70238032SpeterR$@			$@ <@>
70338032Speter
70438032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
70538032SpeterR$*			$: $1 <@>			mark addresses
70638032SpeterR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
70738032SpeterR@ $* <@>		$: @ $1				unmark @host:...
70890792SgshapiroR$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
70938032SpeterR$* :: $* <@>		$: $1 :: $2			unmark node::addr
71038032SpeterR:`include': $* <@>	$: :`include': $1			unmark :`include':...
71138032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
71238032SpeterR$* : $* <@>		$: $2				strip colon if marked
71338032SpeterR$* <@>			$: $1				unmark
71438032SpeterR$* ;			   $1				strip trailing semi
71571345SgshapiroR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
71638032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
71738032Speter
71838032Speter# null input now results from list:; syntax
71938032SpeterR$@			$@ :; <@>
72038032Speter
72138032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
72238032SpeterR$*			$: < $1 >			housekeeping <>
72338032SpeterR$+ < $* >		   < $2 >			strip excess on left
72438032SpeterR< $* > $+		   < $1 >			strip excess on right
72538032SpeterR<>			$@ < @ >			MAIL FROM:<> case
72638032SpeterR< $+ >			$: $1				remove housekeeping <>
72738032Speter
72864562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
72938032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
73038032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
73138032Speter
73238032Speter# localize and dispose of route-based addresses
73390792Sgshapirodnl XXX: IPv6 colon conflict
73490792Sgshapiroifdef(`NO_NETINET6', `dnl',
73590792Sgshapiro`R@ [$+] : $+		$@ $>Canonify2 < @ [$1] > : $2	handle <route-addr>')
73664562SgshapiroR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
73764562Sgshapirodnl',`dnl
73864562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d>
73964562SgshapiroR@ $+ , $+		$2
74090792Sgshapiroifdef(`NO_NETINET6', `dnl',
74190792Sgshapiro`R@ [ $* ] : $+		$2')
74264562SgshapiroR@ $+ : $+		$2
74364562Sgshapirodnl')
74438032Speter
74538032Speter# find focus for list syntax
74664562SgshapiroR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
74738032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
74838032Speter
74938032Speter# find focus for @ syntax addresses
75038032SpeterR$+ @ $+		$: $1 < @ $2 >			focus on domain
75138032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
75264562SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
75338032Speter
75490792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here.
75590792Sgshapirodnl # do some sanity checking
75690792Sgshapirodnl R$* < @ $~[ $* : $* > $*	$1 < @ $2 $3 > $4	nix colons in addrs
75738032Speter
75838032Speterifdef(`_NO_UUCP_', `dnl',
75938032Speter`# convert old-style addresses to a domain-based address
76064562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
76164562SgshapiroR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
76264562SgshapiroR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
76338032Speter')
76438032Speterifdef(`_USE_DECNET_SYNTAX_',
76538032Speter`# convert node::user addresses into a domain-based address
76664562SgshapiroR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
76764562SgshapiroR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
76838032Speter',
76938032Speter	`dnl')
77038032Speter# if we have % signs, take the rightmost one
77138032SpeterR$* % $*		$1 @ $2				First make them all @s.
77238032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
77364562SgshapiroR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
77438032Speter
77538032Speter# else we must be a local name
77664562SgshapiroR$*			$@ $>Canonify2 $1
77738032Speter
77838032Speter
77938032Speter################################################
78038032Speter###  Ruleset 96 -- bottom half of ruleset 3  ###
78138032Speter################################################
78238032Speter
78364562SgshapiroSCanonify2=96
78438032Speter
78538032Speter# handle special cases for local names
78638032SpeterR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
78738032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
78838032Speterifdef(`_NO_UUCP_', `dnl',
78938032Speter`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
79064562Sgshapiro
79190792Sgshapiro# check for IPv4/IPv6 domain literal
79290792SgshapiroR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [addr]
79338032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
79438032SpeterR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
79538032Speter
79664562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl
79738032Speter# look up domains in the domain table
79838032SpeterR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
79938032Speter
80064562Sgshapiroundivert(2)dnl LOCAL_RULE_3
80138032Speter
80264562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl
80338032Speter# handle BITNET mapping
80438032SpeterR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
80538032Speter
80664562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl
80738032Speter# handle UUCP mapping
80838032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
80938032Speter
81038032Speterifdef(`_NO_UUCP_', `dnl',
81138032Speter`ifdef(`UUCP_RELAY',
81238032Speter`# pass UUCP addresses straight through
81338032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
81438032Speter`# if really UUCP, handle it immediately
81538032Speterifdef(`_CLASS_U_',
81638032Speter`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
81738032Speterifdef(`_CLASS_V_',
81838032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
81938032Speterifdef(`_CLASS_W_',
82038032Speter`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82138032Speterifdef(`_CLASS_X_',
82238032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82338032Speterifdef(`_CLASS_Y_',
82438032Speter`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82538032Speter
82638032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl
82738032Speter# try UUCP traffic as a local address
82838032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
82938032SpeterR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
83038032Speter')')
83164562Sgshapiro# hostnames ending in class P are always canonical
83264562SgshapiroR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
83364562Sgshapirodnl apply the next rule only for hostnames not in class P
83464562Sgshapirodnl this even works for phrases in class P since . is in class P
83564562Sgshapirodnl which daemon flags are set?
83664562SgshapiroR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
83764562Sgshapirodnl the other rules in this section only apply if the hostname
83864562Sgshapirodnl does not end in class P hence no further checks are done here
83964562Sgshapirodnl if this ever changes make sure the lookups are "protected" again!
84064562Sgshapiroifdef(`_NO_CANONIFY_', `dnl
84164562Sgshapirodnl do not canonify unless:
84264562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection
84364562Sgshapirodnl	with class P is non-empty)
84464562Sgshapirodnl or {daemon_flags} has c set
84564562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify}
84664562SgshapiroR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
84764562Sgshapiro# pass to name server to make hostname canonical if requested
84864562SgshapiroR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
84964562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_
85064562SgshapiroR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
85164562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work
85264562SgshapiroR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
85364562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl
85464562Sgshapirodnl this should only apply to unqualified hostnames
85564562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
85664562Sgshapirodnl then $- does not work.
85764562Sgshapiro# lookup unqualified hostnames
85890792SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
85964562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
86064562Sgshapirodnl {daemon_flags} contains CC (do not canonify)
86171345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work
86271345Sgshapirodnl should we do this for every hostname: even unqualified?
86371345SgshapiroR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
86464562SgshapiroR$* CC $* $| $*			$: $3
86590792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
86690792Sgshapiro# do not canonify header addresses
86790792SgshapiroR$* $| $* < @ $* $~P > $*	$: $&{addr_type} $| $2 < @ $3 $4 > $5
86890792SgshapiroR$* h $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
86990792SgshapiroR$* h $* $| $*			$: $3', `dnl')
87038032Speter# pass to name server to make hostname canonical
87164562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
87264562Sgshapirodnl remove {daemon_flags} for other cases
87364562SgshapiroR$* $| $*			$: $2
87438032Speter
87538032Speter# local host aliases and pseudo-domains are always canonical
87638032SpeterR$* < @ $=w > $*		$: $1 < @ $2 . > $3
87738032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
87838032Speter`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
87938032Speter`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
88064562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
88164562Sgshapirodnl virtual hosts are also canonical
88264562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
88364562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
88464562Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
88564562Sgshapiro`dnl')
88690792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
88790792Sgshapirodnl hosts for genericstable are also canonical
88890792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_',
88990792Sgshapiro`R$* < @ $* $=G > $* 	$: $1 < @ $2 $3 . > $4',
89090792Sgshapiro`R$* < @ $=G > $* 	$: $1 < @ $2 . > $3')',
89190792Sgshapiro`dnl')
89264562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added
89364562Sgshapirodnl by one of the rules before
89438032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
89538032Speter
89638032Speter
89738032Speter##################################################
89838032Speter###  Ruleset 4 -- Final Output Post-rewriting  ###
89938032Speter##################################################
90064562SgshapiroSfinal=4
90138032Speter
90271345SgshapiroR$+ :; <@>		$@ $1 :				handle <list:;>
90338032SpeterR$* <@>			$@				handle <> and list:;
90438032Speter
90538032Speter# strip trailing dot off possibly canonical name
90638032SpeterR$* < @ $+ . > $*	$1 < @ $2 > $3
90738032Speter
90864562Sgshapiro# eliminate internal code
90938032SpeterR$* < @ *LOCAL* > $*	$1 < @ $j > $2
91038032Speter
91138032Speter# externalize local domain info
91238032SpeterR$* < $+ > $*		$1 $2 $3			defocus
91338032SpeterR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
91438032SpeterR@ $*			$@ @ $1				... and exit
91538032Speter
91638032Speterifdef(`_NO_UUCP_', `dnl',
91738032Speter`# UUCP must always be presented in old form
91838032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
91938032Speter
92038032Speterifdef(`_USE_DECNET_SYNTAX_',
92138032Speter`# put DECnet back in :: form
92238032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
92338032Speter	`dnl')
92438032Speter# delete duplicate local names
92538032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
92638032Speter
92738032Speter
92838032Speter
92938032Speter##############################################################
93038032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
93138032Speter###		   (used for recursive calls)		   ###
93238032Speter##############################################################
93338032Speter
93464562SgshapiroSRecurse=97
93564562SgshapiroR$*			$: $>canonify $1
93664562SgshapiroR$*			$@ $>parse $1
93738032Speter
93838032Speter
93938032Speter######################################
94038032Speter###   Ruleset 0 -- Parse Address   ###
94138032Speter######################################
94238032Speter
94364562SgshapiroSparse=0
94438032Speter
94538032SpeterR$*			$: $>Parse0 $1		initial parsing
94638032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
94764562SgshapiroR$*			$: $>ParseLocal $1	handle local hacks
94838032SpeterR$*			$: $>Parse1 $1		final parsing
94938032Speter
95038032Speter#
95138032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
95238032Speter#	This should either return with the (possibly modified) input
95338032Speter#	or return with a #error mailer.  It should not return with a
95438032Speter#	#mailer other than the #error mailer.
95538032Speter#
95638032Speter
95738032SpeterSParse0
95838032SpeterR<@>			$@ <@>			special case error msgs
95990792SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
96064562SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
96190792SgshapiroR<@ $+>			$#error $@ 5.1.3 $: "_CODE553 User address required"
96290792SgshapiroR$+ <@>			$#error $@ 5.1.3 $: "_CODE553 Hostname required"
96338032SpeterR$*			$: <> $1
96490792Sgshapirodnl allow tricks like [host1]:[host2]
96590792SgshapiroR<> $* < @ [ $* ] : $+ > $*	$1 < @ [ $2 ] : $3 > $4
96690792SgshapiroR<> $* < @ [ $* ] , $+ > $*	$1 < @ [ $2 ] , $3 > $4
96790792Sgshapirodnl but no a@[b]c
96890792SgshapiroR<> $* < @ [ $* ] $+ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid address"
96990792SgshapiroR<> $* < @ [ $+ ] > $*		$1 < @ [ $2 ] > $3
97090792SgshapiroR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
97138032SpeterR<> $*			$1
97290792SgshapiroR$* < @ . $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
97390792SgshapiroR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
97490792Sgshapirodnl no a@b@
97590792SgshapiroR$* < @ $* @ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid route address"
97690792Sgshapirodnl no a@b@c
97790792SgshapiroR$* @ $* < @ $* > $*	$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
97864562Sgshapirodnl comma only allowed before @; this check is not complete
97990792SgshapiroR$* , $~O $*		$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
98038032Speter
98190792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks
98290792SgshapiroR$* . < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
98390792SgshapiroR. $* < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
98490792Sgshapirodnl', `dnl')
98590792Sgshapiro
98638032Speter# now delete the local info -- note $=O to find characters that cause forwarding
98764562SgshapiroR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
98864562SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
98938032SpeterR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
99090792SgshapiroR< @ $+ >		$#error $@ 5.1.3 $: "_CODE553 User address required"
99164562SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
99238032SpeterR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
99390792SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "_CODE553 User address required"
99438032SpeterR$* $=O $* < @ *LOCAL* >
99564562Sgshapiro			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
99638032SpeterR$* < @ *LOCAL* >	$: $1
99738032Speter
99838032Speter#
99938032Speter#  Parse1 -- the bottom half of ruleset 0.
100038032Speter#
100138032Speter
100238032SpeterSParse1
100364562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
100464562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute}
100590792SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
100690792SgshapiroR$+ < @ $={LDAPRouteEquiv} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
100764562Sgshapiro`dnl')
100864562Sgshapiro
100938032Speterifdef(`_MAILER_smtp_',
101038032Speter`# handle numeric address spec
101164562Sgshapirodnl there is no check whether this is really an IP number
101264562SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
101364562SgshapiroR$* < @ [ $+ ] > $*	$1 < @ [ $2 ] : $S > $3		Add smart host to path
101490792SgshapiroR$* < @ [ $+ ] : > $*		$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
101564562SgshapiroR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
101664562SgshapiroR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
101738032Speter	`dnl')
101838032Speter
101964562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
102038032Speter# handle virtual users
102190792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
102290792Sgshapirodnl this is not a documented option
102390792Sgshapirodnl it stops looping in virtusertable mapping if input and output
102490792Sgshapirodnl are identical, i.e., if address A is mapped to A.
102590792Sgshapirodnl it does not deal with multi-level recursion
102690792Sgshapiro# handle full domains in RHS of virtusertable
102790792SgshapiroR$+ < @ $+ >			$: $(macro {RecipientAddress} $) $1 < @ $2 >
102890792SgshapiroR$+ < @ $+ > 			$: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
102990792SgshapiroR<?> $+ $| $+			$: $1 $(macro {RecipientAddress} $@ $2 $)
103090792SgshapiroR<?> $+ $| $*			$: $1',
103190792Sgshapiro`dnl')
103264562SgshapiroR$+			$: <!> $1		Mark for lookup
103390792Sgshapirodnl input: <!> local<@domain>
103464562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
103564562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
103664562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
103790792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
103864562SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
103990792Sgshapirodnl if <@> local<@domain>: no match but try lookup
104090792Sgshapirodnl user+detail: try user++@domain if detail not empty
104190792SgshapiroR<@> $+ + $+ < @ $* . >
104290792Sgshapiro			$: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
104390792Sgshapirodnl user+detail: try user+*@domain
104438032SpeterR<@> $+ + $* < @ $* . >
104590792Sgshapiro			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
104690792Sgshapirodnl user+detail: try user@domain
104738032SpeterR<@> $+ + $* < @ $* . >
104890792Sgshapiro			$: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
104964562Sgshapirodnl try default entry: @domain
105090792Sgshapirodnl ++@domain
105190792SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105264562Sgshapirodnl +*@domain
105390792SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105464562Sgshapirodnl @domain if +detail exists
105590792SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105664562Sgshapirodnl without +detail (or no match)
105738032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
105890792Sgshapirodnl no match
105938032SpeterR<@> $+			$: $1
106090792Sgshapirodnl remove mark
106164562SgshapiroR<!> $+			$: $1
106264562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
106338032SpeterR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
106490792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
106590792Sgshapiro# check virtuser input address against output address, if same, skip recursion
106690792SgshapiroR< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
106790792Sgshapiro# it is the same: stop now
106890792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
106990792SgshapiroR< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
107090792Sgshapirodnl', `dnl')
107180785Sgshapirodnl this is not a documented option
107280785Sgshapirodnl it performs no looping at all for virtusertable
107377349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_',
107477349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
107577349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
107677349Sgshapirodnl', `dnl')
107738032Speter
107838032Speter# short circuit local delivery so forwarded email works
107938032Speterifdef(`_MAILER_usenet_', `dnl
108064562SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
108166494Sgshapiro
108266494Sgshapiro
108338032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
108438032Speter`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
108564562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
108664562Sgshapirodnl $H empty (but @$=w.)
108738032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
108838032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
108964562Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
109038032SpeterR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
109138032Speter
109264562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
109338032Speter# not local -- try mailer table lookup
109438032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
109538032SpeterR< $+ . > $*		$: < $1 > $2			strip trailing dot
109638032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
109764562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
109864562SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
109964562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
110038032Speter`dnl')
110164562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)'
110238032Speter
110338032Speterifdef(`_NO_UUCP_', `dnl',
110438032Speter`# resolve remotely connected UUCP links (if any)
110538032Speterifdef(`_CLASS_V_',
110664562Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
110738032Speter	`dnl')
110838032Speterifdef(`_CLASS_W_',
110964562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
111038032Speter	`dnl')
111138032Speterifdef(`_CLASS_X_',
111264562Sgshapiro`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
111338032Speter	`dnl')')
111438032Speter
111538032Speter# resolve fake top level domains by forwarding to other hosts
111638032Speterifdef(`BITNET_RELAY',
111764562Sgshapiro`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
111838032Speter	`dnl')
111938032Speterifdef(`DECNET_RELAY',
112064562Sgshapiro`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
112138032Speter	`dnl')
112238032Speterifdef(`_MAILER_pop_',
112338032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
112438032Speter	`dnl')
112538032Speterifdef(`_MAILER_fax_',
112638032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
112738032Speter`ifdef(`FAX_RELAY',
112864562Sgshapiro`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
112938032Speter	`dnl')')
113038032Speter
113138032Speterifdef(`UUCP_RELAY',
113238032Speter`# forward non-local UUCP traffic to our UUCP relay
113364562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
113438032Speter`ifdef(`_MAILER_uucp_',
113538032Speter`# forward other UUCP traffic straight to UUCP
113638032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
113738032Speter	`dnl')')
113838032Speterifdef(`_MAILER_usenet_', `
113938032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
114064562SgshapiroR$+ . USENET		$#usenet $@ usenet $: $1',
114138032Speter	`dnl')
114238032Speter
114338032Speterifdef(`_LOCAL_RULES_',
114438032Speter`# figure out what should stay in our local mail system
114538032Speterundivert(1)', `dnl')
114638032Speter
114738032Speter# pass names that still have a host to a smarthost (if defined)
114864562SgshapiroR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
114938032Speter
115038032Speter# deal with other remote names
115138032Speterifdef(`_MAILER_smtp_',
115264562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
115390792Sgshapiro`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
115438032Speter
115538032Speter# handle locally delivered names
115664562SgshapiroR$=L			$#_LOCAL_ $: @ $1		special local names
115738032SpeterR$+			$#_LOCAL_ $: $1			regular local names
115838032Speter
115938032Speter###########################################################################
116038032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
116138032Speter###########################################################################
116238032Speter
116364562SgshapiroSLocal_localaddr
116464562SgshapiroSlocaladdr=5
116564562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
116690792SgshapiroR$+ $| $#ok		$@ $1			no change
116764562SgshapiroR$+ $| $#$*		$#$2
116864562SgshapiroR$+ $| $*		$: $1
116938032Speter
117090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
117190792Sgshapiro# Preserve rcpt_host in {Host}
117290792SgshapiroR$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
117390792SgshapiroR$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
117490792SgshapiroR$+ $| $| $+		$: $1			h not set, {Host} set
117590792SgshapiroR$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
117690792SgshapiroR$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
117790792Sgshapiro')dnl
117890792Sgshapiro
117990792Sgshapiroifdef(`_FFR_5_', `dnl
118066494Sgshapiro# Preserve host in a macro
118166494SgshapiroR$+			$: $(macro {LocalAddrHost} $) $1
118266494SgshapiroR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
118366494Sgshapiro
118490792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
118538032Speter# deal with plussed users so aliases work nicely
118666494SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
118766494SgshapiroR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
118866494Sgshapiro')
118938032Speter# prepend an empty "forward host" on the front
119038032SpeterR$+			$: <> $1
119138032Speter
119238032Speterifdef(`LUSER_RELAY', `dnl
119338032Speter# send unrecognized local users to a relay host
119490792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
119566494SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
119666494SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
119766494SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
119866494SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
119964562SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
120090792SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')
120190792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
120290792SgshapiroR< $+ > $+		$: < $1 > $2 $&{Host}')
120390792Sgshapirodnl')
120438032Speter
120590792Sgshapiroifdef(`MAIL_HUB', `dnl
120690792SgshapiroR< > $+			$: < $H > $1			try hub', `dnl')
120790792Sgshapiroifdef(`LOCAL_RELAY', `dnl
120890792SgshapiroR< > $+			$: < $R > $1			try relay', `dnl')
120990792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
121090792SgshapiroR< > $+			$@ $1', `dnl
121164562SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
121290792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
121390792SgshapiroR< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
121464562SgshapiroR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
121564562SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
121638032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
121766494SgshapiroR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
121838032SpeterR< > < $+ >		$@ $1				no +detail
121943730SpeterR$+			$: $1 <> $&h			add +detail back in
122090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
122190792SgshapiroR$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
122243730SpeterR$+ <> + $*		$: $1 + $2			check whether +detail
122366494SgshapiroR$+ <> $*		$: $1				else discard')
122464562SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
122564562SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
122690792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
122790792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
122890792SgshapiroR< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
122990792SgshapiroR< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
123090792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
123190792SgshapiroR< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
123264562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
123338032Speter
123464562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
123590792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
123638032Speter###################################################################
123790792Sgshapiro###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
123890792Sgshapirodnl input: <Domain> FullAddress
123990792Sgshapiro###################################################################
124090792Sgshapiro
124190792SgshapiroSLDAPMailertable
124290792SgshapiroR< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
124390792SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
124490792SgshapiroR< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
124590792SgshapiroR< $+ > $#$*		$#$2					found
124690792SgshapiroR< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
124790792Sgshapiro`dnl')
124890792Sgshapiro
124990792Sgshapiro###################################################################
125038032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
125164562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
125238032Speter###################################################################
125338032Speter
125464562SgshapiroSMailertable=90
125564562Sgshapirodnl shift and check
125664562Sgshapirodnl %2 is not documented in cf/README
125738032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
125864562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
125964562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
126064562SgshapiroR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
126164562Sgshapirodnl is $2 always empty?
126238032SpeterR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
126364562SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
126464562Sgshapirodnl return full address
126538032SpeterR< $* > $*		$@ $2				no mailertable match',
126638032Speter`dnl')
126738032Speter
126838032Speter###################################################################
126938032Speter###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
127064562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
127164562Sgshapirodnl	<> address				-> address
127264562Sgshapirodnl	<error:d.s.n:text>			-> error
127364562Sgshapirodnl	<error:text>				-> error
127464562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
127564562Sgshapirodnl	<mailer:host> address			-> mailer host address
127664562Sgshapirodnl	<localdomain> address			-> address
127764562Sgshapirodnl	<host> address				-> relay host address
127838032Speter###################################################################
127938032Speter
128064562SgshapiroSMailerToTriple=95
128138032SpeterR< > $*				$@ $1			strip off null relay
128264562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
128338032SpeterR< error : $- $+ > $*		$#error $@ $(dequote $1 $) $: $2
128438032SpeterR< local : $* > $*		$>CanonLocal < $1 > $2
128590792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
128690792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
128790792SgshapiroR< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
128838032SpeterR< $=w > $*			$@ $2			delete local host
128938032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
129038032Speter
129138032Speter###################################################################
129238032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
129364562Sgshapirodnl input: <user> address
129464562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
129564562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
129664562Sgshapirodnl <> user <@host> rest		-> local user@host user
129764562Sgshapirodnl <> user				-> local user user
129864562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
129964562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
130064562Sgshapirodnl <user> lp				-> local lp user
130138032Speter###################################################################
130238032Speter
130338032SpeterSCanonLocal
130443730Speter# strip local host from routed addresses
130564562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
130664562SgshapiroR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
130743730Speter
130838032Speter# strip trailing dot from any host name that may appear
130938032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
131038032Speter
131138032Speter# handle local: syntax -- use old user, either with or without host
131238032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
131338032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
131438032Speter
131538032Speter# handle local:user@host syntax -- ignore host part
131638032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
131738032Speter
131838032Speter# handle local:user syntax
131938032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
132038032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
132138032Speter
132238032Speter###################################################################
132338032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
132438032Speter###################################################################
132538032Speter
132664562SgshapiroSMasqHdr=93
132738032Speter
132864562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
132938032Speter# handle generics database
133038032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
133164562Sgshapirodnl if generics should be applied add a @ as mark
133238032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
133338032Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
133438032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
133564562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
133664562Sgshapirodnl ignore the first case for now
133764562Sgshapirodnl if it has the mark lookup full address
133890792Sgshapirodnl broken: %1 is full address not just detail
133964562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
134064562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
134164562Sgshapirodnl no match, try user+detail@domain
134264562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
134364562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
134464562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
134564562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
134664562Sgshapirodnl no match, remove mark
134764562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
134864562Sgshapirodnl no match, try @domain for exceptions
134964562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
135064562Sgshapirodnl workspace: ... or <match> user <@domain>
135164562Sgshapirodnl no match, try local part
135238032SpeterR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
135364562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
135464562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
135564562SgshapiroR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
135664562SgshapiroR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
135738032SpeterR< > $*			$: $1				not found',
135838032Speter`dnl')
135938032Speter
136064562Sgshapiro# do not masquerade anything in class N
136164562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
136264562Sgshapiro
136390792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
136438032Speter# special case the users that should be exposed
136538032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
136638032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
136738032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
136838032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
136938032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
137038032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
137138032Speter
137238032Speter# handle domain-specific masquerading
137338032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
137438032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
137538032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
137638032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
137738032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
137838032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
137938032SpeterR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
138038032SpeterR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
138190792Sgshapirodnl', `dnl no masquerading
138290792Sgshapirodnl just fix *LOCAL* leftovers
138390792SgshapiroR$* < @ *LOCAL* >	$@ $1 < @ $j . >')
138438032Speter
138538032Speter###################################################################
138638032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
138738032Speter###################################################################
138838032Speter
138964562SgshapiroSMasqEnv=94
139038032Speterifdef(`_MASQUERADE_ENVELOPE_',
139164562Sgshapiro`R$+			$@ $>MasqHdr $1',
139238032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
139338032Speter
139438032Speter###################################################################
139538032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
139638032Speter###################################################################
139738032Speter
139864562SgshapiroSParseLocal=98
139964562Sgshapiroundivert(3)dnl LOCAL_RULE_0
140038032Speter
140164562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
140290792Sgshapiro######################################################################
140390792Sgshapiro###  LDAPExpand: Expand address using LDAP routing
140490792Sgshapiro###
140590792Sgshapiro###	Parameters:
140690792Sgshapiro###		<$1> -- parsed address (user < @ domain . >) (pass through)
140790792Sgshapiro###		<$2> -- RFC822 address (user @ domain) (used for lookup)
140890792Sgshapiro###		<$3> -- +detail information
140990792Sgshapiro###
141090792Sgshapiro###	Returns:
141190792Sgshapiro###		Mailer triplet ($#mailer $@ host $: address)
141290792Sgshapiro###		Parsed address (user < @ domain . >)
141390792Sgshapiro######################################################################
141490792Sgshapiro
141564562SgshapiroSLDAPExpand
141664562Sgshapiro# do the LDAP lookups
141790792SgshapiroR<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
141864562Sgshapiro
141964562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
142064562Sgshapiro# return the new mailRoutingAddress
142190792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
142290792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
142390792SgshapiroR<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
142490792SgshapiroR<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
142590792SgshapiroR<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
142664562Sgshapiro
142764562Sgshapiro# if mailRoutingAddress and non-local mailHost,
142864562Sgshapiro# relay to mailHost with new mailRoutingAddress
142990792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
143090792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
143190792Sgshapiro# check mailertable for host, relay from there
143290792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
143390792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
143490792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
143590792Sgshapiro# check mailertable for host, relay from there
143690792SgshapiroR<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
143790792Sgshapiro`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
143864562Sgshapiro
143964562Sgshapiro# if no mailRoutingAddress and local mailHost,
144064562Sgshapiro# return original address
144190792SgshapiroR<> <$=w> <$+> <$+> <$*>	$@ $2
144264562Sgshapiro
144364562Sgshapiro# if no mailRoutingAddress and non-local mailHost,
144464562Sgshapiro# relay to mailHost with original address
144590792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
144690792Sgshapiro# check mailertable for host, relay from there
144790792SgshapiroR<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
144890792Sgshapiro`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
144964562Sgshapiro
145090792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_',
145190792Sgshapiro`# if no mailRoutingAddress and no mailHost,
145290792Sgshapiro# try without +detail
145390792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
145490792Sgshapiro
145590792Sgshapiro# if still no mailRoutingAddress and no mailHost,
145664562Sgshapiro# try @domain
145790792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
145890792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
145990792SgshapiroR<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>
146064562Sgshapiro
146164562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
146264562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
146364562Sgshapiro# user does not exist
146490792SgshapiroR<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
146590792Sgshapiro# only give error for envelope recipient
146690792SgshapiroR<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
146790792SgshapiroR<?> <$*> <$+>			$@ $2',
146864562Sgshapiro`dnl
146964562Sgshapiro# return the original address
147090792SgshapiroR<> <> <$+> <@ $+> <$*>		$@ $1')',
147164562Sgshapiro`dnl')
147264562Sgshapiro
147364562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
147464562Sgshapiro')')
147590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
147638032Speter######################################################################
147790792Sgshapiro###  D: LookUpDomain -- search for domain in access database
147838032Speter###
147938032Speter###	Parameters:
148038032Speter###		<$1> -- key (domain name)
148138032Speter###		<$2> -- default (what to return if not found in db)
148264562Sgshapirodnl			must not be empty
148390792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
148464562Sgshapiro###			! does lookup only with tag
148564562Sgshapiro###			+ does lookup with and without tag
148690792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
148764562Sgshapirodnl returns:		<default> <passthru>
148864562Sgshapirodnl 			<result> <passthru>
148938032Speter######################################################################
149038032Speter
149190792SgshapiroSD
149264562Sgshapirodnl workspace <key> <default> <passthru> <mark>
149364562Sgshapirodnl lookup with tag (in front, no delimiter here)
149490792Sgshapirodnl    2    3  4    5
149590792SgshapiroR<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
149664562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
149764562Sgshapirodnl lookup without tag?
149890792Sgshapirodnl   1    2      3    4
149990792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
150090792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
150190792Sgshapirodnl XXX apply this also to IP addresses?
150290792Sgshapirodnl currently it works the wrong way round for [1.2.3.4]
150390792Sgshapirodnl   1  2    3    4  5    6
150490792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
150590792Sgshapirodnl   1  2    3      4    5
150690792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
150790792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
150890792Sgshapirodnl found SKIP: return <default> and <passthru>
150990792Sgshapirodnl      1    2    3  4    5
151090792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
151190792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!)
151290792Sgshapirodnl    1  2     3    4  5    6
151390792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
151490792Sgshapiroifdef(`NO_NETINET6', `dnl',
151590792Sgshapiro`dnl not found: IPv6 net
151690792Sgshapirodnl (could be merged with previous rule if we have a class containing .:)
151790792Sgshapirodnl    1   2     3    4  5    6
151890792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
151990792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
152064562Sgshapirodnl not found, but subdomain: try again
152190792Sgshapirodnl   1  2    3    4  5    6
152290792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
152390792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
152490792Sgshapirodnl   1    2      3    4
152590792SgshapiroR<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
152690792Sgshapirodnl not found, no subdomain: return <default> and <passthru>
152790792Sgshapirodnl   1    2    3  4    5
152890792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
152990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
153090792Sgshapirodnl            2    3    4  5    6
153190792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
153290792Sgshapirodnl return <result of lookup> and <passthru>
153390792Sgshapirodnl    2    3    4  5    6
153490792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
153538032Speter
153638032Speter######################################################################
153790792Sgshapiro###  A: LookUpAddress -- search for host address in access database
153838032Speter###
153938032Speter###	Parameters:
154038032Speter###		<$1> -- key (dot quadded host address)
154138032Speter###		<$2> -- default (what to return if not found in db)
154264562Sgshapirodnl			must not be empty
154390792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
154464562Sgshapiro###			! does lookup only with tag
154564562Sgshapiro###			+ does lookup with and without tag
154690792Sgshapiro###		<$4> -- passthru (additional data passed through)
154764562Sgshapirodnl	returns:	<default> <passthru>
154864562Sgshapirodnl			<result> <passthru>
154938032Speter######################################################################
155038032Speter
155190792SgshapiroSA
155264562Sgshapirodnl lookup with tag
155390792Sgshapirodnl    2    3  4    5
155490792SgshapiroR<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
155564562Sgshapirodnl lookup without tag
155690792Sgshapirodnl   1    2      3    4
155790792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
155890792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
155990792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
156090792Sgshapirodnl found SKIP: return <default> and <passthru>
156190792Sgshapirodnl      1    2    3  4    5
156290792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
156390792Sgshapiroifdef(`NO_NETINET6', `dnl',
156490792Sgshapiro`dnl no match; IPv6: remove last part
156590792Sgshapirodnl   1   2    3    4  5    6
156690792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
156790792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
156864562Sgshapirodnl no match; IPv4: remove last part
156990792Sgshapirodnl   1  2    3    4  5    6
157090792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
157164562Sgshapirodnl no match: return default
157290792Sgshapirodnl   1    2    3  4    5
157390792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
157490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
157590792Sgshapirodnl            2    3    4  5    6
157690792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
157764562Sgshapirodnl match: return result
157890792Sgshapirodnl    2    3    4  5    6
157990792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
158090792Sgshapirodnl endif _ACCESS_TABLE_
158190792Sgshapirodivert(0)
158238032Speter######################################################################
158342575Speter###  CanonAddr --	Convert an address into a standard form for
158442575Speter###			relay checking.  Route address syntax is
158542575Speter###			crudely converted into a %-hack address.
158642575Speter###
158742575Speter###	Parameters:
158842575Speter###		$1 -- full recipient address
158942575Speter###
159042575Speter###	Returns:
159142575Speter###		parsed address, not in source route form
159264562Sgshapirodnl		user%host%host<@domain>
159364562Sgshapirodnl		host!user<@domain>
159442575Speter######################################################################
159542575Speter
159642575SpeterSCanonAddr
159764562SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
159864562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
159942575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
160042575SpeterR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
160142575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
160264562Sgshapirodnl')
160342575Speter
160442575Speter######################################################################
160538032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
160638032Speter###			$* $=m or the access database.
160738032Speter###			Check user portion for host separators.
160838032Speter###
160938032Speter###	Parameters:
161038032Speter###		$1 -- full recipient address
161138032Speter###
161238032Speter###	Returns:
161338032Speter###		parsed, non-local-relaying address
161438032Speter######################################################################
161538032Speter
161638032SpeterSParseRecipient
161764562Sgshapirodnl mark and canonify address
161842575SpeterR$*				$: <?> $>CanonAddr $1
161964562Sgshapirodnl workspace: <?> localpart<@domain[.]>
162042575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
162164562Sgshapirodnl workspace: <?> localpart<@domain>
162242575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
162338032Speter
162438032Speter# if no $=O character, no host in the user portion, we are done
162542575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
162664562Sgshapirodnl no $=O in localpart: return
162742575SpeterR<?> $*				$@ $1
162838032Speter
162990792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O
163064562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
163138032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
163238032Speter# if we relay, check username portion for user%host so host can be checked also
163342575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
163464562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
163564562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
163690792Sgshapiro
163790792Sgshapirodnl what if access map returns something else than RELAY?
163890792Sgshapirodnl we are only interested in RELAY entries...
163990792Sgshapirodnl other To: entries: blacklist recipient; generic entries?
164090792Sgshapirodnl if it is an error we probably do not want to relay anyway
164138032Speterifdef(`_RELAY_HOSTS_ONLY_',
164242575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
164364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
164464562SgshapiroR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
164542575SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
164642575Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
164764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
164890792SgshapiroR<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
164942575SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
165038032Speter
165164562Sgshapiro
165290792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl
165390792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
165490792SgshapiroR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
165590792SgshapiroR<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
165690792Sgshapirodnl yes: mark it as <RELAY>
165790792SgshapiroR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
165890792Sgshapirodnl no: put old <NO> mark back
165990792SgshapiroR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
166090792Sgshapiro
166190792Sgshapirodnl do we relay to this recipient domain?
166242575SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
166390792Sgshapirodnl something else
166490792SgshapiroR<$+> $*			$@ $2
166542575Speter
166664562Sgshapiro
166738032Speter######################################################################
166838032Speter###  check_relay -- check hostname/address on SMTP startup
166938032Speter######################################################################
167038032Speter
167138032SpeterSLocal_check_relay
167264562SgshapiroScheck`'_U_`'relay
167338032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
167438032SpeterR$* $| $* $| $#$*	$#$3
167538032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
167638032Speter
167738032SpeterSBasic_check_relay
167838032Speter# check for deferred delivery mode
167938032SpeterR$*			$: < ${deliveryMode} > $1
168038032SpeterR< d > $*		$@ deferred
168138032SpeterR< $* > $*		$: $2
168238032Speter
168364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
168466494Sgshapirodnl workspace: {client_name} $| {client_addr}
168590792SgshapiroR$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
168666494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
168790792SgshapiroR<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
168890792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>)
168990792SgshapiroR<?> <$*>		$: OK				found nothing
169090792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
169190792SgshapiroR<$={Accept}> <$*>	$@ $1				return value of lookup
169290792SgshapiroR<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
169390792SgshapiroR<DISCARD> <$*>		$#discard $: discard
169490792Sgshapiroifdef(`_FFR_QUARANTINE',
169590792Sgshapiro`R<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1', `dnl')
169664562Sgshapirodnl error tag
169766494SgshapiroR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
169866494SgshapiroR<ERROR:$+> <$*>		$#error $: $1
169990792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
170064562Sgshapirodnl generic error from access map
170166494SgshapiroR<$+> <$*>		$#error $: $1', `dnl')
170238032Speter
170364562Sgshapiroifdef(`_RBL_',`dnl
170464562Sgshapiro# DNS based IP address spam list
170590792Sgshapirodnl workspace: ignored...
170638032SpeterR$*			$: $&{client_addr}
170764562SgshapiroR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
170864562SgshapiroR<?>OK			$: OKSOFAR
170964562SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"',
171038032Speter`dnl')
171164562Sgshapiroundivert(8)
171238032Speter
171338032Speter######################################################################
171438032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
171538032Speter######################################################################
171638032Speter
171738032SpeterSLocal_check_mail
171864562SgshapiroScheck`'_U_`'mail
171938032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
172038032SpeterR$* $| $#$*		$#$2
172138032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
172238032Speter
172338032SpeterSBasic_check_mail
172438032Speter# check for deferred delivery mode
172538032SpeterR$*			$: < ${deliveryMode} > $1
172638032SpeterR< d > $*		$@ deferred
172738032SpeterR< $* > $*		$: $2
172838032Speter
172964562Sgshapiro# authenticated?
173064562Sgshapirodnl done first: we can require authentication for every mail transaction
173164562Sgshapirodnl workspace: address as given by MAIL FROM: (sender)
173264562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
173364562SgshapiroR$* $| $#$+		$#$2
173464562Sgshapirodnl undo damage: remove result of tls_client call
173564562SgshapiroR$* $| $*		$: $1
173638032Speter
173764562Sgshapirodnl workspace: address as given by MAIL FROM:
173864562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
173938032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
174064562Sgshapirodnl do some additional checks
174164562Sgshapirodnl no user@host
174264562Sgshapirodnl no user@localhost (if nonlocal sender)
174364562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
174464562Sgshapirodnl just make sure the address has <> around it (which is required by
174564562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
174664562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
174764562Sgshapirodnl not be modified by host lookups.
174864562SgshapiroR$+			$: <?> $1
174964562SgshapiroR<?><$+>		$: <@> <$1>
175064562SgshapiroR<?>$+			$: <@> <$1>
175164562Sgshapirodnl workspace: <@> <address>
175264562Sgshapirodnl prepend daemon_flags
175364562SgshapiroR$*			$: $&{daemon_flags} $| $1
175464562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
175564562Sgshapirodnl do not allow these at all or only from local systems?
175664562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
175764562Sgshapirodnl accept unqualified sender: change mark to avoid test
175864562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
175964562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
176064562Sgshapirodnl        or:                    <? ${client_name} > <address>
176164562Sgshapirodnl        or:                    <?> <address>
176264562Sgshapirodnl remove daemon_flags
176364562SgshapiroR$* $| $*		$: $2
176438032Speter# handle case of @localhost on address
176564562SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
176664562SgshapiroR<@> < $* @ [127.0.0.1] >
176764562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
176864562SgshapiroR<@> < $* @ localhost.$m >
176964562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
177038032Speterifdef(`_NO_UUCP_', `dnl',
177164562Sgshapiro`R<@> < $* @ localhost.UUCP >
177264562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
177364562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
177464562Sgshapirodnl	or:    <@> <address>
177564562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
177664562SgshapiroR<@> $*			$: $1			no localhost as domain
177764562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
177864562Sgshapirodnl	or:    <address>
177964562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
178064562SgshapiroR<? $=w> $*		$: $2			local client: ok
178190792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
178264562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
178364562SgshapiroR<?> $*			$: $1')
178464562Sgshapirodnl workspace: address (or <address>)
178564562SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
178664562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
178764562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
178864562SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
178964562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
179064562SgshapiroR<?> $* < @ $* $=P >	$: <OK> $1 < @ $2 $3 >
179164562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
179264562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
179390792Sgshapiro`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
179464562Sgshapiro`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
179564562SgshapiroR<? $* <$->> $* < @ $+ >
179664562Sgshapiro			$: <$2> $3 < @ $4 >')
179790792Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
179864562Sgshapirodnl mark is ? iff the address is user (wo @domain)
179938032Speter
180064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
180164562Sgshapiro# check sender address: user@address, user@, address
180264562Sgshapirodnl should we remove +ext from user?
180390792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
180490792SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
180564562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
180664562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
180764562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
180864562Sgshapirodnl will only return user<@domain when "reversing" the args
180990792SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
181064562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
181164562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
181264562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
181338032Speter# retransform for further use
181464562Sgshapirodnl required form:
181564562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
181664562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
181764562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
181864562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
181964562Sgshapirodnl mark is ? iff the address is user (wo @domain)
182038032Speter
182138032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
182238032Speter# handle case of no @domain on address
182364562Sgshapirodnl prepend daemon_flags
182464562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
182564562Sgshapirodnl accept unqualified sender: change mark to avoid test
182690792SgshapiroR$* u $* $| <?> $*	$: <_RES_OK_> $3
182764562Sgshapirodnl remove daemon_flags
182864562SgshapiroR$* $| $*		$: $2
182938032SpeterR<?> $*			$: < ? $&{client_name} > $1
183038032SpeterR<?> $*			$@ <OK>				...local unqualed ok
183190792SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
183238032Speter							...remote is not')
183338032Speter# check results
183464562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
183590792SgshapiroR<$={ResOk}> $*		$@ <_RES_OK_>	domain ok: stop
183664562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
183790792SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
183864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
183990792SgshapiroR<$={Accept}> $*	$# $1		accept from access map
184038032SpeterR<DISCARD> $*		$#discard $: discard
184190792Sgshapiroifdef(`_FFR_QUARANTINE',
184290792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
184364562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
184464562Sgshapirodnl error tag
184564562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
184664562SgshapiroR<ERROR:$+> $*		$#error $: $1
184790792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
184864562Sgshapirodnl generic error from access map
184964562SgshapiroR<$+> $*		$#error $: $1		error from access db',
185038032Speter`dnl')
185138032Speter
185238032Speter######################################################################
185338032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
185438032Speter######################################################################
185538032Speter
185638032SpeterSLocal_check_rcpt
185764562SgshapiroScheck`'_U_`'rcpt
185838032SpeterR$*			$: $1 $| $>"Local_check_rcpt" $1
185938032SpeterR$* $| $#$*		$#$2
186038032SpeterR$* $| $*		$@ $>"Basic_check_rcpt" $1
186138032Speter
186238032SpeterSBasic_check_rcpt
186390792Sgshapiro# empty address?
186490792SgshapiroR<>			$#error $@ nouser $: "553 User address required"
186590792SgshapiroR$@			$#error $@ nouser $: "553 User address required"
186638032Speter# check for deferred delivery mode
186738032SpeterR$*			$: < ${deliveryMode} > $1
186838032SpeterR< d > $*		$@ deferred
186938032SpeterR< $* > $*		$: $2
187038032Speter
187164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
187290792Sgshapirodnl this code checks for user@host where host is not a FQHN.
187390792Sgshapirodnl it is not activated.
187490792Sgshapirodnl notice: code to check for a recipient without a domain name is
187590792Sgshapirodnl available down below; look for the same macro.
187690792Sgshapirodnl this check is done here because the name might be qualified by the
187790792Sgshapirodnl canonicalization.
187890792Sgshapiro# require fully qualified domain part?
187990792Sgshapirodnl very simple canonification: make sure the address is in < >
188064562SgshapiroR$+			$: <?> $1
188190792SgshapiroR<?> <$+>		$: <@> <$1>
188290792SgshapiroR<?> $+			$: <@> <$1>
188390792SgshapiroR<@> < postmaster >	$: postmaster
188490792SgshapiroR<@> < $* @ $+ . $+ >	$: < $3 @ $4 . $5 >
188564562Sgshapirodnl prepend daemon_flags
188690792SgshapiroR<@> $*			$: $&{daemon_flags} $| <@> $1
188764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
188864562Sgshapirodnl do not allow these at all or only from local systems?
188990792SgshapiroR$* r $* $| <@> < $* @ $* >	$: < ? $&{client_name} > < $3 @ $4 >
189064562SgshapiroR<?> < $* >		$: <$1>
189164562SgshapiroR<? $=w> < $* >		$: <$1>
189290792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
189364562Sgshapirodnl remove daemon_flags for other cases
189464562SgshapiroR$* $| <@> $*		$: $2', `dnl')
189564562Sgshapiro
189690792Sgshapirodnl ##################################################################
189790792Sgshapirodnl call subroutines for recipient and relay
189890792Sgshapirodnl possible returns from subroutines:
189990792Sgshapirodnl $#TEMP	temporary failure
190090792Sgshapirodnl $#error	permanent failure (or temporary if from access map)
190190792Sgshapirodnl $#other	stop processing
190290792Sgshapirodnl RELAY	RELAYing allowed
190390792Sgshapirodnl other	otherwise
190490792Sgshapiro######################################################################
190590792SgshapiroR$*			$: $1 $| @ $>"Rcpt_ok" $1
190690792Sgshapirodnl temporary failure? remove mark @ and remember
190790792SgshapiroR$* $| @ $#TEMP $+	$: $1 $| T $2
190890792Sgshapirodnl error or ok (stop)
190990792SgshapiroR$* $| @ $#$*		$#$2
191090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
191190792SgshapiroR$* $| @ RELAY		$@ RELAY
191290792Sgshapirodnl something else: call check sender (relay)
191390792SgshapiroR$* $| @ $*		$: O $| $>"Relay_ok" $1
191490792Sgshapirodnl temporary failure: call check sender (relay)
191590792SgshapiroR$* $| T $+		$: T $2 $| $>"Relay_ok" $1
191690792Sgshapirodnl temporary failure? return that
191790792SgshapiroR$* $| $#TEMP $+	$#error $2
191890792Sgshapirodnl error or ok (stop)
191990792SgshapiroR$* $| $#$*		$#$2
192090792SgshapiroR$* $| RELAY		$@ RELAY
192190792Sgshapirodnl something else: return previous temp failure
192290792SgshapiroR T $+ $| $*		$#error $1
192390792Sgshapiro# anything else is bogus
192490792SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
192590792Sgshapirodivert(0)
192690792Sgshapiro
192790792Sgshapiro######################################################################
192890792Sgshapiro### Rcpt_ok: is the recipient ok?
192990792Sgshapirodnl input: recipient address (RCPT TO)
193090792Sgshapirodnl output: see explanation at call
193190792Sgshapiro######################################################################
193290792SgshapiroSRcpt_ok
193338032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
193442575SpeterR$*			$: $>CanonAddr $1
193538032SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
193638032Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
193738032Speter
193842575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
193942575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
194042575Speter# unlimited bestmx
194142575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
194242575Speter`dnl
194342575Speter# limit bestmx to $=B
194443730SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
194590792SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
194642575SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
194742575SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
194842575Speter
194938032Speterifdef(`_BLACKLIST_RCPT_',`dnl
195064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
195138032Speter# blacklist local users or any host from receiving mail
195238032SpeterR$*			$: <?> $1
195364562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
195464562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
195590792SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
195690792SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
195764562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
195864562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
195964562Sgshapirodnl will only return user<@domain when "reversing" the args
196090792SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
196164562SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
196264562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
196390792Sgshapirodnl we may have to filter here because otherwise some RHSs
196490792Sgshapirodnl would be interpreted as generic error messages...
196590792Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
196690792Sgshapirodnl that would make a lot of things easier.
196764562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
196890792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
196990792SgshapiroR<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
197090792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
197190792Sgshapirodnl compatility with 8.11/8.10:
197264562Sgshapirodnl we have to filter these because otherwise they would be interpreted
197364562Sgshapirodnl as generic error message...
197464562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
197564562Sgshapirodnl that would make a lot of things easier.
197664562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
197764562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
197890792SgshapiroR<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
197964562SgshapiroR<DISCARD> $*		$#discard $: discard
198090792Sgshapiroifdef(`_FFR_QUARANTINE',
198190792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
198264562Sgshapirodnl error tag
198364562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
198464562SgshapiroR<ERROR:$+> $*		$#error $: $1
198590792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
198664562Sgshapirodnl generic error from access map
198764562SgshapiroR<$+> $*		$#error $: $1		error from access db
198864562SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
198938032Speter
199090792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
199190792Sgshapiro# authenticated via TLS?
199290792SgshapiroR$*			$: $1 $| $>RelayTLS	client authenticated?
199390792SgshapiroR$* $| $# $+		$# $2			error/ok?
199490792SgshapiroR$* $| $*		$: $1			no
199564562Sgshapiro
199690792SgshapiroR$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
199790792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth
199890792SgshapiroR$* $| $# $*		$# $2
199990792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
200090792SgshapiroR$* $| NO		$: $1
200190792SgshapiroR$* $| $*		$: $1 $| $&{auth_type}
200290792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ]
200364562Sgshapirodnl empty ${auth_type}?
200464562SgshapiroR$* $|			$: $1
200564562Sgshapirodnl mechanism ${auth_type} accepted?
200664562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
200790792SgshapiroR$* $| $={TrustAuthMech}	$# RELAY
200890792Sgshapirodnl remove ${auth_type}
200964562SgshapiroR$* $| $*		$: $1
201071345Sgshapirodnl workspace: localpart<@domain> | localpart
201164562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
201271345Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
201371345SgshapiroR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
201438032Speter# anything terminating locally is ok
201538032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
201690792SgshapiroR$+ < @ $* $=m >	$@ RELAY', `dnl')
201790792SgshapiroR$+ < @ $=w >		$@ RELAY
201838032Speterifdef(`_RELAY_HOSTS_ONLY_',
201990792Sgshapiro`R$+ < @ $=R >		$@ RELAY
202064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
202164562SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
202264562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
202364562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
202490792Sgshapiro`R$+ < @ $* $=R >	$@ RELAY
202564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
202690792SgshapiroR$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')')
202764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
202864562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
202990792SgshapiroR<RELAY> $*		$@ RELAY
203090792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
203138032SpeterR<$*> <$*>		$: $2',`dnl')
203238032Speter
203364562Sgshapiro
203438032Speterifdef(`_RELAY_MX_SERVED_', `dnl
203538032Speter# allow relaying for hosts which we MX serve
203664562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
203764562Sgshapirodnl this must not necessarily happen if the client is checked first...
203890792SgshapiroR< : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
203990792SgshapiroR<$* : $=w . : $*> $*	$@ RELAY
204042575SpeterR< : $* : > $*		$: $2',
204138032Speter`dnl')
204238032Speter
204338032Speter# check for local user (i.e. unqualified address)
204438032SpeterR$*			$: <?> $1
204542575SpeterR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
204638032Speter# local user is ok
204764562Sgshapirodnl is it really? the standard requires user@domain, not just user
204864562Sgshapirodnl but we should accept it anyway (maybe making it an option:
204964562Sgshapirodnl RequireFQDN ?)
205064562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
205164562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
205290792SgshapiroR<?> postmaster		$@ OK
205364562Sgshapiro# require qualified recipient?
205464562Sgshapirodnl prepend daemon_flags
205564562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
205664562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
205764562Sgshapirodnl do not allow these at all or only from local systems?
205864562Sgshapirodnl r flag? add client_name
205964562SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
206064562Sgshapirodnl no r flag: relay to local user (only local part)
206164562Sgshapiro# no qualified recipient required
206290792SgshapiroR$* $| <?> $+		$@ RELAY
206364562Sgshapirodnl client_name is empty
206490792SgshapiroR<?> <?> $+		$@ RELAY
206564562Sgshapirodnl client_name is local
206690792SgshapiroR<? $=w> <?> $+		$@ RELAY
206764562Sgshapirodnl client_name is not local
206864562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
206964562Sgshapirodnl no qualified recipient required
207090792SgshapiroR<?> $+			$@ RELAY')
207164562Sgshapirodnl it is a remote user: remove mark and then check client
207238032SpeterR<$+> $*		$: $2
207364562Sgshapirodnl currently the recipient address is not used below
207438032Speter
207590792Sgshapiro######################################################################
207690792Sgshapiro### Relay_ok: is the relay/sender ok?
207790792Sgshapirodnl input: ignored
207890792Sgshapirodnl output: see explanation at call
207990792Sgshapiro######################################################################
208090792SgshapiroSRelay_ok
208138032Speter# anything originating locally is ok
208264562Sgshapiro# check IP address
208364562SgshapiroR$*			$: $&{client_addr}
208490792SgshapiroR$@			$@ RELAY		originated locally
208590792SgshapiroR0			$@ RELAY		originated locally
208690792SgshapiroR$=R $*			$@ RELAY		relayable IP address
208764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
208890792SgshapiroR$*			$: $>A <$1> <?> <+ Connect> <$1>
208990792SgshapiroR<RELAY> $* 		$@ RELAY		relayable IP address
209090792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
209164562SgshapiroR<$*> <$*>		$: $2', `dnl')
209264562SgshapiroR$*			$: [ $1 ]		put brackets around it...
209390792SgshapiroR$=w			$@ RELAY		... and see if it is local
209464562Sgshapiro
209564562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
209664562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
209764562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
209864562Sgshapirodnl input: {client_addr} or something "broken"
209964562Sgshapirodnl just throw the input away; we do not need it.
210064562Sgshapiro# check whether FROM is allowed to use system as relay
210164562SgshapiroR$*			$: <?> $>CanonAddr $&f
210290792SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
210364562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
210464562Sgshapiro# check whether local FROM is ok
210590792SgshapiroR<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
210664562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
210790792SgshapiroR<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<D:$2>') <>
210890792SgshapiroR<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
210990792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
211090792Sgshapiro', `dnl
211190792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_',
211290792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
211364562Sgshapiro')',
211464562Sgshapiro`dnl')
211564562Sgshapirodnl')', `dnl')
211690792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind.
211790792Sgshapirodnl it does not matter in this case because the following rule ignores
211890792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace.
211964562Sgshapiro
212064562Sgshapiro# check client name: first: did it resolve?
212164562Sgshapirodnl input: ignored
212264562SgshapiroR$*			$: < $&{client_resolve} >
212390792SgshapiroR<TEMP>			$#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
212464562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
212564562SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
212664562Sgshapirodnl ${client_resolve} should be OK, so go ahead
212790792SgshapiroR$*			$: <@> $&{client_name}
212890792Sgshapirodnl should not be necessary since it has been done for client_addr already
212990792SgshapiroR<@>			$@ RELAY
213090792Sgshapirodnl workspace: <@> ${client_name} (not empty)
213138032Speter# pass to name server to make hostname canonical
213290792SgshapiroR<@> $* $=P 		$:<?>  $1 $2
213390792SgshapiroR<@> $+			$:<?>  $[ $1 $]
213490792Sgshapirodnl workspace: <?> ${client_name} (canonified)
213564562SgshapiroR$* .			$1			strip trailing dots
213638032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
213790792SgshapiroR<?> $* $=m		$@ RELAY', `dnl')
213890792SgshapiroR<?> $=w		$@ RELAY
213938032Speterifdef(`_RELAY_HOSTS_ONLY_',
214090792Sgshapiro`R<?> $=R		$@ RELAY
214164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
214264562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
214364562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
214490792Sgshapiro`R<?> $* $=R			$@ RELAY
214564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
214690792SgshapiroR<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
214764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
214890792SgshapiroR<RELAY> $*		$@ RELAY
214990792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
215038032SpeterR<$*> <$*>		$: $2',`dnl')
215190792Sgshapirodnl end of _PROMISCUOUS_RELAY_
215264562Sgshapirodivert(0)
215364562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
215464562Sgshapiro# turn a canonical address in the form user<@domain>
215564562Sgshapiro# qualify unqual. addresses with $j
215664562Sgshapirodnl it might have been only user (without <@domain>)
215764562SgshapiroSFullAddr
215864562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
215964562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
216064562SgshapiroR$+			$@ $1 <@ $j >
216138032Speter
216264562Sgshapiro# call all necessary rulesets
216364562SgshapiroScheck_rcpt
216464562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
216564562Sgshapirodnl which is the correct DSN code?
216664562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
216764562SgshapiroR$+			$: $1 $| $>checkrcpt $1
216864562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
216964562SgshapiroR$+ $| $#$*		$#$2
217064562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
217164562Sgshapiroifdef(`_SPAM_FH_',
217264562Sgshapiro`dnl lookup user@ and user@address
217364562Sgshapiroifdef(`_ACCESS_TABLE_', `',
217464562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
217564562Sgshapiro')')dnl
217664562Sgshapirodnl one of the next two rules is supposed to match
217764562Sgshapirodnl this code has been copied from BLACKLIST... etc
217864562Sgshapirodnl and simplified by omitting some < >.
217990792SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
218090792SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
218164562Sgshapirodnl R<?>		$@ something_is_very_wrong_here
218290792Sgshapiro# lookup the addresses only with Spam tag
218390792SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
218464562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
218564562Sgshapirodnl', `dnl')
218664562Sgshapiroifdef(`_SPAM_FRIEND_',
218764562Sgshapiro`# is the recipient a spam friend?
218864562Sgshapiroifdef(`_SPAM_HATER_',
218964562Sgshapiro	`errprint(`*** ERROR: define either SpamHater or SpamFriend
219064562Sgshapiro')', `dnl')
219190792SgshapiroR<FRIEND> $+		$@ SPAMFRIEND
219264562SgshapiroR<$*> $+		$: $2',
219364562Sgshapiro`dnl')
219464562Sgshapiroifdef(`_SPAM_HATER_',
219564562Sgshapiro`# is the recipient no spam hater?
219690792SgshapiroR<HATER> $+		$: $1			spam hater: continue checks
219764562SgshapiroR<$*> $+		$@ NOSPAMHATER		everyone else: stop
219864562Sgshapirodnl',`dnl')
219964562Sgshapirodnl run further checks: check_mail
220064562Sgshapirodnl should we "clean up" $&f?
220190792Sgshapiroifdef(`_FFR_MAIL_MACRO',
220290792Sgshapiro`R$*			$: $1 $| $>checkmail $&{mail_from}',
220390792Sgshapiro`R$*			$: $1 $| $>checkmail <$&f>')
220464562SgshapiroR$* $| $#$*		$#$2
220564562Sgshapirodnl run further checks: check_relay
220664562SgshapiroR$*			$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
220764562SgshapiroR$* $| $#$*		$#$2
220838032SpeterR$* $| $*		$: $1
220938032Speter', `dnl')
221090792Sgshapiro
221190792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
221264562Sgshapiro######################################################################
221390792Sgshapiro###  F: LookUpFull -- search for an entry in access database
221490792Sgshapiro###
221590792Sgshapiro###	lookup of full key (which should be an address) and
221690792Sgshapiro###	variations if +detail exists: +* and without +detail
221790792Sgshapiro###
221890792Sgshapiro###	Parameters:
221990792Sgshapiro###		<$1> -- key
222090792Sgshapiro###		<$2> -- default (what to return if not found in db)
222190792Sgshapirodnl			must not be empty
222290792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
222390792Sgshapiro###			! does lookup only with tag
222490792Sgshapiro###			+ does lookup with and without tag
222590792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
222690792Sgshapirodnl returns:		<default> <passthru>
222790792Sgshapirodnl 			<result> <passthru>
222890792Sgshapiro######################################################################
222990792Sgshapiro
223090792SgshapiroSF
223190792Sgshapirodnl workspace: <key> <def> <o tag> <thru>
223290792Sgshapirodnl full lookup
223390792Sgshapirodnl    2    3  4    5
223490792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
223590792Sgshapirodnl no match, try without tag
223690792Sgshapirodnl   1    2      3    4
223790792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
223890792Sgshapirodnl no match, +detail: try +*
223990792Sgshapirodnl   1    2    3    4    5  6    7
224090792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
224190792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
224290792Sgshapirodnl no match, +detail: try +* without tag
224390792Sgshapirodnl   1    2    3    4      5    6
224490792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
224590792Sgshapiro			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
224690792Sgshapirodnl no match, +detail: try without +detail
224790792Sgshapirodnl   1    2    3    4    5  6    7
224890792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
224990792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
225090792Sgshapirodnl no match, +detail: try without +detail and without tag
225190792Sgshapirodnl   1    2    3    4      5    6
225290792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
225390792Sgshapiro			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
225490792Sgshapirodnl no match, return <default> <passthru>
225590792Sgshapirodnl   1    2    3  4    5
225690792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
225790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
225890792Sgshapirodnl            2    3  4    5
225990792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
226090792Sgshapirodnl match, return <match> <passthru>
226190792Sgshapirodnl    2    3  4    5
226290792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
226390792Sgshapiro
226490792Sgshapiro######################################################################
226590792Sgshapiro###  E: LookUpExact -- search for an entry in access database
226690792Sgshapiro###
226790792Sgshapiro###	Parameters:
226890792Sgshapiro###		<$1> -- key
226990792Sgshapiro###		<$2> -- default (what to return if not found in db)
227090792Sgshapirodnl			must not be empty
227190792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
227290792Sgshapiro###			! does lookup only with tag
227390792Sgshapiro###			+ does lookup with and without tag
227490792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
227590792Sgshapirodnl returns:		<default> <passthru>
227690792Sgshapirodnl 			<result> <passthru>
227790792Sgshapiro######################################################################
227890792Sgshapiro
227990792SgshapiroSE
228090792Sgshapirodnl    2    3  4    5
228190792SgshapiroR<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
228290792Sgshapirodnl no match, try without tag
228390792Sgshapirodnl   1    2      3    4
228490792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
228590792Sgshapirodnl no match, return default passthru
228690792Sgshapirodnl   1    2    3  4    5
228790792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
228890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
228990792Sgshapirodnl            2    3  4    5
229090792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
229190792Sgshapirodnl match, return <match> <passthru>
229290792Sgshapirodnl    2    3  4    5
229390792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
229490792Sgshapiro
229590792Sgshapiro######################################################################
229690792Sgshapiro###  U: LookUpUser -- search for an entry in access database
229790792Sgshapiro###
229890792Sgshapiro###	lookup of key (which should be a local part) and
229990792Sgshapiro###	variations if +detail exists: +* and without +detail
230090792Sgshapiro###
230190792Sgshapiro###	Parameters:
230290792Sgshapiro###		<$1> -- key (user@)
230390792Sgshapiro###		<$2> -- default (what to return if not found in db)
230490792Sgshapirodnl			must not be empty
230590792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
230690792Sgshapiro###			! does lookup only with tag
230790792Sgshapiro###			+ does lookup with and without tag
230890792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
230990792Sgshapirodnl returns:		<default> <passthru>
231090792Sgshapirodnl 			<result> <passthru>
231190792Sgshapiro######################################################################
231290792Sgshapiro
231390792SgshapiroSU
231490792Sgshapirodnl user lookups are always with trailing @
231590792Sgshapirodnl    2    3  4    5
231690792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
231790792Sgshapirodnl no match, try without tag
231890792Sgshapirodnl   1    2      3    4
231990792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
232090792Sgshapirodnl do not remove the @ from the lookup:
232190792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
232290792Sgshapirodnl no match, +detail: try +*
232390792Sgshapirodnl   1    2      3    4  5    6
232490792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
232590792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
232690792Sgshapirodnl no match, +detail: try +* without tag
232790792Sgshapirodnl   1    2      3      4    5
232890792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
232990792Sgshapiro			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
233090792Sgshapirodnl no match, +detail: try without +detail
233190792Sgshapirodnl   1    2      3    4  5    6
233290792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
233390792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
233490792Sgshapirodnl no match, +detail: try without +detail and without tag
233590792Sgshapirodnl   1    2      3      4    5
233690792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
233790792Sgshapiro			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
233890792Sgshapirodnl no match, return <default> <passthru>
233990792Sgshapirodnl   1    2    3  4    5
234090792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
234190792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
234290792Sgshapirodnl            2    3  4    5
234390792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
234490792Sgshapirodnl match, return <match> <passthru>
234590792Sgshapirodnl    2    3  4    5
234690792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
234790792Sgshapiro
234890792Sgshapiro######################################################################
234964562Sgshapiro###  SearchList: search a list of items in the access map
235064562Sgshapiro###	Parameters:
235164562Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
235264562Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
235364562Sgshapirodnl	avoid errorneous matches (with error messages?)
235464562Sgshapirodnl	if we can make sure that tag is always a single token
235564562Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
235690792Sgshapirodnl	to avoid errorneous matchs (first rule: D: if there
235764562Sgshapirodnl	is that mark somewhere in the list, it will be taken).
235864562Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
235964562Sgshapirodnl	the tag only, e.g.:
236064562Sgshapiro###	where "exact" is either "+" or "!":
236164562Sgshapiro###	<+ TAG>	lookup with and w/o tag
236264562Sgshapiro###	<! TAG>	lookup with tag
236364562Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
236464562Sgshapirodnl		a blank between them and the tag.
236564562Sgshapiro###	possible values for "mark" are:
236690792Sgshapiro###		D: recursive host lookup (LookUpDomain)
236764562Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
236864562Sgshapiro###		E: exact lookup, no modifications
236964562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
237064562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
237164562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
237264562Sgshapiro######################################################################
237338032Speter
237464562Sgshapiro# class with valid marks for SearchList
237564562Sgshapirodnl if A is activated: add it
237690792SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
237764562SgshapiroSSearchList
237890792Sgshapiro# just call the ruleset with the name of the tag... nice trick...
237990792Sgshapirodnl       2       3    4
238090792SgshapiroR<$+> $| <$={src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
238190792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <>
238290792Sgshapirodnl no match and nothing left: return
238390792SgshapiroR<$+> $| <> $| <?> <>		$@ <?>
238490792Sgshapirodnl no match but something left: continue
238590792SgshapiroR<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
238690792Sgshapirodnl match: return
238790792SgshapiroR<$+> $| <$*> $| <$+> <>	$@ <$3>
238864562Sgshapirodnl return result from recursive invocation
238990792SgshapiroR<$+> $| <$+>			$@ <$2>
239090792Sgshapirodnl endif _ACCESS_TABLE_
239190792Sgshapirodivert(0)
239238032Speter
239390792Sgshapiro######################################################################
239490792Sgshapiro###  trust_auth: is user trusted to authenticate as someone else?
239590792Sgshapiro###
239690792Sgshapiro###	Parameters:
239790792Sgshapiro###		$1: AUTH= parameter from MAIL command
239890792Sgshapiro######################################################################
239990792Sgshapiro
240090792Sgshapirodnl empty ruleset definition so it can be called
240190792SgshapiroSLocal_trust_auth
240264562SgshapiroStrust_auth
240364562SgshapiroR$*			$: $&{auth_type} $| $1
240464562Sgshapiro# required by RFC 2554 section 4.
240564562SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
240664562Sgshapirodnl seems to be useful...
240764562SgshapiroR$* $| $&{auth_authen}		$@ identical
240864562SgshapiroR$* $| <$&{auth_authen}>	$@ identical
240964562Sgshapirodnl call user supplied code
241064562SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $1
241164562SgshapiroR$* $| $#$*		$#$2
241264562Sgshapirodnl default: error
241364562SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
241464562Sgshapiro
241590792Sgshapiro######################################################################
241690792Sgshapiro###  Relay_Auth: allow relaying based on authentication?
241790792Sgshapiro###
241890792Sgshapiro###	Parameters:
241990792Sgshapiro###		$1: ${auth_type}
242090792Sgshapiro######################################################################
242190792SgshapiroSLocal_Relay_Auth
242264562Sgshapiro
242390792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
242490792Sgshapiro######################################################################
242590792Sgshapiro###  srv_features: which features to offer to a client?
242690792Sgshapiro###	(done in server)
242790792Sgshapiro######################################################################
242890792SgshapiroSsrv_features
242990792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl
243090792SgshapiroR$*			$: $1 $| $>"Local_srv_features" $1
243190792SgshapiroR$* $| $#$*		$#$2
243290792SgshapiroR$* $| $*		$: $1', `dnl')
243390792SgshapiroR$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
243490792SgshapiroR<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
243590792SgshapiroR<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
243664562SgshapiroR<?>$*		$@ OK
243790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
243890792SgshapiroR<$* _ATMPF_>$*	$#temp', `dnl')
243990792SgshapiroR<$+>$*		$# $1
244064562Sgshapiro
244190792Sgshapiro######################################################################
244290792Sgshapiro###  try_tls: try to use STARTTLS?
244390792Sgshapiro###	(done in client)
244490792Sgshapiro######################################################################
244564562SgshapiroStry_tls
244690792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl
244790792SgshapiroR$*			$: $1 $| $>"Local_try_tls" $1
244890792SgshapiroR$* $| $#$*		$#$2
244990792SgshapiroR$* $| $*		$: $1', `dnl')
245090792SgshapiroR$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
245190792SgshapiroR<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
245290792SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
245364562SgshapiroR<?>$*		$@ OK
245490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
245590792SgshapiroR<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
245671345SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
245790792Sgshapiro  
245890792Sgshapiro######################################################################
245990792Sgshapiro###  tls_rcpt: is connection with server "good" enough?
246090792Sgshapiro###	(done in client, per recipient)
246190792Sgshapirodnl called from deliver() before RCPT command
246290792Sgshapiro###
246390792Sgshapiro###	Parameters:
246490792Sgshapiro###		$1: recipient
246590792Sgshapiro######################################################################
246690792SgshapiroStls_rcpt
246790792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl
246890792SgshapiroR$*			$: $1 $| $>"Local_tls_rcpt" $1
246990792SgshapiroR$* $| $#$*		$#$2
247090792SgshapiroR$* $| $*		$: $1', `dnl')
247190792Sgshapirodnl store name of other side
247290792SgshapiroR$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
247390792Sgshapirodnl canonify recipient address
247490792SgshapiroR$+			$: <?> $>CanonAddr $1
247590792Sgshapirodnl strip trailing dots
247690792SgshapiroR<?> $+ < @ $+ . >	<?> $1 <@ $2 >
247790792Sgshapirodnl full address?
247890792SgshapiroR<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
247990792Sgshapirodnl only localpart?
248090792SgshapiroR<?> $+			$: $1 $| <U:$1@> <E:>
248190792Sgshapirodnl look it up
248290792Sgshapirodnl also look up a default value via E:
248390792SgshapiroR$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
248490792Sgshapirodnl found nothing: stop here
248590792SgshapiroR$* $| <?>	$@ OK
248690792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
248790792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
248890792Sgshapirodnl use the generic routine (for now)
248990792SgshapiroR$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
249064562Sgshapiro
249190792Sgshapiro######################################################################
249290792Sgshapiro###  tls_client: is connection with client "good" enough?
249390792Sgshapiro###	(done in server)
249490792Sgshapiro###
249590792Sgshapiro###	Parameters:
249690792Sgshapiro###		${verify} $| (MAIL|STARTTLS)
249790792Sgshapiro######################################################################
249864562Sgshapirodnl MAIL: called from check_mail
249964562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
250064562SgshapiroStls_client
250190792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl
250290792SgshapiroR$*			$: $1 $| $>"Local_tls_client" $1
250390792SgshapiroR$* $| $#$*		$#$2
250490792SgshapiroR$* $| $*		$: $1', `dnl')
250564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
250690792Sgshapirodnl store name of other side
250790792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
250864562Sgshapirodnl ignore second arg for now
250964562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
251064562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
251164562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
251290792SgshapiroR$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
251390792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
251464562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
251564562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
251690792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
251790792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
251890792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
251990792SgshapiroR$* $| $*	$@ $>"TLS_connection" $1')
252064562Sgshapiro
252190792Sgshapiro######################################################################
252290792Sgshapiro###  tls_server: is connection with server "good" enough?
252390792Sgshapiro###	(done in client)
252490792Sgshapiro###
252590792Sgshapiro###	Parameter:
252690792Sgshapiro###		${verify}
252790792Sgshapiro######################################################################
252864562Sgshapirodnl i.e. has the server been authenticated and is encryption active?
252964562Sgshapirodnl called from deliver() after STARTTLS command
253064562SgshapiroStls_server
253190792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl
253290792SgshapiroR$*			$: $1 $| $>"Local_tls_server" $1
253390792SgshapiroR$* $| $#$*		$#$2
253490792SgshapiroR$* $| $*		$: $1', `dnl')
253564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
253690792Sgshapirodnl store name of other side
253790792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
253890792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
253990792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
254064562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
254164562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
254290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
254390792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
254490792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
254590792SgshapiroR$*		$@ $>"TLS_connection" $1')
254664562Sgshapiro
254790792Sgshapiro######################################################################
254890792Sgshapiro###  TLS_connection: is TLS connection "good" enough?
254990792Sgshapiro###
255090792Sgshapiro###	Parameters:
255164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
255290792Sgshapiro###		${verify} $| <Requirement> [<>]', `dnl
255390792Sgshapiro###		${verify}')
255490792Sgshapiro###		Requirement: RHS from access map, may be ? for none.
255590792Sgshapirodnl	syntax for Requirement:
255690792Sgshapirodnl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
255790792Sgshapirodnl	extensions: could be a list of further requirements
255890792Sgshapirodnl		for now: CN:string	{cn_subject} == string
255990792Sgshapiro######################################################################
256090792SgshapiroSTLS_connection
256190792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
256290792Sgshapirodnl deal with TLS handshake failures: abort
256390792SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
256490792Sgshapirodivert(-1)')
256564562Sgshapirodnl common ruleset for tls_{client|server}
256690792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>]
256764562Sgshapirodnl remove optional <>
256864562SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
256990792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup>
257090792Sgshapiro# create the appropriate error codes
257164562Sgshapirodnl permanent or temporary error?
257264562SgshapiroR$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
257364562SgshapiroR$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
257464562Sgshapirodnl default case depends on TLS_PERM_ERR
257564562SgshapiroR$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
257690792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
257790792Sgshapiro# deal with TLS handshake failures: abort
257864562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
257964562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
258064562Sgshapirodnl use default error
258164562SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
258290792SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
258390792Sgshapirodnl separate optional requirements
258490792SgshapiroR$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
258590792SgshapiroR$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> <> $1
258690792Sgshapirodnl separate optional requirements
258790792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
258864562Sgshapirodnl some other value in access map: accept
258964562Sgshapirodnl this also allows to override the default case (if used)
259064562SgshapiroR$* $| $*			$@ OK
259164562Sgshapiro# authentication required: give appropriate error
259264562Sgshapiro# other side did authenticate (via STARTTLS)
259390792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
259464562Sgshapirodnl only verification required and it succeeded
259590792SgshapiroR<$*><VERIFY> <> OK		$@ OK
259690792Sgshapirodnl verification required and it succeeded but extensions are given
259790792Sgshapirodnl change it to <SMTP:ESC> <REQ:0>  <extensions>
259890792SgshapiroR<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
259964562Sgshapirodnl verification required + some level of encryption
260090792SgshapiroR<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
260164562Sgshapirodnl just some level of encryption required
260290792SgshapiroR<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
260390792Sgshapirodnl workspace:
260490792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
260590792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
260690792Sgshapirodnl verification required but ${verify} is not set (case 1.)
260790792SgshapiroR<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
260890792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
260990792SgshapiroR<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
261090792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
261190792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
261264562Sgshapirodnl some other value for ${verify}
261390792SgshapiroR<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
261490792Sgshapirodnl some level of encryption required: get the maximum level (case 2.)
261590792SgshapiroR<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
261664562Sgshapirodnl compare required bits with actual bits
261790792SgshapiroR<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
261890792SgshapiroR<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
261990792Sgshapirodnl strength requirements fulfilled
262090792Sgshapirodnl TLS Additional Requirements Separator
262190792Sgshapirodnl this should be something which does not appear in the extensions itself
262290792Sgshapirodnl @ could be part of a CN, DN, etc...
262390792Sgshapirodnl use < > ? those are encoded in CN, DN, ...
262490792Sgshapirodefine(`_TLS_ARS_', `++')dnl
262590792Sgshapirodnl workspace:
262690792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
262790792SgshapiroR<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
262890792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
262990792Sgshapirodnl continue: check  extensions
263090792SgshapiroR<$-:$+ _TLS_ARS_ >			$@ OK
263190792Sgshapirodnl split extensions into own list
263290792SgshapiroR<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
263390792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
263490792SgshapiroR<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
263564562Sgshapiro
263690792Sgshapiro######################################################################
263790792Sgshapiro###  TLS_req: check additional TLS requirements
263890792Sgshapiro###
263990792Sgshapiro###	Parameters: [<list> <of> <req>] $| <$-:$+>
264090792Sgshapiro###		$-: SMTP reply code
264190792Sgshapiro###		$+: Enhanced Status Code
264290792Sgshapirodnl  further requirements for this ruleset:
264390792Sgshapirodnl	name of "other side" is stored is {TLS_name} (client/server_name)
264490792Sgshapirodnl
264590792Sgshapirodnl	currently only CN[:common_name] is implemented
264690792Sgshapirodnl	right now this is only a logical AND
264790792Sgshapirodnl	i.e. all requirements must be true
264890792Sgshapirodnl	how about an OR? CN must be X or CN must be Y or ..
264990792Sgshapirodnl	use a macro to compute this as a trivial sequential
265090792Sgshapirodnl	operations (no precedences etc)?
265190792Sgshapiro######################################################################
265290792SgshapiroSTLS_req
265390792Sgshapirodnl no additional requirements: ok
265490792SgshapiroR $| $+		$@ OK
265590792Sgshapirodnl require CN: but no CN specified: use name of other side
265690792SgshapiroR<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
265790792Sgshapirodnl match, check rest
265890792SgshapiroR<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
265990792Sgshapirodnl CN does not match
266090792Sgshapirodnl  1   2      3  4
266190792SgshapiroR<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
266290792Sgshapirodnl cert subject
266390792SgshapiroR<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
266490792Sgshapirodnl CS does not match
266590792Sgshapirodnl  1   2      3  4
266690792SgshapiroR<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CERT Subject " $&{cert_subject} " does not match " $1
266790792Sgshapirodnl match, check rest
266890792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
266990792Sgshapirodnl CI does not match
267090792Sgshapirodnl  1   2      3  4
267190792SgshapiroR<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CERT Issuer " $&{cert_issuer} " does not match " $1
267290792Sgshapirodnl return from recursive call
267390792SgshapiroROK			$@ OK
267490792Sgshapiro
267590792Sgshapiro######################################################################
267690792Sgshapiro###  max: return the maximum of two values separated by :
267790792Sgshapiro###
267890792Sgshapiro###	Parameters: [$-]:[$-]
267990792Sgshapiro######################################################################
268064562SgshapiroSmax
268164562SgshapiroR:		$: 0
268264562SgshapiroR:$-		$: $1
268364562SgshapiroR$-:		$: $1
268464562SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
268564562SgshapiroRTRUE:$-:$-	$: $2
268690792SgshapiroR$-:$-:$-	$: $2
268790792Sgshapirodnl endif _ACCESS_TABLE_
268890792Sgshapirodivert(0)
268964562Sgshapiro
269090792Sgshapiro######################################################################
269190792Sgshapiro###  RelayTLS: allow relaying based on TLS authentication
269290792Sgshapiro###
269390792Sgshapiro###	Parameters:
269490792Sgshapiro###		none
269590792Sgshapiro######################################################################
269690792SgshapiroSRelayTLS
269764562Sgshapiro# authenticated?
269864562Sgshapirodnl we do not allow relaying for anyone who can present a cert
269964562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
270064562Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow
270164562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
270264562Sgshapirodnl but anyway).
270364562Sgshapirodnl so here is the trick: if the verification succeeded
270464562Sgshapirodnl we look up the cert issuer in the access map
270564562Sgshapirodnl (maybe after extracting a part with a regular expression)
270664562Sgshapirodnl if this returns RELAY we relay without further questions
270764562Sgshapirodnl if it returns SUBJECT we perform a similar check on the
270864562Sgshapirodnl cert subject.
270964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
271090792SgshapiroR$*			$: <?> $&{verify}
271190792SgshapiroR<?> OK			$: OK		authenticated: continue
271290792SgshapiroR<?> $*			$@ NO		not authenticated
271364562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
271490792SgshapiroR$*			$: $(CERTIssuer $&{cert_issuer} $)',
271590792Sgshapiro`R$*			$: $&{cert_issuer}')
271690792SgshapiroR$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
271764562Sgshapirodnl use $# to stop further checks (delay_check)
271890792SgshapiroRRELAY			$# RELAY
271964562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
272090792SgshapiroRSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
272190792Sgshapiro`RSUBJECT		$: <@> $&{cert_subject}')
272290792SgshapiroR<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
272390792SgshapiroR<@> RELAY		$# RELAY
272490792SgshapiroR$*			$: NO', `dnl')
272564562Sgshapiro
272690792Sgshapiro######################################################################
272790792Sgshapiro###  authinfo: lookup authinfo in the access map
272890792Sgshapiro###
272990792Sgshapiro###	Parameters:
273090792Sgshapiro###		$1: {server_name}
273190792Sgshapiro###		$2: {server_addr}
273290792Sgshapirodnl	both are currently ignored
273390792Sgshapirodnl if it should be done via another map, we either need to restrict
273490792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another
273590792Sgshapirodnl parameter which I want to avoid, it's quite complex already)
273690792Sgshapiro######################################################################
273790792Sgshapirodnl omit this ruleset if neither is defined?
273890792Sgshapirodnl it causes DefaultAuthInfo to be ignored
273990792Sgshapirodnl (which may be considered a good thing).
274090792SgshapiroSauthinfo
274190792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl
274290792SgshapiroR$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
274390792SgshapiroR<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
274490792SgshapiroR<?>		$: <$(authinfo AuthInfo: $: ? $)>
274590792SgshapiroR<?>		$@ no				no authinfo available
274690792SgshapiroR<$*>		$# $1
274790792Sgshapirodnl', `dnl
274890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
274990792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
275090792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
275190792SgshapiroR$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
275290792SgshapiroR$* $| <?>$*	$@ no				no authinfo available
275390792SgshapiroR$* $| <$*> <>	$# $2
275490792Sgshapirodnl', `dnl')')
275590792Sgshapiro
275664562Sgshapiroundivert(9)dnl LOCAL_RULESETS
275738032Speter#
275838032Speter######################################################################
275938032Speter######################################################################
276038032Speter#####
276164562Sgshapiro`#####			MAIL FILTER DEFINITIONS'
276264562Sgshapiro#####
276364562Sgshapiro######################################################################
276464562Sgshapiro######################################################################
276590792Sgshapiro_MAIL_FILTERS_
276664562Sgshapiro#
276764562Sgshapiro######################################################################
276864562Sgshapiro######################################################################
276964562Sgshapiro#####
277038032Speter`#####			MAILER DEFINITIONS'
277138032Speter#####
277238032Speter######################################################################
277338032Speter######################################################################
277464562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
277566494Sgshapiro
2776