proto.m4 revision 223067
138032Speterdivert(-1)
238032Speter#
3223067Sgshapiro# Copyright (c) 1998-2010 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
16223067SgshapiroVERSIONID(`$Id: proto.m4,v 8.744 2010/11/23 20:29:47 guenther Exp $')
1738032Speter
1864562Sgshapiro# level CF_LEVEL config file format
19223067SgshapiroV`'CF_LEVEL`'ifdef(`NO_VENDOR',`', `/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley')')
2038032Speterdivert(-1)
2138032Speter
2290792Sgshapirodnl if MAILER(`local') not defined: do it ourself; be nice
2390792Sgshapirodnl maybe we should issue a warning?
2490792Sgshapiroifdef(`_MAILER_local_',`', `MAILER(local)')
2590792Sgshapiro
2638032Speter# do some sanity checking
2738032Speterifdef(`__OSTYPE__',,
2864562Sgshapiro	`errprint(`*** ERROR: No system type defined (use OSTYPE macro)
2964562Sgshapiro')')
3038032Speter
3138032Speter# pick our default mailers
3238032Speterifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')')
3338032Speterifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')')
3438032Speterifdef(`confRELAY_MAILER',,
3538032Speter	`define(`confRELAY_MAILER',
3638032Speter		`ifdef(`_MAILER_smtp_', `relay',
3738032Speter			`ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')')
3838032Speterifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')')
3938032Speterdefine(`_SMTP_', `confSMTP_MAILER')dnl		for readability only
4038032Speterdefine(`_LOCAL_', `confLOCAL_MAILER')dnl	for readability only
4138032Speterdefine(`_RELAY_', `confRELAY_MAILER')dnl	for readability only
4238032Speterdefine(`_UUCP_', `confUUCP_MAILER')dnl		for readability only
4338032Speter
4438032Speter# back compatibility with old config files
4538032Speterifdef(`confDEF_GROUP_ID',
4664562Sgshapiro`errprint(`*** confDEF_GROUP_ID is obsolete.
4764562Sgshapiro    Use confDEF_USER_ID with a colon in the value instead.
4864562Sgshapiro')')
4938032Speterifdef(`confREAD_TIMEOUT',
5064562Sgshapiro`errprint(`*** confREAD_TIMEOUT is obsolete.
5164562Sgshapiro    Use individual confTO_<timeout> parameters instead.
5264562Sgshapiro')')
5338032Speterifdef(`confMESSAGE_TIMEOUT',
5438032Speter	`define(`_ARG_', index(confMESSAGE_TIMEOUT, /))
5538032Speter	 ifelse(_ARG_, -1,
5638032Speter		`define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)',
5738032Speter		`define(`confTO_QUEUERETURN',
5838032Speter			substr(confMESSAGE_TIMEOUT, 0, _ARG_))
5938032Speter		 define(`confTO_QUEUEWARN',
6038032Speter			substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')')
6138032Speterifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,,
6264562Sgshapiro`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete.
6364562Sgshapiro    Use confMAX_MESSAGE_SIZE for the second part of the value.
6464562Sgshapiro')')')
6538032Speter
6664562Sgshapiro
6764562Sgshapiro# Sanity check on ldap_routing feature
6864562Sgshapiro# If the user doesn't specify a new map, they better have given as a
6964562Sgshapiro# default LDAP specification which has the LDAP base (and most likely the host)
7064562Sgshapiroifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(`
7164562SgshapiroWARNING: Using default FEATURE(ldap_routing) map definition(s)
7264562Sgshapirowithout setting confLDAP_DEFAULT_SPEC option.
7364562Sgshapiro')')')dnl
7464562Sgshapiro
7538032Speter# clean option definitions below....
7664562Sgshapirodefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl
7738032Speter
7864562Sgshapirodnl required to "rename" the check_* rulesets...
7964562Sgshapirodefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_'))
8064562Sgshapirodnl default relaying denied message
8190792Sgshapiroifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG',
8290792Sgshapiroifdef(`_USE_AUTH_', `"550 Relaying denied. Proper authentication required."', `"550 Relaying denied"'))')
8390792Sgshapiroifdef(`confRCPTREJ_MSG', `', `define(`confRCPTREJ_MSG', `"550 Mailbox disabled for this recipient"')')
8490792Sgshapirodefine(`_CODE553', `553')
8538032Speterdivert(0)dnl
8638032Speter
8764562Sgshapiro# override file safeties - setting this option compromises system security,
8864562Sgshapiro# addressing the actual file configuration problem is preferred
8964562Sgshapiro# need to set this before any file actions are encountered in the cf file
9064562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe')
9138032Speter
9264562Sgshapiro# default LDAP map specification
9364562Sgshapiro# need to set this now before any LDAP maps are defined
9464562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost')
9564562Sgshapiro
9638032Speter##################
9738032Speter#   local info   #
9838032Speter##################
9938032Speter
10090792Sgshapiro# my LDAP cluster
10190792Sgshapiro# need to set this before any LDAP lookups are done (including classes)
10290792Sgshapiroifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m')
10390792Sgshapiro
10438032SpeterCwlocalhost
10538032Speterifdef(`USE_CW_FILE',
10638032Speter`# file containing names of hosts for which we receive email
10738032SpeterFw`'confCW_FILE',
10838032Speter	`dnl')
10938032Speter
11038032Speter# my official domain name
11138032Speter# ... `define' this only if sendmail cannot automatically determine your domain
11238032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM')
11338032Speter
114125820Sgshapiro# host/domain names ending with a token in class P are canonical
11538032SpeterCP.
11638032Speter
11738032Speterifdef(`UUCP_RELAY',
11838032Speter`# UUCP relay host
11938032SpeterDY`'UUCP_RELAY
12038032SpeterCPUUCP
12138032Speter
12238032Speter')dnl
12338032Speterifdef(`BITNET_RELAY',
12438032Speter`#  BITNET relay host
12538032SpeterDB`'BITNET_RELAY
12638032SpeterCPBITNET
12738032Speter
12838032Speter')dnl
12938032Speterifdef(`DECNET_RELAY',
13038032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl
13138032Speter# DECnet relay host
13238032SpeterDC`'DECNET_RELAY
13338032SpeterCPDECNET
13438032Speter
13538032Speter')dnl
13638032Speterifdef(`FAX_RELAY',
13738032Speter`# FAX relay host
13838032SpeterDF`'FAX_RELAY
13938032SpeterCPFAX
14038032Speter
14138032Speter')dnl
14238032Speter# "Smart" relay host (may be null)
14390792SgshapiroDS`'ifdef(`SMART_HOST', `SMART_HOST')
14438032Speter
14538032Speterifdef(`LUSER_RELAY', `dnl
14638032Speter# place to which unknown users should be forwarded
14738032SpeterKuser user -m -a<>
14838032SpeterDL`'LUSER_RELAY',
14938032Speter`dnl')
15038032Speter
15138032Speter# operators that cannot be in local usernames (i.e., network indicators)
15238032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!')
15338032Speter
15438032Speter# a class with just dot (for identifying canonical names)
15538032SpeterC..
15638032Speter
15738032Speter# a class with just a left bracket (for identifying domain literals)
15838032SpeterC[[
15938032Speter
16064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
16164562Sgshapiro# access_db acceptance class
16264562SgshapiroC{Accept}OK RELAY
16390792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
16464562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl
16564562Sgshapiro# possible access_db RHS for spam friends/haters
16664562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')',
16738032Speter`dnl')
16838032Speter
16990792Sgshapirodnl mark for "domain is ok" (resolved or accepted anyway)
17090792Sgshapirodefine(`_RES_OK_', `OKR')dnl
17138032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
17238032Speter# Resolve map (to check if a host exists in check_mail)
17390792SgshapiroKresolve host -a<_RES_OK_> -T<TEMP>')
17490792SgshapiroC{ResOk}_RES_OK_
17538032Speter
17680785Sgshapiroifdef(`_NEED_MACRO_MAP_', `dnl
17780785Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map
17880785Sgshapirodefine(`_MACRO_MAP_', `1')dnl
17980785SgshapiroKmacro macro')', `dnl')
18066494Sgshapiro
18138032Speterifdef(`confCR_FILE', `dnl
18266494Sgshapiro# Hosts for which relaying is permitted ($=R)
18338032SpeterFR`'confCR_FILE',
18438032Speter`dnl')
18538032Speter
18690792Sgshapirodefine(`TLS_SRV_TAG', `"TLS_Srv"')dnl
18790792Sgshapirodefine(`TLS_CLT_TAG', `"TLS_Clt"')dnl
18890792Sgshapirodefine(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl
18990792Sgshapirodefine(`TLS_TRY_TAG', `"Try_TLS"')dnl
19090792Sgshapirodefine(`SRV_FEAT_TAG', `"Srv_Features"')dnl
19164562Sgshapirodnl this may be useful in other contexts too
19264562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map
19364562Sgshapirodefine(`_ARITH_MAP_', `1')dnl
19464562SgshapiroKarith arith')
19564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
19690792Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map
19790792Sgshapirodefine(`_MACRO_MAP_', `1')dnl
19890792SgshapiroKmacro macro')
19990792Sgshapiro# possible values for TLS_connection in access map
200132943SgshapiroC{Tls}VERIFY ENCR', `dnl')
20164562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
20264562Sgshapiro# extract relevant part from cert issuer
20364562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
20464562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
20564562Sgshapiro# extract relevant part from cert subject
20664562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
20764562Sgshapiro
20890792Sgshapiroifdef(`LOCAL_RELAY', `dnl
209110647Sgshapiro# who I send unqualified names to if `FEATURE(stickyhost)' is used
210110560Sgshapiro# (null means deliver locally)
21190792SgshapiroDR`'LOCAL_RELAY')
21238032Speter
21390792Sgshapiroifdef(`MAIL_HUB', `dnl
214110560Sgshapiro# who gets all local email traffic
215110647Sgshapiro# ($R has precedence for unqualified names if `FEATURE(stickyhost)' is used)
21690792SgshapiroDH`'MAIL_HUB')
21738032Speter
21838032Speter# dequoting map
21990792SgshapiroKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `')
22038032Speter
22138032Speterdivert(0)dnl	# end of nullclient diversion
22238032Speter# class E: names that should be exposed as from this host, even if we masquerade
22364562Sgshapiro# class L: names that should be delivered locally, even if we have a relay
22438032Speter# class M: domains that should be converted to $M
22564562Sgshapiro# class N: domains that should not be converted to $M
22638032Speter#CL root
22738032Speterundivert(5)dnl
22864562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
22938032Speter
23090792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
23138032Speter# who I masquerade as (null for no masquerading) (see also $=M)
23290792SgshapiroDM`'MASQUERADE_NAME')
23338032Speter
23438032Speter# my name for error messages
23538032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
23638032Speter
23764562Sgshapiroundivert(6)dnl LOCAL_CONFIG
23838032Speterinclude(_CF_DIR_`m4/version.m4')
23938032Speter
24038032Speter###############
24138032Speter#   Options   #
24238032Speter###############
24390792Sgshapiroifdef(`confAUTO_REBUILD',
24490792Sgshapiro`errprint(WARNING: `confAUTO_REBUILD' is no longer valid.
24590792Sgshapiro	There was a potential for a denial of service attack if this is set.
24690792Sgshapiro)')dnl
24738032Speter
24838032Speter# strip message body to 7 bits on input?
24964562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
25038032Speter
25138032Speter# 8-bit data handling
25277349Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8')
25338032Speter
25438032Speter# wait for alias file rebuild (default units: minutes)
25564562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m')
25638032Speter
25738032Speter# location of alias file
25864562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
25964562Sgshapiro
26038032Speter# minimum number of free blocks on filesystem
26164562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
26238032Speter
26338032Speter# maximum message size
264132943Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `0')
26538032Speter
26638032Speter# substitution for space (blank) characters
26764562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_')
26838032Speter
26938032Speter# avoid connecting to "expensive" mailers on initial submission?
27064562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
27138032Speter
27238032Speter# checkpoint queue runs after every N successful deliveries
27364562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
27438032Speter
27538032Speter# default delivery mode
27664562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
27738032Speter
27838032Speter# error message header/file
27964562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
28038032Speter
28138032Speter# error mode
28264562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print')
28338032Speter
28438032Speter# save Unix-style "From_" lines at top of header?
28564562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
28638032Speter
28790792Sgshapiro# queue file mode (qf files)
28890792Sgshapiro_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600')
28990792Sgshapiro
29038032Speter# temporary file mode
29164562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
29238032Speter
29338032Speter# match recipients against GECOS field?
29464562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
29538032Speter
29638032Speter# maximum hop count
29790792Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `25')
29838032Speter
29938032Speter# location of help file
30064562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
30138032Speter
30238032Speter# ignore dots as terminators in incoming messages?
30364562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
30438032Speter
30538032Speter# name resolver options
30664562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
30738032Speter
30838032Speter# deliver MIME-encapsulated error messages?
30964562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
31038032Speter
31138032Speter# Forward file search path
31264562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
31338032Speter
31438032Speter# open connection cache size
31564562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
31638032Speter
31738032Speter# open connection cache timeout
31864562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
31938032Speter
32038032Speter# persistent host status directory
32164562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
32238032Speter
32338032Speter# single thread deliveries (requires HostStatusDirectory)?
32464562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
32538032Speter
32638032Speter# use Errors-To: header?
32764562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
32838032Speter
32938032Speter# log level
33064562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10')
33138032Speter
33238032Speter# send to me too, even in an alias expansion?
33364562Sgshapiro_OPTION(MeToo, `confME_TOO', `True')
33438032Speter
33538032Speter# verify RHS in newaliases?
33664562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
33738032Speter
33838032Speter# default messages to old style headers if no special punctuation?
33964562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
34038032Speter
34138032Speter# SMTP daemon options
34264562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
34394334Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.
34494334Sgshapiro	Use `DAEMON_OPTIONS()'; see cf/README.
34564562Sgshapiro)'dnl
34664562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
34766494Sgshapiroifelse(defn(`_DPO_'), `',
34890792Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet
34990792SgshapiroO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
35064562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
35138032Speter
35264562Sgshapiro# SMTP client options
35390792Sgshapiroifelse(defn(`confCLIENT_OPTIONS'), `', `dnl',
35490792Sgshapiro`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid.  See cf/README for more information.
35590792Sgshapiro)'dnl
35690792Sgshapiro`CLIENT_OPTIONS(`confCLIENT_OPTIONS')')
35790792Sgshapiroifelse(defn(`_CPO_'), `',
35890792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_')
35964562Sgshapiro
36090792Sgshapiro# Modifiers to `define' {daemon_flags} for direct submissions
36190792Sgshapiro_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `')
36290792Sgshapiro
36390792Sgshapiro# Use as mail submission program? See sendmail/SECURITY
36490792Sgshapiro_OPTION(UseMSP, `confUSE_MSP', `')
36590792Sgshapiro
36638032Speter# privacy flags
36764562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
36838032Speter
36938032Speter# who (if anyone) should get extra copies of error messages
37064562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
37138032Speter
37238032Speter# slope of queue-only function
37364562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
37438032Speter
37590792Sgshapiro# limit on number of concurrent queue runners
37690792Sgshapiro_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `')
37790792Sgshapiro
37890792Sgshapiro# maximum number of queue-runners per queue-grouping with multiple queues
37990792Sgshapiro_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1')
38090792Sgshapiro
38190792Sgshapiro# priority of queue runners (nice(3))
38290792Sgshapiro_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `')
38390792Sgshapiro
38490792Sgshapiro# shall we sort the queue by hostname first?
38590792Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
38690792Sgshapiro
38790792Sgshapiro# minimum time in queue before retry
38890792Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
38990792Sgshapiro
39090792Sgshapiro# how many jobs can you process in the queue?
391157001Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `0')
39290792Sgshapiro
39390792Sgshapiro# perform initial split of envelope without checking MX records
39490792Sgshapiro_OPTION(FastSplit, `confFAST_SPLIT', `1')
39590792Sgshapiro
39638032Speter# queue directory
39764562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
39838032Speter
399168515Sgshapiro# key for shared memory; 0 to turn off, -1 to auto-select
40090792Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
40190792Sgshapiro
402168515Sgshapiro# file to store auto-selected key for shared memory (SharedMemoryKey = -1)
403168515Sgshapiro_OPTION(SharedMemoryKeyFile, `confSHARED_MEMORY_KEY_FILE', `')
40494334Sgshapiro
40538032Speter# timeouts (many of these)
40664562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
40764562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
40890792Sgshapiro_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s')
40964562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
41064562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m')
41164562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m')
41264562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
41364562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
41464562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
41564562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
41664562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m')
41764562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m')
41864562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m')
41964562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h')
42064562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s')
42164562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
42264562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m')
42364562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
42464562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
42564562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
42664562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
427132943Sgshapiro_OPTION(Timeout.queuereturn.dsn, `confTO_QUEUERETURN_DSN', `5d')
42864562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
42964562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
43064562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
43164562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
432132943Sgshapiro_OPTION(Timeout.queuewarn.dsn, `confTO_QUEUEWARN_DSN', `4h')
43364562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
43464562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
43564562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
43664562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
43764562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
43864562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
43964562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
44090792Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
44190792Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m')
44290792Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
44338032Speter
44490792Sgshapiro# time for DeliverBy; extension disabled if less than 0
44590792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
44690792Sgshapiro
44738032Speter# should we not prune routes in route-addr syntax addresses?
44864562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
44938032Speter
45038032Speter# queue up everything before forking?
45164562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
45238032Speter
45338032Speter# status file
454168515Sgshapiro_OPTION(StatusFile, `STATUS_FILE')
45538032Speter
45638032Speter# time zone handling:
45738032Speter#  if undefined, use system default
45838032Speter#  if defined but null, use TZ envariable passed in
45938032Speter#  if defined and non-null, use that info
46038032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
46138032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
46238032Speter	`O TimeZoneSpec=confTIME_ZONE')
46338032Speter
46438032Speter# default UID (can be username or userid:groupid)
46564562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
46638032Speter
46738032Speter# list of locations of user database file (null means no lookup)
46864562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
46938032Speter
47038032Speter# fallback MX host
47164562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
47238032Speter
473132943Sgshapiro# fallback smart host
474132943Sgshapiro_OPTION(FallbackSmartHost, `confFALLBACK_SMARTHOST', `fall.back.host.net')
475132943Sgshapiro
47638032Speter# if we are the best MX host for a site, try it directly instead of config err
47764562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
47838032Speter
47938032Speter# load average at which we just queue messages
48064562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8')
48138032Speter
48238032Speter# load average at which we refuse connections
48364562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
48438032Speter
485132943Sgshapiro# log interval when refusing connections for this long
486132943Sgshapiro_OPTION(RejectLogInterval, `confREJECT_LOG_INTERVAL', `3h')
487132943Sgshapiro
48890792Sgshapiro# load average at which we delay connections; 0 means no limit
48990792Sgshapiro_OPTION(DelayLA, `confDELAY_LA', `0')
49090792Sgshapiro
49138032Speter# maximum number of children we allow at one time
49298841Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0')
49338032Speter
49438032Speter# maximum number of new connections per second
49571345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
49638032Speter
497132943Sgshapiro# Width of the window 
498132943Sgshapiro_OPTION(ConnectionRateWindowSize, `confCONNECTION_RATE_WINDOW_SIZE', `60s')
499132943Sgshapiro
50038032Speter# work recipient factor
50164562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
50238032Speter
50338032Speter# deliver each queued job in a separate process?
50464562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
50538032Speter
50638032Speter# work class factor
50764562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
50838032Speter
50938032Speter# work time factor
51064562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
51138032Speter
51238032Speter# default character set
513141858Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `unknown-8bit')
51438032Speter
51590792Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
51664562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
51738032Speter
51838032Speter# hosts file (normally /etc/hosts)
51964562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
52038032Speter
52138032Speter# dialup line delay on connection failure
522157001Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `0s')
52338032Speter
52438032Speter# action to take if there are no recipients in the message
525157001Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `none')
52638032Speter
52738032Speter# chrooted environment for writing to files
528157001Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `')
52938032Speter
53038032Speter# are colons OK in addresses?
53164562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
53238032Speter
53338032Speter# shall I avoid expanding CNAMEs (violates protocols)?
53464562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
53538032Speter
53638032Speter# SMTP initial login message (old $e macro)
53764562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
53838032Speter
53938032Speter# UNIX initial From header format (old $l macro)
54064562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
54138032Speter
54238032Speter# From: lines that have embedded newlines are unwrapped onto one line
54364562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
54438032Speter
54538032Speter# Allow HELO SMTP command that does not `include' a host name
54664562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
54738032Speter
54838032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
54964562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
55038032Speter
55138032Speter# delimiter (operator) characters (old $o macro)
55264562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
55338032Speter
55438032Speter# shall I avoid calling initgroups(3) because of high NIS costs?
55564562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
55638032Speter
55738032Speter# are group-writable `:include:' and .forward files (un)trustworthy?
55890792Sgshapiro# True (the default) means they are not trustworthy.
55964562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
56090792Sgshapiroifdef(`confUNSAFE_GROUP_WRITES',
56190792Sgshapiro`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
56290792Sgshapiro')')
56338032Speter
56438032Speter# where do errors that occur when sending errors get sent?
56564562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
56638032Speter
567168515Sgshapiro# issue temporary errors (4xy) instead of permanent errors (5xy)?
568168515Sgshapiro_OPTION(SoftBounce, `confSOFT_BOUNCE', `False')
569168515Sgshapiro
57064562Sgshapiro# where to save bounces if all else fails
57164562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
57264562Sgshapiro
57338032Speter# what user id do we assume for the majority of the processing?
57464562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
57538032Speter
57638032Speter# maximum number of recipients per SMTP envelope
577132943Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `0')
57838032Speter
57990792Sgshapiro# limit the rate recipients per SMTP envelope are accepted
58090792Sgshapiro# once the threshold number of recipients have been rejected
581132943Sgshapiro_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `0')
58290792Sgshapiro
583203004Sgshapiro
58438032Speter# shall we get local names from our installed interfaces?
58564562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
58638032Speter
58764562Sgshapiro# Return-Receipt-To: header implies DSN request
58864562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
58964562Sgshapiro
59064562Sgshapiro# override connection address (for testing)
59164562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
59264562Sgshapiro
59364562Sgshapiro# Trusted user for file ownership and starting the daemon
59464562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
59564562Sgshapiro
59664562Sgshapiro# Control socket for daemon management
59764562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
59864562Sgshapiro
59964562Sgshapiro# Maximum MIME header length to protect MUAs
600132943Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
60164562Sgshapiro
60264562Sgshapiro# Maximum length of the sum of all headers
60364562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
60464562Sgshapiro
60564562Sgshapiro# Maximum depth of alias recursion
60664562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
60764562Sgshapiro
60864562Sgshapiro# location of pid file
60964562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
61064562Sgshapiro
61164562Sgshapiro# Prefix string for the process title shown on 'ps' listings
61264562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
61364562Sgshapiro
61464562Sgshapiro# Data file (df) memory-buffer file maximum size
61564562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
61664562Sgshapiro
61764562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
61864562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
61964562Sgshapiro
62090792Sgshapiro# lookup type to find information about local mailboxes
62190792Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
62290792Sgshapiro
623132943Sgshapiro# override compile time flag REQUIRES_DIR_FSYNC
624132943Sgshapiro_OPTION(RequiresDirfsync, `confREQUIRES_DIR_FSYNC', `true')
625132943Sgshapiro
62664562Sgshapiro# list of authentication mechanisms
62790792Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
62864562Sgshapiro
629132943Sgshapiro# Authentication realm
630132943Sgshapiro_OPTION(AuthRealm, `confAUTH_REALM', `')
631132943Sgshapiro
63264562Sgshapiro# default authentication information for outgoing connections
63364562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
63464562Sgshapiro
63564562Sgshapiro# SMTP AUTH flags
63664562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
63764562Sgshapiro
63890792Sgshapiro# SMTP AUTH maximum encryption strength
63990792Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
64090792Sgshapiro
64190792Sgshapiro# SMTP STARTTLS server options
64290792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
64390792Sgshapiro
644203004Sgshapiro
64564562Sgshapiro# Input mail filters
64664562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
64764562Sgshapiro
64898841Sgshapiroifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl
64964562Sgshapiro# Milter options
65090792Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
65164562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
65264562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
65364562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
654125820Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')
655168515Sgshapiro_OPTION(Milter.macros.eom, `confMILTER_MACROS_EOM', `')
656168515Sgshapiro_OPTION(Milter.macros.eoh, `confMILTER_MACROS_EOH', `')
657168515Sgshapiro_OPTION(Milter.macros.data, `confMILTER_MACROS_DATA', `')')
65864562Sgshapiro
65964562Sgshapiro# CA directory
660110560Sgshapiro_OPTION(CACertPath, `confCACERT_PATH', `')
66164562Sgshapiro# CA file
662110560Sgshapiro_OPTION(CACertFile, `confCACERT', `')
66364562Sgshapiro# Server Cert
66464562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
66564562Sgshapiro# Server private key
66664562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
66764562Sgshapiro# Client Cert
66864562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
66964562Sgshapiro# Client private key
67064562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
671132943Sgshapiro# File containing certificate revocation lists 
672132943Sgshapiro_OPTION(CRLFile, `confCRL', `')
67364562Sgshapiro# DHParameters (only required if DSA/DH is used)
67464562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
67564562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
67664562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
67764562Sgshapiro
678168515Sgshapiro# Maximum number of "useless" commands before slowing down
679168515Sgshapiro_OPTION(MaxNOOPCommands, `confMAX_NOOP_COMMANDS', `20')
680168515Sgshapiro
681168515Sgshapiro# Name to use for EHLO (defaults to $j)
682168515Sgshapiro_OPTION(HeloName, `confHELO_NAME')
683168515Sgshapiro
68490792Sgshapiro############################
68590792Sgshapiro`# QUEUE GROUP DEFINITIONS  #'
68690792Sgshapiro############################
68790792Sgshapiro_QUEUE_GROUP_
68842575Speter
68938032Speter###########################
69038032Speter#   Message precedences   #
69138032Speter###########################
69238032Speter
69338032SpeterPfirst-class=0
69438032SpeterPspecial-delivery=100
69538032SpeterPlist=-30
69638032SpeterPbulk=-60
69738032SpeterPjunk=-100
69838032Speter
69938032Speter#####################
70038032Speter#   Trusted users   #
70138032Speter#####################
70238032Speter
70338032Speter# this is equivalent to setting class "t"
70464562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
70538032SpeterTroot
70638032SpeterTdaemon
70738032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp')
70838032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
70938032Speter
71038032Speter#########################
71138032Speter#   Format of headers   #
71238032Speter#########################
71338032Speter
71438032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
715132943Sgshapiroifdef(`confMESSAGEID_HEADER',, `define(`confMESSAGEID_HEADER', `<$t.$i@$j>')')dnl
71638032SpeterH?P?Return-Path: <$g>
71738032SpeterHReceived: confRECEIVED_HEADER
71838032SpeterH?D?Resent-Date: $a
71938032SpeterH?D?Date: $a
72038032SpeterH?F?Resent-From: confFROM_HEADER
72138032SpeterH?F?From: confFROM_HEADER
72238032SpeterH?x?Full-Name: $x
72338032Speter# HPosted-Date: $a
72438032Speter# H?l?Received-Date: $b
725132943SgshapiroH?M?Resent-Message-Id: confMESSAGEID_HEADER
726132943SgshapiroH?M?Message-Id: confMESSAGEID_HEADER
72764562Sgshapiro
72838032Speter#
72938032Speter######################################################################
73038032Speter######################################################################
73138032Speter#####
73238032Speter#####			REWRITING RULES
73338032Speter#####
73438032Speter######################################################################
73538032Speter######################################################################
73638032Speter
73738032Speter############################################
73838032Speter###  Ruleset 3 -- Name Canonicalization  ###
73938032Speter############################################
74064562SgshapiroScanonify=3
74138032Speter
74238032Speter# handle null input (translate to <@> special case)
74338032SpeterR$@			$@ <@>
74438032Speter
74538032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
74638032SpeterR$*			$: $1 <@>			mark addresses
74738032SpeterR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
74838032SpeterR@ $* <@>		$: @ $1				unmark @host:...
74990792SgshapiroR$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
75038032SpeterR$* :: $* <@>		$: $1 :: $2			unmark node::addr
75138032SpeterR:`include': $* <@>	$: :`include': $1			unmark :`include':...
75238032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
75338032SpeterR$* : $* <@>		$: $2				strip colon if marked
75438032SpeterR$* <@>			$: $1				unmark
75538032SpeterR$* ;			   $1				strip trailing semi
75671345SgshapiroR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
75738032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
75838032Speter
75938032Speter# null input now results from list:; syntax
76038032SpeterR$@			$@ :; <@>
76138032Speter
76238032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
76338032SpeterR$*			$: < $1 >			housekeeping <>
76438032SpeterR$+ < $* >		   < $2 >			strip excess on left
76538032SpeterR< $* > $+		   < $1 >			strip excess on right
76638032SpeterR<>			$@ < @ >			MAIL FROM:<> case
76738032SpeterR< $+ >			$: $1				remove housekeeping <>
76838032Speter
76964562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
77038032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
77138032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
77238032Speter
77338032Speter# localize and dispose of route-based addresses
77490792Sgshapirodnl XXX: IPv6 colon conflict
77590792Sgshapiroifdef(`NO_NETINET6', `dnl',
77690792Sgshapiro`R@ [$+] : $+		$@ $>Canonify2 < @ [$1] > : $2	handle <route-addr>')
77764562SgshapiroR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
77864562Sgshapirodnl',`dnl
77964562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d>
78064562SgshapiroR@ $+ , $+		$2
78190792Sgshapiroifdef(`NO_NETINET6', `dnl',
78290792Sgshapiro`R@ [ $* ] : $+		$2')
78364562SgshapiroR@ $+ : $+		$2
78464562Sgshapirodnl')
78538032Speter
78638032Speter# find focus for list syntax
78764562SgshapiroR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
78838032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
78938032Speter
79038032Speter# find focus for @ syntax addresses
79138032SpeterR$+ @ $+		$: $1 < @ $2 >			focus on domain
79238032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
79364562SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
79438032Speter
79590792Sgshapirodnl This is flagged as an error in S0; no need to silently fix it here.
79690792Sgshapirodnl # do some sanity checking
79790792Sgshapirodnl R$* < @ $~[ $* : $* > $*	$1 < @ $2 $3 > $4	nix colons in addrs
79838032Speter
79938032Speterifdef(`_NO_UUCP_', `dnl',
80038032Speter`# convert old-style addresses to a domain-based address
80164562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
80264562SgshapiroR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
80364562SgshapiroR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
80438032Speter')
80538032Speterifdef(`_USE_DECNET_SYNTAX_',
80638032Speter`# convert node::user addresses into a domain-based address
80764562SgshapiroR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
80864562SgshapiroR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
80938032Speter',
81038032Speter	`dnl')
81138032Speter# if we have % signs, take the rightmost one
81238032SpeterR$* % $*		$1 @ $2				First make them all @s.
81338032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
81464562SgshapiroR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
81538032Speter
81638032Speter# else we must be a local name
81764562SgshapiroR$*			$@ $>Canonify2 $1
81838032Speter
81938032Speter
82038032Speter################################################
82138032Speter###  Ruleset 96 -- bottom half of ruleset 3  ###
82238032Speter################################################
82338032Speter
82464562SgshapiroSCanonify2=96
82538032Speter
82638032Speter# handle special cases for local names
82738032SpeterR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
82838032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
82938032Speterifdef(`_NO_UUCP_', `dnl',
83038032Speter`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
83164562Sgshapiro
83290792Sgshapiro# check for IPv4/IPv6 domain literal
83390792SgshapiroR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [addr]
83438032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
83538032SpeterR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
83638032Speter
83764562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl
83838032Speter# look up domains in the domain table
83938032SpeterR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
84038032Speter
84164562Sgshapiroundivert(2)dnl LOCAL_RULE_3
84238032Speter
84364562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl
84438032Speter# handle BITNET mapping
84538032SpeterR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
84638032Speter
84764562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl
84838032Speter# handle UUCP mapping
84938032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
85038032Speter
85138032Speterifdef(`_NO_UUCP_', `dnl',
85238032Speter`ifdef(`UUCP_RELAY',
85338032Speter`# pass UUCP addresses straight through
85438032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
85538032Speter`# if really UUCP, handle it immediately
85638032Speterifdef(`_CLASS_U_',
85738032Speter`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
85838032Speterifdef(`_CLASS_V_',
85938032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
86038032Speterifdef(`_CLASS_W_',
86138032Speter`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
86238032Speterifdef(`_CLASS_X_',
86338032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
86438032Speterifdef(`_CLASS_Y_',
86538032Speter`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
86638032Speter
86738032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl
86838032Speter# try UUCP traffic as a local address
86938032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
87038032SpeterR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
87138032Speter')')
87264562Sgshapiro# hostnames ending in class P are always canonical
87364562SgshapiroR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
87464562Sgshapirodnl apply the next rule only for hostnames not in class P
87564562Sgshapirodnl this even works for phrases in class P since . is in class P
87664562Sgshapirodnl which daemon flags are set?
87764562SgshapiroR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
87864562Sgshapirodnl the other rules in this section only apply if the hostname
87964562Sgshapirodnl does not end in class P hence no further checks are done here
88064562Sgshapirodnl if this ever changes make sure the lookups are "protected" again!
88164562Sgshapiroifdef(`_NO_CANONIFY_', `dnl
88264562Sgshapirodnl do not canonify unless:
88364562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection
88464562Sgshapirodnl	with class P is non-empty)
88564562Sgshapirodnl or {daemon_flags} has c set
88664562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify}
88764562SgshapiroR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
88864562Sgshapiro# pass to name server to make hostname canonical if requested
88964562SgshapiroR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
89064562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_
89164562SgshapiroR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
89264562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work
89364562SgshapiroR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
89464562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl
89564562Sgshapirodnl this should only apply to unqualified hostnames
89664562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
89764562Sgshapirodnl then $- does not work.
89864562Sgshapiro# lookup unqualified hostnames
89990792SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
90064562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
90164562Sgshapirodnl {daemon_flags} contains CC (do not canonify)
90271345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work
90371345Sgshapirodnl should we do this for every hostname: even unqualified?
90471345SgshapiroR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
90564562SgshapiroR$* CC $* $| $*			$: $3
90690792Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
90790792Sgshapiro# do not canonify header addresses
90890792SgshapiroR$* $| $* < @ $* $~P > $*	$: $&{addr_type} $| $2 < @ $3 $4 > $5
90990792SgshapiroR$* h $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
91090792SgshapiroR$* h $* $| $*			$: $3', `dnl')
91138032Speter# pass to name server to make hostname canonical
91264562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
91364562Sgshapirodnl remove {daemon_flags} for other cases
91464562SgshapiroR$* $| $*			$: $2
91538032Speter
91638032Speter# local host aliases and pseudo-domains are always canonical
91738032SpeterR$* < @ $=w > $*		$: $1 < @ $2 . > $3
91838032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
91938032Speter`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
92038032Speter`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
92164562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
92264562Sgshapirodnl virtual hosts are also canonical
92364562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
92464562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
92564562Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
92664562Sgshapiro`dnl')
92790792Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
92890792Sgshapirodnl hosts for genericstable are also canonical
92990792Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_',
93090792Sgshapiro`R$* < @ $* $=G > $* 	$: $1 < @ $2 $3 . > $4',
93190792Sgshapiro`R$* < @ $=G > $* 	$: $1 < @ $2 . > $3')',
93290792Sgshapiro`dnl')
93364562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added
93464562Sgshapirodnl by one of the rules before
93538032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
93638032Speter
93738032Speter
93838032Speter##################################################
93938032Speter###  Ruleset 4 -- Final Output Post-rewriting  ###
94038032Speter##################################################
94164562SgshapiroSfinal=4
94238032Speter
94371345SgshapiroR$+ :; <@>		$@ $1 :				handle <list:;>
94438032SpeterR$* <@>			$@				handle <> and list:;
94538032Speter
94638032Speter# strip trailing dot off possibly canonical name
94738032SpeterR$* < @ $+ . > $*	$1 < @ $2 > $3
94838032Speter
94964562Sgshapiro# eliminate internal code
95038032SpeterR$* < @ *LOCAL* > $*	$1 < @ $j > $2
95138032Speter
95238032Speter# externalize local domain info
95338032SpeterR$* < $+ > $*		$1 $2 $3			defocus
95438032SpeterR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
95538032SpeterR@ $*			$@ @ $1				... and exit
95638032Speter
95738032Speterifdef(`_NO_UUCP_', `dnl',
95838032Speter`# UUCP must always be presented in old form
95938032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
96038032Speter
96138032Speterifdef(`_USE_DECNET_SYNTAX_',
96238032Speter`# put DECnet back in :: form
96338032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
96438032Speter	`dnl')
96538032Speter# delete duplicate local names
96638032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
96738032Speter
96838032Speter
96938032Speter
97038032Speter##############################################################
97138032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
97238032Speter###		   (used for recursive calls)		   ###
97338032Speter##############################################################
97438032Speter
97564562SgshapiroSRecurse=97
97664562SgshapiroR$*			$: $>canonify $1
97764562SgshapiroR$*			$@ $>parse $1
97838032Speter
97938032Speter
98038032Speter######################################
98138032Speter###   Ruleset 0 -- Parse Address   ###
98238032Speter######################################
98338032Speter
98464562SgshapiroSparse=0
98538032Speter
98638032SpeterR$*			$: $>Parse0 $1		initial parsing
98738032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
98864562SgshapiroR$*			$: $>ParseLocal $1	handle local hacks
98938032SpeterR$*			$: $>Parse1 $1		final parsing
99038032Speter
99138032Speter#
99238032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
99338032Speter#	This should either return with the (possibly modified) input
99438032Speter#	or return with a #error mailer.  It should not return with a
99538032Speter#	#mailer other than the #error mailer.
99638032Speter#
99738032Speter
99838032SpeterSParse0
99938032SpeterR<@>			$@ <@>			special case error msgs
100090792SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
100164562SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
100290792SgshapiroR<@ $+>			$#error $@ 5.1.3 $: "_CODE553 User address required"
100390792SgshapiroR$+ <@>			$#error $@ 5.1.3 $: "_CODE553 Hostname required"
100438032SpeterR$*			$: <> $1
100590792Sgshapirodnl allow tricks like [host1]:[host2]
100690792SgshapiroR<> $* < @ [ $* ] : $+ > $*	$1 < @ [ $2 ] : $3 > $4
100790792SgshapiroR<> $* < @ [ $* ] , $+ > $*	$1 < @ [ $2 ] , $3 > $4
100890792Sgshapirodnl but no a@[b]c
100990792SgshapiroR<> $* < @ [ $* ] $+ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid address"
101090792SgshapiroR<> $* < @ [ $+ ] > $*		$1 < @ [ $2 ] > $3
101190792SgshapiroR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
101238032SpeterR<> $*			$1
101390792SgshapiroR$* < @ . $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
101490792SgshapiroR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
101590792Sgshapirodnl no a@b@
101690792SgshapiroR$* < @ $* @ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid route address"
101790792Sgshapirodnl no a@b@c
101890792SgshapiroR$* @ $* < @ $* > $*	$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
101964562Sgshapirodnl comma only allowed before @; this check is not complete
102090792SgshapiroR$* , $~O $*		$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
102138032Speter
102290792Sgshapiroifdef(`_STRICT_RFC821_', `# more RFC 821 checks
102390792SgshapiroR$* . < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
102490792SgshapiroR. $* < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
102590792Sgshapirodnl', `dnl')
102690792Sgshapiro
102738032Speter# now delete the local info -- note $=O to find characters that cause forwarding
102864562SgshapiroR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
102964562SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
103038032SpeterR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
103190792SgshapiroR< @ $+ >		$#error $@ 5.1.3 $: "_CODE553 User address required"
103264562SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
103338032SpeterR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
103490792SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "_CODE553 User address required"
103538032SpeterR$* $=O $* < @ *LOCAL* >
103664562Sgshapiro			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
103738032SpeterR$* < @ *LOCAL* >	$: $1
103838032Speter
103938032Speter#
104038032Speter#  Parse1 -- the bottom half of ruleset 0.
104138032Speter#
104238032Speter
104338032SpeterSParse1
104464562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
104564562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute}
104690792SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
104790792SgshapiroR$+ < @ $={LDAPRouteEquiv} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
104864562Sgshapiro`dnl')
104964562Sgshapiro
105038032Speterifdef(`_MAILER_smtp_',
105138032Speter`# handle numeric address spec
105264562Sgshapirodnl there is no check whether this is really an IP number
105364562SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
1054112810SgshapiroR$* < @ [ $+ ] > $*	$: $1 < @ [ $2 ] : $S > $3	Add smart host to path
105590792SgshapiroR$* < @ [ $+ ] : > $*		$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
105664562SgshapiroR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
105764562SgshapiroR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
105838032Speter	`dnl')
105938032Speter
106064562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
106138032Speter# handle virtual users
106290792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
106390792Sgshapirodnl this is not a documented option
106490792Sgshapirodnl it stops looping in virtusertable mapping if input and output
106590792Sgshapirodnl are identical, i.e., if address A is mapped to A.
106690792Sgshapirodnl it does not deal with multi-level recursion
106790792Sgshapiro# handle full domains in RHS of virtusertable
106890792SgshapiroR$+ < @ $+ >			$: $(macro {RecipientAddress} $) $1 < @ $2 >
106990792SgshapiroR$+ < @ $+ > 			$: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
107090792SgshapiroR<?> $+ $| $+			$: $1 $(macro {RecipientAddress} $@ $2 $)
107190792SgshapiroR<?> $+ $| $*			$: $1',
107290792Sgshapiro`dnl')
107364562SgshapiroR$+			$: <!> $1		Mark for lookup
107490792Sgshapirodnl input: <!> local<@domain>
107564562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
107664562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
107764562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
107890792Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
107964562SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
108090792Sgshapirodnl if <@> local<@domain>: no match but try lookup
108190792Sgshapirodnl user+detail: try user++@domain if detail not empty
108290792SgshapiroR<@> $+ + $+ < @ $* . >
108390792Sgshapiro			$: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
108490792Sgshapirodnl user+detail: try user+*@domain
108538032SpeterR<@> $+ + $* < @ $* . >
108690792Sgshapiro			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
108790792Sgshapirodnl user+detail: try user@domain
108838032SpeterR<@> $+ + $* < @ $* . >
108990792Sgshapiro			$: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
109064562Sgshapirodnl try default entry: @domain
109190792Sgshapirodnl ++@domain
109290792SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
109364562Sgshapirodnl +*@domain
109490792SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
109564562Sgshapirodnl @domain if +detail exists
109698121Sgshapirodnl if no match, change marker to prevent a second @domain lookup
109798121SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . >
109898121Sgshapirodnl without +detail
109938032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
110090792Sgshapirodnl no match
110138032SpeterR<@> $+			$: $1
110290792Sgshapirodnl remove mark
110364562SgshapiroR<!> $+			$: $1
110464562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
110538032SpeterR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
110690792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
110790792Sgshapiro# check virtuser input address against output address, if same, skip recursion
110890792SgshapiroR< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
110990792Sgshapiro# it is the same: stop now
111090792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
111190792SgshapiroR< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
111290792Sgshapirodnl', `dnl')
111380785Sgshapirodnl this is not a documented option
111480785Sgshapirodnl it performs no looping at all for virtusertable
111577349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_',
111677349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
111777349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
111877349Sgshapirodnl', `dnl')
111938032Speter
112038032Speter# short circuit local delivery so forwarded email works
112138032Speterifdef(`_MAILER_usenet_', `dnl
112264562SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
112366494Sgshapiro
112466494Sgshapiro
112538032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
112638032Speter`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
112764562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
112864562Sgshapirodnl $H empty (but @$=w.)
112938032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
113038032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
113164562Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
113238032SpeterR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
113338032Speter
113464562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
113538032Speter# not local -- try mailer table lookup
113638032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
113738032SpeterR< $+ . > $*		$: < $1 > $2			strip trailing dot
113838032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
113964562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
114064562SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
114164562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
114238032Speter`dnl')
114364562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)'
114438032Speter
114538032Speterifdef(`_NO_UUCP_', `dnl',
114638032Speter`# resolve remotely connected UUCP links (if any)
114738032Speterifdef(`_CLASS_V_',
114864562Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
114938032Speter	`dnl')
115038032Speterifdef(`_CLASS_W_',
115164562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
115238032Speter	`dnl')
115338032Speterifdef(`_CLASS_X_',
115464562Sgshapiro`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
115538032Speter	`dnl')')
115638032Speter
115738032Speter# resolve fake top level domains by forwarding to other hosts
115838032Speterifdef(`BITNET_RELAY',
115964562Sgshapiro`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
116038032Speter	`dnl')
116138032Speterifdef(`DECNET_RELAY',
116264562Sgshapiro`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
116338032Speter	`dnl')
116438032Speterifdef(`_MAILER_pop_',
116538032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
116638032Speter	`dnl')
116738032Speterifdef(`_MAILER_fax_',
116838032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
116938032Speter`ifdef(`FAX_RELAY',
117064562Sgshapiro`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
117138032Speter	`dnl')')
117238032Speter
117338032Speterifdef(`UUCP_RELAY',
117438032Speter`# forward non-local UUCP traffic to our UUCP relay
117564562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
117638032Speter`ifdef(`_MAILER_uucp_',
117738032Speter`# forward other UUCP traffic straight to UUCP
117838032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
117938032Speter	`dnl')')
118038032Speterifdef(`_MAILER_usenet_', `
118138032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
118264562SgshapiroR$+ . USENET		$#usenet $@ usenet $: $1',
118338032Speter	`dnl')
118438032Speter
118538032Speterifdef(`_LOCAL_RULES_',
118638032Speter`# figure out what should stay in our local mail system
118738032Speterundivert(1)', `dnl')
118838032Speter
118938032Speter# pass names that still have a host to a smarthost (if defined)
119064562SgshapiroR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
119138032Speter
119238032Speter# deal with other remote names
119338032Speterifdef(`_MAILER_smtp_',
119464562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
119590792Sgshapiro`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
119638032Speter
119738032Speter# handle locally delivered names
119864562SgshapiroR$=L			$#_LOCAL_ $: @ $1		special local names
119938032SpeterR$+			$#_LOCAL_ $: $1			regular local names
120038032Speter
120138032Speter###########################################################################
120238032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
120338032Speter###########################################################################
120438032Speter
120564562SgshapiroSLocal_localaddr
120664562SgshapiroSlocaladdr=5
120764562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
120890792SgshapiroR$+ $| $#ok		$@ $1			no change
120964562SgshapiroR$+ $| $#$*		$#$2
121064562SgshapiroR$+ $| $*		$: $1
121138032Speter
121290792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
121390792Sgshapiro# Preserve rcpt_host in {Host}
121490792SgshapiroR$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
121590792SgshapiroR$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
121690792SgshapiroR$+ $| $| $+		$: $1			h not set, {Host} set
121790792SgshapiroR$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
121895154SgshapiroR$+ $| $* @ $+ $| $*	$: $(macro {Host} $@ @$3 $) $1	set {Host} to host in h
121990792SgshapiroR$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
122090792Sgshapiro')dnl
122190792Sgshapiro
122290792Sgshapiroifdef(`_FFR_5_', `dnl
122366494Sgshapiro# Preserve host in a macro
122466494SgshapiroR$+			$: $(macro {LocalAddrHost} $) $1
122566494SgshapiroR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
122666494Sgshapiro
122790792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
122838032Speter# deal with plussed users so aliases work nicely
122966494SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
123066494SgshapiroR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
123166494Sgshapiro')
123238032Speter# prepend an empty "forward host" on the front
123338032SpeterR$+			$: <> $1
123438032Speter
123538032Speterifdef(`LUSER_RELAY', `dnl
123638032Speter# send unrecognized local users to a relay host
123790792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
123866494SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
123966494SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
124066494SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
124166494SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
124264562SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
124390792SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')
124490792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
124590792SgshapiroR< $+ > $+		$: < $1 > $2 $&{Host}')
124690792Sgshapirodnl')
124738032Speter
124890792Sgshapiroifdef(`MAIL_HUB', `dnl
124990792SgshapiroR< > $+			$: < $H > $1			try hub', `dnl')
125090792Sgshapiroifdef(`LOCAL_RELAY', `dnl
125190792SgshapiroR< > $+			$: < $R > $1			try relay', `dnl')
125290792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
125390792SgshapiroR< > $+			$@ $1', `dnl
125464562SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
125590792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
125690792SgshapiroR< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
125764562SgshapiroR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
125864562SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
125938032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
126066494SgshapiroR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
126138032SpeterR< > < $+ >		$@ $1				no +detail
126243730SpeterR$+			$: $1 <> $&h			add +detail back in
126390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
126490792SgshapiroR$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
126543730SpeterR$+ <> + $*		$: $1 + $2			check whether +detail
126666494SgshapiroR$+ <> $*		$: $1				else discard')
126764562SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
126864562SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
126990792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
127090792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
127190792SgshapiroR< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
127290792SgshapiroR< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
127390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
127490792SgshapiroR< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
127564562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
127638032Speter
127764562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
127890792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
127938032Speter###################################################################
128090792Sgshapiro###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
128190792Sgshapirodnl input: <Domain> FullAddress
128290792Sgshapiro###################################################################
128390792Sgshapiro
128490792SgshapiroSLDAPMailertable
128590792SgshapiroR< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
128690792SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
128790792SgshapiroR< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
128890792SgshapiroR< $+ > $#$*		$#$2					found
128990792SgshapiroR< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
129090792Sgshapiro`dnl')
129190792Sgshapiro
129290792Sgshapiro###################################################################
129338032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
129464562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
129538032Speter###################################################################
129638032Speter
129764562SgshapiroSMailertable=90
129864562Sgshapirodnl shift and check
129964562Sgshapirodnl %2 is not documented in cf/README
130038032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
130164562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
130264562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
130364562SgshapiroR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
130464562Sgshapirodnl is $2 always empty?
130538032SpeterR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
130664562SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
130764562Sgshapirodnl return full address
130838032SpeterR< $* > $*		$@ $2				no mailertable match',
130938032Speter`dnl')
131038032Speter
131138032Speter###################################################################
131238032Speter###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
131364562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
131464562Sgshapirodnl	<> address				-> address
131564562Sgshapirodnl	<error:d.s.n:text>			-> error
1316120256Sgshapirodnl	<error:keyword:text>			-> error
131764562Sgshapirodnl	<error:text>				-> error
131864562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
131964562Sgshapirodnl	<mailer:host> address			-> mailer host address
132064562Sgshapirodnl	<localdomain> address			-> address
132164562Sgshapirodnl	<host> address				-> relay host address
132238032Speter###################################################################
132338032Speter
132464562SgshapiroSMailerToTriple=95
132538032SpeterR< > $*				$@ $1			strip off null relay
132664562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
1327120256SgshapiroR< error : $- : $+ > $*		$#error $@ $(dequote $1 $) $: $2
1328120256SgshapiroR< error : $+ > $*		$#error $: $1
132938032SpeterR< local : $* > $*		$>CanonLocal < $1 > $2
133090792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
133190792SgshapiroR< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
133290792SgshapiroR< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
133338032SpeterR< $=w > $*			$@ $2			delete local host
133438032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
133538032Speter
133638032Speter###################################################################
133738032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
133864562Sgshapirodnl input: <user> address
133964562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
134064562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
134164562Sgshapirodnl <> user <@host> rest		-> local user@host user
134264562Sgshapirodnl <> user				-> local user user
134364562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
134464562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
134564562Sgshapirodnl <user> lp				-> local lp user
134638032Speter###################################################################
134738032Speter
134838032SpeterSCanonLocal
134943730Speter# strip local host from routed addresses
135064562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
135164562SgshapiroR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
135243730Speter
135338032Speter# strip trailing dot from any host name that may appear
135438032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
135538032Speter
135638032Speter# handle local: syntax -- use old user, either with or without host
135738032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
135838032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
135938032Speter
136038032Speter# handle local:user@host syntax -- ignore host part
136138032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
136238032Speter
136338032Speter# handle local:user syntax
136438032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
136538032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
136638032Speter
136738032Speter###################################################################
136838032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
136938032Speter###################################################################
137038032Speter
137164562SgshapiroSMasqHdr=93
137238032Speter
137364562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
137438032Speter# handle generics database
137538032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
137664562Sgshapirodnl if generics should be applied add a @ as mark
137738032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
137838032Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
137938032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
138064562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
138164562Sgshapirodnl ignore the first case for now
138264562Sgshapirodnl if it has the mark lookup full address
138390792Sgshapirodnl broken: %1 is full address not just detail
138464562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
138564562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
138664562Sgshapirodnl no match, try user+detail@domain
138764562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
138864562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
138964562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
139064562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
139164562Sgshapirodnl no match, remove mark
139264562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
139364562Sgshapirodnl no match, try @domain for exceptions
139464562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
139564562Sgshapirodnl workspace: ... or <match> user <@domain>
139664562Sgshapirodnl no match, try local part
139738032SpeterR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
139864562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
139964562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
140064562SgshapiroR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
140164562SgshapiroR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
140238032SpeterR< > $*			$: $1				not found',
140338032Speter`dnl')
140438032Speter
140564562Sgshapiro# do not masquerade anything in class N
140664562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
140764562Sgshapiro
140890792Sgshapiroifdef(`MASQUERADE_NAME', `dnl
140938032Speter# special case the users that should be exposed
141038032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
141138032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
141238032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
141338032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
141438032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
141538032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
141638032Speter
141738032Speter# handle domain-specific masquerading
141838032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
141938032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
142038032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
142138032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
142238032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
142338032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
142438032SpeterR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
142538032SpeterR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
142690792Sgshapirodnl', `dnl no masquerading
142790792Sgshapirodnl just fix *LOCAL* leftovers
142890792SgshapiroR$* < @ *LOCAL* >	$@ $1 < @ $j . >')
142938032Speter
143038032Speter###################################################################
143138032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
143238032Speter###################################################################
143338032Speter
143464562SgshapiroSMasqEnv=94
143538032Speterifdef(`_MASQUERADE_ENVELOPE_',
143664562Sgshapiro`R$+			$@ $>MasqHdr $1',
143738032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
143838032Speter
143938032Speter###################################################################
144038032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
144138032Speter###################################################################
144238032Speter
144364562SgshapiroSParseLocal=98
144464562Sgshapiroundivert(3)dnl LOCAL_RULE_0
144538032Speter
144664562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
144790792Sgshapiro######################################################################
144890792Sgshapiro###  LDAPExpand: Expand address using LDAP routing
144990792Sgshapiro###
145090792Sgshapiro###	Parameters:
145190792Sgshapiro###		<$1> -- parsed address (user < @ domain . >) (pass through)
145290792Sgshapiro###		<$2> -- RFC822 address (user @ domain) (used for lookup)
145390792Sgshapiro###		<$3> -- +detail information
145490792Sgshapiro###
145590792Sgshapiro###	Returns:
145690792Sgshapiro###		Mailer triplet ($#mailer $@ host $: address)
145790792Sgshapiro###		Parsed address (user < @ domain . >)
145890792Sgshapiro######################################################################
145990792Sgshapiro
1460132943Sgshapiro# SMTP operation modes
1461132943SgshapiroC{SMTPOpModes} s d D
1462132943Sgshapiro
146364562SgshapiroSLDAPExpand
146464562Sgshapiro# do the LDAP lookups
146590792SgshapiroR<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
146664562Sgshapiro
1467132943Sgshapiro# look for temporary failures and...
1468132943SgshapiroR<$* <TMPF>> <$*> <$+> <$+> <$*>	$: $&{opMode} $| TMPF <$&{addr_type}> $| $3
1469132943SgshapiroR<$*> <$* <TMPF>> <$+> <$+> <$*>	$: $&{opMode} $| TMPF <$&{addr_type}> $| $3
1470132943Sgshapiroifelse(_LDAP_ROUTE_MAPTEMP_, `_TEMPFAIL_', `dnl
1471132943Sgshapiro# ... temp fail RCPT SMTP commands
1472132943SgshapiroR$={SMTPOpModes} $| TMPF <e r> $| $+	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."')
1473132943Sgshapiro# ... return original address for MTA to queue up
1474132943SgshapiroR$* $| TMPF <$*> $| $+			$@ $3
147594334Sgshapiro
147664562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
147764562Sgshapiro# return the new mailRoutingAddress
147890792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
147990792SgshapiroR<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
148090792SgshapiroR<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
148190792SgshapiroR<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
148290792SgshapiroR<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
148364562Sgshapiro
148498121Sgshapiro
148564562Sgshapiro# if mailRoutingAddress and non-local mailHost,
148664562Sgshapiro# relay to mailHost with new mailRoutingAddress
148790792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
148890792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
148990792Sgshapiro# check mailertable for host, relay from there
149090792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
149190792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
149290792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
149390792Sgshapiro# check mailertable for host, relay from there
149490792SgshapiroR<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
149590792Sgshapiro`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
149664562Sgshapiro
149764562Sgshapiro# if no mailRoutingAddress and local mailHost,
149864562Sgshapiro# return original address
149990792SgshapiroR<> <$=w> <$+> <$+> <$*>	$@ $2
150064562Sgshapiro
150198121Sgshapiro
150264562Sgshapiro# if no mailRoutingAddress and non-local mailHost,
150364562Sgshapiro# relay to mailHost with original address
150490792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
150590792Sgshapiro# check mailertable for host, relay from there
150690792SgshapiroR<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
150790792Sgshapiro`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
150864562Sgshapiro
150990792Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_',
151090792Sgshapiro`# if no mailRoutingAddress and no mailHost,
151190792Sgshapiro# try without +detail
151290792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
151390792Sgshapiro
1514203004Sgshapiroifdef(`_LDAP_ROUTE_NODOMAIN_', `
1515203004Sgshapiro# pretend we did the @domain lookup
1516203004SgshapiroR<> <> <$+> <$+ @ $+> <$*>	$: <> <> <$1> <@ $3> <$4>', `
151790792Sgshapiro# if still no mailRoutingAddress and no mailHost,
151864562Sgshapiro# try @domain
151990792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
152090792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
1521132943SgshapiroR<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>')
152264562Sgshapiro
152364562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
152464562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
152564562Sgshapiro# user does not exist
152690792SgshapiroR<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
152790792Sgshapiro# only give error for envelope recipient
152890792SgshapiroR<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
1529132943Sgshapiroifdef(`_LDAP_SENDER_MUST_EXIST_', `dnl
1530132943Sgshapiro# and the sender too
1531132943SgshapiroR<?> <e s> <$+>			$#error $@ nouser $: "550 User unknown"')
153290792SgshapiroR<?> <$*> <$+>			$@ $2',
153364562Sgshapiro`dnl
153464562Sgshapiro# return the original address
153590792SgshapiroR<> <> <$+> <@ $+> <$*>		$@ $1')',
153664562Sgshapiro`dnl')
153764562Sgshapiro
153864562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
153964562Sgshapiro')')
154090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
154138032Speter######################################################################
154290792Sgshapiro###  D: LookUpDomain -- search for domain in access database
154338032Speter###
154438032Speter###	Parameters:
154538032Speter###		<$1> -- key (domain name)
154638032Speter###		<$2> -- default (what to return if not found in db)
154764562Sgshapirodnl			must not be empty
154890792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
154964562Sgshapiro###			! does lookup only with tag
155064562Sgshapiro###			+ does lookup with and without tag
155190792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
155264562Sgshapirodnl returns:		<default> <passthru>
155364562Sgshapirodnl 			<result> <passthru>
155438032Speter######################################################################
155538032Speter
155690792SgshapiroSD
155764562Sgshapirodnl workspace <key> <default> <passthru> <mark>
155864562Sgshapirodnl lookup with tag (in front, no delimiter here)
155990792Sgshapirodnl    2    3  4    5
156090792SgshapiroR<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
156164562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
156264562Sgshapirodnl lookup without tag?
156390792Sgshapirodnl   1    2      3    4
156490792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
156590792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
156690792Sgshapirodnl XXX apply this also to IP addresses?
156790792Sgshapirodnl currently it works the wrong way round for [1.2.3.4]
156890792Sgshapirodnl   1  2    3    4  5    6
156990792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
157090792Sgshapirodnl   1  2    3      4    5
157190792SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
157290792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
157390792Sgshapirodnl found SKIP: return <default> and <passthru>
157490792Sgshapirodnl      1    2    3  4    5
157590792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
157690792Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!)
157790792Sgshapirodnl    1  2     3    4  5    6
157890792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
157990792Sgshapiroifdef(`NO_NETINET6', `dnl',
158090792Sgshapiro`dnl not found: IPv6 net
158190792Sgshapirodnl (could be merged with previous rule if we have a class containing .:)
158290792Sgshapirodnl    1   2     3    4  5    6
158390792SgshapiroR<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
158490792SgshapiroR<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
158564562Sgshapirodnl not found, but subdomain: try again
158690792Sgshapirodnl   1  2    3    4  5    6
158790792SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
158890792Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
158990792Sgshapirodnl   1    2      3    4
159090792SgshapiroR<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
159190792Sgshapirodnl not found, no subdomain: return <default> and <passthru>
159290792Sgshapirodnl   1    2    3  4    5
159390792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
159490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
159590792Sgshapirodnl            2    3    4  5    6
159690792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
159790792Sgshapirodnl return <result of lookup> and <passthru>
159890792Sgshapirodnl    2    3    4  5    6
159990792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
160038032Speter
160138032Speter######################################################################
160290792Sgshapiro###  A: LookUpAddress -- search for host address in access database
160338032Speter###
160438032Speter###	Parameters:
160538032Speter###		<$1> -- key (dot quadded host address)
160638032Speter###		<$2> -- default (what to return if not found in db)
160764562Sgshapirodnl			must not be empty
160890792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
160964562Sgshapiro###			! does lookup only with tag
161064562Sgshapiro###			+ does lookup with and without tag
161190792Sgshapiro###		<$4> -- passthru (additional data passed through)
161264562Sgshapirodnl	returns:	<default> <passthru>
161364562Sgshapirodnl			<result> <passthru>
161438032Speter######################################################################
161538032Speter
161690792SgshapiroSA
161764562Sgshapirodnl lookup with tag
161890792Sgshapirodnl    2    3  4    5
161990792SgshapiroR<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
162064562Sgshapirodnl lookup without tag
162190792Sgshapirodnl   1    2      3    4
162290792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
162390792Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
162490792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
162590792Sgshapirodnl found SKIP: return <default> and <passthru>
162690792Sgshapirodnl      1    2    3  4    5
162790792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
162890792Sgshapiroifdef(`NO_NETINET6', `dnl',
162990792Sgshapiro`dnl no match; IPv6: remove last part
163090792Sgshapirodnl   1   2    3    4  5    6
163190792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
163290792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
163364562Sgshapirodnl no match; IPv4: remove last part
163490792Sgshapirodnl   1  2    3    4  5    6
163590792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
163664562Sgshapirodnl no match: return default
163790792Sgshapirodnl   1    2    3  4    5
163890792SgshapiroR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
163990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
164090792Sgshapirodnl            2    3    4  5    6
164190792SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
164264562Sgshapirodnl match: return result
164390792Sgshapirodnl    2    3    4  5    6
164490792SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
164590792Sgshapirodnl endif _ACCESS_TABLE_
164690792Sgshapirodivert(0)
164738032Speter######################################################################
164842575Speter###  CanonAddr --	Convert an address into a standard form for
164942575Speter###			relay checking.  Route address syntax is
165042575Speter###			crudely converted into a %-hack address.
165142575Speter###
165242575Speter###	Parameters:
165342575Speter###		$1 -- full recipient address
165442575Speter###
165542575Speter###	Returns:
165642575Speter###		parsed address, not in source route form
165764562Sgshapirodnl		user%host%host<@domain>
165864562Sgshapirodnl		host!user<@domain>
165942575Speter######################################################################
166042575Speter
166142575SpeterSCanonAddr
166264562SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
166364562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
166442575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
166542575SpeterR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
166642575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
166764562Sgshapirodnl')
166842575Speter
166942575Speter######################################################################
167038032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
167138032Speter###			$* $=m or the access database.
167238032Speter###			Check user portion for host separators.
167338032Speter###
167438032Speter###	Parameters:
167538032Speter###		$1 -- full recipient address
167638032Speter###
167738032Speter###	Returns:
167838032Speter###		parsed, non-local-relaying address
167938032Speter######################################################################
168038032Speter
168138032SpeterSParseRecipient
168264562Sgshapirodnl mark and canonify address
168342575SpeterR$*				$: <?> $>CanonAddr $1
168464562Sgshapirodnl workspace: <?> localpart<@domain[.]>
168542575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
168664562Sgshapirodnl workspace: <?> localpart<@domain>
168742575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
168838032Speter
168938032Speter# if no $=O character, no host in the user portion, we are done
169042575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
169164562Sgshapirodnl no $=O in localpart: return
169242575SpeterR<?> $*				$@ $1
169338032Speter
169490792Sgshapirodnl workspace: <NO> localpart<@domain>, where localpart contains $=O
169564562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
169638032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
169738032Speter# if we relay, check username portion for user%host so host can be checked also
169842575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
169964562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
170064562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
170190792Sgshapiro
170290792Sgshapirodnl what if access map returns something else than RELAY?
170390792Sgshapirodnl we are only interested in RELAY entries...
170490792Sgshapirodnl other To: entries: blacklist recipient; generic entries?
170590792Sgshapirodnl if it is an error we probably do not want to relay anyway
170638032Speterifdef(`_RELAY_HOSTS_ONLY_',
170742575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
170864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
170964562SgshapiroR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
171042575SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
171142575Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
171264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
171390792SgshapiroR<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
171442575SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
171538032Speter
171664562Sgshapiro
171790792Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl
171890792Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
171990792SgshapiroR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
1720132943SgshapiroR<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1
172190792Sgshapirodnl yes: mark it as <RELAY>
172290792SgshapiroR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
172390792Sgshapirodnl no: put old <NO> mark back
172490792SgshapiroR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
172590792Sgshapiro
172690792Sgshapirodnl do we relay to this recipient domain?
172742575SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
172890792Sgshapirodnl something else
172990792SgshapiroR<$+> $*			$@ $2
173042575Speter
173164562Sgshapiro
173238032Speter######################################################################
173338032Speter###  check_relay -- check hostname/address on SMTP startup
173438032Speter######################################################################
173538032Speter
1736132943Sgshapiroifdef(`_CONTROL_IMMEDIATE_',`dnl
1737132943SgshapiroScheck_relay
1738132943Sgshapiroifdef(`_RATE_CONTROL_IMMEDIATE_',`dnl
1739132943Sgshapirodnl workspace: ignored...
1740132943SgshapiroR$*		$: $>"RateControl" dummy', `dnl')
1741132943Sgshapiroifdef(`_CONN_CONTROL_IMMEDIATE_',`dnl
1742132943Sgshapirodnl workspace: ignored...
1743132943SgshapiroR$*		$: $>"ConnControl" dummy', `dnl')
1744132943Sgshapirodnl')
1745132943Sgshapiro
174638032SpeterSLocal_check_relay
174764562SgshapiroScheck`'_U_`'relay
1748132943Sgshapiroifdef(`_USE_CLIENT_PTR_',`dnl
1749132943SgshapiroR$* $| $*		$: $&{client_ptr} $| $2', `dnl')
175038032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
175138032SpeterR$* $| $* $| $#$*	$#$3
175238032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
175338032Speter
175438032SpeterSBasic_check_relay
175538032Speter# check for deferred delivery mode
175698121SgshapiroR$*			$: < $&{deliveryMode} > $1
175738032SpeterR< d > $*		$@ deferred
175838032SpeterR< $* > $*		$: $2
175938032Speter
176064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
176166494Sgshapirodnl workspace: {client_name} $| {client_addr}
176290792SgshapiroR$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
176366494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
1764110560Sgshapirodnl OR $| $+ if client_name is empty
1765110560SgshapiroR   $| $+		$: $>A < $1 > <?> <+ Connect> <>	empty client_name
1766110560Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
176790792SgshapiroR<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
176890792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>)
176990792SgshapiroR<?> <$*>		$: OK				found nothing
177090792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
177190792SgshapiroR<$={Accept}> <$*>	$@ $1				return value of lookup
1772132943SgshapiroR<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"')
177390792SgshapiroR<DISCARD> <$*>		$#discard $: discard
1774132943SgshapiroR<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1
177564562Sgshapirodnl error tag
177666494SgshapiroR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
177766494SgshapiroR<ERROR:$+> <$*>		$#error $: $1
177890792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
177964562Sgshapirodnl generic error from access map
178066494SgshapiroR<$+> <$*>		$#error $: $1', `dnl')
178138032Speter
178264562Sgshapiroifdef(`_RBL_',`dnl
178364562Sgshapiro# DNS based IP address spam list
178490792Sgshapirodnl workspace: ignored...
178538032SpeterR$*			$: $&{client_addr}
178664562SgshapiroR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
178764562SgshapiroR<?>OK			$: OKSOFAR
178898121SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"',
178938032Speter`dnl')
1790132943Sgshapiroifdef(`_RATE_CONTROL_',`dnl
1791132943Sgshapiroifdef(`_RATE_CONTROL_IMMEDIATE_',`', `dnl
1792132943Sgshapirodnl workspace: ignored...
1793132943SgshapiroR$*		$: $>"RateControl" dummy')', `dnl')
1794132943Sgshapiroifdef(`_CONN_CONTROL_',`dnl
1795132943Sgshapiroifdef(`_CONN_CONTROL_IMMEDIATE_',`',`dnl
1796132943Sgshapirodnl workspace: ignored...
1797132943SgshapiroR$*		$: $>"ConnControl" dummy')', `dnl')
1798223067Sgshapiroundivert(8)dnl LOCAL_DNSBL
1799168515Sgshapiroifdef(`_REQUIRE_RDNS_', `dnl
1800168515SgshapiroR$*			$: $&{client_addr} $| $&{client_resolve}
1801168515SgshapiroR$=R $*			$@ RELAY		We relay for these
1802168515SgshapiroR$* $| OK		$@ OK			Resolves.
1803168515SgshapiroR$* $| FAIL		$#error $@ 5.7.1 $: 550 Fix reverse DNS for $1
1804168515SgshapiroR$* $| TEMP		$#error $@ 4.1.8 $: 451 Client IP address $1 does not resolve
1805168515SgshapiroR$* $| FORGED		$#error $@ 4.1.8 $: 451 Possibly forged hostname for $1
1806168515Sgshapiro', `dnl')
180738032Speter
180838032Speter######################################################################
180938032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
181038032Speter######################################################################
181138032Speter
181238032SpeterSLocal_check_mail
181364562SgshapiroScheck`'_U_`'mail
181438032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
181538032SpeterR$* $| $#$*		$#$2
181638032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
181738032Speter
181838032SpeterSBasic_check_mail
181938032Speter# check for deferred delivery mode
182098121SgshapiroR$*			$: < $&{deliveryMode} > $1
182138032SpeterR< d > $*		$@ deferred
182238032SpeterR< $* > $*		$: $2
182338032Speter
182464562Sgshapiro# authenticated?
182564562Sgshapirodnl done first: we can require authentication for every mail transaction
182664562Sgshapirodnl workspace: address as given by MAIL FROM: (sender)
182764562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
182864562SgshapiroR$* $| $#$+		$#$2
182964562Sgshapirodnl undo damage: remove result of tls_client call
183064562SgshapiroR$* $| $*		$: $1
183138032Speter
183264562Sgshapirodnl workspace: address as given by MAIL FROM:
183364562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
183438032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
183564562Sgshapirodnl do some additional checks
183664562Sgshapirodnl no user@host
183764562Sgshapirodnl no user@localhost (if nonlocal sender)
183864562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
183964562Sgshapirodnl just make sure the address has <> around it (which is required by
184064562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
184164562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
184264562Sgshapirodnl not be modified by host lookups.
184364562SgshapiroR$+			$: <?> $1
184464562SgshapiroR<?><$+>		$: <@> <$1>
184564562SgshapiroR<?>$+			$: <@> <$1>
184664562Sgshapirodnl workspace: <@> <address>
184764562Sgshapirodnl prepend daemon_flags
184864562SgshapiroR$*			$: $&{daemon_flags} $| $1
184964562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
185064562Sgshapirodnl do not allow these at all or only from local systems?
185164562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
185264562Sgshapirodnl accept unqualified sender: change mark to avoid test
185364562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
185464562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
185564562Sgshapirodnl        or:                    <? ${client_name} > <address>
185664562Sgshapirodnl        or:                    <?> <address>
185764562Sgshapirodnl remove daemon_flags
185864562SgshapiroR$* $| $*		$: $2
185938032Speter# handle case of @localhost on address
186064562SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
186164562SgshapiroR<@> < $* @ [127.0.0.1] >
186264562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
186364562SgshapiroR<@> < $* @ localhost.$m >
186464562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
186538032Speterifdef(`_NO_UUCP_', `dnl',
186664562Sgshapiro`R<@> < $* @ localhost.UUCP >
186764562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
186864562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
186964562Sgshapirodnl	or:    <@> <address>
187064562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
187164562SgshapiroR<@> $*			$: $1			no localhost as domain
187264562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
187364562Sgshapirodnl	or:    <address>
187464562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
187564562SgshapiroR<? $=w> $*		$: $2			local client: ok
187690792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
187764562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
187864562SgshapiroR<?> $*			$: $1')
187964562Sgshapirodnl workspace: address (or <address>)
188064562SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
188164562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
188264562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
188364562SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
188464562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
1885102528SgshapiroR<?> $* < @ $* $=P >	$: <_RES_OK_> $1 < @ $2 $3 >
188664562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
188798121Sgshapirodnl A sender address with my local host name ($j) is safe
1888102528SgshapiroR<?> $* < @ $j >	$: <_RES_OK_> $1 < @ $j >
188964562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
189090792Sgshapiro`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
189164562Sgshapiro`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
189264562SgshapiroR<? $* <$->> $* < @ $+ >
189364562Sgshapiro			$: <$2> $3 < @ $4 >')
189490792Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
189564562Sgshapirodnl mark is ? iff the address is user (wo @domain)
189638032Speter
189764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
189864562Sgshapiro# check sender address: user@address, user@, address
189964562Sgshapirodnl should we remove +ext from user?
190090792Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
190190792SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
190264562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
190364562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
190464562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
190564562Sgshapirodnl will only return user<@domain when "reversing" the args
190690792SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
190764562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
190864562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
190964562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
191038032Speter# retransform for further use
191164562Sgshapirodnl required form:
191264562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
191364562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
191464562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
191564562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
191664562Sgshapirodnl mark is ? iff the address is user (wo @domain)
191738032Speter
191838032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
191938032Speter# handle case of no @domain on address
192064562Sgshapirodnl prepend daemon_flags
192164562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
192264562Sgshapirodnl accept unqualified sender: change mark to avoid test
192390792SgshapiroR$* u $* $| <?> $*	$: <_RES_OK_> $3
192464562Sgshapirodnl remove daemon_flags
192564562SgshapiroR$* $| $*		$: $2
1926110560SgshapiroR<?> $*			$: < ? $&{client_addr} > $1
1927102528SgshapiroR<?> $*			$@ <_RES_OK_>			...local unqualed ok
192890792SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
192938032Speter							...remote is not')
193038032Speter# check results
193164562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
1932168515SgshapiroR<$={ResOk}> $*		$: @ $2		domain ok
193364562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
193490792SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
193564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
193690792SgshapiroR<$={Accept}> $*	$# $1		accept from access map
193738032SpeterR<DISCARD> $*		$#discard $: discard
1938132943SgshapiroR<QUARANTINE:$+> $*	$#error $@ quarantine $: $1
1939132943SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"')
194064562Sgshapirodnl error tag
194164562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
194264562SgshapiroR<ERROR:$+> $*		$#error $: $1
194390792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
194464562Sgshapirodnl generic error from access map
194564562SgshapiroR<$+> $*		$#error $: $1		error from access db',
194638032Speter`dnl')
1947168515Sgshapirodnl workspace: @ CanonicalAddress (i.e. address in canonical form localpart<@host>)
194838032Speter
1949168515Sgshapiroifdef(`_BADMX_CHK_', `dnl
1950168515SgshapiroR@ $*<@$+>$*		$: $1<@$2>$3 $| $>BadMX $2
1951168515SgshapiroR$* $| $#$*		$#$2
1952168515Sgshapiro
1953168515SgshapiroSBadMX
1954168515Sgshapiro# Look up MX records and ferret away a copy of the original address.
1955168515Sgshapiro# input: domain part of address to check
1956168515SgshapiroR$+				$:<MX><$1><:$(mxlist $1$):><:>
1957168515Sgshapiro# workspace: <MX><domain><: mxlist-result $><:>
1958168515SgshapiroR<MX><$+><:$*<TEMP>:><$*>	$#error $@ 4.1.2 $: "450 MX lookup failure for "$1
1959168515Sgshapiro# workspace: <MX> <original destination> <unchecked mxlist> <checked mxlist>
1960168515Sgshapiro# Recursively run badmx check on each mx.
1961168515SgshapiroR<MX><$*><:$+:$*><:$*>		<MX><$1><:$3><: $4 $(badmx $2 $):>
1962168515Sgshapiro# See if any of them fail.
1963182352SgshapiroR<MX><$*><$*><$*<BADMX>:$*>	$#error $@ 5.1.2 $:"550 Illegal MX record for host "$1
1964168515Sgshapiro# Reverse the mxlists so we can use the same argument order again.
1965168515SgshapiroR<MX><$*><$*><$*>		$:<MX><$1><$3><$2>
1966168515SgshapiroR<MX><$*><:$+:$*><:$*>		<MX><$1><:$3><:$4 $(dnsA $2 $) :>
1967168515Sgshapiro
1968168515Sgshapiro# Reverse the lists so we can use the same argument order again.
1969168515SgshapiroR<MX><$*><$*><$*>		$:<MX><$1><$3><$2>
1970168515SgshapiroR<MX><$*><:$+:$*><:$*>		<MX><$1><:$3><:$4 $(BadMXIP $2 $) :>
1971168515Sgshapiro
1972182352SgshapiroR<MX><$*><$*><$*<BADMXIP>:$*>	$#error $@ 5.1.2 $:"550 Invalid MX record for host "$1',
1973168515Sgshapiro`dnl')
1974168515Sgshapiro
1975168515Sgshapiro
197638032Speter######################################################################
197738032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
197838032Speter######################################################################
197938032Speter
198038032SpeterSLocal_check_rcpt
198164562SgshapiroScheck`'_U_`'rcpt
198238032SpeterR$*			$: $1 $| $>"Local_check_rcpt" $1
198338032SpeterR$* $| $#$*		$#$2
198438032SpeterR$* $| $*		$@ $>"Basic_check_rcpt" $1
198538032Speter
198638032SpeterSBasic_check_rcpt
198790792Sgshapiro# empty address?
198890792SgshapiroR<>			$#error $@ nouser $: "553 User address required"
198990792SgshapiroR$@			$#error $@ nouser $: "553 User address required"
199038032Speter# check for deferred delivery mode
199198121SgshapiroR$*			$: < $&{deliveryMode} > $1
199238032SpeterR< d > $*		$@ deferred
199338032SpeterR< $* > $*		$: $2
199438032Speter
199564562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
199690792Sgshapirodnl this code checks for user@host where host is not a FQHN.
199790792Sgshapirodnl it is not activated.
199890792Sgshapirodnl notice: code to check for a recipient without a domain name is
199990792Sgshapirodnl available down below; look for the same macro.
200090792Sgshapirodnl this check is done here because the name might be qualified by the
200190792Sgshapirodnl canonicalization.
200290792Sgshapiro# require fully qualified domain part?
200390792Sgshapirodnl very simple canonification: make sure the address is in < >
200464562SgshapiroR$+			$: <?> $1
200590792SgshapiroR<?> <$+>		$: <@> <$1>
200690792SgshapiroR<?> $+			$: <@> <$1>
200790792SgshapiroR<@> < postmaster >	$: postmaster
2008110560SgshapiroR<@> < $* @ $+ . $+ >	$: < $1 @ $2 . $3 >
200964562Sgshapirodnl prepend daemon_flags
201090792SgshapiroR<@> $*			$: $&{daemon_flags} $| <@> $1
201164562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
2012159609Sgshapirodnl _r_equire qual.rcpt: ok
2013120256SgshapiroR$* r $* $| <@> < $+ @ $+ >	$: < $3 @ $4 >
201464562Sgshapirodnl do not allow these at all or only from local systems?
2015120256SgshapiroR$* r $* $| <@> < $* >	$: < ? $&{client_name} > < $3 >
201664562SgshapiroR<?> < $* >		$: <$1>
201764562SgshapiroR<? $=w> < $* >		$: <$1>
201890792SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
201964562Sgshapirodnl remove daemon_flags for other cases
202064562SgshapiroR$* $| <@> $*		$: $2', `dnl')
202164562Sgshapiro
202290792Sgshapirodnl ##################################################################
202390792Sgshapirodnl call subroutines for recipient and relay
202490792Sgshapirodnl possible returns from subroutines:
202590792Sgshapirodnl $#TEMP	temporary failure
202690792Sgshapirodnl $#error	permanent failure (or temporary if from access map)
202790792Sgshapirodnl $#other	stop processing
202890792Sgshapirodnl RELAY	RELAYing allowed
202990792Sgshapirodnl other	otherwise
203090792Sgshapiro######################################################################
203190792SgshapiroR$*			$: $1 $| @ $>"Rcpt_ok" $1
203290792Sgshapirodnl temporary failure? remove mark @ and remember
203390792SgshapiroR$* $| @ $#TEMP $+	$: $1 $| T $2
203490792Sgshapirodnl error or ok (stop)
203590792SgshapiroR$* $| @ $#$*		$#$2
203690792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
203790792SgshapiroR$* $| @ RELAY		$@ RELAY
203890792Sgshapirodnl something else: call check sender (relay)
203990792SgshapiroR$* $| @ $*		$: O $| $>"Relay_ok" $1
204090792Sgshapirodnl temporary failure: call check sender (relay)
204190792SgshapiroR$* $| T $+		$: T $2 $| $>"Relay_ok" $1
204290792Sgshapirodnl temporary failure? return that
204390792SgshapiroR$* $| $#TEMP $+	$#error $2
204490792Sgshapirodnl error or ok (stop)
204590792SgshapiroR$* $| $#$*		$#$2
204690792SgshapiroR$* $| RELAY		$@ RELAY
204790792Sgshapirodnl something else: return previous temp failure
204890792SgshapiroR T $+ $| $*		$#error $1
204990792Sgshapiro# anything else is bogus
205090792SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
205190792Sgshapirodivert(0)
205290792Sgshapiro
205390792Sgshapiro######################################################################
205490792Sgshapiro### Rcpt_ok: is the recipient ok?
205590792Sgshapirodnl input: recipient address (RCPT TO)
205690792Sgshapirodnl output: see explanation at call
205790792Sgshapiro######################################################################
205890792SgshapiroSRcpt_ok
205938032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
206042575SpeterR$*			$: $>CanonAddr $1
206138032SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
206238032Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
206338032Speter
206442575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
206542575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
206642575Speter# unlimited bestmx
206742575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
206842575Speter`dnl
206942575Speter# limit bestmx to $=B
207043730SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
207190792SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
207242575SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
207342575SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
207442575Speter
207538032Speterifdef(`_BLACKLIST_RCPT_',`dnl
207664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
207738032Speter# blacklist local users or any host from receiving mail
207838032SpeterR$*			$: <?> $1
207964562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
208064562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
208190792SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
208290792SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
208364562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
208464562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
208564562Sgshapirodnl will only return user<@domain when "reversing" the args
208690792SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
208764562SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
208864562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
208990792Sgshapirodnl we may have to filter here because otherwise some RHSs
209090792Sgshapirodnl would be interpreted as generic error messages...
209190792Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
209290792Sgshapirodnl that would make a lot of things easier.
209364562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
209490792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
209590792SgshapiroR<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
209690792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
209790792Sgshapirodnl compatility with 8.11/8.10:
209864562Sgshapirodnl we have to filter these because otherwise they would be interpreted
209964562Sgshapirodnl as generic error message...
210064562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
210164562Sgshapirodnl that would make a lot of things easier.
210264562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
210364562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
210490792SgshapiroR<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
210564562SgshapiroR<DISCARD> $*		$#discard $: discard
2106132943SgshapiroR<QUARANTINE:$+> $*	$#error $@ quarantine $: $1
210764562Sgshapirodnl error tag
210864562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
210964562SgshapiroR<ERROR:$+> $*		$#error $: $1
211090792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
211164562Sgshapirodnl generic error from access map
211264562SgshapiroR<$+> $*		$#error $: $1		error from access db
211364562SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
211438032Speter
211590792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
211690792Sgshapiro# authenticated via TLS?
211790792SgshapiroR$*			$: $1 $| $>RelayTLS	client authenticated?
211890792SgshapiroR$* $| $# $+		$# $2			error/ok?
211990792SgshapiroR$* $| $*		$: $1			no
212064562Sgshapiro
212190792SgshapiroR$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
212290792Sgshapirodnl workspace: localpart<@domain> $| result of Local_Relay_Auth
212390792SgshapiroR$* $| $# $*		$# $2
212490792Sgshapirodnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
212590792SgshapiroR$* $| NO		$: $1
212690792SgshapiroR$* $| $*		$: $1 $| $&{auth_type}
212790792Sgshapirodnl workspace: localpart<@domain> [ $| ${auth_type} ]
212864562Sgshapirodnl empty ${auth_type}?
212964562SgshapiroR$* $|			$: $1
213064562Sgshapirodnl mechanism ${auth_type} accepted?
213164562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
213290792SgshapiroR$* $| $={TrustAuthMech}	$# RELAY
213390792Sgshapirodnl remove ${auth_type}
213464562SgshapiroR$* $| $*		$: $1
213571345Sgshapirodnl workspace: localpart<@domain> | localpart
213664562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
213771345Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
213871345SgshapiroR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
213938032Speter# anything terminating locally is ok
214038032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
214190792SgshapiroR$+ < @ $* $=m >	$@ RELAY', `dnl')
214290792SgshapiroR$+ < @ $=w >		$@ RELAY
214338032Speterifdef(`_RELAY_HOSTS_ONLY_',
214490792Sgshapiro`R$+ < @ $=R >		$@ RELAY
214564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2146203004Sgshapiroifdef(`_RELAY_FULL_ADDR_', `dnl
2147203004SgshapiroR$+ < @ $+ >		$: <$(access To:$1@$2 $: ? $)> <$1 < @ $2 >>
2148203004SgshapiroR<?> <$+ < @ $+ >>	$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>',`
2149203004SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>')
215064562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
215164562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
215290792Sgshapiro`R$+ < @ $* $=R >	$@ RELAY
215364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2154132943Sgshapiroifdef(`_RELAY_FULL_ADDR_', `dnl
2155132943SgshapiroR$+ < @ $+ >		$: $1 < @ $2 > $| $>SearchList <+ To> $| <F:$1@$2> <D:$2> <F:$1@> <>
2156132943SgshapiroR$+ < @ $+ > $| <$*>	$: <$3> <$1 <@ $2>>
2157132943SgshapiroR$+ < @ $+ > $| $*	$: <$3> <$1 <@ $2>>',
2158132943Sgshapiro`R$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>')')')
215964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
216064562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
216190792SgshapiroR<RELAY> $*		$@ RELAY
216290792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
216338032SpeterR<$*> <$*>		$: $2',`dnl')
216438032Speter
216564562Sgshapiro
216638032Speterifdef(`_RELAY_MX_SERVED_', `dnl
216738032Speter# allow relaying for hosts which we MX serve
216864562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
216964562Sgshapirodnl this must not necessarily happen if the client is checked first...
2170132943SgshapiroR< : $* <TEMP> : > $*	$#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1
217190792SgshapiroR<$* : $=w . : $*> $*	$@ RELAY
217242575SpeterR< : $* : > $*		$: $2',
217338032Speter`dnl')
217438032Speter
217538032Speter# check for local user (i.e. unqualified address)
217638032SpeterR$*			$: <?> $1
217742575SpeterR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
217838032Speter# local user is ok
217964562Sgshapirodnl is it really? the standard requires user@domain, not just user
218064562Sgshapirodnl but we should accept it anyway (maybe making it an option:
218164562Sgshapirodnl RequireFQDN ?)
218264562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
218364562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
218490792SgshapiroR<?> postmaster		$@ OK
218564562Sgshapiro# require qualified recipient?
218664562Sgshapirodnl prepend daemon_flags
218764562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
218864562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
218964562Sgshapirodnl do not allow these at all or only from local systems?
219064562Sgshapirodnl r flag? add client_name
219164562SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
219264562Sgshapirodnl no r flag: relay to local user (only local part)
219364562Sgshapiro# no qualified recipient required
219490792SgshapiroR$* $| <?> $+		$@ RELAY
219564562Sgshapirodnl client_name is empty
219690792SgshapiroR<?> <?> $+		$@ RELAY
219764562Sgshapirodnl client_name is local
219890792SgshapiroR<? $=w> <?> $+		$@ RELAY
219964562Sgshapirodnl client_name is not local
220064562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
220164562Sgshapirodnl no qualified recipient required
220290792SgshapiroR<?> $+			$@ RELAY')
220364562Sgshapirodnl it is a remote user: remove mark and then check client
220438032SpeterR<$+> $*		$: $2
220564562Sgshapirodnl currently the recipient address is not used below
220638032Speter
220790792Sgshapiro######################################################################
220890792Sgshapiro### Relay_ok: is the relay/sender ok?
220990792Sgshapirodnl input: ignored
221090792Sgshapirodnl output: see explanation at call
221190792Sgshapiro######################################################################
221290792SgshapiroSRelay_ok
221338032Speter# anything originating locally is ok
221464562Sgshapiro# check IP address
221564562SgshapiroR$*			$: $&{client_addr}
221690792SgshapiroR$@			$@ RELAY		originated locally
221790792SgshapiroR0			$@ RELAY		originated locally
2218110560SgshapiroR127.0.0.1		$@ RELAY		originated locally
2219110560SgshapiroRIPv6:::1		$@ RELAY		originated locally
222090792SgshapiroR$=R $*			$@ RELAY		relayable IP address
222164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
222290792SgshapiroR$*			$: $>A <$1> <?> <+ Connect> <$1>
222390792SgshapiroR<RELAY> $* 		$@ RELAY		relayable IP address
2224102528Sgshapiroifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl
2225102528Sgshapirodnl this will cause rejections in cases like:
2226102528Sgshapirodnl Connect:My.Host.Domain	RELAY
2227102528Sgshapirodnl Connect:My.Net		REJECT
2228102528Sgshapirodnl since in check_relay client_name is checked before client_addr
2229102528SgshapiroR<REJECT> $* 		$@ REJECT		rejected IP address')
223090792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
223164562SgshapiroR<$*> <$*>		$: $2', `dnl')
223264562SgshapiroR$*			$: [ $1 ]		put brackets around it...
223390792SgshapiroR$=w			$@ RELAY		... and see if it is local
223464562Sgshapiro
223564562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
223664562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
223764562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
223864562Sgshapirodnl input: {client_addr} or something "broken"
223964562Sgshapirodnl just throw the input away; we do not need it.
224064562Sgshapiro# check whether FROM is allowed to use system as relay
224164562SgshapiroR$*			$: <?> $>CanonAddr $&f
224290792SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
224364562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
224464562Sgshapiro# check whether local FROM is ok
224590792SgshapiroR<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
224664562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
224794334SgshapiroR<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <>
224890792SgshapiroR<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
224990792Sgshapiroifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
225090792Sgshapiro', `dnl
225190792Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_',
225290792Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
225364562Sgshapiro')',
225464562Sgshapiro`dnl')
225564562Sgshapirodnl')', `dnl')
225690792Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind.
225790792Sgshapirodnl it does not matter in this case because the following rule ignores
225890792Sgshapirodnl the input. otherwise these rules must "clean up" the workspace.
225964562Sgshapiro
226064562Sgshapiro# check client name: first: did it resolve?
226164562Sgshapirodnl input: ignored
226264562SgshapiroR$*			$: < $&{client_resolve} >
2263132943SgshapiroR<TEMP>			$#TEMP $@ 4.4.0 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
226464562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
226564562SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
226664562Sgshapirodnl ${client_resolve} should be OK, so go ahead
226790792SgshapiroR$*			$: <@> $&{client_name}
226890792Sgshapirodnl should not be necessary since it has been done for client_addr already
2269110560Sgshapirodnl this rule actually may cause a problem if {client_name} resolves to ""
2270110560Sgshapirodnl however, this should not happen since the forward lookup should fail
2271110560Sgshapirodnl and {client_resolve} should be TEMP or FAIL.
2272110560Sgshapirodnl nevertheless, removing the rule doesn't hurt.
2273110560Sgshapirodnl R<@>			$@ RELAY
227490792Sgshapirodnl workspace: <@> ${client_name} (not empty)
227538032Speter# pass to name server to make hostname canonical
227690792SgshapiroR<@> $* $=P 		$:<?>  $1 $2
227790792SgshapiroR<@> $+			$:<?>  $[ $1 $]
227890792Sgshapirodnl workspace: <?> ${client_name} (canonified)
227964562SgshapiroR$* .			$1			strip trailing dots
228038032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
228190792SgshapiroR<?> $* $=m		$@ RELAY', `dnl')
228290792SgshapiroR<?> $=w		$@ RELAY
228338032Speterifdef(`_RELAY_HOSTS_ONLY_',
228490792Sgshapiro`R<?> $=R		$@ RELAY
228564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
228664562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
228764562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
228890792Sgshapiro`R<?> $* $=R			$@ RELAY
228964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
229090792SgshapiroR<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
229164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
229290792SgshapiroR<RELAY> $*		$@ RELAY
229390792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
229438032SpeterR<$*> <$*>		$: $2',`dnl')
229590792Sgshapirodnl end of _PROMISCUOUS_RELAY_
229664562Sgshapirodivert(0)
229764562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
229864562Sgshapiro# turn a canonical address in the form user<@domain>
229964562Sgshapiro# qualify unqual. addresses with $j
230064562Sgshapirodnl it might have been only user (without <@domain>)
230164562SgshapiroSFullAddr
230264562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
230364562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
230464562SgshapiroR$+			$@ $1 <@ $j >
230538032Speter
2306120256SgshapiroSDelay_TLS_Clt
2307110560Sgshapiro# authenticated?
2308110560Sgshapirodnl code repeated here from Basic_check_mail
2309110560Sgshapirodnl only called from check_rcpt in delay mode if checkrcpt returns $#
2310110560SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
2311110560SgshapiroR$* $| $#$+		$#$2
2312110560Sgshapirodnl return result from checkrcpt
2313120256SgshapiroR$* $| $*		$# $1
2314110560SgshapiroR$*			$# $1
2315110560Sgshapiro
2316120256SgshapiroSDelay_TLS_Clt2
2317110560Sgshapiro# authenticated?
2318110560Sgshapirodnl code repeated here from Basic_check_mail
2319110560Sgshapirodnl only called from check_rcpt in delay mode if stopping due to Friend/Hater
2320110560SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
2321110560SgshapiroR$* $| $#$+		$#$2
2322110560Sgshapirodnl return result from friend/hater check
2323120256SgshapiroR$* $| $*		$@ $1
2324110560SgshapiroR$*			$@ $1
2325110560Sgshapiro
232664562Sgshapiro# call all necessary rulesets
232764562SgshapiroScheck_rcpt
232864562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
232964562Sgshapirodnl which is the correct DSN code?
233064562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
2331110560Sgshapiro
233264562SgshapiroR$+			$: $1 $| $>checkrcpt $1
233364562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
2334110560Sgshapirodnl on error (or discard) stop now
2335110560SgshapiroR$+ $| $#error $*	$#error $2
2336110560SgshapiroR$+ $| $#discard $*	$#discard $2
2337110560Sgshapirodnl otherwise call tls_client; see above
2338120256SgshapiroR$+ $| $#$*		$@ $>"Delay_TLS_Clt" $2
233964562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
234064562Sgshapiroifdef(`_SPAM_FH_',
234164562Sgshapiro`dnl lookup user@ and user@address
234264562Sgshapiroifdef(`_ACCESS_TABLE_', `',
234364562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
234464562Sgshapiro')')dnl
234564562Sgshapirodnl one of the next two rules is supposed to match
234664562Sgshapirodnl this code has been copied from BLACKLIST... etc
234764562Sgshapirodnl and simplified by omitting some < >.
234890792SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
234990792SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
235064562Sgshapirodnl R<?>		$@ something_is_very_wrong_here
235190792Sgshapiro# lookup the addresses only with Spam tag
235290792SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
235364562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
235464562Sgshapirodnl', `dnl')
235564562Sgshapiroifdef(`_SPAM_FRIEND_',
235664562Sgshapiro`# is the recipient a spam friend?
235764562Sgshapiroifdef(`_SPAM_HATER_',
2358110560Sgshapiro	`errprint(`*** ERROR: define either Hater or Friend -- not both.
235964562Sgshapiro')', `dnl')
2360120256SgshapiroR<FRIEND> $+		$@ $>"Delay_TLS_Clt2" SPAMFRIEND
236164562SgshapiroR<$*> $+		$: $2',
236264562Sgshapiro`dnl')
236364562Sgshapiroifdef(`_SPAM_HATER_',
236464562Sgshapiro`# is the recipient no spam hater?
236590792SgshapiroR<HATER> $+		$: $1			spam hater: continue checks
2366120256SgshapiroR<$*> $+		$@ $>"Delay_TLS_Clt2" NOSPAMHATER	everyone else: stop
236764562Sgshapirodnl',`dnl')
2368168515Sgshapiro
236964562Sgshapirodnl run further checks: check_mail
237064562Sgshapirodnl should we "clean up" $&f?
237190792Sgshapiroifdef(`_FFR_MAIL_MACRO',
237290792Sgshapiro`R$*			$: $1 $| $>checkmail $&{mail_from}',
237390792Sgshapiro`R$*			$: $1 $| $>checkmail <$&f>')
237494334Sgshapirodnl recipient (canonical format) $| result of checkmail
237564562SgshapiroR$* $| $#$*		$#$2
237664562Sgshapirodnl run further checks: check_relay
237794334SgshapiroR$* $| $*		$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
237864562SgshapiroR$* $| $#$*		$#$2
237938032SpeterR$* $| $*		$: $1
238038032Speter', `dnl')
238190792Sgshapiro
2382168515Sgshapiroifdef(`_BLOCK_BAD_HELO_', `dnl
2383168515SgshapiroR$*			$: $1 $| <$&{auth_authen}>	Get auth info
2384168515Sgshapirodnl Bypass the test for users who have authenticated.
2385168515SgshapiroR$* $| <$+>		$: $1				skip if auth
2386168515SgshapiroR$* $| <$*>		$: $1 $| <$&{client_addr}> [$&s]	Get connection info
2387168515Sgshapirodnl Bypass for local clients -- IP address starts with $=R
2388168515SgshapiroR$* $| <$=R $*> [$*]	$: $1				skip if local client
2389168515Sgshapirodnl Bypass a "sendmail -bs" session, which use 0 for client ip address
2390168515SgshapiroR$* $| <0> [$*]		$: $1				skip if sendmail -bs
2391168515Sgshapirodnl Reject our IP - assumes "[ip]" is in class $=w
2392168515SgshapiroR$* $| <$*> $=w		$#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2393168515Sgshapirodnl Reject our hostname
2394168515SgshapiroR$* $| <$*> [$=w]	$#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2395168515Sgshapirodnl Pass anything else with a "." in the domain parameter
2396168515SgshapiroR$* $| <$*> [$+.$+]	$: $1				qualified domain ok
2397168515Sgshapirodnl Reject if there was no "." or only an initial or final "."
2398168515SgshapiroR$* $| <$*> [$*]	$#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2399168515Sgshapirodnl Clean up the workspace
2400168515SgshapiroR$* $| $*		$: $1
2401168515Sgshapiro', `dnl')
2402168515Sgshapiro
240390792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
240464562Sgshapiro######################################################################
240590792Sgshapiro###  F: LookUpFull -- search for an entry in access database
240690792Sgshapiro###
240790792Sgshapiro###	lookup of full key (which should be an address) and
240890792Sgshapiro###	variations if +detail exists: +* and without +detail
240990792Sgshapiro###
241090792Sgshapiro###	Parameters:
241190792Sgshapiro###		<$1> -- key
241290792Sgshapiro###		<$2> -- default (what to return if not found in db)
241390792Sgshapirodnl			must not be empty
241490792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
241590792Sgshapiro###			! does lookup only with tag
241690792Sgshapiro###			+ does lookup with and without tag
241790792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
241890792Sgshapirodnl returns:		<default> <passthru>
241990792Sgshapirodnl 			<result> <passthru>
242090792Sgshapiro######################################################################
242190792Sgshapiro
242290792SgshapiroSF
242390792Sgshapirodnl workspace: <key> <def> <o tag> <thru>
242490792Sgshapirodnl full lookup
242590792Sgshapirodnl    2    3  4    5
242690792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
242790792Sgshapirodnl no match, try without tag
242890792Sgshapirodnl   1    2      3    4
242990792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
243090792Sgshapirodnl no match, +detail: try +*
243190792Sgshapirodnl   1    2    3    4    5  6    7
243290792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
243390792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
243490792Sgshapirodnl no match, +detail: try +* without tag
243590792Sgshapirodnl   1    2    3    4      5    6
243690792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
243790792Sgshapiro			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
243890792Sgshapirodnl no match, +detail: try without +detail
243990792Sgshapirodnl   1    2    3    4    5  6    7
244090792SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
244190792Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
244290792Sgshapirodnl no match, +detail: try without +detail and without tag
244390792Sgshapirodnl   1    2    3    4      5    6
244490792SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
244590792Sgshapiro			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
244690792Sgshapirodnl no match, return <default> <passthru>
244790792Sgshapirodnl   1    2    3  4    5
244890792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
244990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
245090792Sgshapirodnl            2    3  4    5
245190792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
245290792Sgshapirodnl match, return <match> <passthru>
245390792Sgshapirodnl    2    3  4    5
245490792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
245590792Sgshapiro
245690792Sgshapiro######################################################################
245790792Sgshapiro###  E: LookUpExact -- search for an entry in access database
245890792Sgshapiro###
245990792Sgshapiro###	Parameters:
246090792Sgshapiro###		<$1> -- key
246190792Sgshapiro###		<$2> -- default (what to return if not found in db)
246290792Sgshapirodnl			must not be empty
246390792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
246490792Sgshapiro###			! does lookup only with tag
246590792Sgshapiro###			+ does lookup with and without tag
246690792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
246790792Sgshapirodnl returns:		<default> <passthru>
246890792Sgshapirodnl 			<result> <passthru>
246990792Sgshapiro######################################################################
247090792Sgshapiro
247190792SgshapiroSE
247290792Sgshapirodnl    2    3  4    5
247390792SgshapiroR<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
247490792Sgshapirodnl no match, try without tag
247590792Sgshapirodnl   1    2      3    4
247690792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
247790792Sgshapirodnl no match, return default passthru
247890792Sgshapirodnl   1    2    3  4    5
247990792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
248090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
248190792Sgshapirodnl            2    3  4    5
248290792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
248390792Sgshapirodnl match, return <match> <passthru>
248490792Sgshapirodnl    2    3  4    5
248590792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
248690792Sgshapiro
248790792Sgshapiro######################################################################
248890792Sgshapiro###  U: LookUpUser -- search for an entry in access database
248990792Sgshapiro###
249090792Sgshapiro###	lookup of key (which should be a local part) and
249190792Sgshapiro###	variations if +detail exists: +* and without +detail
249290792Sgshapiro###
249390792Sgshapiro###	Parameters:
249490792Sgshapiro###		<$1> -- key (user@)
249590792Sgshapiro###		<$2> -- default (what to return if not found in db)
249690792Sgshapirodnl			must not be empty
249790792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
249890792Sgshapiro###			! does lookup only with tag
249990792Sgshapiro###			+ does lookup with and without tag
250090792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
250190792Sgshapirodnl returns:		<default> <passthru>
250290792Sgshapirodnl 			<result> <passthru>
250390792Sgshapiro######################################################################
250490792Sgshapiro
250590792SgshapiroSU
250690792Sgshapirodnl user lookups are always with trailing @
250790792Sgshapirodnl    2    3  4    5
250890792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
250990792Sgshapirodnl no match, try without tag
251090792Sgshapirodnl   1    2      3    4
251190792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
251290792Sgshapirodnl do not remove the @ from the lookup:
251390792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
251490792Sgshapirodnl no match, +detail: try +*
251590792Sgshapirodnl   1    2      3    4  5    6
251690792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
251790792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
251890792Sgshapirodnl no match, +detail: try +* without tag
251990792Sgshapirodnl   1    2      3      4    5
252090792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
252190792Sgshapiro			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
252290792Sgshapirodnl no match, +detail: try without +detail
252390792Sgshapirodnl   1    2      3    4  5    6
252490792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
252590792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
252690792Sgshapirodnl no match, +detail: try without +detail and without tag
252790792Sgshapirodnl   1    2      3      4    5
252890792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
252990792Sgshapiro			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
253090792Sgshapirodnl no match, return <default> <passthru>
253190792Sgshapirodnl   1    2    3  4    5
253290792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
253390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
253490792Sgshapirodnl            2    3  4    5
253590792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
253690792Sgshapirodnl match, return <match> <passthru>
253790792Sgshapirodnl    2    3  4    5
253890792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
253990792Sgshapiro
254090792Sgshapiro######################################################################
254164562Sgshapiro###  SearchList: search a list of items in the access map
254264562Sgshapiro###	Parameters:
254364562Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
254464562Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
254564562Sgshapirodnl	avoid errorneous matches (with error messages?)
254664562Sgshapirodnl	if we can make sure that tag is always a single token
254764562Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
254890792Sgshapirodnl	to avoid errorneous matchs (first rule: D: if there
254964562Sgshapirodnl	is that mark somewhere in the list, it will be taken).
255064562Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
255164562Sgshapirodnl	the tag only, e.g.:
255264562Sgshapiro###	where "exact" is either "+" or "!":
255364562Sgshapiro###	<+ TAG>	lookup with and w/o tag
255464562Sgshapiro###	<! TAG>	lookup with tag
255564562Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
255664562Sgshapirodnl		a blank between them and the tag.
255764562Sgshapiro###	possible values for "mark" are:
255890792Sgshapiro###		D: recursive host lookup (LookUpDomain)
255964562Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
256064562Sgshapiro###		E: exact lookup, no modifications
256164562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
256264562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
256364562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
256464562Sgshapiro######################################################################
256538032Speter
256664562Sgshapiro# class with valid marks for SearchList
256764562Sgshapirodnl if A is activated: add it
2568132943SgshapiroC{Src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
256964562SgshapiroSSearchList
257090792Sgshapiro# just call the ruleset with the name of the tag... nice trick...
257190792Sgshapirodnl       2       3    4
2572132943SgshapiroR<$+> $| <$={Src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
257390792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <>
257490792Sgshapirodnl no match and nothing left: return
257590792SgshapiroR<$+> $| <> $| <?> <>		$@ <?>
257690792Sgshapirodnl no match but something left: continue
257790792SgshapiroR<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
257890792Sgshapirodnl match: return
257990792SgshapiroR<$+> $| <$*> $| <$+> <>	$@ <$3>
258064562Sgshapirodnl return result from recursive invocation
258190792SgshapiroR<$+> $| <$+>			$@ <$2>
258290792Sgshapirodnl endif _ACCESS_TABLE_
258390792Sgshapirodivert(0)
258438032Speter
258590792Sgshapiro######################################################################
258690792Sgshapiro###  trust_auth: is user trusted to authenticate as someone else?
258790792Sgshapiro###
258890792Sgshapiro###	Parameters:
258990792Sgshapiro###		$1: AUTH= parameter from MAIL command
259090792Sgshapiro######################################################################
259190792Sgshapiro
259290792Sgshapirodnl empty ruleset definition so it can be called
259390792SgshapiroSLocal_trust_auth
259464562SgshapiroStrust_auth
259564562SgshapiroR$*			$: $&{auth_type} $| $1
259664562Sgshapiro# required by RFC 2554 section 4.
259764562SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
259864562Sgshapirodnl seems to be useful...
259964562SgshapiroR$* $| $&{auth_authen}		$@ identical
260064562SgshapiroR$* $| <$&{auth_authen}>	$@ identical
260164562Sgshapirodnl call user supplied code
2602120256SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $2
260364562SgshapiroR$* $| $#$*		$#$2
260464562Sgshapirodnl default: error
260564562SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
260664562Sgshapiro
260790792Sgshapiro######################################################################
260890792Sgshapiro###  Relay_Auth: allow relaying based on authentication?
260990792Sgshapiro###
261090792Sgshapiro###	Parameters:
261190792Sgshapiro###		$1: ${auth_type}
261290792Sgshapiro######################################################################
261390792SgshapiroSLocal_Relay_Auth
261464562Sgshapiro
261590792Sgshapiro######################################################################
261690792Sgshapiro###  srv_features: which features to offer to a client?
261790792Sgshapiro###	(done in server)
261890792Sgshapiro######################################################################
261990792SgshapiroSsrv_features
262090792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl
262190792SgshapiroR$*			$: $1 $| $>"Local_srv_features" $1
262290792SgshapiroR$* $| $#$*		$#$2
262390792SgshapiroR$* $| $*		$: $1', `dnl')
2624132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
262590792SgshapiroR$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
262690792SgshapiroR<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
262790792SgshapiroR<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
262864562SgshapiroR<?>$*		$@ OK
262990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
263090792SgshapiroR<$* _ATMPF_>$*	$#temp', `dnl')
2631132943SgshapiroR<$+>$*		$# $1')
263264562Sgshapiro
263390792Sgshapiro######################################################################
263490792Sgshapiro###  try_tls: try to use STARTTLS?
263590792Sgshapiro###	(done in client)
263690792Sgshapiro######################################################################
263764562SgshapiroStry_tls
263890792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl
263990792SgshapiroR$*			$: $1 $| $>"Local_try_tls" $1
264090792SgshapiroR$* $| $#$*		$#$2
264190792SgshapiroR$* $| $*		$: $1', `dnl')
2642132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
264390792SgshapiroR$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
264490792SgshapiroR<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
264590792SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
264664562SgshapiroR<?>$*		$@ OK
264790792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
264890792SgshapiroR<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2649132943SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"')
2650132943Sgshapiro
265190792Sgshapiro######################################################################
265290792Sgshapiro###  tls_rcpt: is connection with server "good" enough?
265390792Sgshapiro###	(done in client, per recipient)
265490792Sgshapirodnl called from deliver() before RCPT command
265590792Sgshapiro###
265690792Sgshapiro###	Parameters:
265790792Sgshapiro###		$1: recipient
265890792Sgshapiro######################################################################
265990792SgshapiroStls_rcpt
266090792Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl
266190792SgshapiroR$*			$: $1 $| $>"Local_tls_rcpt" $1
266290792SgshapiroR$* $| $#$*		$#$2
266390792SgshapiroR$* $| $*		$: $1', `dnl')
2664132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
266590792Sgshapirodnl store name of other side
266690792SgshapiroR$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
266790792Sgshapirodnl canonify recipient address
266890792SgshapiroR$+			$: <?> $>CanonAddr $1
266990792Sgshapirodnl strip trailing dots
267090792SgshapiroR<?> $+ < @ $+ . >	<?> $1 <@ $2 >
267190792Sgshapirodnl full address?
267290792SgshapiroR<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
267390792Sgshapirodnl only localpart?
267490792SgshapiroR<?> $+			$: $1 $| <U:$1@> <E:>
267590792Sgshapirodnl look it up
267690792Sgshapirodnl also look up a default value via E:
267790792SgshapiroR$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
267890792Sgshapirodnl found nothing: stop here
267990792SgshapiroR$* $| <?>	$@ OK
268090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
268190792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
268290792Sgshapirodnl use the generic routine (for now)
268390792SgshapiroR$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
268464562Sgshapiro
268590792Sgshapiro######################################################################
268690792Sgshapiro###  tls_client: is connection with client "good" enough?
268790792Sgshapiro###	(done in server)
268890792Sgshapiro###
268990792Sgshapiro###	Parameters:
269090792Sgshapiro###		${verify} $| (MAIL|STARTTLS)
269190792Sgshapiro######################################################################
269264562Sgshapirodnl MAIL: called from check_mail
269364562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
269464562SgshapiroStls_client
269590792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl
2696182352SgshapiroR$*			$: $1 <?> $>"Local_tls_client" $1
2697182352SgshapiroR$* <?> $#$*		$#$2
2698182352SgshapiroR$* <?> $*		$: $1', `dnl')
269964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
270090792Sgshapirodnl store name of other side
2701203004SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{client_name} $) $1
270264562Sgshapirodnl ignore second arg for now
270364562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
270464562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
270564562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
270690792SgshapiroR$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
270790792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
270864562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
270964562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
271090792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
271190792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
271290792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
271390792SgshapiroR$* $| $*	$@ $>"TLS_connection" $1')
271464562Sgshapiro
271590792Sgshapiro######################################################################
271690792Sgshapiro###  tls_server: is connection with server "good" enough?
271790792Sgshapiro###	(done in client)
271890792Sgshapiro###
271990792Sgshapiro###	Parameter:
272090792Sgshapiro###		${verify}
272190792Sgshapiro######################################################################
272264562Sgshapirodnl i.e. has the server been authenticated and is encryption active?
272364562Sgshapirodnl called from deliver() after STARTTLS command
272464562SgshapiroStls_server
272590792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl
272690792SgshapiroR$*			$: $1 $| $>"Local_tls_server" $1
272790792SgshapiroR$* $| $#$*		$#$2
272890792SgshapiroR$* $| $*		$: $1', `dnl')
272964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
273090792Sgshapirodnl store name of other side
273190792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
273290792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
273390792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
273464562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
273564562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
273690792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
273790792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
273890792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
273990792SgshapiroR$*		$@ $>"TLS_connection" $1')
274064562Sgshapiro
274190792Sgshapiro######################################################################
274290792Sgshapiro###  TLS_connection: is TLS connection "good" enough?
274390792Sgshapiro###
274490792Sgshapiro###	Parameters:
274564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
274690792Sgshapiro###		${verify} $| <Requirement> [<>]', `dnl
274790792Sgshapiro###		${verify}')
274890792Sgshapiro###		Requirement: RHS from access map, may be ? for none.
274990792Sgshapirodnl	syntax for Requirement:
275090792Sgshapirodnl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
275190792Sgshapirodnl	extensions: could be a list of further requirements
275290792Sgshapirodnl		for now: CN:string	{cn_subject} == string
275390792Sgshapiro######################################################################
275490792SgshapiroSTLS_connection
275590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
275690792Sgshapirodnl deal with TLS handshake failures: abort
275790792SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
275890792Sgshapirodivert(-1)')
275964562Sgshapirodnl common ruleset for tls_{client|server}
276090792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>]
276164562Sgshapirodnl remove optional <>
276264562SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
276390792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup>
276490792Sgshapiro# create the appropriate error codes
276564562Sgshapirodnl permanent or temporary error?
2766132943SgshapiroR$* $| <PERM + $={Tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
2767132943SgshapiroR$* $| <TEMP + $={Tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
276864562Sgshapirodnl default case depends on TLS_PERM_ERR
2769132943SgshapiroR$* $| <$={Tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
277090792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
277190792Sgshapiro# deal with TLS handshake failures: abort
277264562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
277364562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
277464562Sgshapirodnl use default error
277564562SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
2776157001Sgshapiro# deal with TLS protocol errors: abort
2777157001SgshapiroRPROTOCOL $| <$-:$+> $* 	$#error $@ $2 $: $1 " STARTTLS failed."
2778157001Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
2779157001Sgshapirodnl use default error
2780157001SgshapiroRPROTOCOL $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') STARTTLS failed."
278190792SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
278290792Sgshapirodnl separate optional requirements
278390792SgshapiroR$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
2784132943SgshapiroR$* $| <$*> <$={Tls}:$->$*	$: <$2> <$3:$4> <> $1
278590792Sgshapirodnl separate optional requirements
2786132943SgshapiroR$* $| <$*> <$={Tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
278764562Sgshapirodnl some other value in access map: accept
278864562Sgshapirodnl this also allows to override the default case (if used)
278964562SgshapiroR$* $| $*			$@ OK
279064562Sgshapiro# authentication required: give appropriate error
279164562Sgshapiro# other side did authenticate (via STARTTLS)
279290792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
279364562Sgshapirodnl only verification required and it succeeded
279490792SgshapiroR<$*><VERIFY> <> OK		$@ OK
279590792Sgshapirodnl verification required and it succeeded but extensions are given
279690792Sgshapirodnl change it to <SMTP:ESC> <REQ:0>  <extensions>
279790792SgshapiroR<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
279864562Sgshapirodnl verification required + some level of encryption
279990792SgshapiroR<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
280064562Sgshapirodnl just some level of encryption required
280190792SgshapiroR<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
280290792Sgshapirodnl workspace:
280390792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
280490792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
280590792Sgshapirodnl verification required but ${verify} is not set (case 1.)
280690792SgshapiroR<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
280790792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
280890792SgshapiroR<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
280990792SgshapiroR<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
281090792SgshapiroR<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
281164562Sgshapirodnl some other value for ${verify}
281290792SgshapiroR<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
281390792Sgshapirodnl some level of encryption required: get the maximum level (case 2.)
281490792SgshapiroR<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
281564562Sgshapirodnl compare required bits with actual bits
281690792SgshapiroR<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
281790792SgshapiroR<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
281890792Sgshapirodnl strength requirements fulfilled
281990792Sgshapirodnl TLS Additional Requirements Separator
282090792Sgshapirodnl this should be something which does not appear in the extensions itself
282190792Sgshapirodnl @ could be part of a CN, DN, etc...
282290792Sgshapirodnl use < > ? those are encoded in CN, DN, ...
282390792Sgshapirodefine(`_TLS_ARS_', `++')dnl
282490792Sgshapirodnl workspace:
282590792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
282690792SgshapiroR<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
282790792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
282890792Sgshapirodnl continue: check  extensions
282990792SgshapiroR<$-:$+ _TLS_ARS_ >			$@ OK
283090792Sgshapirodnl split extensions into own list
283190792SgshapiroR<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
283290792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
283390792SgshapiroR<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
283464562Sgshapiro
283590792Sgshapiro######################################################################
283690792Sgshapiro###  TLS_req: check additional TLS requirements
283790792Sgshapiro###
283890792Sgshapiro###	Parameters: [<list> <of> <req>] $| <$-:$+>
283990792Sgshapiro###		$-: SMTP reply code
284090792Sgshapiro###		$+: Enhanced Status Code
284190792Sgshapirodnl  further requirements for this ruleset:
284290792Sgshapirodnl	name of "other side" is stored is {TLS_name} (client/server_name)
284390792Sgshapirodnl
284490792Sgshapirodnl	currently only CN[:common_name] is implemented
284590792Sgshapirodnl	right now this is only a logical AND
284690792Sgshapirodnl	i.e. all requirements must be true
284790792Sgshapirodnl	how about an OR? CN must be X or CN must be Y or ..
284890792Sgshapirodnl	use a macro to compute this as a trivial sequential
284990792Sgshapirodnl	operations (no precedences etc)?
285090792Sgshapiro######################################################################
285190792SgshapiroSTLS_req
285290792Sgshapirodnl no additional requirements: ok
285390792SgshapiroR $| $+		$@ OK
285490792Sgshapirodnl require CN: but no CN specified: use name of other side
285590792SgshapiroR<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
285690792Sgshapirodnl match, check rest
285790792SgshapiroR<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
285890792Sgshapirodnl CN does not match
285990792Sgshapirodnl  1   2      3  4
286090792SgshapiroR<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
286190792Sgshapirodnl cert subject
286290792SgshapiroR<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
286390792Sgshapirodnl CS does not match
286490792Sgshapirodnl  1   2      3  4
2865110560SgshapiroR<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1
286690792Sgshapirodnl match, check rest
286790792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
286890792Sgshapirodnl CI does not match
286990792Sgshapirodnl  1   2      3  4
2870110560SgshapiroR<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1
287190792Sgshapirodnl return from recursive call
287290792SgshapiroROK			$@ OK
287390792Sgshapiro
287490792Sgshapiro######################################################################
287590792Sgshapiro###  max: return the maximum of two values separated by :
287690792Sgshapiro###
287790792Sgshapiro###	Parameters: [$-]:[$-]
287890792Sgshapiro######################################################################
287964562SgshapiroSmax
288064562SgshapiroR:		$: 0
288164562SgshapiroR:$-		$: $1
288264562SgshapiroR$-:		$: $1
288364562SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
288464562SgshapiroRTRUE:$-:$-	$: $2
288590792SgshapiroR$-:$-:$-	$: $2
288690792Sgshapirodnl endif _ACCESS_TABLE_
288790792Sgshapirodivert(0)
288864562Sgshapiro
288990792Sgshapiro######################################################################
289090792Sgshapiro###  RelayTLS: allow relaying based on TLS authentication
289190792Sgshapiro###
289290792Sgshapiro###	Parameters:
289390792Sgshapiro###		none
289490792Sgshapiro######################################################################
289590792SgshapiroSRelayTLS
289664562Sgshapiro# authenticated?
289764562Sgshapirodnl we do not allow relaying for anyone who can present a cert
289864562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
2899110560Sgshapirodnl CA in CertPath so we can authenticate users, we do not allow
290064562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
290164562Sgshapirodnl but anyway).
290264562Sgshapirodnl so here is the trick: if the verification succeeded
290364562Sgshapirodnl we look up the cert issuer in the access map
290464562Sgshapirodnl (maybe after extracting a part with a regular expression)
290564562Sgshapirodnl if this returns RELAY we relay without further questions
290664562Sgshapirodnl if it returns SUBJECT we perform a similar check on the
290764562Sgshapirodnl cert subject.
290864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
290990792SgshapiroR$*			$: <?> $&{verify}
291090792SgshapiroR<?> OK			$: OK		authenticated: continue
291190792SgshapiroR<?> $*			$@ NO		not authenticated
291264562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
291390792SgshapiroR$*			$: $(CERTIssuer $&{cert_issuer} $)',
291490792Sgshapiro`R$*			$: $&{cert_issuer}')
291590792SgshapiroR$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
291664562Sgshapirodnl use $# to stop further checks (delay_check)
291790792SgshapiroRRELAY			$# RELAY
291864562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
291990792SgshapiroRSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
292090792Sgshapiro`RSUBJECT		$: <@> $&{cert_subject}')
292190792SgshapiroR<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
292290792SgshapiroR<@> RELAY		$# RELAY
292390792SgshapiroR$*			$: NO', `dnl')
292464562Sgshapiro
292590792Sgshapiro######################################################################
292690792Sgshapiro###  authinfo: lookup authinfo in the access map
292790792Sgshapiro###
292890792Sgshapiro###	Parameters:
292990792Sgshapiro###		$1: {server_name}
293090792Sgshapiro###		$2: {server_addr}
293190792Sgshapirodnl	both are currently ignored
293290792Sgshapirodnl if it should be done via another map, we either need to restrict
293390792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another
293490792Sgshapirodnl parameter which I want to avoid, it's quite complex already)
293590792Sgshapiro######################################################################
293690792Sgshapirodnl omit this ruleset if neither is defined?
293790792Sgshapirodnl it causes DefaultAuthInfo to be ignored
293890792Sgshapirodnl (which may be considered a good thing).
293990792SgshapiroSauthinfo
294090792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl
294190792SgshapiroR$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
294290792SgshapiroR<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
294390792SgshapiroR<?>		$: <$(authinfo AuthInfo: $: ? $)>
294490792SgshapiroR<?>		$@ no				no authinfo available
294590792SgshapiroR<$*>		$# $1
294690792Sgshapirodnl', `dnl
294790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
294890792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
294990792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
295090792SgshapiroR$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
295190792SgshapiroR$* $| <?>$*	$@ no				no authinfo available
295290792SgshapiroR$* $| <$*> <>	$# $2
295390792Sgshapirodnl', `dnl')')
295490792Sgshapiro
2955132943Sgshapiroifdef(`_RATE_CONTROL_',`dnl
2956132943Sgshapiro######################################################################
2957132943Sgshapiro###  RateControl: 
2958132943Sgshapiro###	Parameters:	ignored
2959132943Sgshapiro###	return: $#error or OK
2960132943Sgshapiro######################################################################
2961132943SgshapiroSRateControl
2962132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2963132943SgshapiroR$*		$: <A:$&{client_addr}> <E:>
2964132943Sgshapirodnl also look up a default value via E:
2965132943SgshapiroR$+		$: $>SearchList <! ClientRate> $| $1 <>
2966132943Sgshapirodnl found nothing: stop here
2967132943SgshapiroR<?>		$@ OK
2968132943Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
2969132943SgshapiroR<$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2970132943Sgshapirodnl use the generic routine (for now)
2971132943SgshapiroR<0>		$@ OK		no limit
2972173340SgshapiroR<$+>		$: <$1> $| $(arith l $@ $1 $@ $&{client_rate} $)
2973132943Sgshapirodnl log this? Connection rate $&{client_rate} exceeds limit $1.
2974173340SgshapiroR<$+> $| TRUE	$#error $@ 4.3.2 $: _RATE_CONTROL_REPLY Connection rate limit exceeded.
2975132943Sgshapiro')')
2976132943Sgshapiro
2977132943Sgshapiroifdef(`_CONN_CONTROL_',`dnl
2978132943Sgshapiro######################################################################
2979132943Sgshapiro###  ConnControl: 
2980132943Sgshapiro###	Parameters:	ignored
2981132943Sgshapiro###	return: $#error or OK
2982132943Sgshapiro######################################################################
2983132943SgshapiroSConnControl
2984132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2985132943SgshapiroR$*		$: <A:$&{client_addr}> <E:>
2986132943Sgshapirodnl also look up a default value via E:
2987132943SgshapiroR$+		$: $>SearchList <! ClientConn> $| $1 <>
2988132943Sgshapirodnl found nothing: stop here
2989132943SgshapiroR<?>		$@ OK
2990132943Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
2991132943SgshapiroR<$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2992132943Sgshapirodnl use the generic routine (for now)
2993132943SgshapiroR<0>		$@ OK		no limit
2994173340SgshapiroR<$+>		$: <$1> $| $(arith l $@ $1 $@ $&{client_connections} $)
2995132943Sgshapirodnl log this: Open connections $&{client_connections} exceeds limit $1.
2996173340SgshapiroR<$+> $| TRUE	$#error $@ 4.3.2 $: _CONN_CONTROL_REPLY Too many open connections.
2997132943Sgshapiro')')
2998132943Sgshapiro
299964562Sgshapiroundivert(9)dnl LOCAL_RULESETS
300038032Speter#
300138032Speter######################################################################
300238032Speter######################################################################
300338032Speter#####
300464562Sgshapiro`#####			MAIL FILTER DEFINITIONS'
300564562Sgshapiro#####
300664562Sgshapiro######################################################################
300764562Sgshapiro######################################################################
300890792Sgshapiro_MAIL_FILTERS_
300964562Sgshapiro#
301064562Sgshapiro######################################################################
301164562Sgshapiro######################################################################
301264562Sgshapiro#####
301338032Speter`#####			MAILER DEFINITIONS'
301438032Speter#####
301538032Speter######################################################################
301638032Speter######################################################################
301764562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
301866494Sgshapiro
3019