proto.m4 revision 98121
138032Speterdivert(-1)
238032Speter#
3125820Sgshapiro# Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
464562Sgshapiro#	All rights reserved.
538032Speter# Copyright (c) 1983, 1995 Eric P. Allman.  All rights reserved.
638032Speter# Copyright (c) 1988, 1993
738032Speter#	The Regents of the University of California.  All rights reserved.
838032Speter#
938032Speter# By using this file, you agree to the terms and conditions set
1038032Speter# forth in the LICENSE file which can be found at the top level of
1138032Speter# the sendmail distribution.
1238032Speter#
1338032Speter#
1438032Speterdivert(0)
1538032Speter
16141858SgshapiroVERSIONID(`$Id: proto.m4,v 8.646 2002/05/19 21:22:40 gshapiro Exp $')
1738032Speter
1864562Sgshapiro# level CF_LEVEL config file format
1964562SgshapiroV`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley')
2038032Speterdivert(-1)
2138032Speter
2290792Sgshapirodnl if MAILER(`local') not defined: do it ourself; be nice
2390792Sgshapirodnl maybe we should issue a warning?
2490792Sgshapiroifdef(`_MAILER_local_',`', `MAILER(local)')
2590792Sgshapiro
2638032Speter# do some sanity checking
2738032Speterifdef(`__OSTYPE__',,
2864562Sgshapiro	`errprint(`*** ERROR: No system type defined (use OSTYPE macro)
2964562Sgshapiro')')
3038032Speter
3138032Speter# pick our default mailers
3238032Speterifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')')
3338032Speterifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')')
3438032Speterifdef(`confRELAY_MAILER',,
3538032Speter	`define(`confRELAY_MAILER',
3638032Speter		`ifdef(`_MAILER_smtp_', `relay',
3738032Speter			`ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')')
3838032Speterifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')')
3938032Speterdefine(`_SMTP_', `confSMTP_MAILER')dnl		for readability only
4038032Speterdefine(`_LOCAL_', `confLOCAL_MAILER')dnl	for readability only
4138032Speterdefine(`_RELAY_', `confRELAY_MAILER')dnl	for readability only
4238032Speterdefine(`_UUCP_', `confUUCP_MAILER')dnl		for readability only
4338032Speter
4438032Speter# back compatibility with old config files
4538032Speterifdef(`confDEF_GROUP_ID',
4664562Sgshapiro`errprint(`*** confDEF_GROUP_ID is obsolete.
4764562Sgshapiro    Use confDEF_USER_ID with a colon in the value instead.
4864562Sgshapiro')')
4938032Speterifdef(`confREAD_TIMEOUT',
5064562Sgshapiro`errprint(`*** confREAD_TIMEOUT is obsolete.
5164562Sgshapiro    Use individual confTO_<timeout> parameters instead.
5264562Sgshapiro')')
5338032Speterifdef(`confMESSAGE_TIMEOUT',
5438032Speter	`define(`_ARG_', index(confMESSAGE_TIMEOUT, /))
5538032Speter	 ifelse(_ARG_, -1,
5638032Speter		`define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)',
5738032Speter		`define(`confTO_QUEUERETURN',
5838032Speter			substr(confMESSAGE_TIMEOUT, 0, _ARG_))
5938032Speter		 define(`confTO_QUEUEWARN',
6038032Speter			substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')')
6138032Speterifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,,
6264562Sgshapiro`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete.
6364562Sgshapiro    Use confMAX_MESSAGE_SIZE for the second part of the value.
6464562Sgshapiro')')')
6538032Speter
6664562Sgshapiro
6764562Sgshapiro# Sanity check on ldap_routing feature
6864562Sgshapiro# If the user doesn't specify a new map, they better have given as a
6964562Sgshapiro# default LDAP specification which has the LDAP base (and most likely the host)
7064562Sgshapiroifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(`
7164562SgshapiroWARNING: Using default FEATURE(ldap_routing) map definition(s)
7264562Sgshapirowithout setting confLDAP_DEFAULT_SPEC option.
7364562Sgshapiro')')')dnl
7464562Sgshapiro
7538032Speter# clean option definitions below....
7664562Sgshapirodefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl
7738032Speter
7864562Sgshapirodnl required to "rename" the check_* rulesets...
7964562Sgshapirodefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_'))
8064562Sgshapirodnl default relaying denied message
8190792Sgshapiroifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG',
8290792Sgshapiroifdef(`_USE_AUTH_', `"550 Relaying denied. Proper authentication required."', `"550 Relaying denied"'))')
8390792Sgshapiroifdef(`confRCPTREJ_MSG', `', `define(`confRCPTREJ_MSG', `"550 Mailbox disabled for this recipient"')')
8490792Sgshapirodefine(`_CODE553', `553')
8538032Speterdivert(0)dnl
8638032Speter
8764562Sgshapiro# override file safeties - setting this option compromises system security,
8864562Sgshapiro# addressing the actual file configuration problem is preferred
8964562Sgshapiro# need to set this before any file actions are encountered in the cf file
9064562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe')
9138032Speter
9264562Sgshapiro# default LDAP map specification
9364562Sgshapiro# need to set this now before any LDAP maps are defined
9464562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost')
9564562Sgshapiro
9638032Speter##################
9738032Speter#   local info   #
9838032Speter##################
9938032Speter
10090792Sgshapiro# my LDAP cluster
10190792Sgshapiro# need to set this before any LDAP lookups are done (including classes)
10290792Sgshapiroifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m')
10390792Sgshapiro
10438032SpeterCwlocalhost
10538032Speterifdef(`USE_CW_FILE',
10638032Speter`# file containing names of hosts for which we receive email
10738032SpeterFw`'confCW_FILE',
10838032Speter	`dnl')
10938032Speter
11038032Speter# my official domain name
11138032Speter# ... `define' this only if sendmail cannot automatically determine your domain
11238032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM')
11338032Speter
114125820SgshapiroCP.
11538032Speter
11638032Speterifdef(`UUCP_RELAY',
11738032Speter`# UUCP relay host
11838032SpeterDY`'UUCP_RELAY
11938032SpeterCPUUCP
12038032Speter
12138032Speter')dnl
12238032Speterifdef(`BITNET_RELAY',
12338032Speter`#  BITNET relay host
12438032SpeterDB`'BITNET_RELAY
12538032SpeterCPBITNET
12638032Speter
12738032Speter')dnl
12838032Speterifdef(`DECNET_RELAY',
12938032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl
13038032Speter# DECnet relay host
13138032SpeterDC`'DECNET_RELAY
13238032SpeterCPDECNET
13338032Speter
13438032Speter')dnl
13538032Speterifdef(`FAX_RELAY',
13638032Speter`# FAX relay host
13738032SpeterDF`'FAX_RELAY
13838032SpeterCPFAX
13938032Speter
14038032Speter')dnl
14138032Speter# "Smart" relay host (may be null)
14238032SpeterDS`'ifdef(`SMART_HOST', `SMART_HOST')
14390792Sgshapiro
14438032Speterifdef(`LUSER_RELAY', `dnl
14538032Speter# place to which unknown users should be forwarded
14638032SpeterKuser user -m -a<>
14738032SpeterDL`'LUSER_RELAY',
14838032Speter`dnl')
14938032Speter
15038032Speter# operators that cannot be in local usernames (i.e., network indicators)
15138032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!')
15238032Speter
15338032Speter# a class with just dot (for identifying canonical names)
15438032SpeterC..
15538032Speter
15638032Speter# a class with just a left bracket (for identifying domain literals)
15738032SpeterC[[
15838032Speter
15938032Speterifdef(`_ACCESS_TABLE_', `dnl
16064562Sgshapiro# access_db acceptance class
16164562SgshapiroC{Accept}OK RELAY
16264562Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
16390792Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl
16464562Sgshapiro# possible access_db RHS for spam friends/haters
16564562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')',
16664562Sgshapiro`dnl')
16738032Speter
16838032Speterdnl mark for "domain is ok" (resolved or accepted anyway)
16990792Sgshapirodefine(`_RES_OK_', `OKR')dnl
17090792Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
17138032Speter# Resolve map (to check if a host exists in check_mail)
17238032SpeterKresolve host -a<_RES_OK_> -T<TEMP>')
17390792SgshapiroC{ResOk}_RES_OK_
17490792Sgshapiro
17538032Speterifdef(`_NEED_MACRO_MAP_', `dnl
17680785Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map
17780785Sgshapirodefine(`_MACRO_MAP_', `1')dnl
17880785SgshapiroKmacro macro')', `dnl')
17980785Sgshapiro
18066494Sgshapiroifdef(`confCR_FILE', `dnl
18138032Speter# Hosts for which relaying is permitted ($=R)
18266494SgshapiroFR`'confCR_FILE',
18338032Speter`dnl')
18438032Speter
18538032Speterdefine(`TLS_SRV_TAG', `"TLS_Srv"')dnl
18690792Sgshapirodefine(`TLS_CLT_TAG', `"TLS_Clt"')dnl
18790792Sgshapirodefine(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl
18890792Sgshapirodefine(`TLS_TRY_TAG', `"Try_TLS"')dnl
18990792Sgshapirodefine(`SRV_FEAT_TAG', `"Srv_Features"')dnl
19090792Sgshapirodnl this may be useful in other contexts too
19164562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map
19264562Sgshapirodefine(`_ARITH_MAP_', `1')dnl
19364562SgshapiroKarith arith')
19464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
19564562Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map
19690792Sgshapirodefine(`_MACRO_MAP_', `1')dnl
19790792SgshapiroKmacro macro')
19890792Sgshapiro# possible values for TLS_connection in access map
19990792SgshapiroC{tls}VERIFY ENCR', `dnl')
200132943Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
20164562Sgshapiro# extract relevant part from cert issuer
20264562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
20364562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
20464562Sgshapiro# extract relevant part from cert subject
20564562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
20664562Sgshapiro
20764562Sgshapiroifdef(`LOCAL_RELAY', `dnl
20890792Sgshapiro# who I send unqualified names to (null means deliver locally)
209110647SgshapiroDR`'LOCAL_RELAY')
210110560Sgshapiro
21190792Sgshapiroifdef(`MAIL_HUB', `dnl
21238032Speter# who gets all local email traffic ($R has precedence for unqualified names)
21390792SgshapiroDH`'MAIL_HUB')
214110560Sgshapiro
215110647Sgshapiro# dequoting map
21690792SgshapiroKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `')
21738032Speter
21838032Speterdivert(0)dnl	# end of nullclient diversion
21990792Sgshapiro# class E: names that should be exposed as from this host, even if we masquerade
22038032Speter# class L: names that should be delivered locally, even if we have a relay
22138032Speter# class M: domains that should be converted to $M
22238032Speter# class N: domains that should not be converted to $M
22364562Sgshapiro#CL root
22438032Speterundivert(5)dnl
22564562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
22638032Speter
22738032Speterifdef(`MASQUERADE_NAME', `dnl
22864562Sgshapiro# who I masquerade as (null for no masquerading) (see also $=M)
22938032SpeterDM`'MASQUERADE_NAME')
23090792Sgshapiro
23138032Speter# my name for error messages
23290792Sgshapiroifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
23338032Speter
23438032Speterundivert(6)dnl LOCAL_CONFIG
23538032Speterinclude(_CF_DIR_`m4/version.m4')
23638032Speter
23764562Sgshapiro###############
23838032Speter#   Options   #
23938032Speter###############
24038032Speterifdef(`confAUTO_REBUILD',
24138032Speter`errprint(WARNING: `confAUTO_REBUILD' is no longer valid.
24238032Speter	There was a potential for a denial of service attack if this is set.
24390792Sgshapiro)')dnl
24490792Sgshapiro
24590792Sgshapiro# strip message body to 7 bits on input?
24690792Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
24738032Speter
24838032Speter# 8-bit data handling
24964562Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8')
25038032Speter
25138032Speter# wait for alias file rebuild (default units: minutes)
25277349Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m')
25338032Speter
25438032Speter# location of alias file
25564562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
25638032Speter
25738032Speter# minimum number of free blocks on filesystem
25864562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
25964562Sgshapiro
26038032Speter# maximum message size
26164562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000')
26238032Speter
26338032Speter# substitution for space (blank) characters
264132943Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_')
26538032Speter
26638032Speter# avoid connecting to "expensive" mailers on initial submission?
26764562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
26838032Speter
26938032Speter# checkpoint queue runs after every N successful deliveries
27064562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
27138032Speter
27238032Speter# default delivery mode
27364562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
27438032Speter
27538032Speter# error message header/file
27664562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
27738032Speter
27838032Speter# error mode
27964562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print')
28038032Speter
28138032Speter# save Unix-style "From_" lines at top of header?
28264562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
28338032Speter
28438032Speter# queue file mode (qf files)
28564562Sgshapiro_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600')
28638032Speter
28790792Sgshapiro# temporary file mode
28890792Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
28990792Sgshapiro
29038032Speter# match recipients against GECOS field?
29164562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
29238032Speter
29338032Speter# maximum hop count
29464562Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `25')
29538032Speter
29638032Speter# location of help file
29790792SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
29838032Speter
29938032Speter# ignore dots as terminators in incoming messages?
30064562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
30138032Speter
30238032Speter# name resolver options
30364562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
30438032Speter
30538032Speter# deliver MIME-encapsulated error messages?
30664562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
30738032Speter
30838032Speter# Forward file search path
30964562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
31038032Speter
31138032Speter# open connection cache size
31264562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
31338032Speter
31438032Speter# open connection cache timeout
31564562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
31638032Speter
31738032Speter# persistent host status directory
31864562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
31938032Speter
32038032Speter# single thread deliveries (requires HostStatusDirectory)?
32164562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
32238032Speter
32338032Speter# use Errors-To: header?
32464562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
32538032Speter
32638032Speter# log level
32764562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10')
32838032Speter
32938032Speter# send to me too, even in an alias expansion?
33064562Sgshapiro_OPTION(MeToo, `confME_TOO', `True')
33138032Speter
33238032Speter# verify RHS in newaliases?
33364562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
33438032Speter
33538032Speter# default messages to old style headers if no special punctuation?
33664562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
33738032Speter
33838032Speter# SMTP daemon options
33964562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
34038032Speter`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.
34138032Speter	Use `DAEMON_OPTIONS()'; see cf/README.
34264562Sgshapiro)'dnl
34394334Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
34494334Sgshapiroifelse(defn(`_DPO_'), `',
34564562Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet
34664562SgshapiroO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
34766494Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
34890792Sgshapiro
34990792Sgshapiro# SMTP client options
35064562Sgshapiroifelse(defn(`confCLIENT_OPTIONS'), `', `dnl',
35138032Speter`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid.  See cf/README for more information.
35264562Sgshapiro)'dnl
35390792Sgshapiro`CLIENT_OPTIONS(`confCLIENT_OPTIONS')')
35490792Sgshapiroifelse(defn(`_CPO_'), `',
35590792Sgshapiro`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_')
35690792Sgshapiro
35790792Sgshapiro# Modifiers to `define' {daemon_flags} for direct submissions
35890792Sgshapiro_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `')
35964562Sgshapiro
36090792Sgshapiro# Use as mail submission program? See sendmail/SECURITY
36190792Sgshapiro_OPTION(UseMSP, `confUSE_MSP', `')
36290792Sgshapiro
36390792Sgshapiro# privacy flags
36490792Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
36590792Sgshapiro
36638032Speter# who (if anyone) should get extra copies of error messages
36764562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
36838032Speter
36938032Speter# slope of queue-only function
37064562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
37138032Speter
37238032Speter# limit on number of concurrent queue runners
37364562Sgshapiro_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `')
37438032Speter
37590792Sgshapiro# maximum number of queue-runners per queue-grouping with multiple queues
37690792Sgshapiro_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1')
37790792Sgshapiro
37890792Sgshapiro# priority of queue runners (nice(3))
37990792Sgshapiro_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `')
38090792Sgshapiro
38190792Sgshapiro# shall we sort the queue by hostname first?
38290792Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
38390792Sgshapiro
38490792Sgshapiro# minimum time in queue before retry
38590792Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
38690792Sgshapiro
38790792Sgshapiro# how many jobs can you process in the queue?
38890792Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
38990792Sgshapiro
39090792Sgshapiro# perform initial split of envelope without checking MX records
39190792Sgshapiro_OPTION(FastSplit, `confFAST_SPLIT', `1')
39290792Sgshapiro
39390792Sgshapiro# queue directory
39490792SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
39590792Sgshapiro
39638032Speter# key for shared memory; 0 to turn off
39764562Sgshapiro_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
39838032Speter
39990792Sgshapiroifdef(`confSHARED_MEMORY_KEY_FILE', `dnl
40090792Sgshapiro# file to store key for shared memory (if SharedMemoryKey = -1)
40190792SgshapiroO SharedMemoryKeyFile=confSHARED_MEMORY_KEY_FILE')
40294334Sgshapiro
40394334Sgshapiro# timeouts (many of these)
40494334Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
40594334Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
40638032Speter_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s')
40764562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
40864562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m')
40990792Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m')
41064562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
41164562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
41264562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
41364562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
41464562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m')
41564562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m')
41664562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m')
41764562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h')
41864562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s')
41964562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
42064562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m')
42164562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
42264562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
42364562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
42464562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
42564562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
42664562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
42764562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
428132943Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
42964562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
43064562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
43164562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
43264562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
433132943Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
43464562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
43564562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
43664562Sgshapiro_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
43764562Sgshapiro_OPTION(Timeout.auth, `confTO_AUTH', `10m')
43864562Sgshapiro_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
43964562Sgshapiro
44064562Sgshapiro# time for DeliverBy; extension disabled if less than 0
44190792Sgshapiro_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
44290792Sgshapiro
44390792Sgshapiro# should we not prune routes in route-addr syntax addresses?
44438032Speter_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
44590792Sgshapiro
44690792Sgshapiro# queue up everything before forking?
44790792Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
44838032Speter
44964562Sgshapiro# status file
45038032SpeterO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
45138032Speter
45264562Sgshapiro# time zone handling:
45338032Speter#  if undefined, use system default
45438032Speter#  if defined but null, use TZ envariable passed in
45564562Sgshapiro#  if defined and non-null, use that info
45638032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
45738032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
45838032Speter	`O TimeZoneSpec=confTIME_ZONE')
45938032Speter
46038032Speter# default UID (can be username or userid:groupid)
46138032Speter_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
46238032Speter
46338032Speter# list of locations of user database file (null means no lookup)
46438032Speter_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
46538032Speter
46664562Sgshapiro# fallback MX host
46738032Speter_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
46838032Speter
46964562Sgshapiro# if we are the best MX host for a site, try it directly instead of config err
47038032Speter_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
47138032Speter
47264562Sgshapiro# load average at which we just queue messages
47338032Speter_OPTION(QueueLA, `confQUEUE_LA', `8')
474132943Sgshapiro
475132943Sgshapiro# load average at which we refuse connections
476132943Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
47738032Speter
47864562Sgshapiro# load average at which we delay connections; 0 means no limit
47938032Speter_OPTION(DelayLA, `confDELAY_LA', `0')
48038032Speter
48164562Sgshapiro# maximum number of children we allow at one time
48238032Speter_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12')
48338032Speter
48464562Sgshapiro# maximum number of new connections per second
48538032Speter_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
486132943Sgshapiro
487132943Sgshapiro# work recipient factor
488132943Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
48990792Sgshapiro
49090792Sgshapiro# deliver each queued job in a separate process?
49190792Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
49238032Speter
49398841Sgshapiro# work class factor
49438032Speter_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
49538032Speter
49671345Sgshapiro# work time factor
49738032Speter_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
498132943Sgshapiro
499132943Sgshapiro# default character set
500132943Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
50138032Speter
50264562Sgshapiro# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
50338032Speter_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
50438032Speter
50564562Sgshapiro# hosts file (normally /etc/hosts)
50638032Speter_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
50738032Speter
50864562Sgshapiro# dialup line delay on connection failure
50938032Speter_OPTION(DialDelay, `confDIAL_DELAY', `10s')
51038032Speter
51164562Sgshapiro# action to take if there are no recipients in the message
51238032Speter_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed')
51338032Speter
514141858Sgshapiro# chrooted environment for writing to files
51538032Speter_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
51690792Sgshapiro
51764562Sgshapiro# are colons OK in addresses?
51838032Speter_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
51938032Speter
52064562Sgshapiro# shall I avoid expanding CNAMEs (violates protocols)?
52138032Speter_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
52238032Speter
52364562Sgshapiro# SMTP initial login message (old $e macro)
52438032Speter_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
52538032Speter
52664562Sgshapiro# UNIX initial From header format (old $l macro)
52738032Speter_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
52838032Speter
52964562Sgshapiro# From: lines that have embedded newlines are unwrapped onto one line
53038032Speter_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
53138032Speter
53264562Sgshapiro# Allow HELO SMTP command that does not `include' a host name
53338032Speter_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
53438032Speter
53564562Sgshapiro# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
53638032Speter_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
53738032Speter
53864562Sgshapiro# delimiter (operator) characters (old $o macro)
53938032Speter_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
54038032Speter
54164562Sgshapiro# shall I avoid calling initgroups(3) because of high NIS costs?
54238032Speter_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
54338032Speter
54464562Sgshapiro# are group-writable `:include:' and .forward files (un)trustworthy?
54538032Speter# True (the default) means they are not trustworthy.
54638032Speter_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
54764562Sgshapiroifdef(`confUNSAFE_GROUP_WRITES',
54838032Speter`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
54938032Speter')')
55064562Sgshapiro
55138032Speter# where do errors that occur when sending errors get sent?
55238032Speter_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
55364562Sgshapiro
55438032Speter# where to save bounces if all else fails
55538032Speter_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
55664562Sgshapiro
55738032Speter# what user id do we assume for the majority of the processing?
55838032Speter_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
55990792Sgshapiro
56064562Sgshapiro# maximum number of recipients per SMTP envelope
56190792Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
56290792Sgshapiro
56390792Sgshapiro# limit the rate recipients per SMTP envelope are accepted
56438032Speter# once the threshold number of recipients have been rejected
56538032Speter_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20')
56664562Sgshapiro
56738032Speter# shall we get local names from our installed interfaces?
56864562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
56964562Sgshapiro
57064562Sgshapiro# Return-Receipt-To: header implies DSN request
57138032Speter_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
57264562Sgshapiro
57338032Speter# override connection address (for testing)
57438032Speter_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
575132943Sgshapiro
57638032Speter# Trusted user for file ownership and starting the daemon
57790792Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
57890792Sgshapiro
579132943Sgshapiro# Control socket for daemon management
58090792Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
58138032Speter
58264562Sgshapiro# Maximum MIME header length to protect MUAs
58338032Speter_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
58464562Sgshapiro
58564562Sgshapiro# Maximum length of the sum of all headers
58664562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
58764562Sgshapiro
58864562Sgshapiro# Maximum depth of alias recursion
58964562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
59064562Sgshapiro
59164562Sgshapiro# location of pid file
59264562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
59364562Sgshapiro
59464562Sgshapiro# Prefix string for the process title shown on 'ps' listings
59564562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
59664562Sgshapiro
597132943Sgshapiro# Data file (df) memory-buffer file maximum size
59864562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
59964562Sgshapiro
60064562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
60164562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
60264562Sgshapiro
60364562Sgshapiro# lookup type to find information about local mailboxes
60464562Sgshapiro_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
60564562Sgshapiro
60664562Sgshapiro# list of authentication mechanisms
60764562Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
60864562Sgshapiro
60964562Sgshapiro# default authentication information for outgoing connections
61064562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
61164562Sgshapiro
61264562Sgshapiro# SMTP AUTH flags
61364562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
61464562Sgshapiro
61564562Sgshapiro# SMTP AUTH maximum encryption strength
61664562Sgshapiro_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
61790792Sgshapiro
61890792Sgshapiro# SMTP STARTTLS server options
61990792Sgshapiro_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
620132943Sgshapiro
621132943Sgshapiro# Input mail filters
622132943Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
62364562Sgshapiro
62490792Sgshapiroifdef(`confINPUT_MAIL_FILTERS', `dnl
62564562Sgshapiro# Milter options
626132943Sgshapiro_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
627132943Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
628132943Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
62964562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
63064562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')')
63164562Sgshapiro
63264562Sgshapiro# CA directory
63364562Sgshapiro_OPTION(CACERTPath, `confCACERT_PATH', `')
63464562Sgshapiro# CA file
63590792Sgshapiro_OPTION(CACERTFile, `confCACERT', `')
63690792Sgshapiro# Server Cert
63790792Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
63890792Sgshapiro# Server private key
63990792Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
64090792Sgshapiro# Client Cert
64164562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
64264562Sgshapiro# Client private key
64364562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
64498841Sgshapiro# DHParameters (only required if DSA/DH is used)
64564562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
64690792Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
64764562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
64864562Sgshapiro
64964562Sgshapiro############################
650125820Sgshapiro`# QUEUE GROUP DEFINITIONS  #'
651132943Sgshapiro############################
65264562Sgshapiro_QUEUE_GROUP_
65364562Sgshapiro
654110560Sgshapiro###########################
65564562Sgshapiro#   Message precedences   #
656110560Sgshapiro###########################
65764562Sgshapiro
65864562SgshapiroPfirst-class=0
65964562SgshapiroPspecial-delivery=100
66064562SgshapiroPlist=-30
66164562SgshapiroPbulk=-60
66264562SgshapiroPjunk=-100
66364562Sgshapiro
66464562Sgshapiro#####################
665132943Sgshapiro#   Trusted users   #
666132943Sgshapiro#####################
66764562Sgshapiro
66864562Sgshapiro# this is equivalent to setting class "t"
66964562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
67064562SgshapiroTroot
67164562SgshapiroTdaemon
67290792Sgshapiroifdef(`_NO_UUCP_', `dnl', `Tuucp')
67390792Sgshapiroifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
67490792Sgshapiro
67590792Sgshapiro#########################
67642575Speter#   Format of headers   #
67738032Speter#########################
67838032Speter
67938032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
68038032SpeterH?P?Return-Path: <$g>
68138032SpeterHReceived: confRECEIVED_HEADER
68238032SpeterH?D?Resent-Date: $a
68338032SpeterH?D?Date: $a
68438032SpeterH?F?Resent-From: confFROM_HEADER
68538032SpeterH?F?From: confFROM_HEADER
68638032SpeterH?x?Full-Name: $x
68738032Speter# HPosted-Date: $a
68838032Speter# H?l?Received-Date: $b
68938032SpeterH?M?Resent-Message-Id: <$t.$i@$j>
69038032SpeterH?M?Message-Id: <$t.$i@$j>
69138032Speter
69264562Sgshapiro#
69338032Speter######################################################################
69438032Speter######################################################################
69538032Speter#####
69638032Speter#####			REWRITING RULES
69738032Speter#####
69838032Speter######################################################################
69938032Speter######################################################################
70038032Speter
70138032Speter############################################
70238032Speter###  Ruleset 3 -- Name Canonicalization  ###
703132943Sgshapiro############################################
70438032SpeterScanonify=3
70538032Speter
70638032Speter# handle null input (translate to <@> special case)
70738032SpeterR$@			$@ <@>
70838032Speter
70938032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
71038032SpeterR$*			$: $1 <@>			mark addresses
71138032SpeterR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
71238032SpeterR@ $* <@>		$: @ $1				unmark @host:...
713132943SgshapiroR$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
714132943SgshapiroR$* :: $* <@>		$: $1 :: $2			unmark node::addr
71564562SgshapiroR:`include': $* <@>	$: :`include': $1			unmark :`include':...
71638032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
71738032SpeterR$* : $* <@>		$: $2				strip colon if marked
71838032SpeterR$* <@>			$: $1				unmark
71938032SpeterR$* ;			   $1				strip trailing semi
72038032SpeterR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
72138032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
72238032Speter
72338032Speter# null input now results from list:; syntax
72438032SpeterR$@			$@ :; <@>
72538032Speter
72638032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
72738032SpeterR$*			$: < $1 >			housekeeping <>
72864562SgshapiroR$+ < $* >		   < $2 >			strip excess on left
72938032SpeterR< $* > $+		   < $1 >			strip excess on right
73038032SpeterR<>			$@ < @ >			MAIL FROM:<> case
73138032SpeterR< $+ >			$: $1				remove housekeeping <>
73238032Speter
73338032Speterifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
73438032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
73538032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
73638032Speter
73790792Sgshapiro# localize and dispose of route-based addresses
73838032Speterdnl XXX: IPv6 colon conflict
73938032Speterifdef(`NO_NETINET6', `dnl',
74038032Speter`R@ [$+] : $+		$@ $>Canonify2 < @ [$1] > : $2	handle <route-addr>')
74138032SpeterR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
74238032Speterdnl',`dnl
74338032Speter# strip route address <@a,@b,@c:user@d> -> <user@d>
74471345SgshapiroR@ $+ , $+		$2
74538032Speterifdef(`NO_NETINET6', `dnl',
74638032Speter`R@ [ $* ] : $+		$2')
74738032SpeterR@ $+ : $+		$2
74838032Speterdnl')
74938032Speter
75038032Speter# find focus for list syntax
75138032SpeterR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
75238032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
75338032Speter
75438032Speter# find focus for @ syntax addresses
75538032SpeterR$+ @ $+		$: $1 < @ $2 >			focus on domain
75638032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
75764562SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
75838032Speter
75938032Speterdnl This is flagged as an error in S0; no need to silently fix it here.
76038032Speterdnl # do some sanity checking
76138032Speterdnl R$* < @ $~[ $* : $* > $*	$1 < @ $2 $3 > $4	nix colons in addrs
76290792Sgshapiro
76390792Sgshapiroifdef(`_NO_UUCP_', `dnl',
76490792Sgshapiro`# convert old-style addresses to a domain-based address
76564562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
76664562SgshapiroR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
76764562SgshapiroR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
76864562Sgshapiro')
76990792Sgshapiroifdef(`_USE_DECNET_SYNTAX_',
77090792Sgshapiro`# convert node::user addresses into a domain-based address
77164562SgshapiroR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
77264562SgshapiroR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
77338032Speter',
77438032Speter	`dnl')
77564562Sgshapiro# if we have % signs, take the rightmost one
77638032SpeterR$* % $*		$1 @ $2				First make them all @s.
77738032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
77838032SpeterR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
77938032Speter
78038032Speter# else we must be a local name
78164562SgshapiroR$*			$@ $>Canonify2 $1
78238032Speter
78390792Sgshapiro
78490792Sgshapiro################################################
78590792Sgshapiro###  Ruleset 96 -- bottom half of ruleset 3  ###
78638032Speter################################################
78738032Speter
78838032SpeterSCanonify2=96
78964562Sgshapiro
79064562Sgshapiro# handle special cases for local names
79164562SgshapiroR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
79238032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
79338032Speterifdef(`_NO_UUCP_', `dnl',
79438032Speter`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
79564562Sgshapiro
79664562Sgshapiro# check for IPv4/IPv6 domain literal
79738032SpeterR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [addr]
79838032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
79938032SpeterR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
80038032Speter
80138032Speterifdef(`_DOMAIN_TABLE_', `dnl
80264562Sgshapiro# look up domains in the domain table
80338032SpeterR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
80438032Speter
80564562Sgshapiroundivert(2)dnl LOCAL_RULE_3
80638032Speter
80738032Speterifdef(`_BITDOMAIN_TABLE_', `dnl
80838032Speter# handle BITNET mapping
80938032SpeterR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
81038032Speter
81138032Speterifdef(`_UUDOMAIN_TABLE_', `dnl
81264562Sgshapiro# handle UUCP mapping
81338032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
81438032Speter
81538032Speterifdef(`_NO_UUCP_', `dnl',
81638032Speter`ifdef(`UUCP_RELAY',
81738032Speter`# pass UUCP addresses straight through
81838032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
81964562Sgshapiro`# if really UUCP, handle it immediately
82090792Sgshapiroifdef(`_CLASS_U_',
82190792Sgshapiro`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82238032Speterifdef(`_CLASS_V_',
82338032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82438032Speterifdef(`_CLASS_W_',
82564562Sgshapiro`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82638032Speterifdef(`_CLASS_X_',
82738032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
82838032Speterifdef(`_CLASS_Y_',
82964562Sgshapiro`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
83038032Speter
83164562Sgshapiroifdef(`_NO_CANONIFY_', `dnl', `dnl
83238032Speter# try UUCP traffic as a local address
83338032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
83438032SpeterR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
83564562Sgshapiro')')
83638032Speter# hostnames ending in class P are always canonical
83738032SpeterR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
83838032Speterdnl apply the next rule only for hostnames not in class P
83938032Speterdnl this even works for phrases in class P since . is in class P
84038032Speterdnl which daemon flags are set?
84138032SpeterR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
84238032Speterdnl the other rules in this section only apply if the hostname
84338032Speterdnl does not end in class P hence no further checks are done here
84438032Speterdnl if this ever changes make sure the lookups are "protected" again!
84538032Speterifdef(`_NO_CANONIFY_', `dnl
84638032Speterdnl do not canonify unless:
84738032Speterdnl domain ends in class {Canonify} (this does not work if the intersection
84838032Speterdnl	with class P is non-empty)
84938032Speterdnl or {daemon_flags} has c set
85038032Speter# pass to name server to make hostname canonical if in class {Canonify}
85138032SpeterR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
85238032Speter# pass to name server to make hostname canonical if requested
85338032SpeterR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
85438032Speterdnl trailing dot? -> do not apply _CANONIFY_HOSTS_
85538032SpeterR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
85638032Speter# add a trailing dot to qualified hostnames so other rules will work
85738032SpeterR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
85838032Speterifdef(`_CANONIFY_HOSTS_', `dnl
85938032Speterdnl this should only apply to unqualified hostnames
86064562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
86164562Sgshapirodnl then $- does not work.
86264562Sgshapiro# lookup unqualified hostnames
86364562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
86464562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
86564562Sgshapirodnl {daemon_flags} contains CC (do not canonify)
86664562Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work
86764562Sgshapirodnl should we do this for every hostname: even unqualified?
86864562SgshapiroR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
86964562SgshapiroR$* CC $* $| $*			$: $3
87064562Sgshapiroifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
87164562Sgshapiro# do not canonify header addresses
87264562SgshapiroR$* $| $* < @ $* $~P > $*	$: $&{addr_type} $| $2 < @ $3 $4 > $5
87364562SgshapiroR$* h $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
87464562SgshapiroR$* h $* $| $*			$: $3', `dnl')
87564562Sgshapiro# pass to name server to make hostname canonical
87664562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
87764562Sgshapirodnl remove {daemon_flags} for other cases
87864562SgshapiroR$* $| $*			$: $2
87964562Sgshapiro
88064562Sgshapiro# local host aliases and pseudo-domains are always canonical
88164562SgshapiroR$* < @ $=w > $*		$: $1 < @ $2 . > $3
88264562Sgshapiroifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
88364562Sgshapiro`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
88464562Sgshapiro`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
88564562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
88664562Sgshapirodnl virtual hosts are also canonical
88790792Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
88864562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
88964562Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
89071345Sgshapiro`dnl')
89171345Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
89271345Sgshapirodnl hosts for genericstable are also canonical
89364562Sgshapiroifdef(`_GENERICS_ENTIRE_DOMAIN_',
89490792Sgshapiro`R$* < @ $* $=G > $* 	$: $1 < @ $2 $3 . > $4',
89590792Sgshapiro`R$* < @ $=G > $* 	$: $1 < @ $2 . > $3')',
89690792Sgshapiro`dnl')
89790792Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added
89890792Sgshapirodnl by one of the rules before
89938032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
90064562Sgshapiro
90164562Sgshapiro
90264562Sgshapiro##################################################
90338032Speter###  Ruleset 4 -- Final Output Post-rewriting  ###
90438032Speter##################################################
90538032SpeterSfinal=4
90638032Speter
90738032SpeterR$+ :; <@>		$@ $1 :				handle <list:;>
90838032SpeterR$* <@>			$@				handle <> and list:;
90964562Sgshapiro
91064562Sgshapiro# strip trailing dot off possibly canonical name
91164562SgshapiroR$* < @ $+ . > $*	$1 < @ $2 > $3
91264562Sgshapiro
91364562Sgshapiro# eliminate internal code
91464562SgshapiroR$* < @ *LOCAL* > $*	$1 < @ $j > $2
91590792Sgshapiro
91690792Sgshapiro# externalize local domain info
91790792SgshapiroR$* < $+ > $*		$1 $2 $3			defocus
91890792SgshapiroR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
91990792SgshapiroR@ $*			$@ @ $1				... and exit
92090792Sgshapiro
92164562Sgshapiroifdef(`_NO_UUCP_', `dnl',
92264562Sgshapiro`# UUCP must always be presented in old form
92338032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
92438032Speter
92538032Speterifdef(`_USE_DECNET_SYNTAX_',
92638032Speter`# put DECnet back in :: form
92738032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
92838032Speter	`dnl')
92964562Sgshapiro# delete duplicate local names
93038032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
93171345Sgshapiro
93238032Speter
93338032Speter
93438032Speter##############################################################
93538032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
93638032Speter###		   (used for recursive calls)		   ###
93764562Sgshapiro##############################################################
93838032Speter
93938032SpeterSRecurse=97
94038032SpeterR$*			$: $>canonify $1
94138032SpeterR$*			$@ $>parse $1
94238032Speter
94338032Speter
94438032Speter######################################
94538032Speter###   Ruleset 0 -- Parse Address   ###
94638032Speter######################################
94738032Speter
94838032SpeterSparse=0
94938032Speter
95038032SpeterR$*			$: $>Parse0 $1		initial parsing
95138032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
95238032SpeterR$*			$: $>ParseLocal $1	handle local hacks
95338032SpeterR$*			$: $>Parse1 $1		final parsing
95438032Speter
95538032Speter#
95638032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
95738032Speter#	This should either return with the (possibly modified) input
95838032Speter#	or return with a #error mailer.  It should not return with a
95938032Speter#	#mailer other than the #error mailer.
96038032Speter#
96138032Speter
96238032SpeterSParse0
96364562SgshapiroR<@>			$@ <@>			special case error msgs
96464562SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
96564562SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
96638032SpeterR<@ $+>			$#error $@ 5.1.3 $: "_CODE553 User address required"
96738032SpeterR$+ <@>			$#error $@ 5.1.3 $: "_CODE553 Hostname required"
96838032SpeterR$*			$: <> $1
96938032Speterdnl allow tricks like [host1]:[host2]
97038032SpeterR<> $* < @ [ $* ] : $+ > $*	$1 < @ [ $2 ] : $3 > $4
97138032SpeterR<> $* < @ [ $* ] , $+ > $*	$1 < @ [ $2 ] , $3 > $4
97264562Sgshapirodnl but no a@[b]c
97338032SpeterR<> $* < @ [ $* ] $+ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid address"
97438032SpeterR<> $* < @ [ $+ ] > $*		$1 < @ [ $2 ] > $3
97538032SpeterR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
97664562SgshapiroR<> $*			$1
97738032SpeterR$* < @ . $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
97838032SpeterR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
97938032Speterdnl no a@b@
98038032SpeterR$* < @ $* @ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid route address"
98138032Speterdnl no a@b@c
98238032SpeterR$* @ $* < @ $* > $*	$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
98338032Speterdnl comma only allowed before @; this check is not complete
98438032SpeterR$* , $~O $*		$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
98538032Speter
98638032Speterifdef(`_STRICT_RFC821_', `# more RFC 821 checks
98738032SpeterR$* . < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
98890792SgshapiroR. $* < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
98964562Sgshapirodnl', `dnl')
99090792Sgshapiro
99190792Sgshapiro# now delete the local info -- note $=O to find characters that cause forwarding
99238032SpeterR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
99390792SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
99490792SgshapiroR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
99590792SgshapiroR< @ $+ >		$#error $@ 5.1.3 $: "_CODE553 User address required"
99690792SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
99790792SgshapiroR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
99890792SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "_CODE553 User address required"
99990792SgshapiroR$* $=O $* < @ *LOCAL* >
100038032Speter			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
100190792SgshapiroR$* < @ *LOCAL* >	$: $1
100290792Sgshapiro
100390792Sgshapiro#
100490792Sgshapiro#  Parse1 -- the bottom half of ruleset 0.
100590792Sgshapiro#
100690792Sgshapiro
100764562SgshapiroSParse1
100890792Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
100938032Speter# handle LDAP routing for hosts in $={LDAPRoute}
101090792SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
101190792SgshapiroR$+ < @ $={LDAPRouteEquiv} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
101290792Sgshapiro`dnl')
101390792Sgshapiro
101490792Sgshapiroifdef(`_MAILER_smtp_',
101538032Speter`# handle numeric address spec
101664562Sgshapirodnl there is no check whether this is really an IP number
101764562SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
101838032SpeterR$* < @ [ $+ ] > $*	$1 < @ [ $2 ] : $S > $3		Add smart host to path
101990792SgshapiroR$* < @ [ $+ ] : > $*		$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
102064562SgshapiroR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
102138032SpeterR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
102290792Sgshapiro	`dnl')
102338032Speter
102464562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
102538032Speter# handle virtual users
102638032Speterifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
102738032Speterdnl this is not a documented option
102838032Speterdnl it stops looping in virtusertable mapping if input and output
102938032Speterdnl are identical, i.e., if address A is mapped to A.
103038032Speterdnl it does not deal with multi-level recursion
103138032Speter# handle full domains in RHS of virtusertable
103264562SgshapiroR$+ < @ $+ >			$: $(macro {RecipientAddress} $) $1 < @ $2 >
103364562SgshapiroR$+ < @ $+ > 			$: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
103490792SgshapiroR<?> $+ $| $+			$: $1 $(macro {RecipientAddress} $@ $2 $)
103590792SgshapiroR<?> $+ $| $*			$: $1',
103664562Sgshapiro`dnl')
103764562SgshapiroR$+			$: <!> $1		Mark for lookup
103838032Speterdnl input: <!> local<@domain>
103938032Speterifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
104064562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
104164562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
1042112810Sgshapirodnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
104390792SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
104464562Sgshapirodnl if <@> local<@domain>: no match but try lookup
104564562Sgshapirodnl user+detail: try user++@domain if detail not empty
104638032SpeterR<@> $+ + $+ < @ $* . >
104738032Speter			$: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
104864562Sgshapirodnl user+detail: try user+*@domain
104938032SpeterR<@> $+ + $* < @ $* . >
105090792Sgshapiro			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105190792Sgshapirodnl user+detail: try user@domain
105290792SgshapiroR<@> $+ + $* < @ $* . >
105390792Sgshapiro			$: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105490792Sgshapirodnl try default entry: @domain
105590792Sgshapirodnl ++@domain
105690792SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105790792Sgshapirodnl +*@domain
105890792SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
105990792Sgshapirodnl @domain if +detail exists
106090792Sgshapirodnl if no match, change marker to prevent a second @domain lookup
106164562SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . >
106290792Sgshapirodnl without +detail
106364562SgshapiroR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
106464562Sgshapirodnl no match
106564562SgshapiroR<@> $+			$: $1
106690792Sgshapirodnl remove mark
106764562SgshapiroR<!> $+			$: $1
106890792SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
106990792SgshapiroR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
107090792Sgshapiroifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
107190792Sgshapiro# check virtuser input address against output address, if same, skip recursion
107290792SgshapiroR< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
107338032Speter# it is the same: stop now
107490792SgshapiroR< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
107590792SgshapiroR< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
107638032Speterdnl', `dnl')
107790792Sgshapirodnl this is not a documented option
107864562Sgshapirodnl it performs no looping at all for virtusertable
107990792Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_',
108090792Sgshapiro`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
108164562Sgshapiro`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
108290792Sgshapirodnl', `dnl')
108364562Sgshapiro
108498121Sgshapiro# short circuit local delivery so forwarded email works
108598121Sgshapiroifdef(`_MAILER_usenet_', `dnl
108698121SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
108738032Speter
108890792Sgshapiro
108938032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
109090792Sgshapiro`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
109164562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
109264562Sgshapirodnl $H empty (but @$=w.)
109338032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
109490792SgshapiroR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
109590792Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
109690792SgshapiroR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
109790792Sgshapiro
109890792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
109990792Sgshapiro# not local -- try mailer table lookup
110090792SgshapiroR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
110180785SgshapiroR< $+ . > $*		$: < $1 > $2			strip trailing dot
110280785SgshapiroR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
110377349Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
110477349SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
110577349SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
110677349Sgshapiro`dnl')
110738032Speterundivert(4)dnl UUCP rules from `MAILER(uucp)'
110838032Speter
110938032Speterifdef(`_NO_UUCP_', `dnl',
111064562Sgshapiro`# resolve remotely connected UUCP links (if any)
111166494Sgshapiroifdef(`_CLASS_V_',
111266494Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
111338032Speter	`dnl')
111438032Speterifdef(`_CLASS_W_',
111564562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
111664562Sgshapiro	`dnl')
111738032Speterifdef(`_CLASS_X_',
111838032Speter`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
111964562Sgshapiro	`dnl')')
112038032Speter
112138032Speter# resolve fake top level domains by forwarding to other hosts
112264562Sgshapiroifdef(`BITNET_RELAY',
112338032Speter`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
112438032Speter	`dnl')
112538032Speterifdef(`DECNET_RELAY',
112638032Speter`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
112764562Sgshapiro	`dnl')
112864562Sgshapiroifdef(`_MAILER_pop_',
112964562Sgshapiro`R$+ < @ POP. >		$#pop $: $1			user@POP',
113038032Speter	`dnl')
113164562Sgshapiroifdef(`_MAILER_fax_',
113238032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
113338032Speter`ifdef(`FAX_RELAY',
113438032Speter`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
113538032Speter	`dnl')')
113664562Sgshapiro
113738032Speterifdef(`UUCP_RELAY',
113838032Speter`# forward non-local UUCP traffic to our UUCP relay
113964562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
114038032Speter`ifdef(`_MAILER_uucp_',
114138032Speter`# forward other UUCP traffic straight to UUCP
114264562SgshapiroR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
114338032Speter	`dnl')')
114438032Speterifdef(`_MAILER_usenet_', `
114538032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
114638032SpeterR$+ . USENET		$#usenet $@ usenet $: $1',
114764562Sgshapiro	`dnl')
114838032Speter
114938032Speterifdef(`_LOCAL_RULES_',
115064562Sgshapiro`# figure out what should stay in our local mail system
115138032Speterundivert(1)', `dnl')
115238032Speter
115338032Speter# pass names that still have a host to a smarthost (if defined)
115438032SpeterR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
115538032Speter
115638032Speter# deal with other remote names
115738032Speterifdef(`_MAILER_smtp_',
115864562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
115938032Speter`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
116038032Speter
116138032Speter# handle locally delivered names
116238032SpeterR$=L			$#_LOCAL_ $: @ $1		special local names
116364562SgshapiroR$+			$#_LOCAL_ $: $1			regular local names
116438032Speter
116538032Speter###########################################################################
116638032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
116738032Speter###########################################################################
116838032Speter
116938032SpeterSLocal_localaddr
117064562SgshapiroSlocaladdr=5
117138032SpeterR$+			$: $1 $| $>"Local_localaddr" $1
117238032SpeterR$+ $| $#ok		$@ $1			no change
117338032SpeterR$+ $| $#$*		$#$2
117438032SpeterR$+ $| $*		$: $1
117538032Speter
117638032Speterifdef(`_PRESERVE_LUSER_HOST_', `dnl
117738032Speter# Preserve rcpt_host in {Host}
117864562SgshapiroR$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
117938032SpeterR$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
118038032SpeterR$+ $| $| $+		$: $1			h not set, {Host} set
118138032SpeterR$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
118264562SgshapiroR$+ $| $* @ $+ $| $*	$: $(macro {Host} $@ @$3 $) $1	set {Host} to host in h
118390792SgshapiroR$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
118438032Speter')dnl
118538032Speter
118664562Sgshapiroifdef(`_FFR_5_', `dnl
118738032Speter# Preserve host in a macro
118838032SpeterR$+			$: $(macro {LocalAddrHost} $) $1
118938032SpeterR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
119038032Speter
119138032Speterifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
119238032Speter# deal with plussed users so aliases work nicely
119364562SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
119464562SgshapiroR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
119564562Sgshapiro')
119690792Sgshapiro# prepend an empty "forward host" on the front
119764562SgshapiroR$+			$: <> $1
119864562Sgshapiro
119938032Speterifdef(`LUSER_RELAY', `dnl
120090792Sgshapiro# send unrecognized local users to a relay host
120190792Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
120290792SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
120390792SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
120490792SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
120590792SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
120695154SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
120790792SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')
120890792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
120990792SgshapiroR< $+ > $+		$: < $1 > $2 $&{Host}')
121090792Sgshapirodnl')
121166494Sgshapiro
121266494Sgshapiroifdef(`MAIL_HUB', `dnl
121366494SgshapiroR< > $+			$: < $H > $1			try hub', `dnl')
121466494Sgshapiroifdef(`LOCAL_RELAY', `dnl
121590792SgshapiroR< > $+			$: < $R > $1			try relay', `dnl')
121638032Speterifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
121766494SgshapiroR< > $+			$@ $1', `dnl
121866494SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
121966494Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
122038032SpeterR< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
122138032SpeterR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
122238032SpeterR< > < $+ <> $* >	$: < > < $1 >			else discard
122338032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
122438032SpeterR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
122590792SgshapiroR< > < $+ >		$@ $1				no +detail
122666494SgshapiroR$+			$: $1 <> $&h			add +detail back in
122766494Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
122866494SgshapiroR$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
122966494SgshapiroR$+ <> + $*		$: $1 + $2			check whether +detail
123064562SgshapiroR$+ <> $*		$: $1				else discard')
123190792SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
123290792SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
123390792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
123490792Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
123538032SpeterR< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
123690792SgshapiroR< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
123790792Sgshapiroifdef(`_PRESERVE_LUSER_HOST_', `dnl
123890792SgshapiroR< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
123990792SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
124090792Sgshapiro
124190792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
124264562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
124390792Sgshapiro###################################################################
124490792Sgshapiro###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
124564562Sgshapirodnl input: <Domain> FullAddress
124664562Sgshapiro###################################################################
124738032Speter
124866494SgshapiroSLDAPMailertable
124938032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
125043730SpeterR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
125190792SgshapiroR< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
125290792SgshapiroR< $+ > $#$*		$#$2					found
125343730SpeterR< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
125466494Sgshapiro`dnl')
125564562Sgshapiro
125664562Sgshapiro###################################################################
125790792Sgshapiro###  Ruleset 90 -- try domain part of mailertable entry 	###
125890792Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
125990792Sgshapiro###################################################################
126090792Sgshapiro
126190792SgshapiroSMailertable=90
126290792Sgshapirodnl shift and check
126364562Sgshapirodnl %2 is not documented in cf/README
126438032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
126564562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
126690792SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
126738032SpeterR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
126890792Sgshapirodnl is $2 always empty?
126990792SgshapiroR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
127090792SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
127190792Sgshapirodnl return full address
127290792SgshapiroR< $* > $*		$@ $2				no mailertable match',
127390792Sgshapiro`dnl')
127490792Sgshapiro
127590792Sgshapiro###################################################################
127690792Sgshapiro###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
127790792Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
127890792Sgshapirodnl	<> address				-> address
127990792Sgshapirodnl	<error:d.s.n:text>			-> error
128090792Sgshapirodnl	<error:text>				-> error
128138032Speterdnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
128264562Sgshapirodnl	<mailer:host> address			-> mailer host address
128338032Speterdnl	<localdomain> address			-> address
128438032Speterdnl	<host> address				-> relay host address
128564562Sgshapiro###################################################################
128664562Sgshapiro
128764562SgshapiroSMailerToTriple=95
128838032SpeterR< > $*				$@ $1			strip off null relay
128964562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
129064562SgshapiroR< error : $- $+ > $*		$#error $@ $(dequote $1 $) $: $2
129164562SgshapiroR< local : $* > $*		$>CanonLocal < $1 > $2
129264562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
129338032SpeterR< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
129464562SgshapiroR< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
129564562SgshapiroR< $=w > $*			$@ $2			delete local host
129638032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
129738032Speter
129838032Speter###################################################################
129938032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
130038032Speterdnl input: <user> address
130164562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
130264562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
130364562Sgshapirodnl <> user <@host> rest		-> local user@host user
1304120256Sgshapirodnl <> user				-> local user user
130564562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
130664562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
130764562Sgshapirodnl <user> lp				-> local lp user
130864562Sgshapiro###################################################################
130964562Sgshapiro
131038032SpeterSCanonLocal
131138032Speter# strip local host from routed addresses
131264562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
131338032SpeterR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
131464562Sgshapiro
1315120256Sgshapiro# strip trailing dot from any host name that may appear
1316120256SgshapiroR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
131738032Speter
131890792Sgshapiro# handle local: syntax -- use old user, either with or without host
131990792SgshapiroR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
132090792SgshapiroR< > $+				$#_LOCAL_ $@ $1    $: $1
132138032Speter
132238032Speter# handle local:user@host syntax -- ignore host part
132338032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
132438032Speter
132538032Speter# handle local:user syntax
132664562SgshapiroR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
132764562SgshapiroR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
132864562Sgshapiro
132964562Sgshapiro###################################################################
133064562Sgshapiro###  Ruleset 93 -- convert header names to masqueraded form	###
133164562Sgshapiro###################################################################
133264562Sgshapiro
133364562SgshapiroSMasqHdr=93
133438032Speter
133538032Speterifdef(`_GENERICS_TABLE_', `dnl
133638032Speter# handle generics database
133743730Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
133864562Sgshapirodnl if generics should be applied add a @ as mark
133964562Sgshapiro`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
134043730Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
134138032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
134238032Speterdnl workspace: either user<@domain> or <user@domain> user <@domain> @
134338032Speterdnl ignore the first case for now
134438032Speterdnl if it has the mark lookup full address
134538032Speterdnl broken: %1 is full address not just detail
134638032SpeterR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
134738032Speterdnl workspace: ... or <match|@user@domain> user <@domain>
134838032Speterdnl no match, try user+detail@domain
134938032SpeterR<@$+ + $* @ $+> $+ < @ $+ >
135038032Speter		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
135138032SpeterR<@$+ + $* @ $+> $+ < @ $+ >
135238032Speter		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
135338032Speterdnl no match, remove mark
135438032SpeterR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
135538032Speterdnl no match, try @domain for exceptions
135638032SpeterR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
135738032Speterdnl workspace: ... or <match> user <@domain>
135838032Speterdnl no match, try local part
135964562SgshapiroR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
136038032SpeterR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
136164562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
136238032SpeterR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
136338032SpeterR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
136464562SgshapiroR< > $*			$: $1				not found',
136538032Speter`dnl')
136638032Speter
136738032Speter# do not masquerade anything in class N
136864562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
136964562Sgshapiro
137064562Sgshapiroifdef(`MASQUERADE_NAME', `dnl
137190792Sgshapiro# special case the users that should be exposed
137264562SgshapiroR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
137364562Sgshapiroifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
137464562Sgshapiro`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
137564562Sgshapiro`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
137664562Sgshapiroifdef(`_LIMITED_MASQUERADE_', `dnl',
137764562Sgshapiro`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
137864562Sgshapiro
137964562Sgshapiro# handle domain-specific masquerading
138064562Sgshapiroifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
138164562Sgshapiro`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
138264562Sgshapiro`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
138364562Sgshapiroifdef(`_LIMITED_MASQUERADE_', `dnl',
138464562Sgshapiro`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
138538032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
138664562SgshapiroR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
138764562SgshapiroR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
138864562Sgshapirodnl', `dnl no masquerading
138964562Sgshapirodnl just fix *LOCAL* leftovers
139038032SpeterR$* < @ *LOCAL* >	$@ $1 < @ $j . >')
139138032Speter
139238032Speter###################################################################
139364562Sgshapiro###  Ruleset 94 -- convert envelope names to masqueraded form	###
139464562Sgshapiro###################################################################
139564562Sgshapiro
139690792SgshapiroSMasqEnv=94
139738032Speterifdef(`_MASQUERADE_ENVELOPE_',
139838032Speter`R$+			$@ $>MasqHdr $1',
139938032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
140038032Speter
140138032Speter###################################################################
140238032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
140338032Speter###################################################################
140438032Speter
140538032SpeterSParseLocal=98
140638032Speterundivert(3)dnl LOCAL_RULE_0
140738032Speter
140838032Speterifdef(`_LDAP_ROUTING_', `dnl
140938032Speter######################################################################
141038032Speter###  LDAPExpand: Expand address using LDAP routing
141138032Speter###
141238032Speter###	Parameters:
141338032Speter###		<$1> -- parsed address (user < @ domain . >) (pass through)
141490792Sgshapiro###		<$2> -- RFC822 address (user @ domain) (used for lookup)
141590792Sgshapiro###		<$3> -- +detail information
141690792Sgshapiro###
141738032Speter###	Returns:
141838032Speter###		Mailer triplet ($#mailer $@ host $: address)
141938032Speter###		Parsed address (user < @ domain . >)
142038032Speter######################################################################
142138032Speter
142264562SgshapiroSLDAPExpand
142338032Speter# do the LDAP lookups
142464562SgshapiroR<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
142538032Speter
142638032Speter# look for temporary failures (return original address, MTA will queue up)
142738032SpeterR<$* <TMPF>> <$*> <$+> <$+> <$*>	$@ $2
142838032SpeterR<$*> <$* <TMPF>> <$+> <$+> <$*>	$@ $2
142938032Speter
143038032Speter# if mailRoutingAddress and local or non-existant mailHost,
143164562Sgshapiro# return the new mailRoutingAddress
143264562Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
143338032SpeterR<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
143464562SgshapiroR<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
143590792SgshapiroR<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
143690792SgshapiroR<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
143790792Sgshapiro
143890792Sgshapiro
143990792Sgshapiro# if mailRoutingAddress and non-local mailHost,
144090792Sgshapiro# relay to mailHost with new mailRoutingAddress
144190792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
144290792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
144390792Sgshapiro# check mailertable for host, relay from there
144490792SgshapiroR<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
144590792Sgshapiro`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
144690792Sgshapiroifdef(`_MAILER_TABLE_', `dnl
144790792Sgshapiro# check mailertable for host, relay from there
1448132943SgshapiroR<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
1449132943Sgshapiro`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
1450132943Sgshapiro
145164562Sgshapiro# if no mailRoutingAddress and local mailHost,
145264562Sgshapiro# return original address
145390792SgshapiroR<> <$=w> <$+> <$+> <$*>	$@ $2
145464562Sgshapiro
1455132943Sgshapiro
1456132943Sgshapiro# if no mailRoutingAddress and non-local mailHost,
1457132943Sgshapiro# relay to mailHost with original address
1458132943Sgshapiroifdef(`_MAILER_TABLE_', `dnl
1459132943Sgshapiro# check mailertable for host, relay from there
1460132943SgshapiroR<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
1461132943Sgshapiro`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
1462132943Sgshapiro
146394334Sgshapiroifdef(`_LDAP_ROUTE_DETAIL_',
146464562Sgshapiro`# if no mailRoutingAddress and no mailHost,
146564562Sgshapiro# try without +detail
146690792SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
146790792Sgshapiro
146890792Sgshapiro# if still no mailRoutingAddress and no mailHost,
146990792Sgshapiro# try @domain
147090792Sgshapiroifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
147164562SgshapiroR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
147298121SgshapiroR<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>
147364562Sgshapiro
147464562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
147590792Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
147690792Sgshapiro# user does not exist
147790792SgshapiroR<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
147890792Sgshapiro# only give error for envelope recipient
147990792SgshapiroR<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
148090792SgshapiroR<?> <$*> <$+>			$@ $2',
148190792Sgshapiro`dnl
148290792Sgshapiro# return the original address
148390792SgshapiroR<> <> <$+> <@ $+> <$*>		$@ $1')',
148464562Sgshapiro`dnl')
148564562Sgshapiro
148664562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
148790792Sgshapiro')')
148864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
148998121Sgshapiro######################################################################
149064562Sgshapiro###  D: LookUpDomain -- search for domain in access database
149164562Sgshapiro###
149290792Sgshapiro###	Parameters:
149390792Sgshapiro###		<$1> -- key (domain name)
149490792Sgshapiro###		<$2> -- default (what to return if not found in db)
149590792Sgshapirodnl			must not be empty
149664562Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
149790792Sgshapiro###			! does lookup only with tag
149890792Sgshapiro###			+ does lookup with and without tag
149990792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
150090792Sgshapirodnl returns:		<default> <passthru>
150190792Sgshapirodnl 			<result> <passthru>
1502132943Sgshapiro######################################################################
150390792Sgshapiro
150464562SgshapiroSD
150590792Sgshapirodnl workspace <key> <default> <passthru> <mark>
150690792Sgshapirodnl lookup with tag (in front, no delimiter here)
1507132943Sgshapirodnl    2    3  4    5
150864562SgshapiroR<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
150964562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
151064562Sgshapirodnl lookup without tag?
151164562Sgshapirodnl   1    2      3    4
151290792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
151390792Sgshapiroifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
151490792Sgshapirodnl XXX apply this also to IP addresses?
1515132943Sgshapirodnl currently it works the wrong way round for [1.2.3.4]
1516132943Sgshapirodnl   1  2    3    4  5    6
1517132943SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
151890792Sgshapirodnl   1  2    3      4    5
151964562SgshapiroR<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
152064562Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
152190792Sgshapirodnl found SKIP: return <default> and <passthru>
152264562Sgshapirodnl      1    2    3  4    5
152364562SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
152464562Sgshapirodnl not found: IPv4 net (no check is done whether it is an IP number!)
152564562Sgshapirodnl    1  2     3    4  5    6
152690792SgshapiroR<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
152738032Speterifdef(`NO_NETINET6', `dnl',
152890792Sgshapiro`dnl not found: IPv6 net
152938032Speterdnl (could be merged with previous rule if we have a class containing .:)
153038032Speterdnl    1   2     3    4  5    6
153138032SpeterR<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
153238032SpeterR<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
153364562Sgshapirodnl not found, but subdomain: try again
153490792Sgshapirodnl   1  2    3    4  5    6
153564562SgshapiroR<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
153664562Sgshapiroifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
153790792Sgshapirodnl   1    2      3    4
153864562SgshapiroR<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
153964562Sgshapirodnl not found, no subdomain: return <default> and <passthru>
154038032Speterdnl   1    2    3  4    5
154138032SpeterR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
154290792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
154364562Sgshapirodnl            2    3    4  5    6
154464562SgshapiroR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
154590792Sgshapirodnl return <result of lookup> and <passthru>
154690792Sgshapirodnl    2    3    4  5    6
154764562SgshapiroR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
154864562Sgshapiro
154990792Sgshapiro######################################################################
155090792Sgshapiro###  A: LookUpAddress -- search for host address in access database
155190792Sgshapiro###
155290792Sgshapiro###	Parameters:
155390792Sgshapiro###		<$1> -- key (dot quadded host address)
155490792Sgshapiro###		<$2> -- default (what to return if not found in db)
155590792Sgshapirodnl			must not be empty
155690792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
155790792Sgshapiro###			! does lookup only with tag
155890792Sgshapiro###			+ does lookup with and without tag
155990792Sgshapiro###		<$4> -- passthru (additional data passed through)
156090792Sgshapirodnl	returns:	<default> <passthru>
156190792Sgshapirodnl			<result> <passthru>
156290792Sgshapiro######################################################################
156390792Sgshapiro
156490792SgshapiroSA
156590792Sgshapirodnl lookup with tag
156690792Sgshapirodnl    2    3  4    5
156790792SgshapiroR<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
156890792Sgshapirodnl lookup without tag
156990792Sgshapirodnl   1    2      3    4
157090792SgshapiroR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
157164562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
157290792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
157390792Sgshapirodnl found SKIP: return <default> and <passthru>
157490792Sgshapirodnl      1    2    3  4    5
157590792SgshapiroR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
157690792Sgshapiroifdef(`NO_NETINET6', `dnl',
157790792Sgshapiro`dnl no match; IPv6: remove last part
157890792Sgshapirodnl   1   2    3    4  5    6
157990792SgshapiroR<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
158090792SgshapiroR<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
158190792Sgshapirodnl no match; IPv4: remove last part
158290792Sgshapirodnl   1  2    3    4  5    6
158390792SgshapiroR<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
158490792Sgshapirodnl no match: return default
158590792Sgshapirodnl   1    2    3  4    5
158638032SpeterR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
158738032Speterifdef(`_ATMPF_', `dnl tempfail?
158890792Sgshapirodnl            2    3    4  5    6
158938032SpeterR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
159038032Speterdnl match: return result
159138032Speterdnl    2    3    4  5    6
159238032SpeterR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
159364562Sgshapirodnl endif _ACCESS_TABLE_
159490792Sgshapirodivert(0)
159564562Sgshapiro######################################################################
159664562Sgshapiro###  CanonAddr --	Convert an address into a standard form for
159790792Sgshapiro###			relay checking.  Route address syntax is
159864562Sgshapiro###			crudely converted into a %-hack address.
159964562Sgshapiro###
160038032Speter###	Parameters:
160138032Speter###		$1 -- full recipient address
160290792Sgshapiro###
160364562Sgshapiro###	Returns:
160490792Sgshapiro###		parsed address, not in source route form
160590792Sgshapirodnl		user%host%host<@domain>
160664562Sgshapirodnl		host!user<@domain>
160790792Sgshapiro######################################################################
160890792Sgshapiro
160990792SgshapiroSCanonAddr
161090792SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
161190792Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
161290792SgshapiroR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
161390792SgshapiroR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
161490792SgshapiroR$* < @ $+ > : $*	$3 $1 < @ $2 >
161590792Sgshapirodnl')
161690792Sgshapiro
161790792Sgshapiro######################################################################
161890792Sgshapiro###  ParseRecipient --	Strip off hosts in $=R as well as possibly
161964562Sgshapiro###			$* $=m or the access database.
162090792Sgshapiro###			Check user portion for host separators.
162190792Sgshapiro###
162264562Sgshapiro###	Parameters:
162390792Sgshapiro###		$1 -- full recipient address
162490792Sgshapiro###
162590792Sgshapiro###	Returns:
162690792Sgshapiro###		parsed, non-local-relaying address
162790792Sgshapiro######################################################################
162864562Sgshapiro
162990792SgshapiroSParseRecipient
163090792Sgshapirodnl mark and canonify address
163190792SgshapiroR$*				$: <?> $>CanonAddr $1
163290792Sgshapirodnl workspace: <?> localpart<@domain[.]>
163338032SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
163442575Speterdnl workspace: <?> localpart<@domain>
163542575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
163642575Speter
163742575Speter# if no $=O character, no host in the user portion, we are done
163842575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
163942575Speterdnl no $=O in localpart: return
164042575SpeterR<?> $*				$@ $1
164142575Speter
164242575Speterdnl workspace: <NO> localpart<@domain>, where localpart contains $=O
164364562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
164464562Sgshapiroifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
164542575Speter# if we relay, check username portion for user%host so host can be checked also
164642575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
164742575Speterdnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
164864562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
164964562Sgshapiro
165042575Speterdnl what if access map returns something else than RELAY?
165142575Speterdnl we are only interested in RELAY entries...
165242575Speterdnl other To: entries: blacklist recipient; generic entries?
165364562Sgshapirodnl if it is an error we probably do not want to relay anyway
165442575Speterifdef(`_RELAY_HOSTS_ONLY_',
165542575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
165638032Speterifdef(`_ACCESS_TABLE_', `dnl
165738032SpeterR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
165838032SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
165938032Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
166038032Speterifdef(`_ACCESS_TABLE_', `dnl
166138032SpeterR<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
166238032SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
166338032Speter
166438032Speter
166538032Speterifdef(`_RELAY_MX_SERVED_', `dnl
166638032Speterdnl do "we" ($=w) act as backup MX server for the destination domain?
166738032SpeterR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
166864562SgshapiroR<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
166942575Speterdnl yes: mark it as <RELAY>
167064562SgshapiroR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
167142575Speterdnl no: put old <NO> mark back
167264562SgshapiroR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
167342575Speter
167438032Speterdnl do we relay to this recipient domain?
167538032SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
167642575Speterdnl something else
167764562SgshapiroR<$+> $*			$@ $2
167842575Speter
167938032Speter
168090792Sgshapiro######################################################################
168164562Sgshapiro###  check_relay -- check hostname/address on SMTP startup
168238032Speter######################################################################
168338032Speter
168442575SpeterSLocal_check_relay
168564562SgshapiroScheck`'_U_`'relay
168664562SgshapiroR$*			$: $1 $| $>"Local_check_relay" $1
168790792SgshapiroR$* $| $* $| $#$*	$#$3
168890792SgshapiroR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
168990792Sgshapiro
169090792SgshapiroSBasic_check_relay
169190792Sgshapiro# check for deferred delivery mode
169238032SpeterR$*			$: < $&{deliveryMode} > $1
169342575SpeterR< d > $*		$@ deferred
169464562SgshapiroR< $* > $*		$: $2
169564562Sgshapiro
169642575Speterifdef(`_ACCESS_TABLE_', `dnl
169742575Speterdnl workspace: {client_name} $| {client_addr}
169864562SgshapiroR$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
169990792Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
170042575SpeterR<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
170138032Speterdnl workspace: <result-of-lookup> (<>|<{client_addr}>)
170264562SgshapiroR<?> <$*>		$: OK				found nothing
170390792Sgshapirodnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
170490792SgshapiroR<$={Accept}> <$*>	$@ $1				return value of lookup
170590792SgshapiroR<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
1706132943SgshapiroR<DISCARD> <$*>		$#discard $: discard
170790792Sgshapiroifdef(`_FFR_QUARANTINE',
170890792Sgshapiro`R<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1', `dnl')
170990792Sgshapirodnl error tag
171090792SgshapiroR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
171190792SgshapiroR<ERROR:$+> <$*>		$#error $: $1
171290792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
171342575Speterdnl generic error from access map
171490792SgshapiroR<$+> <$*>		$#error $: $1', `dnl')
171590792Sgshapiro
171642575Speterifdef(`_RBL_',`dnl
171764562Sgshapiro# DNS based IP address spam list
171838032Speterdnl workspace: ignored...
171938032SpeterR$*			$: $&{client_addr}
172038032SpeterR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
172138032SpeterR<?>OK			$: OKSOFAR
1722132943SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"',
1723132943Sgshapiro`dnl')
1724132943Sgshapiroundivert(8)
1725132943Sgshapiro
1726132943Sgshapiro######################################################################
1727132943Sgshapiro###  check_mail -- check SMTP ``MAIL FROM:'' command argument
1728132943Sgshapiro######################################################################
1729132943Sgshapiro
1730132943SgshapiroSLocal_check_mail
1731132943SgshapiroScheck`'_U_`'mail
173238032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
173364562SgshapiroR$* $| $#$*		$#$2
1734132943SgshapiroR$* $| $*		$@ $>"Basic_check_mail" $1
1735132943Sgshapiro
173638032SpeterSBasic_check_mail
173738032Speter# check for deferred delivery mode
173838032SpeterR$*			$: < $&{deliveryMode} > $1
173938032SpeterR< d > $*		$@ deferred
174038032SpeterR< $* > $*		$: $2
174138032Speter
174298121Sgshapiro# authenticated?
174338032Speterdnl done first: we can require authentication for every mail transaction
174438032Speterdnl workspace: address as given by MAIL FROM: (sender)
174538032SpeterR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
174664562SgshapiroR$* $| $#$+		$#$2
174766494Sgshapirodnl undo damage: remove result of tls_client call
174890792SgshapiroR$* $| $*		$: $1
174966494Sgshapiro
1750110560Sgshapirodnl workspace: address as given by MAIL FROM:
1751110560SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
1752110560Sgshapiroifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
175390792Sgshapirodnl do some additional checks
175490792Sgshapirodnl no user@host
175590792Sgshapirodnl no user@localhost (if nonlocal sender)
175690792Sgshapirodnl this is a pretty simple canonification, it will not catch every case
175790792Sgshapirodnl just make sure the address has <> around it (which is required by
1758132943Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
175990792Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
1760132943Sgshapirodnl not be modified by host lookups.
176164562SgshapiroR$+			$: <?> $1
176266494SgshapiroR<?><$+>		$: <@> <$1>
176366494SgshapiroR<?>$+			$: <@> <$1>
176490792Sgshapirodnl workspace: <@> <address>
176564562Sgshapirodnl prepend daemon_flags
176666494SgshapiroR$*			$: $&{daemon_flags} $| $1
176738032Speterdnl workspace: ${daemon_flags} $| <@> <address>
176864562Sgshapirodnl do not allow these at all or only from local systems?
176964562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
177090792Sgshapirodnl accept unqualified sender: change mark to avoid test
177138032SpeterR$* u $* $| <@> < $* >	$: <?> < $3 >
177264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
177364562Sgshapirodnl        or:                    <? ${client_name} > <address>
177498121Sgshapirodnl        or:                    <?> <address>
177538032Speterdnl remove daemon_flags
1776132943SgshapiroR$* $| $*		$: $2
1777132943Sgshapiro# handle case of @localhost on address
1778132943SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
1779132943SgshapiroR<@> < $* @ [127.0.0.1] >
1780132943Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
1781132943SgshapiroR<@> < $* @ localhost.$m >
1782132943Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
1783132943Sgshapiroifdef(`_NO_UUCP_', `dnl',
178464562Sgshapiro`R<@> < $* @ localhost.UUCP >
178538032Speter			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
178638032Speterdnl workspace: < ? $&{client_name} > <user@localhost|host>
178738032Speterdnl	or:    <@> <address>
178838032Speterdnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
178938032SpeterR<@> $*			$: $1			no localhost as domain
179038032Speterdnl workspace: < ? $&{client_name} > <user@localhost|host>
179164562Sgshapirodnl	or:    <address>
179238032Speterdnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
179338032SpeterR<? $=w> $*		$: $2			local client: ok
179438032SpeterR<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
179538032Speterdnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
179638032SpeterR<?> $*			$: $1')
179738032Speterdnl workspace: address (or <address>)
179898121SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
179938032Speterdnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
180038032Speterdnl there is nothing behind the <@host> so no trailing $* needed
180138032SpeterR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
180264562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
180364562SgshapiroR<?> $* < @ $* $=P >	$: <OK> $1 < @ $2 $3 >
180464562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
180564562Sgshapirodnl A sender address with my local host name ($j) is safe
180664562SgshapiroR<?> $* < @ $j >	$: <OK> $1 < @ $j >
180764562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
180864562Sgshapiro`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
180938032Speter`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
181064562SgshapiroR<? $* <$->> $* < @ $+ >
181164562Sgshapiro			$: <$2> $3 < @ $4 >')
181238032Speterdnl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
181364562Sgshapirodnl mark is ? iff the address is user (wo @domain)
181464562Sgshapiro
181564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
181664562Sgshapiro# check sender address: user@address, user@, address
181764562Sgshapirodnl should we remove +ext from user?
181864562Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
181964562SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
182064562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
182164562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
182264562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
182364562Sgshapirodnl will only return user<@domain when "reversing" the args
182464562SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
182564562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
182664562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
182764562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
182864562Sgshapiro# retransform for further use
182964562Sgshapirodnl required form:
183064562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
183164562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
183264562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
183364562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
183464562Sgshapirodnl mark is ? iff the address is user (wo @domain)
183564562Sgshapiro
183664562Sgshapiroifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
183738032Speter# handle case of no @domain on address
183864562Sgshapirodnl prepend daemon_flags
183964562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
184064562Sgshapirodnl accept unqualified sender: change mark to avoid test
184164562SgshapiroR$* u $* $| <?> $*	$: <_RES_OK_> $3
184264562Sgshapirodnl remove daemon_flags
184338032SpeterR$* $| $*		$: $2
184464562SgshapiroR<?> $*			$: < ? $&{client_name} > $1
184564562SgshapiroR<?> $*			$@ <OK>				...local unqualed ok
184664562SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
184764562Sgshapiro							...remote is not')
184864562Sgshapiro# check results
184964562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
185064562SgshapiroR<$={ResOk}> $*		$@ <_RES_OK_>	domain ok: stop
185164562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
185264562SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
185364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
185490792SgshapiroR<$={Accept}> $*	$# $1		accept from access map
185564562SgshapiroR<DISCARD> $*		$#discard $: discard
185664562Sgshapiroifdef(`_FFR_QUARANTINE',
185764562Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
185864562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
185964562Sgshapirodnl error tag
186064562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
186164562SgshapiroR<ERROR:$+> $*		$#error $: $1
186264562Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
1863102528Sgshapirodnl generic error from access map
186464562SgshapiroR<$+> $*		$#error $: $1		error from access db',
186598121Sgshapiro`dnl')
1866102528Sgshapiro
186764562Sgshapiro######################################################################
186890792Sgshapiro###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
186964562Sgshapiro######################################################################
187064562Sgshapiro
187164562SgshapiroSLocal_check_rcpt
187290792SgshapiroScheck`'_U_`'rcpt
187364562SgshapiroR$*			$: $1 $| $>"Local_check_rcpt" $1
187438032SpeterR$* $| $#$*		$#$2
187564562SgshapiroR$* $| $*		$@ $>"Basic_check_rcpt" $1
187664562Sgshapiro
187764562SgshapiroSBasic_check_rcpt
187890792Sgshapiro# empty address?
187990792SgshapiroR<>			$#error $@ nouser $: "553 User address required"
188064562SgshapiroR$@			$#error $@ nouser $: "553 User address required"
188164562Sgshapiro# check for deferred delivery mode
188264562SgshapiroR$*			$: < $&{deliveryMode} > $1
188364562SgshapiroR< d > $*		$@ deferred
188490792SgshapiroR< $* > $*		$: $2
188564562Sgshapiro
188664562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
188764562Sgshapirodnl this code checks for user@host where host is not a FQHN.
188838032Speterdnl it is not activated.
188964562Sgshapirodnl notice: code to check for a recipient without a domain name is
189064562Sgshapirodnl available down below; look for the same macro.
189164562Sgshapirodnl this check is done here because the name might be qualified by the
189264562Sgshapirodnl canonicalization.
189364562Sgshapiro# require fully qualified domain part?
189464562Sgshapirodnl very simple canonification: make sure the address is in < >
189538032SpeterR$+			$: <?> $1
189638032SpeterR<?> <$+>		$: <@> <$1>
189738032SpeterR<?> $+			$: <@> <$1>
189864562SgshapiroR<@> < postmaster >	$: postmaster
189964562SgshapiroR<@> < $* @ $+ . $+ >	$: < $3 @ $4 . $5 >
190064562Sgshapirodnl prepend daemon_flags
190190792SgshapiroR<@> $*			$: $&{daemon_flags} $| <@> $1
190264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
190364562Sgshapirodnl do not allow these at all or only from local systems?
1904110560SgshapiroR$* r $* $| <@> < $* @ $* >	$: < ? $&{client_name} > < $3 @ $4 >
1905102528SgshapiroR<?> < $* >		$: <$1>
190690792SgshapiroR<? $=w> < $* >		$: <$1>
190738032SpeterR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
190838032Speterdnl remove daemon_flags for other cases
190964562SgshapiroR$* $| <@> $*		$: $2', `dnl')
191090792Sgshapiro
191164562Sgshapirodnl ##################################################################
191290792Sgshapirodnl call subroutines for recipient and relay
191364562Sgshapirodnl possible returns from subroutines:
191490792Sgshapirodnl $#TEMP	temporary failure
191538032Speterdnl $#error	permanent failure (or temporary if from access map)
1916132943Sgshapirodnl $#other	stop processing
1917132943Sgshapirodnl RELAY	RELAYing allowed
191864562Sgshapirodnl other	otherwise
191964562Sgshapiro######################################################################
192064562SgshapiroR$*			$: $1 $| @ $>"Rcpt_ok" $1
192190792Sgshapirodnl temporary failure? remove mark @ and remember
192264562SgshapiroR$* $| @ $#TEMP $+	$: $1 $| T $2
192364562Sgshapirodnl error or ok (stop)
192438032SpeterR$* $| @ $#$*		$#$2
192538032Speterifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
192638032SpeterR$* $| @ RELAY		$@ RELAY
192738032Speterdnl something else: call check sender (relay)
192838032SpeterR$* $| @ $*		$: O $| $>"Relay_ok" $1
192938032Speterdnl temporary failure: call check sender (relay)
193038032SpeterR$* $| T $+		$: T $2 $| $>"Relay_ok" $1
193164562Sgshapirodnl temporary failure? return that
193238032SpeterR$* $| $#TEMP $+	$#error $2
193338032Speterdnl error or ok (stop)
193438032SpeterR$* $| $#$*		$#$2
193538032SpeterR$* $| RELAY		$@ RELAY
193638032Speterdnl something else: return previous temp failure
193790792SgshapiroR T $+ $| $*		$#error $1
193890792Sgshapiro# anything else is bogus
193990792SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
194038032Speterdivert(0)
194198121Sgshapiro
194238032Speter######################################################################
194338032Speter### Rcpt_ok: is the recipient ok?
194438032Speterdnl input: recipient address (RCPT TO)
194564562Sgshapirodnl output: see explanation at call
194690792Sgshapiro######################################################################
194790792SgshapiroSRcpt_ok
194890792Sgshapiroifdef(`_LOOSE_RELAY_CHECK_',`dnl
194990792SgshapiroR$*			$: $>CanonAddr $1
195090792SgshapiroR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
195190792Sgshapiro`R$*			$: $>ParseRecipient $1		strip relayable hosts')
195290792Sgshapiro
195390792Sgshapiroifdef(`_BESTMX_IS_LOCAL_',`dnl
195464562Sgshapiroifelse(_BESTMX_IS_LOCAL_, `', `dnl
195590792Sgshapiro# unlimited bestmx
195690792SgshapiroR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
195790792Sgshapiro`dnl
1958110560Sgshapiro# limit bestmx to $=B
195964562SgshapiroR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
196090792SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
196164562SgshapiroR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
1962120256SgshapiroR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
1963120256Sgshapiro
196464562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl
1965120256Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
196664562Sgshapiro# blacklist local users or any host from receiving mail
196764562SgshapiroR$*			$: <?> $1
196890792Sgshapirodnl user is now tagged with @ to be consistent with check_mail
196964562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
197064562SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
197164562SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
197290792SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
197390792Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
197490792Sgshapirodnl will only return user<@domain when "reversing" the args
197590792SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
197690792SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
197790792SgshapiroR<?> <$*>		$: @ $1		mark address as no match
197890792Sgshapirodnl we may have to filter here because otherwise some RHSs
197990792Sgshapirodnl would be interpreted as generic error messages...
198090792Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
198190792Sgshapirodnl that would make a lot of things easier.
198290792SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
198390792Sgshapiroifdef(`_ACCESS_SKIP_', `dnl
198490792SgshapiroR<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
198590792Sgshapiroifdef(`_DELAY_COMPAT_8_10_',`dnl
198690792Sgshapirodnl compatility with 8.11/8.10:
198790792Sgshapirodnl we have to filter these because otherwise they would be interpreted
198890792Sgshapirodnl as generic error message...
198990792Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
199090792Sgshapirodnl that would make a lot of things easier.
199190792Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
199290792SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
199390792SgshapiroR<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
199490792SgshapiroR<DISCARD> $*		$#discard $: discard
199590792Sgshapiroifdef(`_FFR_QUARANTINE',
199690792Sgshapiro`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
199790792Sgshapirodnl error tag
199890792SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
199990792SgshapiroR<ERROR:$+> $*		$#error $: $1
200090792Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
200190792Sgshapirodnl generic error from access map
200290792SgshapiroR<$+> $*		$#error $: $1		error from access db
200390792SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
200490792Sgshapiro
200590792Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
200690792Sgshapiro# authenticated via TLS?
200790792SgshapiroR$*			$: $1 $| $>RelayTLS	client authenticated?
200890792SgshapiroR$* $| $# $+		$# $2			error/ok?
200938032SpeterR$* $| $*		$: $1			no
201042575Speter
201138032SpeterR$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
201238032Speterdnl workspace: localpart<@domain> $| result of Local_Relay_Auth
201338032SpeterR$* $| $# $*		$# $2
201442575Speterdnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
201542575SpeterR$* $| NO		$: $1
201642575SpeterR$* $| $*		$: $1 $| $&{auth_type}
201742575Speterdnl workspace: localpart<@domain> [ $| ${auth_type} ]
201842575Speterdnl empty ${auth_type}?
201942575SpeterR$* $|			$: $1
202043730Speterdnl mechanism ${auth_type} accepted?
202190792Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
202242575SpeterR$* $| $={TrustAuthMech}	$# RELAY
202342575Speterdnl remove ${auth_type}
202442575SpeterR$* $| $*		$: $1
202538032Speterdnl workspace: localpart<@domain> | localpart
202664562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
202738032Speter`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
202838032SpeterR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
202964562Sgshapiro# anything terminating locally is ok
203064562Sgshapiroifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
203190792SgshapiroR$+ < @ $* $=m >	$@ RELAY', `dnl')
203290792SgshapiroR$+ < @ $=w >		$@ RELAY
203364562Sgshapiroifdef(`_RELAY_HOSTS_ONLY_',
203464562Sgshapiro`R$+ < @ $=R >		$@ RELAY
203564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
203690792SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
203764562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
203864562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
203990792Sgshapiro`R$+ < @ $* $=R >	$@ RELAY
204090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
204190792SgshapiroR$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')')
204290792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
204364562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
204490792SgshapiroR<RELAY> $*		$@ RELAY
204590792Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
204690792SgshapiroR<$*> <$*>		$: $2',`dnl')
204790792Sgshapiro
204864562Sgshapiro
204964562Sgshapiroifdef(`_RELAY_MX_SERVED_', `dnl
205064562Sgshapiro# allow relaying for hosts which we MX serve
205164562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
205264562Sgshapirodnl this must not necessarily happen if the client is checked first...
205364562SgshapiroR< : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
205490792SgshapiroR<$* : $=w . : $*> $*	$@ RELAY
205564562SgshapiroR< : $* : > $*		$: $2',
2056132943Sgshapiro`dnl')
205764562Sgshapiro
205864562Sgshapiro# check for local user (i.e. unqualified address)
205964562SgshapiroR$*			$: <?> $1
206090792SgshapiroR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
206164562Sgshapiro# local user is ok
206264562Sgshapirodnl is it really? the standard requires user@domain, not just user
206364562Sgshapirodnl but we should accept it anyway (maybe making it an option:
206438032Speterdnl RequireFQDN ?)
206590792Sgshapirodnl postmaster must be accepted without domain (DRUMS)
206690792Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
206790792SgshapiroR<?> postmaster		$@ OK
206890792Sgshapiro# require qualified recipient?
206990792Sgshapirodnl prepend daemon_flags
207064562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
207190792Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
207290792Sgshapirodnl do not allow these at all or only from local systems?
207390792Sgshapirodnl r flag? add client_name
207490792SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
207590792Sgshapirodnl no r flag: relay to local user (only local part)
207690792Sgshapiro# no qualified recipient required
207790792SgshapiroR$* $| <?> $+		$@ RELAY
207864562Sgshapirodnl client_name is empty
207964562SgshapiroR<?> <?> $+		$@ RELAY
208064562Sgshapirodnl client_name is local
208164562SgshapiroR<? $=w> <?> $+		$@ RELAY
208290792Sgshapirodnl client_name is not local
208390792SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
208464562Sgshapirodnl no qualified recipient required
208571345SgshapiroR<?> $+			$@ RELAY')
208664562Sgshapirodnl it is a remote user: remove mark and then check client
208771345SgshapiroR<$+> $*		$: $2
208871345Sgshapirodnl currently the recipient address is not used below
208938032Speter
209038032Speter######################################################################
209190792Sgshapiro### Relay_ok: is the relay/sender ok?
209290792Sgshapirodnl input: ignored
209338032Speterdnl output: see explanation at call
209490792Sgshapiro######################################################################
209564562SgshapiroSRelay_ok
209664562Sgshapiro# anything originating locally is ok
209764562Sgshapiro# check IP address
209864562SgshapiroR$*			$: $&{client_addr}
209990792SgshapiroR$@			$@ RELAY		originated locally
210064562SgshapiroR0			$@ RELAY		originated locally
2101132943SgshapiroR$=R $*			$@ RELAY		relayable IP address
2102132943Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
2103132943SgshapiroR$*			$: $>A <$1> <?> <+ Connect> <$1>
2104132943SgshapiroR<RELAY> $* 		$@ RELAY		relayable IP address
2105132943SgshapiroR<REJECT> $* 		$@ REJECT		rejected IP address
210664562Sgshapiroifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
210764562SgshapiroR<$*> <$*>		$: $2', `dnl')
210890792SgshapiroR$*			$: [ $1 ]		put brackets around it...
210990792SgshapiroR$=w			$@ RELAY		... and see if it is local
211038032Speter
211138032Speterifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
211264562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
211338032Speterifdef(`_RELAY_MAIL_FROM_', `dnl
211438032Speterdnl input: {client_addr} or something "broken"
211564562Sgshapirodnl just throw the input away; we do not need it.
211664562Sgshapiro# check whether FROM is allowed to use system as relay
2117132943SgshapiroR$*			$: <?> $>CanonAddr $&f
211890792SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
211942575Speterifdef(`_RELAY_LOCAL_FROM_', `dnl
212038032Speter# check whether local FROM is ok
212138032SpeterR<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
212238032Speterifdef(`_RELAY_DB_FROM_', `dnl
212338032SpeterR<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <>
212442575SpeterR<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
212538032Speterifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
212664562Sgshapiro', `dnl
212764562Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_',
212864562Sgshapiro`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
212964562Sgshapiro')',
213064562Sgshapiro`dnl')
213190792Sgshapirodnl')', `dnl')
213264562Sgshapirodnl notice: the rulesets above do not leave a unique workspace behind.
213364562Sgshapirodnl it does not matter in this case because the following rule ignores
213464562Sgshapirodnl the input. otherwise these rules must "clean up" the workspace.
213564562Sgshapiro
213664562Sgshapiro# check client name: first: did it resolve?
213764562Sgshapirodnl input: ignored
213864562SgshapiroR$*			$: < $&{client_resolve} >
213964562SgshapiroR<TEMP>			$#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
214064562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
214190792SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
214264562Sgshapirodnl ${client_resolve} should be OK, so go ahead
214390792SgshapiroR$*			$: <@> $&{client_name}
214464562Sgshapirodnl should not be necessary since it has been done for client_addr already
214590792SgshapiroR<@>			$@ RELAY
214664562Sgshapirodnl workspace: <@> ${client_name} (not empty)
214764562Sgshapiro# pass to name server to make hostname canonical
214864562SgshapiroR<@> $* $=P 		$:<?>  $1 $2
214990792SgshapiroR<@> $+			$:<?>  $[ $1 $]
215064562Sgshapirodnl workspace: <?> ${client_name} (canonified)
215138032SpeterR$* .			$1			strip trailing dots
215264562Sgshapiroifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
215338032SpeterR<?> $* $=m		$@ RELAY', `dnl')
215490792SgshapiroR<?> $=w		$@ RELAY
215590792Sgshapiroifdef(`_RELAY_HOSTS_ONLY_',
215690792Sgshapiro`R<?> $=R		$@ RELAY
215790792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
215890792SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
215990792SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
216038032Speter`R<?> $* $=R			$@ RELAY
216164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
216264562SgshapiroR<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
216390792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
216490792SgshapiroR<RELAY> $*		$@ RELAY
2165110560Sgshapiroifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2166110560SgshapiroR<$*> <$*>		$: $2',`dnl')
216790792Sgshapirodnl end of _PROMISCUOUS_RELAY_
216864562Sgshapirodivert(0)
216990792Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
217090792Sgshapiro# turn a canonical address in the form user<@domain>
2171102528Sgshapiro# qualify unqual. addresses with $j
2172102528Sgshapirodnl it might have been only user (without <@domain>)
2173102528SgshapiroSFullAddr
2174102528SgshapiroR$* <@ $+ . >		$1 <@ $2 >
2175102528SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
2176102528SgshapiroR$+			$@ $1 <@ $j >
217790792Sgshapiro
217864562Sgshapiro# call all necessary rulesets
217964562SgshapiroScheck_rcpt
218090792Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
218164562Sgshapirodnl which is the correct DSN code?
218264562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
218364562SgshapiroR$+			$: $1 $| $>checkrcpt $1
218464562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
218564562SgshapiroR$+ $| $#$*		$#$2
218664562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
218764562Sgshapiroifdef(`_SPAM_FH_',
218864562Sgshapiro`dnl lookup user@ and user@address
218990792Sgshapiroifdef(`_ACCESS_TABLE_', `',
219064562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
219164562Sgshapiro')')dnl
219290792Sgshapirodnl one of the next two rules is supposed to match
219364562Sgshapirodnl this code has been copied from BLACKLIST... etc
219494334Sgshapirodnl and simplified by omitting some < >.
219590792SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
219690792SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
219790792Sgshapirodnl R<?>		$@ something_is_very_wrong_here
219890792Sgshapiro# lookup the addresses only with Spam tag
219990792SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
220064562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
220164562Sgshapirodnl', `dnl')
220264562Sgshapiroifdef(`_SPAM_FRIEND_',
220390792Sgshapiro`# is the recipient a spam friend?
220490792Sgshapiroifdef(`_SPAM_HATER_',
220590792Sgshapiro	`errprint(`*** ERROR: define either SpamHater or SpamFriend
220664562Sgshapiro')', `dnl')
220764562SgshapiroR<FRIEND> $+		$@ SPAMFRIEND
220864562SgshapiroR<$*> $+		$: $2',
220964562Sgshapiro`dnl')
2210132943Sgshapiroifdef(`_SPAM_HATER_',
221164562Sgshapiro`# is the recipient no spam hater?
221264562SgshapiroR<HATER> $+		$: $1			spam hater: continue checks
221364562SgshapiroR<$*> $+		$@ NOSPAMHATER		everyone else: stop
221490792Sgshapirodnl',`dnl')
221590792Sgshapirodnl run further checks: check_mail
2216110560Sgshapirodnl should we "clean up" $&f?
2217110560Sgshapiroifdef(`_FFR_MAIL_MACRO',
2218110560Sgshapiro`R$*			$: $1 $| $>checkmail $&{mail_from}',
2219110560Sgshapiro`R$*			$: $1 $| $>checkmail <$&f>')
2220110560Sgshapirodnl recipient (canonical format) $| result of checkmail
222190792SgshapiroR$* $| $#$*		$#$2
222238032Speterdnl run further checks: check_relay
222390792SgshapiroR$* $| $*		$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
222490792SgshapiroR$* $| $#$*		$#$2
222590792SgshapiroR$* $| $*		$: $1
222664562Sgshapiro', `dnl')
222738032Speter
222890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
222990792Sgshapiro######################################################################
223038032Speter###  F: LookUpFull -- search for an entry in access database
223190792Sgshapiro###
223264562Sgshapiro###	lookup of full key (which should be an address) and
223364562Sgshapiro###	variations if +detail exists: +* and without +detail
223464562Sgshapiro###
223590792Sgshapiro###	Parameters:
223664562Sgshapiro###		<$1> -- key
223790792Sgshapiro###		<$2> -- default (what to return if not found in db)
223864562Sgshapirodnl			must not be empty
223990792Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
224090792Sgshapiro###			! does lookup only with tag
224138032Speter###			+ does lookup with and without tag
224290792Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
224364562Sgshapirodnl returns:		<default> <passthru>
224464562Sgshapirodnl 			<result> <passthru>
224564562Sgshapiro######################################################################
224664562Sgshapiro
224764562SgshapiroSF
224864562Sgshapirodnl workspace: <key> <def> <o tag> <thru>
224964562Sgshapirodnl full lookup
225064562Sgshapirodnl    2    3  4    5
225164562SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
225238032Speterdnl no match, try without tag
2253120256Sgshapirodnl   1    2      3    4
2254110560SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
2255110560Sgshapirodnl no match, +detail: try +*
2256110560Sgshapirodnl   1    2    3    4    5  6    7
2257110560SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
2258110560Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
2259110560Sgshapirodnl no match, +detail: try +* without tag
2260120256Sgshapirodnl   1    2    3    4      5    6
2261110560SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
2262110560Sgshapiro			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
2263120256Sgshapirodnl no match, +detail: try without +detail
2264110560Sgshapirodnl   1    2    3    4    5  6    7
2265110560SgshapiroR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
2266110560Sgshapiro			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
2267110560Sgshapirodnl no match, +detail: try without +detail and without tag
2268110560Sgshapirodnl   1    2    3    4      5    6
2269110560SgshapiroR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
2270120256Sgshapiro			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
2271110560Sgshapirodnl no match, return <default> <passthru>
2272110560Sgshapirodnl   1    2    3  4    5
227364562SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
227464562Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
227564562Sgshapirodnl            2    3  4    5
227664562SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
227764562Sgshapirodnl match, return <match> <passthru>
2278110560Sgshapirodnl    2    3  4    5
227964562SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
228064562Sgshapiro
2281110560Sgshapiro######################################################################
2282110560Sgshapiro###  E: LookUpExact -- search for an entry in access database
2283110560Sgshapiro###
2284110560Sgshapiro###	Parameters:
2285120256Sgshapiro###		<$1> -- key
228664562Sgshapiro###		<$2> -- default (what to return if not found in db)
228764562Sgshapirodnl			must not be empty
228864562Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
228964562Sgshapiro###			! does lookup only with tag
229064562Sgshapiro###			+ does lookup with and without tag
229164562Sgshapiro###		<$4> -- passthru (additional data passed unchanged through)
229264562Sgshapirodnl returns:		<default> <passthru>
229364562Sgshapirodnl 			<result> <passthru>
229464562Sgshapiro######################################################################
229590792Sgshapiro
229690792SgshapiroSE
229764562Sgshapirodnl    2    3  4    5
229890792SgshapiroR<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
229990792Sgshapirodnl no match, try without tag
230064562Sgshapirodnl   1    2      3    4
230164562SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
230264562Sgshapirodnl no match, return default passthru
230364562Sgshapirodnl   1    2    3  4    5
230464562SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
2305110560Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
230664562Sgshapirodnl            2    3  4    5
2307120256SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
230864562Sgshapirodnl match, return <match> <passthru>
230964562Sgshapirodnl    2    3  4    5
231064562SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
231164562Sgshapiro
231290792Sgshapiro######################################################################
2313120256Sgshapiro###  U: LookUpUser -- search for an entry in access database
231464562Sgshapiro###
231564562Sgshapiro###	lookup of key (which should be a local part) and
231664562Sgshapiro###	variations if +detail exists: +* and without +detail
231790792Sgshapiro###
231890792Sgshapiro###	Parameters:
231990792Sgshapiro###		<$1> -- key (user@)
232094334Sgshapiro###		<$2> -- default (what to return if not found in db)
232164562Sgshapirodnl			must not be empty
232264562Sgshapiro###		<$3> -- mark (must be <(!|+) single-token>)
232394334Sgshapiro###			! does lookup only with tag
232464562Sgshapiro###			+ does lookup with and without tag
232538032Speter###		<$4> -- passthru (additional data passed unchanged through)
232638032Speterdnl returns:		<default> <passthru>
232790792Sgshapirodnl 			<result> <passthru>
232890792Sgshapiro######################################################################
232964562Sgshapiro
233090792SgshapiroSU
233190792Sgshapirodnl user lookups are always with trailing @
233290792Sgshapirodnl    2    3  4    5
233390792SgshapiroR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
233490792Sgshapirodnl no match, try without tag
233590792Sgshapirodnl   1    2      3    4
233690792SgshapiroR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
233790792Sgshapirodnl do not remove the @ from the lookup:
233890792Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
233990792Sgshapirodnl no match, +detail: try +*
234090792Sgshapirodnl   1    2      3    4  5    6
234190792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
234290792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
234390792Sgshapirodnl no match, +detail: try +* without tag
234490792Sgshapirodnl   1    2      3      4    5
234590792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
234690792Sgshapiro			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
234790792Sgshapirodnl no match, +detail: try without +detail
234890792Sgshapirodnl   1    2      3    4  5    6
234990792SgshapiroR<?> <$+ + $* @> <$*> <$- $-> <$*>
235090792Sgshapiro			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
235190792Sgshapirodnl no match, +detail: try without +detail and without tag
235290792Sgshapirodnl   1    2      3      4    5
235390792SgshapiroR<?> <$+ + $* @> <$*> <+ $-> <$*>
235490792Sgshapiro			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
235590792Sgshapirodnl no match, return <default> <passthru>
235690792Sgshapirodnl   1    2    3  4    5
235790792SgshapiroR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
235890792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
235990792Sgshapirodnl            2    3  4    5
236090792SgshapiroR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
236190792Sgshapirodnl match, return <match> <passthru>
236290792Sgshapirodnl    2    3  4    5
236390792SgshapiroR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
236490792Sgshapiro
236590792Sgshapiro######################################################################
236690792Sgshapiro###  SearchList: search a list of items in the access map
236790792Sgshapiro###	Parameters:
236890792Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
236990792Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
237090792Sgshapirodnl	avoid errorneous matches (with error messages?)
237190792Sgshapirodnl	if we can make sure that tag is always a single token
237290792Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
237390792Sgshapirodnl	to avoid errorneous matchs (first rule: D: if there
237490792Sgshapirodnl	is that mark somewhere in the list, it will be taken).
237590792Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
237690792Sgshapirodnl	the tag only, e.g.:
237790792Sgshapiro###	where "exact" is either "+" or "!":
237890792Sgshapiro###	<+ TAG>	lookup with and w/o tag
237990792Sgshapiro###	<! TAG>	lookup with tag
238090792Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
238190792Sgshapirodnl		a blank between them and the tag.
238290792Sgshapiro###	possible values for "mark" are:
238390792Sgshapiro###		D: recursive host lookup (LookUpDomain)
238490792Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
238590792Sgshapiro###		E: exact lookup, no modifications
238690792Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
238790792Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
238890792Sgshapiro###	return: <RHS of lookup> or <?> (not found)
238990792Sgshapiro######################################################################
239090792Sgshapiro
239190792Sgshapiro# class with valid marks for SearchList
239290792Sgshapirodnl if A is activated: add it
239390792SgshapiroC{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
239490792SgshapiroSSearchList
239590792Sgshapiro# just call the ruleset with the name of the tag... nice trick...
239690792Sgshapirodnl       2       3    4
239790792SgshapiroR<$+> $| <$={src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
239890792Sgshapirodnl workspace: <o tag> $| <rest> $| <result of lookup> <>
239990792Sgshapirodnl no match and nothing left: return
240090792SgshapiroR<$+> $| <> $| <?> <>		$@ <?>
240190792Sgshapirodnl no match but something left: continue
240290792SgshapiroR<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
240390792Sgshapirodnl match: return
240490792SgshapiroR<$+> $| <$*> $| <$+> <>	$@ <$3>
240590792Sgshapirodnl return result from recursive invocation
240690792SgshapiroR<$+> $| <$+>			$@ <$2>
240790792Sgshapirodnl endif _ACCESS_TABLE_
240890792Sgshapirodivert(0)
240990792Sgshapiro
241090792Sgshapiro######################################################################
241190792Sgshapiro###  trust_auth: is user trusted to authenticate as someone else?
241290792Sgshapiro###
241390792Sgshapiro###	Parameters:
241490792Sgshapiro###		$1: AUTH= parameter from MAIL command
241590792Sgshapiro######################################################################
241690792Sgshapiro
241790792Sgshapirodnl empty ruleset definition so it can be called
241890792SgshapiroSLocal_trust_auth
241990792SgshapiroStrust_auth
242090792SgshapiroR$*			$: $&{auth_type} $| $1
242190792Sgshapiro# required by RFC 2554 section 4.
242290792SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
242390792Sgshapirodnl seems to be useful...
242490792SgshapiroR$* $| $&{auth_authen}		$@ identical
242590792SgshapiroR$* $| <$&{auth_authen}>	$@ identical
242690792Sgshapirodnl call user supplied code
242790792SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $1
242890792SgshapiroR$* $| $#$*		$#$2
242990792Sgshapirodnl default: error
243090792SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
243190792Sgshapiro
243290792Sgshapiro######################################################################
243390792Sgshapiro###  Relay_Auth: allow relaying based on authentication?
243490792Sgshapiro###
243590792Sgshapiro###	Parameters:
243690792Sgshapiro###		$1: ${auth_type}
243790792Sgshapiro######################################################################
243890792SgshapiroSLocal_Relay_Auth
243990792Sgshapiro
244090792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
244190792Sgshapiro######################################################################
244290792Sgshapiro###  srv_features: which features to offer to a client?
244390792Sgshapiro###	(done in server)
244490792Sgshapiro######################################################################
244590792SgshapiroSsrv_features
244690792Sgshapiroifdef(`_LOCAL_SRV_FEATURES_', `dnl
244790792SgshapiroR$*			$: $1 $| $>"Local_srv_features" $1
244890792SgshapiroR$* $| $#$*		$#$2
244990792SgshapiroR$* $| $*		$: $1', `dnl')
245090792SgshapiroR$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
245190792SgshapiroR<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
245290792SgshapiroR<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
245390792SgshapiroR<?>$*		$@ OK
245490792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
245590792SgshapiroR<$* _ATMPF_>$*	$#temp', `dnl')
245690792SgshapiroR<$+>$*		$# $1
245790792Sgshapiro
245890792Sgshapiro######################################################################
245990792Sgshapiro###  try_tls: try to use STARTTLS?
246090792Sgshapiro###	(done in client)
246190792Sgshapiro######################################################################
246290792SgshapiroStry_tls
246390792Sgshapiroifdef(`_LOCAL_TRY_TLS_', `dnl
246490792SgshapiroR$*			$: $1 $| $>"Local_try_tls" $1
246590792SgshapiroR$* $| $#$*		$#$2
246664562SgshapiroR$* $| $*		$: $1', `dnl')
246764562SgshapiroR$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
246864562SgshapiroR<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
246964562SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
247064562SgshapiroR<?>$*		$@ OK
247164562Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
247264562SgshapiroR<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
247390792SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
247464562Sgshapiro  
247564562Sgshapiro######################################################################
247664562Sgshapiro###  tls_rcpt: is connection with server "good" enough?
247764562Sgshapiro###	(done in client, per recipient)
247864562Sgshapirodnl called from deliver() before RCPT command
247964562Sgshapiro###
248064562Sgshapiro###	Parameters:
248164562Sgshapiro###		$1: recipient
248264562Sgshapiro######################################################################
248390792SgshapiroStls_rcpt
248464562Sgshapiroifdef(`_LOCAL_TLS_RCPT_', `dnl
248564562SgshapiroR$*			$: $1 $| $>"Local_tls_rcpt" $1
248664562SgshapiroR$* $| $#$*		$#$2
248764562SgshapiroR$* $| $*		$: $1', `dnl')
248864562Sgshapirodnl store name of other side
248964562SgshapiroR$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
249038032Speterdnl canonify recipient address
249164562SgshapiroR$+			$: <?> $>CanonAddr $1
249264562Sgshapirodnl strip trailing dots
2493132943SgshapiroR<?> $+ < @ $+ . >	<?> $1 <@ $2 >
249464562Sgshapirodnl full address?
249590792SgshapiroR<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
249690792Sgshapirodnl only localpart?
2497132943SgshapiroR<?> $+			$: $1 $| <U:$1@> <E:>
249890792Sgshapirodnl look it up
249990792Sgshapirodnl also look up a default value via E:
250090792SgshapiroR$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
250190792Sgshapirodnl found nothing: stop here
250290792SgshapiroR$* $| <?>	$@ OK
250390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
250490792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
250564562Sgshapirodnl use the generic routine (for now)
250690792SgshapiroR$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
250790792Sgshapiro
250890792Sgshapiro######################################################################
250938032Speter###  tls_client: is connection with client "good" enough?
251090792Sgshapiro###	(done in server)
251190792Sgshapiro###
251290792Sgshapiro###	Parameters:
251390792Sgshapiro###		${verify} $| (MAIL|STARTTLS)
251490792Sgshapiro######################################################################
251590792Sgshapirodnl MAIL: called from check_mail
251690792Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
251790792SgshapiroStls_client
251890792Sgshapiroifdef(`_LOCAL_TLS_CLIENT_', `dnl
251964562SgshapiroR$*			$: $1 $| $>"Local_tls_client" $1
252064562SgshapiroR$* $| $#$*		$#$2
252164562SgshapiroR$* $| $*		$: $1', `dnl')
252264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
252364562Sgshapirodnl store name of other side
252464562SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
252564562Sgshapirodnl ignore second arg for now
252664562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
2527120256Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
252864562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
252964562SgshapiroR$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
253064562SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
253164562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
253290792SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
253390792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
253490792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
253590792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
253690792SgshapiroR$* $| $*	$@ $>"TLS_connection" $1')
253790792Sgshapiro
253890792Sgshapiro######################################################################
253964562Sgshapiro###  tls_server: is connection with server "good" enough?
254090792Sgshapiro###	(done in client)
254190792Sgshapiro###
254290792Sgshapiro###	Parameter:
254390792Sgshapiro###		${verify}
254490792Sgshapiro######################################################################
254590792Sgshapirodnl i.e. has the server been authenticated and is encryption active?
254690792Sgshapirodnl called from deliver() after STARTTLS command
254790792SgshapiroStls_server
254890792Sgshapiroifdef(`_LOCAL_TLS_SERVER_', `dnl
2549132943SgshapiroR$*			$: $1 $| $>"Local_tls_server" $1
255090792SgshapiroR$* $| $#$*		$#$2
255190792SgshapiroR$* $| $*		$: $1', `dnl')
255290792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
255364562Sgshapirodnl store name of other side
255490792SgshapiroR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
255590792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
2556132943SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
255764562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
255890792SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
255990792Sgshapiroifdef(`_ATMPF_', `dnl tempfail?
256090792SgshapiroR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
256190792SgshapiroR$*		$@ $>"TLS_connection" $1', `dnl
256264562SgshapiroR$*		$@ $>"TLS_connection" $1')
256390792Sgshapiro
256490792Sgshapiro######################################################################
256590792Sgshapiro###  TLS_connection: is TLS connection "good" enough?
256690792Sgshapiro###
2567132943Sgshapiro###	Parameters:
256890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
256990792Sgshapiro###		${verify} $| <Requirement> [<>]', `dnl
257090792Sgshapiro###		${verify}')
257164562Sgshapiro###		Requirement: RHS from access map, may be ? for none.
257290792Sgshapirodnl	syntax for Requirement:
257390792Sgshapirodnl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
2574132943Sgshapirodnl	extensions: could be a list of further requirements
2575132943Sgshapirodnl		for now: CN:string	{cn_subject} == string
257690792Sgshapiro######################################################################
257790792SgshapiroSTLS_connection
257890792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
257990792Sgshapirodnl deal with TLS handshake failures: abort
258090792SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
258190792Sgshapirodivert(-1)')
258290792Sgshapirodnl common ruleset for tls_{client|server}
258390792Sgshapirodnl input: ${verify} $| <ResultOfLookup> [<>]
258490792Sgshapirodnl remove optional <>
258590792SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
258690792Sgshapirodnl workspace: ${verify} $| <ResultOfLookup>
258790792Sgshapiro# create the appropriate error codes
258890792Sgshapirodnl permanent or temporary error?
2589132943SgshapiroR$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
259090792SgshapiroR$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
259190792Sgshapirodnl default case depends on TLS_PERM_ERR
259290792SgshapiroR$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
259390792Sgshapirodnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
259490792Sgshapiro# deal with TLS handshake failures: abort
259590792SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
259690792Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
259790792Sgshapirodnl use default error
259890792SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
259990792SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
260090792Sgshapirodnl separate optional requirements
260190792SgshapiroR$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
260290792SgshapiroR$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> <> $1
260390792Sgshapirodnl separate optional requirements
260490792SgshapiroR$* $| <$*> <$={tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
260590792Sgshapirodnl some other value in access map: accept
260690792Sgshapirodnl this also allows to override the default case (if used)
260790792SgshapiroR$* $| $*			$@ OK
260890792Sgshapiro# authentication required: give appropriate error
260964562Sgshapiro# other side did authenticate (via STARTTLS)
261090792Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
261190792Sgshapirodnl only verification required and it succeeded
261290792SgshapiroR<$*><VERIFY> <> OK		$@ OK
261390792Sgshapirodnl verification required and it succeeded but extensions are given
261490792Sgshapirodnl change it to <SMTP:ESC> <REQ:0>  <extensions>
261590792SgshapiroR<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
261690792Sgshapirodnl verification required + some level of encryption
261764562SgshapiroR<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
261864562Sgshapirodnl just some level of encryption required
261964562SgshapiroR<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
262090792Sgshapirodnl workspace:
262190792Sgshapirodnl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
262290792Sgshapirodnl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
262390792Sgshapirodnl verification required but ${verify} is not set (case 1.)
262464562SgshapiroR<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
262590792SgshapiroR<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
262690792SgshapiroR<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
262764562SgshapiroR<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
262864562SgshapiroR<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
262964562Sgshapirodnl some other value for ${verify}
263064562SgshapiroR<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
263190792Sgshapirodnl some level of encryption required: get the maximum level (case 2.)
263290792SgshapiroR<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
263364562Sgshapirodnl compare required bits with actual bits
263464562SgshapiroR<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
263590792SgshapiroR<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
263690792Sgshapirodnl strength requirements fulfilled
263790792Sgshapirodnl TLS Additional Requirements Separator
263890792Sgshapirodnl this should be something which does not appear in the extensions itself
263964562Sgshapirodnl @ could be part of a CN, DN, etc...
264090792Sgshapirodnl use < > ? those are encoded in CN, DN, ...
264190792Sgshapirodefine(`_TLS_ARS_', `++')dnl
264290792Sgshapirodnl workspace:
264390792Sgshapirodnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
264490792SgshapiroR<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
264590792Sgshapirodnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
264690792Sgshapirodnl continue: check  extensions
264764562SgshapiroR<$-:$+ _TLS_ARS_ >			$@ OK
264864562Sgshapirodnl split extensions into own list
264964562SgshapiroR<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
265090792SgshapiroR<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
265190792SgshapiroR<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
265290792Sgshapiro
265390792Sgshapiro######################################################################
265464562Sgshapiro###  TLS_req: check additional TLS requirements
265590792Sgshapiro###
265690792Sgshapiro###	Parameters: [<list> <of> <req>] $| <$-:$+>
265790792Sgshapiro###		$-: SMTP reply code
265890792Sgshapiro###		$+: Enhanced Status Code
265964562Sgshapirodnl  further requirements for this ruleset:
266064562Sgshapirodnl	name of "other side" is stored is {TLS_name} (client/server_name)
266190792Sgshapirodnl
266290792Sgshapirodnl	currently only CN[:common_name] is implemented
266390792Sgshapirodnl	right now this is only a logical AND
266490792Sgshapirodnl	i.e. all requirements must be true
266564562Sgshapirodnl	how about an OR? CN must be X or CN must be Y or ..
266690792Sgshapirodnl	use a macro to compute this as a trivial sequential
266790792Sgshapirodnl	operations (no precedences etc)?
266890792Sgshapiro######################################################################
266990792SgshapiroSTLS_req
267064562Sgshapirodnl no additional requirements: ok
267190792SgshapiroR $| $+		$@ OK
267290792Sgshapirodnl require CN: but no CN specified: use name of other side
267390792SgshapiroR<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
267490792Sgshapirodnl match, check rest
267590792SgshapiroR<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
267690792Sgshapirodnl CN does not match
267790792Sgshapirodnl  1   2      3  4
267890792SgshapiroR<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
267990792Sgshapirodnl cert subject
268090792SgshapiroR<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
268190792Sgshapirodnl CS does not match
268290792Sgshapirodnl  1   2      3  4
268390792SgshapiroR<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CERT Subject " $&{cert_subject} " does not match " $1
268464562Sgshapirodnl match, check rest
268590792SgshapiroR<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
268664562Sgshapirodnl CI does not match
268764562Sgshapirodnl  1   2      3  4
268890792SgshapiroR<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CERT Issuer " $&{cert_issuer} " does not match " $1
268990792Sgshapirodnl return from recursive call
269064562SgshapiroROK			$@ OK
2691132943Sgshapiro
2692132943Sgshapiro######################################################################
269364562Sgshapiro###  max: return the maximum of two values separated by :
2694132943Sgshapiro###
269590792Sgshapiro###	Parameters: [$-]:[$-]
269690792Sgshapiro######################################################################
269764562SgshapiroSmax
269864562SgshapiroR:		$: 0
269964562SgshapiroR:$-		$: $1
270064562SgshapiroR$-:		$: $1
270190792SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
270290792SgshapiroRTRUE:$-:$-	$: $2
270390792SgshapiroR$-:$-:$-	$: $2
2704132943Sgshapirodnl endif _ACCESS_TABLE_
270590792Sgshapirodivert(0)
2706132943Sgshapiro
270764562Sgshapiro######################################################################
270864562Sgshapiro###  RelayTLS: allow relaying based on TLS authentication
270964562Sgshapiro###
271064562Sgshapiro###	Parameters:
271164562Sgshapiro###		none
271290792Sgshapiro######################################################################
271364562SgshapiroSRelayTLS
271490792Sgshapiro# authenticated?
271590792Sgshapirodnl we do not allow relaying for anyone who can present a cert
271690792Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
271790792Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow
271864562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
271990792Sgshapirodnl but anyway).
272064562Sgshapirodnl so here is the trick: if the verification succeeded
272190792Sgshapirodnl we look up the cert issuer in the access map
272290792Sgshapirodnl (maybe after extracting a part with a regular expression)
272390792Sgshapirodnl if this returns RELAY we relay without further questions
272490792Sgshapirodnl if it returns SUBJECT we perform a similar check on the
272590792Sgshapirodnl cert subject.
272690792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
272790792SgshapiroR$*			$: <?> $&{verify}
272890792SgshapiroR<?> OK			$: OK		authenticated: continue
272990792SgshapiroR<?> $*			$@ NO		not authenticated
273090792Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
273164562SgshapiroR$*			$: $(CERTIssuer $&{cert_issuer} $)',
273290792Sgshapiro`R$*			$: $&{cert_issuer}')
273390792SgshapiroR$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
273490792Sgshapirodnl use $# to stop further checks (delay_check)
273564562SgshapiroRRELAY			$# RELAY
273690792Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
273790792SgshapiroRSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
273890792Sgshapiro`RSUBJECT		$: <@> $&{cert_subject}')
273990792SgshapiroR<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
274090792SgshapiroR<@> RELAY		$# RELAY
274190792SgshapiroR$*			$: NO', `dnl')
274290792Sgshapiro
274390792Sgshapiro######################################################################
274490792Sgshapiro###  authinfo: lookup authinfo in the access map
274590792Sgshapiro###
274690792Sgshapiro###	Parameters:
274790792Sgshapiro###		$1: {server_name}
274890792Sgshapiro###		$2: {server_addr}
274990792Sgshapirodnl	both are currently ignored
275090792Sgshapirodnl if it should be done via another map, we either need to restrict
275190792Sgshapirodnl functionality (it calls D and A) or copy those rulesets (or add another
275290792Sgshapirodnl parameter which I want to avoid, it's quite complex already)
275390792Sgshapiro######################################################################
275464562Sgshapirodnl omit this ruleset if neither is defined?
275590792Sgshapirodnl it causes DefaultAuthInfo to be ignored
275690792Sgshapirodnl (which may be considered a good thing).
275790792SgshapiroSauthinfo
275890792Sgshapiroifdef(`_AUTHINFO_TABLE_', `dnl
275990792SgshapiroR$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
276090792SgshapiroR<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
276190792SgshapiroR<?>		$: <$(authinfo AuthInfo: $: ? $)>
276290792SgshapiroR<?>		$@ no				no authinfo available
276390792SgshapiroR<$*>		$# $1
276490792Sgshapirodnl', `dnl
276590792Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
276690792SgshapiroR$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
276790792SgshapiroR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
276890792SgshapiroR$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
276990792SgshapiroR$* $| <?>$*	$@ no				no authinfo available
277090792SgshapiroR$* $| <$*> <>	$# $2
277190792Sgshapirodnl', `dnl')')
277290792Sgshapiro
277390792Sgshapiroundivert(9)dnl LOCAL_RULESETS
277490792Sgshapiro#
277590792Sgshapiro######################################################################
277690792Sgshapiro######################################################################
277790792Sgshapiro#####
277890792Sgshapiro`#####			MAIL FILTER DEFINITIONS'
277990792Sgshapiro#####
278090792Sgshapiro######################################################################
278190792Sgshapiro######################################################################
278290792Sgshapiro_MAIL_FILTERS_
278390792Sgshapiro#
278490792Sgshapiro######################################################################
2785110560Sgshapiro######################################################################
278690792Sgshapiro#####
278790792Sgshapiro`#####			MAILER DEFINITIONS'
278890792Sgshapiro#####
278990792Sgshapiro######################################################################
2790110560Sgshapiro######################################################################
279190792Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
279290792Sgshapiro
279390792Sgshapiro