proto.m4 revision 80785
138032Speterdivert(-1)
238032Speter#
364562Sgshapiro# Copyright (c) 1998-2000 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
1680785SgshapiroVERSIONID(`$Id: proto.m4,v 8.446.2.5.2.44 2001/07/31 22:25:49 gshapiro Exp $')
1738032Speter
1838032SpeterMAILER(local)dnl
1938032Speter
2064562Sgshapiro# level CF_LEVEL config file format
2164562SgshapiroV`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley')
2238032Speterdivert(-1)
2338032Speter
2438032Speter# do some sanity checking
2538032Speterifdef(`__OSTYPE__',,
2664562Sgshapiro	`errprint(`*** ERROR: No system type defined (use OSTYPE macro)
2764562Sgshapiro')')
2838032Speter
2938032Speter# pick our default mailers
3038032Speterifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')')
3138032Speterifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')')
3238032Speterifdef(`confRELAY_MAILER',,
3338032Speter	`define(`confRELAY_MAILER',
3438032Speter		`ifdef(`_MAILER_smtp_', `relay',
3538032Speter			`ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')')
3638032Speterifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')')
3738032Speterdefine(`_SMTP_', `confSMTP_MAILER')dnl		for readability only
3838032Speterdefine(`_LOCAL_', `confLOCAL_MAILER')dnl	for readability only
3938032Speterdefine(`_RELAY_', `confRELAY_MAILER')dnl	for readability only
4038032Speterdefine(`_UUCP_', `confUUCP_MAILER')dnl		for readability only
4138032Speter
4238032Speter# back compatibility with old config files
4338032Speterifdef(`confDEF_GROUP_ID',
4464562Sgshapiro`errprint(`*** confDEF_GROUP_ID is obsolete.
4564562Sgshapiro    Use confDEF_USER_ID with a colon in the value instead.
4664562Sgshapiro')')
4738032Speterifdef(`confREAD_TIMEOUT',
4864562Sgshapiro`errprint(`*** confREAD_TIMEOUT is obsolete.
4964562Sgshapiro    Use individual confTO_<timeout> parameters instead.
5064562Sgshapiro')')
5138032Speterifdef(`confMESSAGE_TIMEOUT',
5238032Speter	`define(`_ARG_', index(confMESSAGE_TIMEOUT, /))
5338032Speter	 ifelse(_ARG_, -1,
5438032Speter		`define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)',
5538032Speter		`define(`confTO_QUEUERETURN',
5638032Speter			substr(confMESSAGE_TIMEOUT, 0, _ARG_))
5738032Speter		 define(`confTO_QUEUEWARN',
5838032Speter			substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')')
5938032Speterifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,,
6064562Sgshapiro`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete.
6164562Sgshapiro    Use confMAX_MESSAGE_SIZE for the second part of the value.
6264562Sgshapiro')')')
6338032Speter
6464562Sgshapiro
6564562Sgshapiro# Sanity check on ldap_routing feature
6664562Sgshapiro# If the user doesn't specify a new map, they better have given as a
6764562Sgshapiro# default LDAP specification which has the LDAP base (and most likely the host)
6864562Sgshapiroifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(`
6964562SgshapiroWARNING: Using default FEATURE(ldap_routing) map definition(s)
7064562Sgshapirowithout setting confLDAP_DEFAULT_SPEC option.
7164562Sgshapiro')')')dnl
7264562Sgshapiro
7338032Speter# clean option definitions below....
7464562Sgshapirodefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl
7538032Speter
7664562Sgshapirodnl required to "rename" the check_* rulesets...
7764562Sgshapirodefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_'))
7864562Sgshapirodnl default relaying denied message
7964562Sgshapiroifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG', `"550 Relaying denied"')')
8077349Sgshapirodefine(`CODE553', `553')
8138032Speterdivert(0)dnl
8238032Speter
8364562Sgshapiro# override file safeties - setting this option compromises system security,
8464562Sgshapiro# addressing the actual file configuration problem is preferred
8564562Sgshapiro# need to set this before any file actions are encountered in the cf file
8664562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe')
8738032Speter
8864562Sgshapiro# default LDAP map specification
8964562Sgshapiro# need to set this now before any LDAP maps are defined
9064562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost')
9164562Sgshapiro
9238032Speter##################
9338032Speter#   local info   #
9438032Speter##################
9538032Speter
9638032SpeterCwlocalhost
9738032Speterifdef(`USE_CW_FILE',
9838032Speter`# file containing names of hosts for which we receive email
9938032SpeterFw`'confCW_FILE',
10038032Speter	`dnl')
10138032Speter
10238032Speter# my official domain name
10338032Speter# ... `define' this only if sendmail cannot automatically determine your domain
10438032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM')
10538032Speter
10638032SpeterCP.
10738032Speter
10838032Speterifdef(`UUCP_RELAY',
10938032Speter`# UUCP relay host
11038032SpeterDY`'UUCP_RELAY
11138032SpeterCPUUCP
11238032Speter
11338032Speter')dnl
11438032Speterifdef(`BITNET_RELAY',
11538032Speter`#  BITNET relay host
11638032SpeterDB`'BITNET_RELAY
11738032SpeterCPBITNET
11838032Speter
11938032Speter')dnl
12038032Speterifdef(`DECNET_RELAY',
12138032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl
12238032Speter# DECnet relay host
12338032SpeterDC`'DECNET_RELAY
12438032SpeterCPDECNET
12538032Speter
12638032Speter')dnl
12738032Speterifdef(`FAX_RELAY',
12838032Speter`# FAX relay host
12938032SpeterDF`'FAX_RELAY
13038032SpeterCPFAX
13138032Speter
13238032Speter')dnl
13338032Speter# "Smart" relay host (may be null)
13438032SpeterDS`'ifdef(`SMART_HOST', SMART_HOST)
13538032Speter
13638032Speterifdef(`LUSER_RELAY', `dnl
13738032Speter# place to which unknown users should be forwarded
13838032SpeterKuser user -m -a<>
13938032SpeterDL`'LUSER_RELAY',
14038032Speter`dnl')
14138032Speter
14238032Speter# operators that cannot be in local usernames (i.e., network indicators)
14338032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!')
14438032Speter
14538032Speter# a class with just dot (for identifying canonical names)
14638032SpeterC..
14738032Speter
14838032Speter# a class with just a left bracket (for identifying domain literals)
14938032SpeterC[[
15038032Speter
15164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
15264562Sgshapiro# access_db acceptance class
15364562SgshapiroC{Accept}OK RELAY
15464562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
15564562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl
15664562Sgshapiro# possible access_db RHS for spam friends/haters
15764562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')',
15838032Speter`dnl')
15938032Speter
16038032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
16138032Speter# Resolve map (to check if a host exists in check_mail)
16238032SpeterKresolve host -a<OK> -T<TEMP>')
16338032Speter
16480785Sgshapiroifdef(`_NEED_MACRO_MAP_', `dnl
16580785Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map
16680785Sgshapirodefine(`_MACRO_MAP_', `1')dnl
16780785SgshapiroKmacro macro')', `dnl')
16866494Sgshapiro
16938032Speterifdef(`confCR_FILE', `dnl
17066494Sgshapiro# Hosts for which relaying is permitted ($=R)
17138032SpeterFR`'confCR_FILE',
17238032Speter`dnl')
17338032Speter
17464562Sgshapirodefine(`TLS_SRV_TAG', `TLS_Srv')dnl
17564562Sgshapirodefine(`TLS_CLT_TAG', `TLS_Clt')dnl
17664562Sgshapirodefine(`TLS_TRY_TAG', `Try_TLS')dnl
17764562Sgshapirodefine(`TLS_OFF_TAG', `Offer_TLS')dnl
17864562Sgshapirodnl this may be useful in other contexts too
17964562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map
18064562Sgshapirodefine(`_ARITH_MAP_', `1')dnl
18164562SgshapiroKarith arith')
18264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
18364562Sgshapiro# possible values for tls_connect in access map
18464562SgshapiroC{tls}VERIFY ENCR', `dnl')
18564562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
18664562Sgshapiro# extract relevant part from cert issuer
18764562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
18864562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
18964562Sgshapiro# extract relevant part from cert subject
19064562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
19164562Sgshapiro
19238032Speter# who I send unqualified names to (null means deliver locally)
19338032SpeterDR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY)
19438032Speter
19538032Speter# who gets all local email traffic ($R has precedence for unqualified names)
19638032SpeterDH`'ifdef(`MAIL_HUB', MAIL_HUB)
19738032Speter
19838032Speter# dequoting map
19938032SpeterKdequote dequote
20038032Speter
20138032Speterdivert(0)dnl	# end of nullclient diversion
20238032Speter# class E: names that should be exposed as from this host, even if we masquerade
20364562Sgshapiro# class L: names that should be delivered locally, even if we have a relay
20438032Speter# class M: domains that should be converted to $M
20564562Sgshapiro# class N: domains that should not be converted to $M
20638032Speter#CL root
20738032Speterundivert(5)dnl
20864562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
20938032Speter
21038032Speter# who I masquerade as (null for no masquerading) (see also $=M)
21138032SpeterDM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME)
21238032Speter
21338032Speter# my name for error messages
21438032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
21538032Speter
21664562Sgshapiroundivert(6)dnl LOCAL_CONFIG
21738032Speterinclude(_CF_DIR_`m4/version.m4')
21838032Speter
21938032Speter###############
22038032Speter#   Options   #
22138032Speter###############
22238032Speter
22338032Speter# strip message body to 7 bits on input?
22464562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
22538032Speter
22638032Speter# 8-bit data handling
22777349Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8')
22838032Speter
22938032Speter# wait for alias file rebuild (default units: minutes)
23064562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m')
23138032Speter
23238032Speter# location of alias file
23364562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
23464562Sgshapiro
23538032Speter# minimum number of free blocks on filesystem
23664562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
23738032Speter
23838032Speter# maximum message size
23964562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000')
24038032Speter
24138032Speter# substitution for space (blank) characters
24264562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_')
24338032Speter
24438032Speter# avoid connecting to "expensive" mailers on initial submission?
24564562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
24638032Speter
24738032Speter# checkpoint queue runs after every N successful deliveries
24864562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
24938032Speter
25038032Speter# default delivery mode
25164562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
25238032Speter
25338032Speter# automatically rebuild the alias database?
25464562Sgshapiro# NOTE: There is a potential for a denial of service attack if this is set.
25564562Sgshapiro#       This option is deprecated and will be removed from a future version.
25664562Sgshapiro_OPTION(AutoRebuildAliases, `confAUTO_REBUILD', `False')
25738032Speter
25838032Speter# error message header/file
25964562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
26038032Speter
26138032Speter# error mode
26264562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print')
26338032Speter
26438032Speter# save Unix-style "From_" lines at top of header?
26564562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
26638032Speter
26738032Speter# temporary file mode
26864562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
26938032Speter
27038032Speter# match recipients against GECOS field?
27164562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
27238032Speter
27338032Speter# maximum hop count
27464562Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `17')
27538032Speter
27638032Speter# location of help file
27764562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
27838032Speter
27938032Speter# ignore dots as terminators in incoming messages?
28064562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
28138032Speter
28238032Speter# name resolver options
28364562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
28438032Speter
28538032Speter# deliver MIME-encapsulated error messages?
28664562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
28738032Speter
28838032Speter# Forward file search path
28964562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
29038032Speter
29138032Speter# open connection cache size
29264562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
29338032Speter
29438032Speter# open connection cache timeout
29564562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
29638032Speter
29738032Speter# persistent host status directory
29864562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
29938032Speter
30038032Speter# single thread deliveries (requires HostStatusDirectory)?
30164562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
30238032Speter
30338032Speter# use Errors-To: header?
30464562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
30538032Speter
30638032Speter# log level
30764562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10')
30838032Speter
30938032Speter# send to me too, even in an alias expansion?
31064562Sgshapiro_OPTION(MeToo, `confME_TOO', `True')
31138032Speter
31238032Speter# verify RHS in newaliases?
31364562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
31438032Speter
31538032Speter# default messages to old style headers if no special punctuation?
31664562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
31738032Speter
31838032Speter# SMTP daemon options
31964562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
32064562Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.  See cf/README for more information.
32164562Sgshapiro)'dnl
32264562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
32366494Sgshapiroifelse(defn(`_DPO_'), `',
32466494Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-IPv4, Family=inet
32566494SgshapiroO DaemonPortOptions=Name=MTA-IPv6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
32664562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
32738032Speter
32864562Sgshapiro# SMTP client options
32964562Sgshapiro_OPTION(ClientPortOptions, `confCLIENT_OPTIONS', `Address=0.0.0.0')
33064562Sgshapiro
33138032Speter# privacy flags
33264562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
33338032Speter
33438032Speter# who (if anyone) should get extra copies of error messages
33564562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
33638032Speter
33738032Speter# slope of queue-only function
33864562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
33938032Speter
34038032Speter# queue directory
34164562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
34238032Speter
34338032Speter# timeouts (many of these)
34464562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
34564562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
34664562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
34764562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m')
34864562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m')
34964562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
35064562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
35164562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
35264562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
35364562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m')
35464562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m')
35564562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m')
35664562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h')
35764562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s')
35864562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
35964562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m')
36064562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
36164562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
36264562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
36364562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
36464562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
36564562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
36664562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
36764562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
36864562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
36964562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
37064562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
37164562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
37264562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
37364562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
37464562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
37538032Speter
37638032Speter# should we not prune routes in route-addr syntax addresses?
37764562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
37838032Speter
37938032Speter# queue up everything before forking?
38064562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
38138032Speter
38238032Speter# status file
38364562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
38438032Speter
38538032Speter# time zone handling:
38638032Speter#  if undefined, use system default
38738032Speter#  if defined but null, use TZ envariable passed in
38838032Speter#  if defined and non-null, use that info
38938032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
39038032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
39138032Speter	`O TimeZoneSpec=confTIME_ZONE')
39238032Speter
39338032Speter# default UID (can be username or userid:groupid)
39464562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
39538032Speter
39638032Speter# list of locations of user database file (null means no lookup)
39764562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
39838032Speter
39938032Speter# fallback MX host
40064562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
40138032Speter
40238032Speter# if we are the best MX host for a site, try it directly instead of config err
40364562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
40438032Speter
40538032Speter# load average at which we just queue messages
40664562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8')
40738032Speter
40838032Speter# load average at which we refuse connections
40964562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
41038032Speter
41138032Speter# maximum number of children we allow at one time
41264562Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12')
41338032Speter
41438032Speter# maximum number of new connections per second
41571345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
41638032Speter
41738032Speter# work recipient factor
41864562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
41938032Speter
42038032Speter# deliver each queued job in a separate process?
42164562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
42238032Speter
42338032Speter# work class factor
42464562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
42538032Speter
42638032Speter# work time factor
42764562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
42838032Speter
42938032Speter# shall we sort the queue by hostname first?
43064562Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
43138032Speter
43238032Speter# minimum time in queue before retry
43364562Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
43438032Speter
43538032Speter# default character set
43664562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
43738032Speter
43838032Speter# service switch file (ignored on Solaris, Ultrix, OSF/1, others)
43964562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
44038032Speter
44138032Speter# hosts file (normally /etc/hosts)
44264562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
44338032Speter
44438032Speter# dialup line delay on connection failure
44564562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s')
44638032Speter
44738032Speter# action to take if there are no recipients in the message
44864562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed')
44938032Speter
45038032Speter# chrooted environment for writing to files
45164562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
45238032Speter
45338032Speter# are colons OK in addresses?
45464562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
45538032Speter
45638032Speter# how many jobs can you process in the queue?
45764562Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
45838032Speter
45938032Speter# shall I avoid expanding CNAMEs (violates protocols)?
46064562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
46138032Speter
46238032Speter# SMTP initial login message (old $e macro)
46364562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
46438032Speter
46538032Speter# UNIX initial From header format (old $l macro)
46664562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
46738032Speter
46838032Speter# From: lines that have embedded newlines are unwrapped onto one line
46964562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
47038032Speter
47138032Speter# Allow HELO SMTP command that does not `include' a host name
47264562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
47338032Speter
47438032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
47564562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
47638032Speter
47738032Speter# delimiter (operator) characters (old $o macro)
47864562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
47938032Speter
48038032Speter# shall I avoid calling initgroups(3) because of high NIS costs?
48164562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
48238032Speter
48338032Speter# are group-writable `:include:' and .forward files (un)trustworthy?
48464562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
48538032Speter
48638032Speter# where do errors that occur when sending errors get sent?
48764562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
48838032Speter
48964562Sgshapiro# where to save bounces if all else fails
49064562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
49164562Sgshapiro
49238032Speter# what user id do we assume for the majority of the processing?
49364562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
49438032Speter
49538032Speter# maximum number of recipients per SMTP envelope
49664562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
49738032Speter
49838032Speter# shall we get local names from our installed interfaces?
49964562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
50038032Speter
50164562Sgshapiro# Return-Receipt-To: header implies DSN request
50264562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
50364562Sgshapiro
50464562Sgshapiro# override connection address (for testing)
50564562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
50664562Sgshapiro
50764562Sgshapiro# Trusted user for file ownership and starting the daemon
50864562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
50964562Sgshapiro
51064562Sgshapiro# Control socket for daemon management
51164562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
51264562Sgshapiro
51364562Sgshapiro# Maximum MIME header length to protect MUAs
51464562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
51564562Sgshapiro
51664562Sgshapiro# Maximum length of the sum of all headers
51764562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
51864562Sgshapiro
51964562Sgshapiro# Maximum depth of alias recursion
52064562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
52164562Sgshapiro
52264562Sgshapiro# location of pid file
52364562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
52464562Sgshapiro
52564562Sgshapiro# Prefix string for the process title shown on 'ps' listings
52664562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
52764562Sgshapiro
52864562Sgshapiro# Data file (df) memory-buffer file maximum size
52964562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
53064562Sgshapiro
53164562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
53264562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
53364562Sgshapiro
53464562Sgshapiro# list of authentication mechanisms
53564562Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
53664562Sgshapiro
53764562Sgshapiro# default authentication information for outgoing connections
53864562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
53964562Sgshapiro
54064562Sgshapiro# SMTP AUTH flags
54164562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
54264562Sgshapiro
54364562Sgshapiroifdef(`_FFR_MILTER', `
54464562Sgshapiro# Input mail filters
54564562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
54664562Sgshapiro
54764562Sgshapiro# Milter options
54864562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
54964562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
55064562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
55164562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')')
55264562Sgshapiro
55364562Sgshapiro# CA directory
55464562Sgshapiro_OPTION(CACERTPath, `confCACERT_PATH', `')
55564562Sgshapiro# CA file
55664562Sgshapiro_OPTION(CACERTFile, `confCACERT', `')
55764562Sgshapiro# Server Cert
55864562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
55964562Sgshapiro# Server private key
56064562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
56164562Sgshapiro# Client Cert
56264562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
56364562Sgshapiro# Client private key
56464562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
56564562Sgshapiro# DHParameters (only required if DSA/DH is used)
56664562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
56764562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
56864562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
56964562Sgshapiro
57064562Sgshapiroifdef(`confQUEUE_FILE_MODE',
57164562Sgshapiro`# queue file mode (qf files)
57264562SgshapiroO QueueFileMode=confQUEUE_FILE_MODE
57342575Speter')
57442575Speter
57538032Speter###########################
57638032Speter#   Message precedences   #
57738032Speter###########################
57838032Speter
57938032SpeterPfirst-class=0
58038032SpeterPspecial-delivery=100
58138032SpeterPlist=-30
58238032SpeterPbulk=-60
58338032SpeterPjunk=-100
58438032Speter
58538032Speter#####################
58638032Speter#   Trusted users   #
58738032Speter#####################
58838032Speter
58938032Speter# this is equivalent to setting class "t"
59064562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
59138032SpeterTroot
59238032SpeterTdaemon
59338032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp')
59438032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
59538032Speter
59638032Speter#########################
59738032Speter#   Format of headers   #
59838032Speter#########################
59938032Speter
60038032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
60138032SpeterH?P?Return-Path: <$g>
60238032SpeterHReceived: confRECEIVED_HEADER
60338032SpeterH?D?Resent-Date: $a
60438032SpeterH?D?Date: $a
60538032SpeterH?F?Resent-From: confFROM_HEADER
60638032SpeterH?F?From: confFROM_HEADER
60738032SpeterH?x?Full-Name: $x
60838032Speter# HPosted-Date: $a
60938032Speter# H?l?Received-Date: $b
61038032SpeterH?M?Resent-Message-Id: <$t.$i@$j>
61138032SpeterH?M?Message-Id: <$t.$i@$j>
61264562Sgshapiro
61338032Speter#
61438032Speter######################################################################
61538032Speter######################################################################
61638032Speter#####
61738032Speter#####			REWRITING RULES
61838032Speter#####
61938032Speter######################################################################
62038032Speter######################################################################
62138032Speter
62238032Speter############################################
62338032Speter###  Ruleset 3 -- Name Canonicalization  ###
62438032Speter############################################
62564562SgshapiroScanonify=3
62638032Speter
62738032Speter# handle null input (translate to <@> special case)
62838032SpeterR$@			$@ <@>
62938032Speter
63038032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
63138032SpeterR$*			$: $1 <@>			mark addresses
63238032SpeterR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
63338032SpeterR@ $* <@>		$: @ $1				unmark @host:...
63438032SpeterR$* :: $* <@>		$: $1 :: $2			unmark node::addr
63538032SpeterR:`include': $* <@>	$: :`include': $1			unmark :`include':...
63680785SgshapiroR$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
63738032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
63838032SpeterR$* : $* <@>		$: $2				strip colon if marked
63938032SpeterR$* <@>			$: $1				unmark
64038032SpeterR$* ;			   $1				strip trailing semi
64171345SgshapiroR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
64238032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
64338032Speter
64438032Speter# null input now results from list:; syntax
64538032SpeterR$@			$@ :; <@>
64638032Speter
64738032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
64838032SpeterR$*			$: < $1 >			housekeeping <>
64938032SpeterR$+ < $* >		   < $2 >			strip excess on left
65038032SpeterR< $* > $+		   < $1 >			strip excess on right
65138032SpeterR<>			$@ < @ >			MAIL FROM:<> case
65238032SpeterR< $+ >			$: $1				remove housekeeping <>
65338032Speter
65464562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
65538032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
65638032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
65738032Speter
65838032Speter# localize and dispose of route-based addresses
65964562SgshapiroR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
66064562Sgshapirodnl',`dnl
66164562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d>
66264562SgshapiroR@ $+ , $+		$2
66364562SgshapiroR@ $+ : $+		$2
66464562Sgshapirodnl')
66538032Speter
66638032Speter# find focus for list syntax
66764562SgshapiroR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
66838032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
66938032Speter
67038032Speter# find focus for @ syntax addresses
67138032SpeterR$+ @ $+		$: $1 < @ $2 >			focus on domain
67238032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
67364562SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
67438032Speter
67538032Speter# do some sanity checking
67638032SpeterR$* < @ $* : $* > $*	$1 < @ $2 $3 > $4		nix colons in addrs
67738032Speter
67838032Speterifdef(`_NO_UUCP_', `dnl',
67938032Speter`# convert old-style addresses to a domain-based address
68064562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
68164562SgshapiroR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
68264562SgshapiroR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
68338032Speter')
68438032Speterifdef(`_USE_DECNET_SYNTAX_',
68538032Speter`# convert node::user addresses into a domain-based address
68664562SgshapiroR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
68764562SgshapiroR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
68838032Speter',
68938032Speter	`dnl')
69038032Speter# if we have % signs, take the rightmost one
69138032SpeterR$* % $*		$1 @ $2				First make them all @s.
69238032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
69364562SgshapiroR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
69438032Speter
69538032Speter# else we must be a local name
69664562SgshapiroR$*			$@ $>Canonify2 $1
69738032Speter
69838032Speter
69938032Speter################################################
70038032Speter###  Ruleset 96 -- bottom half of ruleset 3  ###
70138032Speter################################################
70238032Speter
70364562SgshapiroSCanonify2=96
70438032Speter
70538032Speter# handle special cases for local names
70638032SpeterR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
70738032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
70838032Speterifdef(`_NO_UUCP_', `dnl',
70938032Speter`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
71064562Sgshapiro
71164562Sgshapiro# check for IPv6 domain literal (save quoted form)
71280785SgshapiroR$* < @ [ IPv6 : $+ ] > $*	$: $2 $| $1 < @@ [ $(dequote $2 $) ] > $3	mark IPv6 addr
71380785SgshapiroR$+ $| $* < @@ $=w > $*		$: $2 < @ $j . > $4		self-literal
71480785SgshapiroR$+ $| $* < @@ [ $+ ] > $*	$@ $2 < @ [ IPv6 : $1 ] > $4	canon IP addr
71564562Sgshapiro
71664562Sgshapiro# check for IPv4 domain literal
71738032SpeterR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [a.b.c.d]
71838032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
71938032SpeterR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
72038032Speter
72164562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl
72238032Speter# look up domains in the domain table
72338032SpeterR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
72438032Speter
72564562Sgshapiroundivert(2)dnl LOCAL_RULE_3
72638032Speter
72764562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl
72838032Speter# handle BITNET mapping
72938032SpeterR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
73038032Speter
73164562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl
73238032Speter# handle UUCP mapping
73338032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
73438032Speter
73538032Speterifdef(`_NO_UUCP_', `dnl',
73638032Speter`ifdef(`UUCP_RELAY',
73738032Speter`# pass UUCP addresses straight through
73838032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
73938032Speter`# if really UUCP, handle it immediately
74038032Speterifdef(`_CLASS_U_',
74138032Speter`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
74238032Speterifdef(`_CLASS_V_',
74338032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
74438032Speterifdef(`_CLASS_W_',
74538032Speter`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
74638032Speterifdef(`_CLASS_X_',
74738032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
74838032Speterifdef(`_CLASS_Y_',
74938032Speter`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
75038032Speter
75138032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl
75238032Speter# try UUCP traffic as a local address
75338032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
75438032SpeterR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
75538032Speter')')
75664562Sgshapiro# hostnames ending in class P are always canonical
75764562SgshapiroR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
75864562Sgshapirodnl apply the next rule only for hostnames not in class P
75964562Sgshapirodnl this even works for phrases in class P since . is in class P
76064562Sgshapirodnl which daemon flags are set?
76164562SgshapiroR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
76264562Sgshapirodnl the other rules in this section only apply if the hostname
76364562Sgshapirodnl does not end in class P hence no further checks are done here
76464562Sgshapirodnl if this ever changes make sure the lookups are "protected" again!
76564562Sgshapiroifdef(`_NO_CANONIFY_', `dnl
76664562Sgshapirodnl do not canonify unless:
76764562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection
76864562Sgshapirodnl	with class P is non-empty)
76964562Sgshapirodnl or {daemon_flags} has c set
77064562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify}
77164562SgshapiroR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
77264562Sgshapiro# pass to name server to make hostname canonical if requested
77364562SgshapiroR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
77464562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_
77564562SgshapiroR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
77664562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work
77764562SgshapiroR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
77864562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl
77964562Sgshapirodnl this should only apply to unqualified hostnames
78064562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
78164562Sgshapirodnl then $- does not work.
78264562Sgshapiro# lookup unqualified hostnames
78364562SgshapiroR$* $| $* < @ $* > $*	$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
78464562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
78564562Sgshapirodnl {daemon_flags} contains CC (do not canonify)
78671345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work
78771345Sgshapirodnl should we do this for every hostname: even unqualified?
78871345SgshapiroR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
78964562SgshapiroR$* CC $* $| $*			$: $3
79038032Speter# pass to name server to make hostname canonical
79164562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
79264562Sgshapirodnl remove {daemon_flags} for other cases
79364562SgshapiroR$* $| $*			$: $2
79438032Speter
79538032Speter# local host aliases and pseudo-domains are always canonical
79638032SpeterR$* < @ $=w > $*		$: $1 < @ $2 . > $3
79738032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
79838032Speter`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
79938032Speter`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
80064562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
80164562Sgshapirodnl virtual hosts are also canonical
80264562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
80364562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
80464562Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
80564562Sgshapiro`dnl')
80664562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added
80764562Sgshapirodnl by one of the rules before
80838032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
80938032Speter
81038032Speter
81138032Speter##################################################
81238032Speter###  Ruleset 4 -- Final Output Post-rewriting  ###
81338032Speter##################################################
81464562SgshapiroSfinal=4
81538032Speter
81671345SgshapiroR$+ :; <@>		$@ $1 :				handle <list:;>
81738032SpeterR$* <@>			$@				handle <> and list:;
81838032Speter
81938032Speter# strip trailing dot off possibly canonical name
82038032SpeterR$* < @ $+ . > $*	$1 < @ $2 > $3
82138032Speter
82264562Sgshapiro# eliminate internal code
82338032SpeterR$* < @ *LOCAL* > $*	$1 < @ $j > $2
82438032Speter
82538032Speter# externalize local domain info
82638032SpeterR$* < $+ > $*		$1 $2 $3			defocus
82738032SpeterR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
82838032SpeterR@ $*			$@ @ $1				... and exit
82938032Speter
83038032Speterifdef(`_NO_UUCP_', `dnl',
83138032Speter`# UUCP must always be presented in old form
83238032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
83338032Speter
83438032Speterifdef(`_USE_DECNET_SYNTAX_',
83538032Speter`# put DECnet back in :: form
83638032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
83738032Speter	`dnl')
83838032Speter# delete duplicate local names
83938032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
84038032Speter
84138032Speter
84238032Speter
84338032Speter##############################################################
84438032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
84538032Speter###		   (used for recursive calls)		   ###
84638032Speter##############################################################
84738032Speter
84864562SgshapiroSRecurse=97
84964562SgshapiroR$*			$: $>canonify $1
85064562SgshapiroR$*			$@ $>parse $1
85138032Speter
85238032Speter
85338032Speter######################################
85438032Speter###   Ruleset 0 -- Parse Address   ###
85538032Speter######################################
85638032Speter
85764562SgshapiroSparse=0
85838032Speter
85938032SpeterR$*			$: $>Parse0 $1		initial parsing
86038032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
86164562SgshapiroR$*			$: $>ParseLocal $1	handle local hacks
86238032SpeterR$*			$: $>Parse1 $1		final parsing
86338032Speter
86438032Speter#
86538032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
86638032Speter#	This should either return with the (possibly modified) input
86738032Speter#	or return with a #error mailer.  It should not return with a
86838032Speter#	#mailer other than the #error mailer.
86938032Speter#
87038032Speter
87138032SpeterSParse0
87238032SpeterR<@>			$@ <@>			special case error msgs
87377349SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "CODE553 List:; syntax illegal for recipient addresses"
87464562SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
87577349SgshapiroR<@ $+>			$#error $@ 5.1.3 $: "CODE553 User address required"
87638032SpeterR$*			$: <> $1
87738032SpeterR<> $* < @ [ $+ ] > $*	$1 < @ [ $2 ] > $3
87877349SgshapiroR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "CODE553 Colon illegal in host name part"
87938032SpeterR<> $*			$1
88077349SgshapiroR$* < @ . $* > $*	$#error $@ 5.1.2 $: "CODE553 Invalid host name"
88177349SgshapiroR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "CODE553 Invalid host name"
88264562Sgshapirodnl comma only allowed before @; this check is not complete
88377349SgshapiroR$* , $~O $*		$#error $@ 5.1.2 $: "CODE553 Invalid route address"
88438032Speter
88538032Speter# now delete the local info -- note $=O to find characters that cause forwarding
88664562SgshapiroR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
88764562SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
88838032SpeterR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
88977349SgshapiroR< @ $+ >		$#error $@ 5.1.3 $: "CODE553 User address required"
89064562SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
89138032SpeterR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
89277349SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "CODE553 User address required"
89338032SpeterR$* $=O $* < @ *LOCAL* >
89464562Sgshapiro			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
89538032SpeterR$* < @ *LOCAL* >	$: $1
89638032Speter
89738032Speter#
89838032Speter#  Parse1 -- the bottom half of ruleset 0.
89938032Speter#
90038032Speter
90138032SpeterSParse1
90264562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
90364562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute}
90464562SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2>',
90564562Sgshapiro`dnl')
90664562Sgshapiro
90738032Speterifdef(`_MAILER_smtp_',
90838032Speter`# handle numeric address spec
90964562Sgshapirodnl there is no check whether this is really an IP number
91064562SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
91164562SgshapiroR$* < @ [ $+ ] > $*	$1 < @ [ $2 ] : $S > $3		Add smart host to path
91280785SgshapiroR$* < @ [ IPv6 : $+ ] : > $*
91380785Sgshapiro		$#_SMTP_ $@ [ $(dequote $2 $) ] $: $1 < @ [IPv6 : $2 ] > $3	no smarthost: send
91464562SgshapiroR$* < @ [ $+ ] : > $*	$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
91564562SgshapiroR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
91664562SgshapiroR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
91738032Speter	`dnl')
91838032Speter
91964562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
92038032Speter# handle virtual users
92164562SgshapiroR$+			$: <!> $1		Mark for lookup
92264562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
92364562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
92464562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
92564562SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
92638032SpeterR<@> $+ + $* < @ $* . >
92764562Sgshapiro			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
92838032SpeterR<@> $+ + $* < @ $* . >
92938032Speter			$: < $(virtuser $1 @ $3 $@ $1 $: @ $) > $1 + $2 < @ $3 . >
93064562Sgshapirodnl try default entry: @domain
93164562Sgshapirodnl +*@domain
93264562SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
93364562Sgshapirodnl @domain if +detail exists
93464562SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
93564562Sgshapirodnl without +detail (or no match)
93638032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
93738032SpeterR<@> $+			$: $1
93864562SgshapiroR<!> $+			$: $1
93964562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
94038032SpeterR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
94180785Sgshapirodnl this is not a documented option
94280785Sgshapirodnl it performs no looping at all for virtusertable
94377349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_',
94477349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
94577349Sgshapiro`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
94677349Sgshapirodnl', `dnl')
94738032Speter
94838032Speter# short circuit local delivery so forwarded email works
94938032Speterifdef(`_MAILER_usenet_', `dnl
95064562SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
95166494Sgshapiro
95266494Sgshapiro
95338032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
95438032Speter`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
95564562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
95664562Sgshapirodnl $H empty (but @$=w.)
95738032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
95838032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
95964562Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
96038032SpeterR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
96138032Speter
96264562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
96338032Speter# not local -- try mailer table lookup
96438032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
96538032SpeterR< $+ . > $*		$: < $1 > $2			strip trailing dot
96638032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
96764562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
96864562SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
96964562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
97038032Speter`dnl')
97164562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)'
97238032Speter
97338032Speterifdef(`_NO_UUCP_', `dnl',
97438032Speter`# resolve remotely connected UUCP links (if any)
97538032Speterifdef(`_CLASS_V_',
97664562Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
97738032Speter	`dnl')
97838032Speterifdef(`_CLASS_W_',
97964562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
98038032Speter	`dnl')
98138032Speterifdef(`_CLASS_X_',
98264562Sgshapiro`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
98338032Speter	`dnl')')
98438032Speter
98538032Speter# resolve fake top level domains by forwarding to other hosts
98638032Speterifdef(`BITNET_RELAY',
98764562Sgshapiro`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
98838032Speter	`dnl')
98938032Speterifdef(`DECNET_RELAY',
99064562Sgshapiro`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
99138032Speter	`dnl')
99238032Speterifdef(`_MAILER_pop_',
99338032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
99438032Speter	`dnl')
99538032Speterifdef(`_MAILER_fax_',
99638032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
99738032Speter`ifdef(`FAX_RELAY',
99864562Sgshapiro`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
99938032Speter	`dnl')')
100038032Speter
100138032Speterifdef(`UUCP_RELAY',
100238032Speter`# forward non-local UUCP traffic to our UUCP relay
100364562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
100438032Speter`ifdef(`_MAILER_uucp_',
100538032Speter`# forward other UUCP traffic straight to UUCP
100638032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
100738032Speter	`dnl')')
100838032Speterifdef(`_MAILER_usenet_', `
100938032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
101064562SgshapiroR$+ . USENET		$#usenet $@ usenet $: $1',
101138032Speter	`dnl')
101238032Speter
101338032Speterifdef(`_LOCAL_RULES_',
101438032Speter`# figure out what should stay in our local mail system
101538032Speterundivert(1)', `dnl')
101638032Speter
101738032Speter# pass names that still have a host to a smarthost (if defined)
101864562SgshapiroR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
101938032Speter
102038032Speter# deal with other remote names
102138032Speterifdef(`_MAILER_smtp_',
102264562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
102377349Sgshapiro`R$* < @$* > $*		$#error $@ 5.1.2 $: "CODE553 Unrecognized host name " $2')
102438032Speter
102538032Speter# handle locally delivered names
102664562SgshapiroR$=L			$#_LOCAL_ $: @ $1		special local names
102738032SpeterR$+			$#_LOCAL_ $: $1			regular local names
102838032Speter
102938032Speter###########################################################################
103038032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
103138032Speter###########################################################################
103238032Speter
103364562SgshapiroSLocal_localaddr
103464562SgshapiroSlocaladdr=5
103564562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
103664562SgshapiroR$+ $| $#$*		$#$2
103764562SgshapiroR$+ $| $*		$: $1
103838032Speter
103966494Sgshapiroifdef(`_FFR_5_', `
104066494Sgshapiro# Preserve host in a macro
104166494SgshapiroR$+			$: $(macro {LocalAddrHost} $) $1
104266494SgshapiroR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
104366494Sgshapiro
104466494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `
104538032Speter# deal with plussed users so aliases work nicely
104666494SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
104766494SgshapiroR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
104866494Sgshapiro')
104938032Speter# prepend an empty "forward host" on the front
105038032SpeterR$+			$: <> $1
105138032Speter
105238032Speterifdef(`LUSER_RELAY', `dnl
105338032Speter# send unrecognized local users to a relay host
105466494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `
105566494SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
105666494SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
105766494SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
105866494SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
105964562SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
106066494SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')',
106138032Speter`dnl')
106238032Speter
106338032Speter# see if we have a relay or a hub
106438032SpeterR< > $+			$: < $H > $1			try hub
106538032SpeterR< > $+			$: < $R > $1			try relay
106666494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `
106766494SgshapiroR< > $+			$@ $1', `
106864562SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
106964562SgshapiroR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
107064562SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
107138032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
107266494SgshapiroR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
107338032SpeterR< > < $+ >		$@ $1				no +detail
107443730SpeterR$+			$: $1 <> $&h			add +detail back in
107543730SpeterR$+ <> + $*		$: $1 + $2			check whether +detail
107666494SgshapiroR$+ <> $*		$: $1				else discard')
107764562SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
107864562SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
107964562SgshapiroR< $- : $+ > $+		$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
108064562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
108138032Speter
108264562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
108338032Speter###################################################################
108438032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
108564562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
108638032Speter###################################################################
108738032Speter
108864562SgshapiroSMailertable=90
108964562Sgshapirodnl shift and check
109064562Sgshapirodnl %2 is not documented in cf/README
109138032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
109264562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
109364562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
109464562SgshapiroR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
109564562Sgshapirodnl is $2 always empty?
109638032SpeterR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
109764562SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
109864562Sgshapirodnl return full address
109938032SpeterR< $* > $*		$@ $2				no mailertable match',
110038032Speter`dnl')
110138032Speter
110238032Speter###################################################################
110338032Speter###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
110464562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
110564562Sgshapirodnl	<> address				-> address
110664562Sgshapirodnl	<error:d.s.n:text>			-> error
110764562Sgshapirodnl	<error:text>				-> error
110864562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
110964562Sgshapirodnl	<mailer:host> address			-> mailer host address
111064562Sgshapirodnl	<localdomain> address			-> address
111180785Sgshapirodnl	<[IPv6:number]> address			-> relay number address
111264562Sgshapirodnl	<host> address				-> relay host address
111338032Speter###################################################################
111438032Speter
111564562SgshapiroSMailerToTriple=95
111638032SpeterR< > $*				$@ $1			strip off null relay
111764562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
111838032SpeterR< error : $- $+ > $*		$#error $@ $(dequote $1 $) $: $2
111938032SpeterR< local : $* > $*		$>CanonLocal < $1 > $2
112038032SpeterR< $- : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
112138032SpeterR< $- : $+ > $*			$# $1 $@ $2 $: $3	try qualified mailer
112238032SpeterR< $=w > $*			$@ $2			delete local host
112380785SgshapiroR< [ IPv6 : $+ ] > $*		$#_RELAY_ $@ $(dequote $1 $) $: $2	use unqualified mailer
112438032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
112538032Speter
112638032Speter###################################################################
112738032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
112864562Sgshapirodnl input: <user> address
112964562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
113064562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
113164562Sgshapirodnl <> user <@host> rest		-> local user@host user
113264562Sgshapirodnl <> user				-> local user user
113364562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
113464562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
113564562Sgshapirodnl <user> lp				-> local lp user
113638032Speter###################################################################
113738032Speter
113838032SpeterSCanonLocal
113943730Speter# strip local host from routed addresses
114064562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
114164562SgshapiroR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
114243730Speter
114338032Speter# strip trailing dot from any host name that may appear
114438032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
114538032Speter
114638032Speter# handle local: syntax -- use old user, either with or without host
114738032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
114838032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
114938032Speter
115038032Speter# handle local:user@host syntax -- ignore host part
115138032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
115238032Speter
115338032Speter# handle local:user syntax
115438032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
115538032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
115638032Speter
115738032Speter###################################################################
115838032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
115938032Speter###################################################################
116038032Speter
116164562SgshapiroSMasqHdr=93
116238032Speter
116364562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
116438032Speter# handle generics database
116538032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
116664562Sgshapirodnl if generics should be applied add a @ as mark
116738032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
116838032Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
116938032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
117064562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
117164562Sgshapirodnl ignore the first case for now
117264562Sgshapirodnl if it has the mark lookup full address
117364562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
117464562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
117564562Sgshapirodnl no match, try user+detail@domain
117664562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
117764562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
117864562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
117964562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
118064562Sgshapirodnl no match, remove mark
118164562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
118264562Sgshapirodnl no match, try @domain for exceptions
118364562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
118464562Sgshapirodnl workspace: ... or <match> user <@domain>
118564562Sgshapirodnl no match, try local part
118638032SpeterR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
118764562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
118864562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
118964562SgshapiroR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
119064562SgshapiroR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
119138032SpeterR< > $*			$: $1				not found',
119238032Speter`dnl')
119338032Speter
119464562Sgshapiro# do not masquerade anything in class N
119564562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
119664562Sgshapiro
119738032Speter# special case the users that should be exposed
119838032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
119938032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
120038032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
120138032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
120238032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
120338032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
120438032Speter
120538032Speter# handle domain-specific masquerading
120638032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
120738032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
120838032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
120938032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
121038032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
121138032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
121238032SpeterR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
121338032SpeterR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
121438032Speter
121538032Speter###################################################################
121638032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
121738032Speter###################################################################
121838032Speter
121964562SgshapiroSMasqEnv=94
122038032Speterifdef(`_MASQUERADE_ENVELOPE_',
122164562Sgshapiro`R$+			$@ $>MasqHdr $1',
122238032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
122338032Speter
122438032Speter###################################################################
122538032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
122638032Speter###################################################################
122738032Speter
122864562SgshapiroSParseLocal=98
122964562Sgshapiroundivert(3)dnl LOCAL_RULE_0
123038032Speter
123164562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
123264562SgshapiroSLDAPExpand
123364562Sgshapiro# do the LDAP lookups
123464562SgshapiroR<$+><$+>		$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2>
123564562Sgshapiro
123664562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
123764562Sgshapiro# return the new mailRoutingAddress
123864562SgshapiroR< $+ > < $=w > < $+ > < $+ >	$@ $>Parse0 $>canonify $1
123964562SgshapiroR< $+ > <  > < $+ > < $+ >	$@ $>Parse0 $>canonify $1
124064562Sgshapiro
124164562Sgshapiro# if mailRoutingAddress and non-local mailHost,
124264562Sgshapiro# relay to mailHost with new mailRoutingAddress
124364562SgshapiroR< $+ > < $+ > < $+ > < $+ >	$#_RELAY_ $@ $2 $: $>canonify $1
124464562Sgshapiro
124564562Sgshapiro# if no mailRoutingAddress and local mailHost,
124664562Sgshapiro# return original address
124764562SgshapiroR< > < $=w > <$+> <$+>		$@ $2
124864562Sgshapiro
124964562Sgshapiro# if no mailRoutingAddress and non-local mailHost,
125064562Sgshapiro# relay to mailHost with original address
125164562SgshapiroR< > < $+ > <$+> <$+>		$#_RELAY_ $@ $1 $: $2
125264562Sgshapiro
125364562Sgshapiro# if no mailRoutingAddress and no mailHost,
125464562Sgshapiro# try @domain
125564562SgshapiroR< > < > <$+> <$+ @ $+>		$@ $>LDAPExpand <$1> <@ $3>
125664562Sgshapiro
125764562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
125864562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
125964562Sgshapiro# user does not exist
126064562SgshapiroR< > < > <$+> <@ $+>		$#error $@ nouser $: "550 User unknown"',
126164562Sgshapiro`dnl
126264562Sgshapiro# return the original address
126364562SgshapiroR< > < > <$+> <@ $+>		$@ $1')',
126464562Sgshapiro`dnl')
126564562Sgshapiro
126664562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
126764562Sgshapiro')')
126864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
126938032Speter######################################################################
127038032Speter###  LookUpDomain -- search for domain in access database
127138032Speter###
127238032Speter###	Parameters:
127338032Speter###		<$1> -- key (domain name)
127438032Speter###		<$2> -- default (what to return if not found in db)
127564562Sgshapirodnl			must not be empty
127638032Speter###		<$3> -- passthru (additional data passed unchanged through)
127764562Sgshapiro###		<$4> -- mark (must be <(!|+) single-token>)
127864562Sgshapiro###			! does lookup only with tag
127964562Sgshapiro###			+ does lookup with and without tag
128064562Sgshapirodnl returns:		<default> <passthru>
128164562Sgshapirodnl 			<result> <passthru>
128238032Speter######################################################################
128338032Speter
128438032SpeterSLookUpDomain
128564562Sgshapirodnl remove IPv6 mark and dequote address
128664562Sgshapirodnl it is a bit ugly because it is checked on each "iteration"
128780785SgshapiroR<[IPv6 : $+]> <$+> <$*> <$*>	$: <[$(dequote $1 $)]> <$2> <$3> <$4>
128864562Sgshapirodnl workspace <key> <default> <passthru> <mark>
128964562Sgshapirodnl lookup with tag (in front, no delimiter here)
129064562SgshapiroR<$*> <$+> <$*> <$- $->		$: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5>
129164562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
129264562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest
129364562SgshapiroR<?> <$+.$+> <$+> <$*> <$- $->	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4> <$5 $6>', `dnl')
129464562Sgshapirodnl lookup without tag?
129564562SgshapiroR<?> <$+> <$+> <$*> <+ $*>	$: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4>
129664562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest
129764562SgshapiroR<?> <$+.$+> <$+> <$*> <+ $*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <$4> <+ $5>', `dnl')
129864562Sgshapirodnl lookup IP address (no check is done whether it is an IP number!)
129964562SgshapiroR<?> <[$+.$-]> <$+> <$*> <$*>	$@ $>LookUpDomain <[$1]> <$3> <$4> <$5>
130064562Sgshapirodnl lookup IPv6 address
130171345SgshapiroR<?> <[$+::$-]> <$+> <$*> <$*>	$: $>LookUpDomain <[$1]> <$3> <$4> <$5>
130264562SgshapiroR<?> <[$+:$-]> <$+> <$*> <$*>	$: $>LookUpDomain <[$1]> <$3> <$4> <$5>
130364562Sgshapirodnl not found, but subdomain: try again
130464562SgshapiroR<?> <$+.$+> <$+> <$*> <$*>	$@ $>LookUpDomain <$2> <$3> <$4> <$5>
130564562Sgshapirodnl not found, no subdomain: return default
130664562SgshapiroR<?> <$+> <$+> <$*> <$*>	$@ <$2> <$3>
130764562Sgshapirodnl return result of lookup
130864562SgshapiroR<$*> <$+> <$+> <$*> <$*>	$@ <$1> <$4>
130938032Speter
131038032Speter######################################################################
131138032Speter###  LookUpAddress -- search for host address in access database
131238032Speter###
131338032Speter###	Parameters:
131438032Speter###		<$1> -- key (dot quadded host address)
131538032Speter###		<$2> -- default (what to return if not found in db)
131664562Sgshapirodnl			must not be empty
131738032Speter###		<$3> -- passthru (additional data passed through)
131864562Sgshapiro###		<$4> -- mark (must be <(!|+) single-token>)
131964562Sgshapiro###			! does lookup only with tag
132064562Sgshapiro###			+ does lookup with and without tag
132164562Sgshapirodnl	returns:	<default> <passthru>
132264562Sgshapirodnl			<result> <passthru>
132338032Speter######################################################################
132438032Speter
132538032SpeterSLookUpAddress
132664562Sgshapirodnl lookup with tag
132764562SgshapiroR<$+> <$+> <$*> <$- $+>		$: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5>
132864562Sgshapirodnl lookup without tag
132964562SgshapiroR<?> <$+> <$+> <$*> <+ $+>	$: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4>
133064562Sgshapirodnl no match; IPv6: remove last part
133171345SgshapiroR<?> <$+::$-> <$+> <$*> <$*>	$@ $>LookUpAddress <$1> <$3> <$4> <$5>
133264562SgshapiroR<?> <$+:$-> <$+> <$*> <$*>	$@ $>LookUpAddress <$1> <$3> <$4> <$5>
133364562Sgshapirodnl no match; IPv4: remove last part
133464562SgshapiroR<?> <$+.$-> <$+> <$*> <$*>	$@ $>LookUpAddress <$1> <$3> <$4> <$5>
133564562Sgshapirodnl no match: return default
133664562SgshapiroR<?> <$+> <$+> <$*> <$*>	$@ <$2> <$3>
133764562Sgshapirodnl match: return result
133864562SgshapiroR<$*> <$+> <$+> <$*> <$*>	$@ <$1> <$4>',
133938032Speter`dnl')
134038032Speter
134138032Speter######################################################################
134242575Speter###  CanonAddr --	Convert an address into a standard form for
134342575Speter###			relay checking.  Route address syntax is
134442575Speter###			crudely converted into a %-hack address.
134542575Speter###
134642575Speter###	Parameters:
134742575Speter###		$1 -- full recipient address
134842575Speter###
134942575Speter###	Returns:
135042575Speter###		parsed address, not in source route form
135164562Sgshapirodnl		user%host%host<@domain>
135264562Sgshapirodnl		host!user<@domain>
135342575Speter######################################################################
135442575Speter
135542575SpeterSCanonAddr
135664562SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
135764562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
135842575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
135942575SpeterR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
136042575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
136164562Sgshapirodnl')
136242575Speter
136342575Speter######################################################################
136438032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
136538032Speter###			$* $=m or the access database.
136638032Speter###			Check user portion for host separators.
136738032Speter###
136838032Speter###	Parameters:
136938032Speter###		$1 -- full recipient address
137038032Speter###
137138032Speter###	Returns:
137238032Speter###		parsed, non-local-relaying address
137338032Speter######################################################################
137438032Speter
137538032SpeterSParseRecipient
137664562Sgshapirodnl mark and canonify address
137742575SpeterR$*				$: <?> $>CanonAddr $1
137864562Sgshapirodnl workspace: <?> localpart<@domain[.]>
137942575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
138064562Sgshapirodnl workspace: <?> localpart<@domain>
138142575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
138238032Speter
138338032Speter# if no $=O character, no host in the user portion, we are done
138442575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
138564562Sgshapirodnl no $=O in localpart: return
138642575SpeterR<?> $*				$@ $1
138738032Speter
138864562Sgshapirodnl workspace: <?> localpart<@domain>, where localpart contains $=O
138964562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
139038032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
139138032Speter# if we relay, check username portion for user%host so host can be checked also
139242575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
139342575Speter
139442575Speterifdef(`_RELAY_MX_SERVED_', `dnl
139564562Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
139642575SpeterR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
139742575SpeterR<MX> < : $* <TEMP> : > $*	$#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
139864562Sgshapirodnl yes: mark it as <RELAY>
139942575SpeterR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
140064562Sgshapirodnl no: put old <NO> mark back
140142575SpeterR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
140242575Speter
140364562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
140464562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
140538032Speterifdef(`_RELAY_HOSTS_ONLY_',
140642575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
140764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
140864562SgshapiroR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
140942575SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
141042575Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
141164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
141264562SgshapiroR<NO> $* < @ $+ >		$: $>LookUpDomain <$2> <NO> <$1 < @ $2 >> <+To>
141342575SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
141438032Speter
141564562Sgshapiro
141642575SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
141742575SpeterR<$-> $*			$@ $2
141842575Speter
141964562Sgshapiro
142038032Speter######################################################################
142138032Speter###  check_relay -- check hostname/address on SMTP startup
142238032Speter######################################################################
142338032Speter
142438032SpeterSLocal_check_relay
142564562SgshapiroScheck`'_U_`'relay
142638032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
142738032SpeterR$* $| $* $| $#$*	$#$3
142838032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
142938032Speter
143038032SpeterSBasic_check_relay
143138032Speter# check for deferred delivery mode
143238032SpeterR$*			$: < ${deliveryMode} > $1
143338032SpeterR< d > $*		$@ deferred
143438032SpeterR< $* > $*		$: $2
143538032Speter
143664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
143766494Sgshapirodnl workspace: {client_name} $| {client_addr}
143864562SgshapiroR$+ $| $+		$: $>LookUpDomain < $1 > <?> < $2 > <+Connect>
143966494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
144064562SgshapiroR<?> <$+>		$: $>LookUpAddress < $1 > <?> < $1 > <+Connect>	no: another lookup
144166494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
144264562SgshapiroR<?> < $+ >		$: $1					found nothing
144366494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
144466494Sgshapirodnl or {client_addr}
144566494SgshapiroR<$={Accept}> < $* >	$@ $1				return value of lookup
144664562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
144738032SpeterR<DISCARD> $*		$#discard $: discard
144864562Sgshapirodnl error tag
144966494SgshapiroR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
145066494SgshapiroR<ERROR:$+> <$*>		$#error $: $1
145164562Sgshapirodnl generic error from access map
145266494SgshapiroR<$+> <$*>		$#error $: $1', `dnl')
145338032Speter
145464562Sgshapiroifdef(`_RBL_',`dnl
145564562Sgshapiro# DNS based IP address spam list
145638032SpeterR$*			$: $&{client_addr}
145764562SgshapiroR::ffff:$-.$-.$-.$-	$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
145864562SgshapiroR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
145964562SgshapiroR<?>OK			$: OKSOFAR
146064562SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"',
146138032Speter`dnl')
146264562Sgshapiroundivert(8)
146338032Speter
146438032Speter######################################################################
146538032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
146638032Speter######################################################################
146738032Speter
146838032SpeterSLocal_check_mail
146964562SgshapiroScheck`'_U_`'mail
147038032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
147138032SpeterR$* $| $#$*		$#$2
147238032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
147338032Speter
147438032SpeterSBasic_check_mail
147538032Speter# check for deferred delivery mode
147638032SpeterR$*			$: < ${deliveryMode} > $1
147738032SpeterR< d > $*		$@ deferred
147838032SpeterR< $* > $*		$: $2
147938032Speter
148064562Sgshapiro# authenticated?
148164562Sgshapirodnl done first: we can require authentication for every mail transaction
148264562Sgshapirodnl workspace: address as given by MAIL FROM: (sender)
148364562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
148464562SgshapiroR$* $| $#$+		$#$2
148564562Sgshapirodnl undo damage: remove result of tls_client call
148664562SgshapiroR$* $| $*		$: $1
148738032Speter
148864562Sgshapirodnl workspace: address as given by MAIL FROM:
148964562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
149038032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
149164562Sgshapirodnl do some additional checks
149264562Sgshapirodnl no user@host
149364562Sgshapirodnl no user@localhost (if nonlocal sender)
149464562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
149564562Sgshapirodnl just make sure the address has <> around it (which is required by
149664562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
149764562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
149864562Sgshapirodnl not be modified by host lookups.
149964562SgshapiroR$+			$: <?> $1
150064562SgshapiroR<?><$+>		$: <@> <$1>
150164562SgshapiroR<?>$+			$: <@> <$1>
150264562Sgshapirodnl workspace: <@> <address>
150364562Sgshapirodnl prepend daemon_flags
150464562SgshapiroR$*			$: $&{daemon_flags} $| $1
150564562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
150664562Sgshapirodnl do not allow these at all or only from local systems?
150764562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
150864562Sgshapirodnl accept unqualified sender: change mark to avoid test
150964562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
151064562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
151164562Sgshapirodnl        or:                    <? ${client_name} > <address>
151264562Sgshapirodnl        or:                    <?> <address>
151364562Sgshapirodnl remove daemon_flags
151464562SgshapiroR$* $| $*		$: $2
151538032Speter# handle case of @localhost on address
151664562SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
151764562SgshapiroR<@> < $* @ [127.0.0.1] >
151864562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
151964562SgshapiroR<@> < $* @ localhost.$m >
152064562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
152138032Speterifdef(`_NO_UUCP_', `dnl',
152264562Sgshapiro`R<@> < $* @ localhost.UUCP >
152364562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
152464562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
152564562Sgshapirodnl	or:    <@> <address>
152664562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
152764562SgshapiroR<@> $*			$: $1			no localhost as domain
152864562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
152964562Sgshapirodnl	or:    <address>
153064562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
153164562SgshapiroR<? $=w> $*		$: $2			local client: ok
153277349SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "CODE553 Real domain name required for sender address"
153364562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
153464562SgshapiroR<?> $*			$: $1')
153564562Sgshapirodnl workspace: address (or <address>)
153664562SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
153764562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
153864562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
153964562SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
154064562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
154164562SgshapiroR<?> $* < @ $* $=P >	$: <OK> $1 < @ $2 $3 >
154264562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
154364562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
154464562Sgshapiro`R<?> $* < @ $+ >	$: <OK> $1 < @ $2 >		... unresolvable OK',
154564562Sgshapiro`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
154664562SgshapiroR<? $* <$->> $* < @ $+ >
154764562Sgshapiro			$: <$2> $3 < @ $4 >')
154864562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, OK, PERM, TEMP
154964562Sgshapirodnl mark is ? iff the address is user (wo @domain)
155038032Speter
155164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
155264562Sgshapiro# check sender address: user@address, user@, address
155364562Sgshapirodnl should we remove +ext from user?
155464562Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, OK, PERM, TEMP
155564562SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <H:$3>
155664562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
155764562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
155864562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
155964562Sgshapirodnl will only return user<@domain when "reversing" the args
156064562SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+From> $| <$3> <>
156164562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
156264562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
156364562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
156438032Speter# retransform for further use
156564562Sgshapirodnl required form:
156664562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
156764562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
156864562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
156964562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
157064562Sgshapirodnl mark is ? iff the address is user (wo @domain)
157138032Speter
157238032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
157338032Speter# handle case of no @domain on address
157464562Sgshapirodnl prepend daemon_flags
157564562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
157664562Sgshapirodnl accept unqualified sender: change mark to avoid test
157764562SgshapiroR$* u $* $| <?> $*	$: <OK> $3
157864562Sgshapirodnl remove daemon_flags
157964562SgshapiroR$* $| $*		$: $2
158038032SpeterR<?> $*			$: < ? $&{client_name} > $1
158138032SpeterR<?> $*			$@ <OK>				...local unqualed ok
158277349SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "CODE553 Domain name required for sender address " $&f
158338032Speter							...remote is not')
158438032Speter# check results
158564562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
158638032SpeterR<OK> $*		$@ <OK>
158764562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
158877349SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "CODE553 Domain of sender address " $&f " does not exist"
158964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
159064562SgshapiroR<$={Accept}> $*	$# $1
159138032SpeterR<DISCARD> $*		$#discard $: discard
159264562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
159364562Sgshapirodnl error tag
159464562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
159564562SgshapiroR<ERROR:$+> $*		$#error $: $1
159664562Sgshapirodnl generic error from access map
159764562SgshapiroR<$+> $*		$#error $: $1		error from access db',
159838032Speter`dnl')
159938032Speter
160038032Speter######################################################################
160138032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
160238032Speter######################################################################
160338032Speter
160438032SpeterSLocal_check_rcpt
160564562SgshapiroScheck`'_U_`'rcpt
160638032SpeterR$*			$: $1 $| $>"Local_check_rcpt" $1
160738032SpeterR$* $| $#$*		$#$2
160838032SpeterR$* $| $*		$@ $>"Basic_check_rcpt" $1
160938032Speter
161038032SpeterSBasic_check_rcpt
161138032Speter# check for deferred delivery mode
161238032SpeterR$*			$: < ${deliveryMode} > $1
161338032SpeterR< d > $*		$@ deferred
161438032SpeterR< $* > $*		$: $2
161538032Speter
161664562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
161764562Sgshapiro# require qualified recipient?
161864562SgshapiroR$+			$: <?> $1
161964562SgshapiroR<?><$+>		$: <@> <$1>
162064562SgshapiroR<?>$+			$: <@> <$1>
162164562Sgshapirodnl prepend daemon_flags
162264562SgshapiroR$*			$: $&{daemon_flags} $| $1
162364562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
162464562Sgshapirodnl do not allow these at all or only from local systems?
162564562SgshapiroR$* r $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
162664562SgshapiroR<?> < $* >		$: <$1>
162764562SgshapiroR<? $=w> < $* >		$: <$1>
162864562SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Domain name required"
162964562Sgshapirodnl remove daemon_flags for other cases
163064562SgshapiroR$* $| <@> $*		$: $2', `dnl')
163164562Sgshapiro
163238032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
163342575SpeterR$*			$: $>CanonAddr $1
163438032SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
163538032Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
163638032Speter
163742575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
163842575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
163942575Speter# unlimited bestmx
164042575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
164142575Speter`dnl
164242575Speter# limit bestmx to $=B
164343730SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
164464562SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Basic_check_rcpt" $1 $2 $3
164542575SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
164642575SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
164742575Speter
164838032Speterifdef(`_BLACKLIST_RCPT_',`dnl
164964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
165038032Speter# blacklist local users or any host from receiving mail
165138032SpeterR$*			$: <?> $1
165264562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
165364562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
165464562SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <H:$2>
165564562SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <H:$2>
165664562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
165764562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
165864562Sgshapirodnl will only return user<@domain when "reversing" the args
165964562SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+To> $| <$2> <>
166064562SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
166164562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
166264562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
166364562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
166464562Sgshapirodnl we have to filter these because otherwise they would be interpreted
166564562Sgshapirodnl as generic error message...
166664562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
166764562Sgshapirodnl that would make a lot of things easier.
166864562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
166964562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
167038032SpeterR<REJECT> $*		$#error $@ 5.2.1 $: "550 Mailbox disabled for this recipient"
167164562SgshapiroR<DISCARD> $*		$#discard $: discard
167264562Sgshapirodnl error tag
167364562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
167464562SgshapiroR<ERROR:$+> $*		$#error $: $1
167564562Sgshapirodnl generic error from access map
167664562SgshapiroR<$+> $*		$#error $: $1		error from access db
167764562SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
167838032Speter
167964562Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)')
168064562Sgshapiro# authenticated?
168164562Sgshapirodnl do this unconditionally? this requires to manage CAs carefully
168264562Sgshapirodnl just because someone has a CERT signed by a "trusted" CA
168364562Sgshapirodnl does not mean we want to allow relaying for her,
168464562Sgshapirodnl either use a subroutine or provide something more sophisticated
168564562Sgshapirodnl this could for example check the DN (maybe an access map lookup)
168664562SgshapiroR$*		$: $1 $| $>RelayAuth $1 $| $&{verify}	client authenticated?
168764562SgshapiroR$* $| $# $+		$# $2				error/ok?
168864562SgshapiroR$* $| $*		$: $1				no
168964562Sgshapiro
169064562Sgshapiro# authenticated by a trusted mechanism?
169164562SgshapiroR$*			$: $1 $| $&{auth_type}
169264562Sgshapirodnl empty ${auth_type}?
169364562SgshapiroR$* $|			$: $1
169464562Sgshapirodnl mechanism ${auth_type} accepted?
169564562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
169664562SgshapiroR$* $| $={TrustAuthMech}	$# RELAYAUTH
169764562Sgshapirodnl undo addition of ${auth_type}
169864562SgshapiroR$* $| $*		$: $1
169971345Sgshapirodnl workspace: localpart<@domain> | localpart
170064562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
170171345Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
170271345SgshapiroR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
170338032Speter# anything terminating locally is ok
170438032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
170564562SgshapiroR$+ < @ $* $=m >	$@ RELAYTO', `dnl')
170664562SgshapiroR$+ < @ $=w >		$@ RELAYTO
170738032Speterifdef(`_RELAY_HOSTS_ONLY_',
170864562Sgshapiro`R$+ < @ $=R >		$@ RELAYTO
170964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
171064562SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
171164562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
171264562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
171364562Sgshapiro`R$+ < @ $* $=R >	$@ RELAYTO
171464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
171564562SgshapiroR$+ < @ $+ >		$: $>LookUpDomain <$2> <?> <$1 < @ $2 >> <+To>',`dnl')')
171664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
171764562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
171864562SgshapiroR<RELAY> $*		$@ RELAYTO
171938032SpeterR<$*> <$*>		$: $2',`dnl')
172038032Speter
172164562Sgshapiro
172238032Speterifdef(`_RELAY_MX_SERVED_', `dnl
172338032Speter# allow relaying for hosts which we MX serve
172464562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
172564562Sgshapirodnl this must not necessarily happen if the client is checked first...
172638032SpeterR< : $* <TEMP> : > $*	$#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
172764562SgshapiroR<$* : $=w . : $*> $*	$@ RELAYTO
172842575SpeterR< : $* : > $*		$: $2',
172938032Speter`dnl')
173038032Speter
173138032Speter# check for local user (i.e. unqualified address)
173238032SpeterR$*			$: <?> $1
173342575SpeterR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
173438032Speter# local user is ok
173564562Sgshapirodnl is it really? the standard requires user@domain, not just user
173664562Sgshapirodnl but we should accept it anyway (maybe making it an option:
173764562Sgshapirodnl RequireFQDN ?)
173864562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
173964562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
174064562SgshapiroR<?> postmaster		$@ TOPOSTMASTER
174164562Sgshapiro# require qualified recipient?
174264562Sgshapirodnl prepend daemon_flags
174364562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
174464562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
174564562Sgshapirodnl do not allow these at all or only from local systems?
174664562Sgshapirodnl r flag? add client_name
174764562SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
174864562Sgshapirodnl no r flag: relay to local user (only local part)
174964562Sgshapiro# no qualified recipient required
175064562SgshapiroR$* $| <?> $+		$@ RELAYTOLOCAL
175164562Sgshapirodnl client_name is empty
175264562SgshapiroR<?> <?> $+		$@ RELAYTOLOCAL
175364562Sgshapirodnl client_name is local
175464562SgshapiroR<? $=w> <?> $+		$@ RELAYTOLOCAL
175564562Sgshapirodnl client_name is not local
175664562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
175764562Sgshapirodnl no qualified recipient required
175864562SgshapiroR<?> $+			$@ RELAYTOLOCAL')
175964562Sgshapirodnl it is a remote user: remove mark and then check client
176038032SpeterR<$+> $*		$: $2
176164562Sgshapirodnl currently the recipient address is not used below
176238032Speter
176338032Speter# anything originating locally is ok
176464562Sgshapiro# check IP address
176564562SgshapiroR$*			$: $&{client_addr}
176664562SgshapiroR$@			$@ RELAYFROM		originated locally
176764562SgshapiroR0			$@ RELAYFROM		originated locally
176864562SgshapiroR$=R $*			$@ RELAYFROM		relayable IP address
176964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
177064562SgshapiroR$*			$: $>LookUpAddress <$1> <?> <$1> <+Connect>
177164562SgshapiroR<RELAY> $* 		$@ RELAYFROM		relayable IP address
177264562SgshapiroR<$*> <$*>		$: $2', `dnl')
177364562SgshapiroR$*			$: [ $1 ]		put brackets around it...
177464562SgshapiroR$=w			$@ RELAYFROM		... and see if it is local
177564562Sgshapiro
177664562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
177764562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
177864562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
177964562Sgshapirodnl input: {client_addr} or something "broken"
178064562Sgshapirodnl just throw the input away; we do not need it.
178164562Sgshapiro# check whether FROM is allowed to use system as relay
178264562SgshapiroR$*			$: <?> $>CanonAddr $&f
178364562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
178464562Sgshapiro# check whether local FROM is ok
178564562SgshapiroR<?> $+ < @ $=w . >	$@ RELAYFROMMAIL	FROM local', `dnl')
178664562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
178764562SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
178864562SgshapiroR<?> $+ < @ $+ >	$: $1 < @ $2 > $| $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<H:$2>') <>
178964562SgshapiroR$* <RELAY>		$@ RELAYFROMMAIL	RELAY FROM sender ok', `dnl
179064562Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', `errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
179164562Sgshapiro')',
179264562Sgshapiro`dnl')
179364562Sgshapirodnl')', `dnl')
179464562Sgshapiro
179564562Sgshapiro# check client name: first: did it resolve?
179664562Sgshapirodnl input: ignored
179764562SgshapiroR$*			$: < $&{client_resolve} >
179864562SgshapiroR<TEMP>			$#error $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
179964562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
180064562SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
180164562Sgshapirodnl ${client_resolve} should be OK, so go ahead
180238032SpeterR$*			$: <?> $&{client_name}
180338032Speter# pass to name server to make hostname canonical
180464562SgshapiroR<?> $* $~P 		$:<?>  $[ $1 $2 $]
180564562SgshapiroR$* .			$1			strip trailing dots
180664562Sgshapirodnl should not be necessary since it has been done for client_addr already
180764562SgshapiroR<?>			$@ RELAYFROM
180838032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
180964562SgshapiroR<?> $* $=m		$@ RELAYFROM', `dnl')
181064562SgshapiroR<?> $=w		$@ RELAYFROM
181138032Speterifdef(`_RELAY_HOSTS_ONLY_',
181264562Sgshapiro`R<?> $=R		$@ RELAYFROM
181364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
181464562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
181564562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
181664562Sgshapiro`R<?> $* $=R			$@ RELAYFROM
181764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
181864562SgshapiroR<?> $*			$: $>LookUpDomain <$1> <?> <$1> <+Connect>',`dnl')')
181964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
182064562SgshapiroR<RELAY> $*		$@ RELAYFROM
182138032SpeterR<$*> <$*>		$: $2',`dnl')
182238032Speter
182364562Sgshapiro# anything else is bogus
182464562SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
182564562Sgshapirodivert(0)
182664562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
182764562Sgshapiro# turn a canonical address in the form user<@domain>
182864562Sgshapiro# qualify unqual. addresses with $j
182964562Sgshapirodnl it might have been only user (without <@domain>)
183064562SgshapiroSFullAddr
183164562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
183264562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
183364562SgshapiroR$+			$@ $1 <@ $j >
183438032Speter
183564562Sgshapiro# call all necessary rulesets
183664562SgshapiroScheck_rcpt
183764562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
183864562Sgshapirodnl which is the correct DSN code?
183964562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
184064562SgshapiroR$+			$: $1 $| $>checkrcpt $1
184164562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
184264562SgshapiroR$+ $| $#$*		$#$2
184364562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
184464562Sgshapiroifdef(`_SPAM_FH_',
184564562Sgshapiro`dnl lookup user@ and user@address
184664562Sgshapiroifdef(`_ACCESS_TABLE_', `',
184764562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
184864562Sgshapiro')')dnl
184964562Sgshapirodnl one of the next two rules is supposed to match
185064562Sgshapirodnl this code has been copied from BLACKLIST... etc
185164562Sgshapirodnl and simplified by omitting some < >.
185264562SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <U: $1@>
185364562SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 >
185464562Sgshapirodnl R<?>		$@ something_is_very_wrong_here
185564562Sgshapiro# lookup the addresses only with To tag
185664562SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <!To> $| <$2> <>
185764562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
185864562Sgshapirodnl', `dnl')
185964562Sgshapiroifdef(`_SPAM_FRIEND_',
186064562Sgshapiro`# is the recipient a spam friend?
186164562Sgshapiroifdef(`_SPAM_HATER_',
186264562Sgshapiro	`errprint(`*** ERROR: define either SpamHater or SpamFriend
186364562Sgshapiro')', `dnl')
186464562SgshapiroR<SPAMFRIEND> $+	$@ SPAMFRIEND
186564562SgshapiroR<$*> $+		$: $2',
186664562Sgshapiro`dnl')
186764562Sgshapiroifdef(`_SPAM_HATER_',
186864562Sgshapiro`# is the recipient no spam hater?
186964562SgshapiroR<SPAMHATER> $+		$: $1			spam hater: continue checks
187064562SgshapiroR<$*> $+		$@ NOSPAMHATER		everyone else: stop
187164562Sgshapirodnl',`dnl')
187264562Sgshapirodnl run further checks: check_mail
187364562Sgshapirodnl should we "clean up" $&f?
187464562SgshapiroR$*			$: $1 $| $>checkmail <$&f>
187564562SgshapiroR$* $| $#$*		$#$2
187664562Sgshapirodnl run further checks: check_relay
187764562SgshapiroR$*			$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
187864562SgshapiroR$* $| $#$*		$#$2
187938032SpeterR$* $| $*		$: $1
188038032Speter', `dnl')
188164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
188264562Sgshapiro######################################################################
188364562Sgshapiro###  SearchList: search a list of items in the access map
188464562Sgshapiro###	Parameters:
188564562Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
188664562Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
188764562Sgshapirodnl	avoid errorneous matches (with error messages?)
188864562Sgshapirodnl	if we can make sure that tag is always a single token
188964562Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
189064562Sgshapirodnl	to avoid errorneous matchs (first rule: H: if there
189164562Sgshapirodnl	is that mark somewhere in the list, it will be taken).
189264562Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
189364562Sgshapirodnl	the tag only, e.g.:
189464562Sgshapiro###	where "exact" is either "+" or "!":
189564562Sgshapiro###	<+ TAG>	lookup with and w/o tag
189664562Sgshapiro###	<! TAG>	lookup with tag
189764562Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
189864562Sgshapirodnl		a blank between them and the tag.
189964562Sgshapiro###	possible values for "mark" are:
190064562Sgshapiro###		H: recursive host lookup (LookUpDomain)
190164562Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
190264562Sgshapiro###		E: exact lookup, no modifications
190364562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
190464562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
190564562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
190664562Sgshapiro######################################################################
190738032Speter
190864562Sgshapiro# class with valid marks for SearchList
190964562Sgshapirodnl if A is activated: add it
191064562SgshapiroC{src}E F H U
191164562SgshapiroSSearchList
191264562Sgshapiro# mark H: lookup domain
191364562SgshapiroR<$+> $| <H:$+> <$*>		$: <$1> $| <@> $>LookUpDomain <$2> <?> <$3> <$1>
191464562SgshapiroR<$+> $| <@> <$+> <$*>		$: <$1> $| <$2> <$3>
191564562Sgshapirodnl A: NOT YET REQUIRED
191664562Sgshapirodnl R<$+> $| <A:$+> <$*>	$: <$1> $| <@> $>LookUpAddress <$2> <?> <$3> <$1>
191764562Sgshapirodnl R<$+> $| <@> <$+> <$*>	$: <$1> $| <$2> <$3>
191864562Sgshapirodnl lookup of the item with tag
191964562Sgshapirodnl this applies to F: U: E:
192064562SgshapiroR<$- $-> $| <$={src}:$+> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5>
192164562Sgshapirodnl no match, try without tag
192264562SgshapiroR<+ $-> $| <$={src}:$+> <$*>	$: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4>
192364562Sgshapirodnl do we really have to distinguish these cases?
192464562Sgshapirodnl probably yes, there might be a + in the domain part (is that allowed?)
192564562Sgshapirodnl user+detail lookups: should it be:
192664562Sgshapirodnl user+detail, user+*, user; just like aliases?
192764562SgshapiroR<$- $-> $| <F:$* + $*@$+> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@$5 $: F:$3 + $4@$5$)> <$6>
192864562SgshapiroR<+ $-> $| <F:$* + $*@$+> <$*>	$: <+ $1> $| <$(access $2@$4 $: F:$2 + $3@$4$)> <$5>
192964562Sgshapirodnl user lookups are always with trailing @
193064562Sgshapirodnl do not remove the @ from the lookup:
193164562Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
193264562SgshapiroR<$- $-> $| <U:$* + $*> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5>
193364562Sgshapirodnl no match, try without tag
193464562SgshapiroR<+ $-> $| <U:$* + $*> <$*>	$: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4>
193564562Sgshapirodnl no match, try rest of list
193664562SgshapiroR<$+> $| <$={src}:$+> <$+>	$@ $>SearchList <$1> $| <$4>
193764562Sgshapirodnl no match, list empty: return failure
193864562SgshapiroR<$+> $| <$={src}:$+> <>	$@ <?>
193964562Sgshapirodnl got result, return it
194064562SgshapiroR<$+> $| <$+> <$*>		$@ <$2>
194164562Sgshapirodnl return result from recursive invocation
194264562SgshapiroR<$+> $| <$+>			$@ <$2>', `dnl')
194338032Speter
194464562Sgshapiro# is user trusted to authenticate as someone else?
194564562Sgshapirodnl AUTH= parameter from MAIL command
194664562SgshapiroStrust_auth
194764562SgshapiroR$*			$: $&{auth_type} $| $1
194864562Sgshapiro# required by RFC 2554 section 4.
194964562SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
195064562Sgshapirodnl seems to be useful...
195164562SgshapiroR$* $| $&{auth_authen}		$@ identical
195264562SgshapiroR$* $| <$&{auth_authen}>	$@ identical
195364562Sgshapirodnl call user supplied code
195464562SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $1
195564562SgshapiroR$* $| $#$*		$#$2
195664562Sgshapirodnl default: error
195764562SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
195864562Sgshapiro
195964562Sgshapirodnl empty ruleset definition so it can be called
196064562SgshapiroSLocal_trust_auth
196164562Sgshapiro
196264562Sgshapiroifdef(`_FFR_TLS_O_T', `dnl
196364562SgshapiroSoffer_tls
196464562SgshapiroR$*		$: $>LookUpDomain <$&{client_name}> <?> <> <! TLS_OFF_TAG>
196564562SgshapiroR<?>$*		$: $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_OFF_TAG>
196664562SgshapiroR<?>$*		$: <$(access TLS_OFF_TAG: $: ? $)>
196764562SgshapiroR<?>$*		$@ OK
196864562SgshapiroR<NO> <>	$#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]"
196964562Sgshapiro
197064562SgshapiroStry_tls
197164562SgshapiroR$*		$: $>LookUpDomain <$&{server_name}> <?> <> <! TLS_TRY_TAG>
197264562SgshapiroR<?>$*		$: $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_TRY_TAG>
197364562SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG: $: ? $)>
197464562SgshapiroR<?>$*		$@ OK
197571345SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
197664562Sgshapiro')dnl
197764562Sgshapiro
197864562Sgshapiro# is connection with client "good" enough? (done in server)
197964562Sgshapiro# input: ${verify} $| (MAIL|STARTTLS)
198064562Sgshapirodnl MAIL: called from check_mail
198164562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
198264562SgshapiroStls_client
198364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
198464562Sgshapirodnl ignore second arg for now
198564562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
198664562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
198764562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
198864562SgshapiroR$* $| $*	$: $1 $| $>LookUpDomain <$&{client_name}> <?> <> <! TLS_CLT_TAG>
198964562SgshapiroR$* $| <?>$*	$: $1 $| $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_CLT_TAG>
199064562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
199164562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
199264562SgshapiroR$*		$@ $>"tls_connection" $1', `dnl
199364562SgshapiroR$* $| $*	$@ $>"tls_connection" $1')
199464562Sgshapiro
199564562Sgshapiro# is connection with server "good" enough? (done in client)
199664562Sgshapirodnl i.e. has the server been authenticated and is encryption active?
199764562Sgshapirodnl called from deliver() after STARTTLS command
199864562Sgshapiro# input: ${verify}
199964562SgshapiroStls_server
200064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
200164562SgshapiroR$*		$: $1 $| $>LookUpDomain <$&{server_name}> <?> <> <! TLS_SRV_TAG>
200264562SgshapiroR$* $| <?>$*	$: $1 $| $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_SRV_TAG>
200364562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
200464562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
200564562SgshapiroR$*		$@ $>"tls_connection" $1', `dnl
200664562SgshapiroR$*		$@ $>"tls_connection" $1')
200764562Sgshapiro
200864562SgshapiroStls_connection
200964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
201064562Sgshapirodnl common ruleset for tls_{client|server}
201164562Sgshapirodnl input: $&{verify} $| <ResultOfLookup> [<>]
201264562Sgshapirodnl remove optional <>
201364562SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
201464562Sgshapirodnl permanent or temporary error?
201564562SgshapiroR$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
201664562SgshapiroR$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
201764562Sgshapirodnl default case depends on TLS_PERM_ERR
201864562SgshapiroR$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
201964562Sgshapirodnl deal with TLS handshake failures: abort
202064562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
202164562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
202264562Sgshapirodnl use default error
202364562SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
202464562SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> $1
202564562SgshapiroR$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> $1
202664562Sgshapirodnl some other value in access map: accept
202764562Sgshapirodnl this also allows to override the default case (if used)
202864562SgshapiroR$* $| $*			$@ OK
202964562Sgshapiro# authentication required: give appropriate error
203064562Sgshapiro# other side did authenticate (via STARTTLS)
203164562Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> ${verify}
203264562Sgshapirodnl only verification required and it succeeded
203364562SgshapiroR<$*><VERIFY> OK		$@ OK
203464562Sgshapirodnl verification required + some level of encryption
203564562SgshapiroR<$*><VERIFY:$-> OK		$: <$1> <REQ:$2>
203664562Sgshapirodnl just some level of encryption required
203764562SgshapiroR<$*><ENCR:$-> $*		$: <$1> <REQ:$2>
203864562Sgshapirodnl verification required but ${verify} is not set
203964562SgshapiroR<$-:$+><VERIFY $*>		$#error $@ $2 $: $1 " authentication required"
204064562SgshapiroR<$-:$+><VERIFY $*> FAIL	$#error $@ $2 $: $1 " authentication failed"
204164562SgshapiroR<$-:$+><VERIFY $*> NO		$#error $@ $2 $: $1 " not authenticated"
204264562SgshapiroR<$-:$+><VERIFY $*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
204364562Sgshapirodnl some other value for ${verify}
204464562SgshapiroR<$-:$+><VERIFY $*> $+		$#error $@ $2 $: $1 " authentication failure " $4
204564562Sgshapirodnl some level of encryption required: get the maximum level
204664562SgshapiroR<$*><REQ:$->			$: <$1> <REQ:$2> $>max $&{cipher_bits} : $&{auth_ssf}
204764562Sgshapirodnl compare required bits with actual bits
204864562SgshapiroR<$*><REQ:$-> $-		$: <$1> <$2:$3> $(arith l $@ $3 $@ $2 $)
204964562SgshapiroR<$-:$+><$-:$-> TRUE		$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
205064562Sgshapiro
205164562SgshapiroSmax
205264562Sgshapirodnl compute the max of two values separated by :
205364562SgshapiroR:		$: 0
205464562SgshapiroR:$-		$: $1
205564562SgshapiroR$-:		$: $1
205664562SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
205764562SgshapiroRTRUE:$-:$-	$: $2
205864562SgshapiroR$-:$-:$-	$: $2',
205964562Sgshapiro`dnl use default error
206064562Sgshapirodnl deal with TLS handshake failures: abort
206164562SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."')
206264562Sgshapiro
206364562SgshapiroSRelayAuth
206464562Sgshapiro# authenticated?
206564562Sgshapirodnl we do not allow relaying for anyone who can present a cert
206664562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
206764562Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow
206864562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
206964562Sgshapirodnl but anyway).
207064562Sgshapirodnl so here is the trick: if the verification succeeded
207164562Sgshapirodnl we look up the cert issuer in the access map
207264562Sgshapirodnl (maybe after extracting a part with a regular expression)
207364562Sgshapirodnl if this returns RELAY we relay without further questions
207464562Sgshapirodnl if it returns SUBJECT we perform a similar check on the
207564562Sgshapirodnl cert subject.
207664562SgshapiroR$* $| OK		$: $1
207764562SgshapiroR$* $| $*		$@ NO		not authenticated
207864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
207964562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
208064562SgshapiroR$*			$: $1 $| $(CERTIssuer $&{cert_issuer} $)',
208164562Sgshapiro`R$*			$: $1 $| $&{cert_issuer}')
208264562SgshapiroR$* $| $+		$: $1 $| $(access CERTISSUER:$2 $)
208364562Sgshapirodnl use $# to stop further checks (delay_check)
208464562SgshapiroR$* $| RELAY		$# RELAYCERTISSUER
208564562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
208664562SgshapiroR$* $| SUBJECT		$: $1 $| <@> $(CERTSubject $&{cert_subject} $)',
208764562Sgshapiro`R$* $| SUBJECT		$: $1 $| <@> $&{cert_subject}')
208866494SgshapiroR$* $| <@> $+		$: $1 $| <@> $(access CERTSUBJECT:$2 $)
208964562SgshapiroR$* $| <@> RELAY	$# RELAYCERTSUBJECT
209064562SgshapiroR$* $| $*		$: $1', `dnl')
209164562Sgshapiro
209264562Sgshapiroundivert(9)dnl LOCAL_RULESETS
209364562Sgshapiroifdef(`_FFR_MILTER', `
209438032Speter#
209538032Speter######################################################################
209638032Speter######################################################################
209738032Speter#####
209864562Sgshapiro`#####			MAIL FILTER DEFINITIONS'
209964562Sgshapiro#####
210064562Sgshapiro######################################################################
210164562Sgshapiro######################################################################
210264562Sgshapiro_MAIL_FILTERS_')
210364562Sgshapiro#
210464562Sgshapiro######################################################################
210564562Sgshapiro######################################################################
210664562Sgshapiro#####
210738032Speter`#####			MAILER DEFINITIONS'
210838032Speter#####
210938032Speter######################################################################
211038032Speter######################################################################
211164562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
211266494Sgshapiro
2113