proto.m4 revision 71345
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
1671345SgshapiroVERSIONID(`$Id: proto.m4,v 8.446.2.5.2.38 2000/12/28 03:37:28 ca 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"')')
8038032Speterdivert(0)dnl
8138032Speter
8264562Sgshapiro# override file safeties - setting this option compromises system security,
8364562Sgshapiro# addressing the actual file configuration problem is preferred
8464562Sgshapiro# need to set this before any file actions are encountered in the cf file
8564562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe')
8638032Speter
8764562Sgshapiro# default LDAP map specification
8864562Sgshapiro# need to set this now before any LDAP maps are defined
8964562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost')
9064562Sgshapiro
9138032Speter##################
9238032Speter#   local info   #
9338032Speter##################
9438032Speter
9538032SpeterCwlocalhost
9638032Speterifdef(`USE_CW_FILE',
9738032Speter`# file containing names of hosts for which we receive email
9838032SpeterFw`'confCW_FILE',
9938032Speter	`dnl')
10038032Speter
10138032Speter# my official domain name
10238032Speter# ... `define' this only if sendmail cannot automatically determine your domain
10338032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM')
10438032Speter
10538032SpeterCP.
10638032Speter
10738032Speterifdef(`UUCP_RELAY',
10838032Speter`# UUCP relay host
10938032SpeterDY`'UUCP_RELAY
11038032SpeterCPUUCP
11138032Speter
11238032Speter')dnl
11338032Speterifdef(`BITNET_RELAY',
11438032Speter`#  BITNET relay host
11538032SpeterDB`'BITNET_RELAY
11638032SpeterCPBITNET
11738032Speter
11838032Speter')dnl
11938032Speterifdef(`DECNET_RELAY',
12038032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl
12138032Speter# DECnet relay host
12238032SpeterDC`'DECNET_RELAY
12338032SpeterCPDECNET
12438032Speter
12538032Speter')dnl
12638032Speterifdef(`FAX_RELAY',
12738032Speter`# FAX relay host
12838032SpeterDF`'FAX_RELAY
12938032SpeterCPFAX
13038032Speter
13138032Speter')dnl
13238032Speter# "Smart" relay host (may be null)
13338032SpeterDS`'ifdef(`SMART_HOST', SMART_HOST)
13438032Speter
13538032Speterifdef(`LUSER_RELAY', `dnl
13638032Speter# place to which unknown users should be forwarded
13738032SpeterKuser user -m -a<>
13838032SpeterDL`'LUSER_RELAY',
13938032Speter`dnl')
14038032Speter
14138032Speter# operators that cannot be in local usernames (i.e., network indicators)
14238032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!')
14338032Speter
14438032Speter# a class with just dot (for identifying canonical names)
14538032SpeterC..
14638032Speter
14738032Speter# a class with just a left bracket (for identifying domain literals)
14838032SpeterC[[
14938032Speter
15064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
15164562Sgshapiro# access_db acceptance class
15264562SgshapiroC{Accept}OK RELAY
15364562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
15464562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl
15564562Sgshapiro# possible access_db RHS for spam friends/haters
15664562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')',
15738032Speter`dnl')
15838032Speter
15938032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
16038032Speter# Resolve map (to check if a host exists in check_mail)
16138032SpeterKresolve host -a<OK> -T<TEMP>')
16238032Speter
16366494Sgshapiroifdef(`_FFR_5_', `# macro storage map
16466494SgshapiroKmacro macro')
16566494Sgshapiro
16638032Speterifdef(`confCR_FILE', `dnl
16766494Sgshapiro# Hosts for which relaying is permitted ($=R)
16838032SpeterFR`'confCR_FILE',
16938032Speter`dnl')
17038032Speter
17164562Sgshapirodefine(`TLS_SRV_TAG', `TLS_Srv')dnl
17264562Sgshapirodefine(`TLS_CLT_TAG', `TLS_Clt')dnl
17364562Sgshapirodefine(`TLS_TRY_TAG', `Try_TLS')dnl
17464562Sgshapirodefine(`TLS_OFF_TAG', `Offer_TLS')dnl
17564562Sgshapirodnl this may be useful in other contexts too
17664562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map
17764562Sgshapirodefine(`_ARITH_MAP_', `1')dnl
17864562SgshapiroKarith arith')
17964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
18064562Sgshapiro# possible values for tls_connect in access map
18164562SgshapiroC{tls}VERIFY ENCR', `dnl')
18264562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
18364562Sgshapiro# extract relevant part from cert issuer
18464562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
18564562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
18664562Sgshapiro# extract relevant part from cert subject
18764562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
18864562Sgshapiro
18938032Speter# who I send unqualified names to (null means deliver locally)
19038032SpeterDR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY)
19138032Speter
19238032Speter# who gets all local email traffic ($R has precedence for unqualified names)
19338032SpeterDH`'ifdef(`MAIL_HUB', MAIL_HUB)
19438032Speter
19538032Speter# dequoting map
19638032SpeterKdequote dequote
19738032Speter
19838032Speterdivert(0)dnl	# end of nullclient diversion
19938032Speter# class E: names that should be exposed as from this host, even if we masquerade
20064562Sgshapiro# class L: names that should be delivered locally, even if we have a relay
20138032Speter# class M: domains that should be converted to $M
20264562Sgshapiro# class N: domains that should not be converted to $M
20338032Speter#CL root
20438032Speterundivert(5)dnl
20564562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
20638032Speter
20738032Speter# who I masquerade as (null for no masquerading) (see also $=M)
20838032SpeterDM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME)
20938032Speter
21038032Speter# my name for error messages
21138032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
21238032Speter
21364562Sgshapiroundivert(6)dnl LOCAL_CONFIG
21438032Speterinclude(_CF_DIR_`m4/version.m4')
21538032Speter
21638032Speter###############
21738032Speter#   Options   #
21838032Speter###############
21938032Speter
22038032Speter# strip message body to 7 bits on input?
22164562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
22238032Speter
22338032Speter# 8-bit data handling
22464562Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `adaptive')
22538032Speter
22638032Speter# wait for alias file rebuild (default units: minutes)
22764562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m')
22838032Speter
22938032Speter# location of alias file
23064562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
23164562Sgshapiro
23238032Speter# minimum number of free blocks on filesystem
23364562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
23438032Speter
23538032Speter# maximum message size
23664562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000')
23738032Speter
23838032Speter# substitution for space (blank) characters
23964562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_')
24038032Speter
24138032Speter# avoid connecting to "expensive" mailers on initial submission?
24264562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
24338032Speter
24438032Speter# checkpoint queue runs after every N successful deliveries
24564562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
24638032Speter
24738032Speter# default delivery mode
24864562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
24938032Speter
25038032Speter# automatically rebuild the alias database?
25164562Sgshapiro# NOTE: There is a potential for a denial of service attack if this is set.
25264562Sgshapiro#       This option is deprecated and will be removed from a future version.
25364562Sgshapiro_OPTION(AutoRebuildAliases, `confAUTO_REBUILD', `False')
25438032Speter
25538032Speter# error message header/file
25664562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
25738032Speter
25838032Speter# error mode
25964562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print')
26038032Speter
26138032Speter# save Unix-style "From_" lines at top of header?
26264562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
26338032Speter
26438032Speter# temporary file mode
26564562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
26638032Speter
26738032Speter# match recipients against GECOS field?
26864562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
26938032Speter
27038032Speter# maximum hop count
27164562Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `17')
27238032Speter
27338032Speter# location of help file
27464562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
27538032Speter
27638032Speter# ignore dots as terminators in incoming messages?
27764562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
27838032Speter
27938032Speter# name resolver options
28064562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
28138032Speter
28238032Speter# deliver MIME-encapsulated error messages?
28364562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
28438032Speter
28538032Speter# Forward file search path
28664562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
28738032Speter
28838032Speter# open connection cache size
28964562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
29038032Speter
29138032Speter# open connection cache timeout
29264562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
29338032Speter
29438032Speter# persistent host status directory
29564562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
29638032Speter
29738032Speter# single thread deliveries (requires HostStatusDirectory)?
29864562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
29938032Speter
30038032Speter# use Errors-To: header?
30164562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
30238032Speter
30338032Speter# log level
30464562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10')
30538032Speter
30638032Speter# send to me too, even in an alias expansion?
30764562Sgshapiro_OPTION(MeToo, `confME_TOO', `True')
30838032Speter
30938032Speter# verify RHS in newaliases?
31064562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
31138032Speter
31238032Speter# default messages to old style headers if no special punctuation?
31364562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
31438032Speter
31538032Speter# SMTP daemon options
31664562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
31764562Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.  See cf/README for more information.
31864562Sgshapiro)'dnl
31964562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
32066494Sgshapiroifelse(defn(`_DPO_'), `',
32166494Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-IPv4, Family=inet
32266494SgshapiroO DaemonPortOptions=Name=MTA-IPv6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
32364562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
32438032Speter
32564562Sgshapiro# SMTP client options
32664562Sgshapiro_OPTION(ClientPortOptions, `confCLIENT_OPTIONS', `Address=0.0.0.0')
32764562Sgshapiro
32838032Speter# privacy flags
32964562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
33038032Speter
33138032Speter# who (if anyone) should get extra copies of error messages
33264562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
33338032Speter
33438032Speter# slope of queue-only function
33564562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
33638032Speter
33738032Speter# queue directory
33864562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
33938032Speter
34038032Speter# timeouts (many of these)
34164562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
34264562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
34364562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
34464562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m')
34564562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m')
34664562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
34764562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
34864562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
34964562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
35064562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m')
35164562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m')
35264562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m')
35364562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h')
35464562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s')
35564562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
35664562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m')
35764562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
35864562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
35964562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
36064562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
36164562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
36264562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
36364562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
36464562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
36564562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
36664562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
36764562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
36864562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
36964562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
37064562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
37164562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
37238032Speter
37338032Speter# should we not prune routes in route-addr syntax addresses?
37464562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
37538032Speter
37638032Speter# queue up everything before forking?
37764562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
37838032Speter
37938032Speter# status file
38064562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
38138032Speter
38238032Speter# time zone handling:
38338032Speter#  if undefined, use system default
38438032Speter#  if defined but null, use TZ envariable passed in
38538032Speter#  if defined and non-null, use that info
38638032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
38738032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
38838032Speter	`O TimeZoneSpec=confTIME_ZONE')
38938032Speter
39038032Speter# default UID (can be username or userid:groupid)
39164562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
39238032Speter
39338032Speter# list of locations of user database file (null means no lookup)
39464562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
39538032Speter
39638032Speter# fallback MX host
39764562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
39838032Speter
39938032Speter# if we are the best MX host for a site, try it directly instead of config err
40064562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
40138032Speter
40238032Speter# load average at which we just queue messages
40364562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8')
40438032Speter
40538032Speter# load average at which we refuse connections
40664562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
40738032Speter
40838032Speter# maximum number of children we allow at one time
40964562Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12')
41038032Speter
41138032Speter# maximum number of new connections per second
41271345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
41338032Speter
41438032Speter# work recipient factor
41564562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
41638032Speter
41738032Speter# deliver each queued job in a separate process?
41864562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
41938032Speter
42038032Speter# work class factor
42164562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
42238032Speter
42338032Speter# work time factor
42464562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
42538032Speter
42638032Speter# shall we sort the queue by hostname first?
42764562Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
42838032Speter
42938032Speter# minimum time in queue before retry
43064562Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
43138032Speter
43238032Speter# default character set
43364562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
43438032Speter
43538032Speter# service switch file (ignored on Solaris, Ultrix, OSF/1, others)
43664562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
43738032Speter
43838032Speter# hosts file (normally /etc/hosts)
43964562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
44038032Speter
44138032Speter# dialup line delay on connection failure
44264562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s')
44338032Speter
44438032Speter# action to take if there are no recipients in the message
44564562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed')
44638032Speter
44738032Speter# chrooted environment for writing to files
44864562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
44938032Speter
45038032Speter# are colons OK in addresses?
45164562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
45238032Speter
45338032Speter# how many jobs can you process in the queue?
45464562Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
45538032Speter
45638032Speter# shall I avoid expanding CNAMEs (violates protocols)?
45764562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
45838032Speter
45938032Speter# SMTP initial login message (old $e macro)
46064562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
46138032Speter
46238032Speter# UNIX initial From header format (old $l macro)
46364562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
46438032Speter
46538032Speter# From: lines that have embedded newlines are unwrapped onto one line
46664562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
46738032Speter
46838032Speter# Allow HELO SMTP command that does not `include' a host name
46964562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
47038032Speter
47138032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
47264562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
47338032Speter
47438032Speter# delimiter (operator) characters (old $o macro)
47564562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
47638032Speter
47738032Speter# shall I avoid calling initgroups(3) because of high NIS costs?
47864562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
47938032Speter
48038032Speter# are group-writable `:include:' and .forward files (un)trustworthy?
48164562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
48238032Speter
48338032Speter# where do errors that occur when sending errors get sent?
48464562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
48538032Speter
48664562Sgshapiro# where to save bounces if all else fails
48764562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
48864562Sgshapiro
48938032Speter# what user id do we assume for the majority of the processing?
49064562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
49138032Speter
49238032Speter# maximum number of recipients per SMTP envelope
49364562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
49438032Speter
49538032Speter# shall we get local names from our installed interfaces?
49664562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
49738032Speter
49864562Sgshapiro# Return-Receipt-To: header implies DSN request
49964562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
50064562Sgshapiro
50164562Sgshapiro# override connection address (for testing)
50264562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
50364562Sgshapiro
50464562Sgshapiro# Trusted user for file ownership and starting the daemon
50564562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
50664562Sgshapiro
50764562Sgshapiro# Control socket for daemon management
50864562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
50964562Sgshapiro
51064562Sgshapiro# Maximum MIME header length to protect MUAs
51164562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
51264562Sgshapiro
51364562Sgshapiro# Maximum length of the sum of all headers
51464562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
51564562Sgshapiro
51664562Sgshapiro# Maximum depth of alias recursion
51764562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
51864562Sgshapiro
51964562Sgshapiro# location of pid file
52064562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
52164562Sgshapiro
52264562Sgshapiro# Prefix string for the process title shown on 'ps' listings
52364562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
52464562Sgshapiro
52564562Sgshapiro# Data file (df) memory-buffer file maximum size
52664562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
52764562Sgshapiro
52864562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
52964562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
53064562Sgshapiro
53164562Sgshapiro# list of authentication mechanisms
53264562Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
53364562Sgshapiro
53464562Sgshapiro# default authentication information for outgoing connections
53564562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
53664562Sgshapiro
53764562Sgshapiro# SMTP AUTH flags
53864562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
53964562Sgshapiro
54064562Sgshapiroifdef(`_FFR_MILTER', `
54164562Sgshapiro# Input mail filters
54264562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
54364562Sgshapiro
54464562Sgshapiro# Milter options
54564562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
54664562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
54764562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
54864562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')')
54964562Sgshapiro
55064562Sgshapiro# CA directory
55164562Sgshapiro_OPTION(CACERTPath, `confCACERT_PATH', `')
55264562Sgshapiro# CA file
55364562Sgshapiro_OPTION(CACERTFile, `confCACERT', `')
55464562Sgshapiro# Server Cert
55564562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
55664562Sgshapiro# Server private key
55764562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
55864562Sgshapiro# Client Cert
55964562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
56064562Sgshapiro# Client private key
56164562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
56264562Sgshapiro# DHParameters (only required if DSA/DH is used)
56364562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
56464562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
56564562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
56664562Sgshapiro
56764562Sgshapiroifdef(`confQUEUE_FILE_MODE',
56864562Sgshapiro`# queue file mode (qf files)
56964562SgshapiroO QueueFileMode=confQUEUE_FILE_MODE
57042575Speter')
57142575Speter
57238032Speter###########################
57338032Speter#   Message precedences   #
57438032Speter###########################
57538032Speter
57638032SpeterPfirst-class=0
57738032SpeterPspecial-delivery=100
57838032SpeterPlist=-30
57938032SpeterPbulk=-60
58038032SpeterPjunk=-100
58138032Speter
58238032Speter#####################
58338032Speter#   Trusted users   #
58438032Speter#####################
58538032Speter
58638032Speter# this is equivalent to setting class "t"
58764562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
58838032SpeterTroot
58938032SpeterTdaemon
59038032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp')
59138032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
59238032Speter
59338032Speter#########################
59438032Speter#   Format of headers   #
59538032Speter#########################
59638032Speter
59738032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
59838032SpeterH?P?Return-Path: <$g>
59938032SpeterHReceived: confRECEIVED_HEADER
60038032SpeterH?D?Resent-Date: $a
60138032SpeterH?D?Date: $a
60238032SpeterH?F?Resent-From: confFROM_HEADER
60338032SpeterH?F?From: confFROM_HEADER
60438032SpeterH?x?Full-Name: $x
60538032Speter# HPosted-Date: $a
60638032Speter# H?l?Received-Date: $b
60738032SpeterH?M?Resent-Message-Id: <$t.$i@$j>
60838032SpeterH?M?Message-Id: <$t.$i@$j>
60964562Sgshapiro
61038032Speter#
61138032Speter######################################################################
61238032Speter######################################################################
61338032Speter#####
61438032Speter#####			REWRITING RULES
61538032Speter#####
61638032Speter######################################################################
61738032Speter######################################################################
61838032Speter
61938032Speter############################################
62038032Speter###  Ruleset 3 -- Name Canonicalization  ###
62138032Speter############################################
62264562SgshapiroScanonify=3
62338032Speter
62438032Speter# handle null input (translate to <@> special case)
62538032SpeterR$@			$@ <@>
62638032Speter
62738032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
62838032SpeterR$*			$: $1 <@>			mark addresses
62938032SpeterR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
63038032SpeterR@ $* <@>		$: @ $1				unmark @host:...
63138032SpeterR$* :: $* <@>		$: $1 :: $2			unmark node::addr
63238032SpeterR:`include': $* <@>	$: :`include': $1			unmark :`include':...
63364562SgshapiroR$* [ IPv6 $- ] <@>	$: $1 [ IPv6 $2 ]		unmark IPv6 addr
63438032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
63538032SpeterR$* : $* <@>		$: $2				strip colon if marked
63638032SpeterR$* <@>			$: $1				unmark
63738032SpeterR$* ;			   $1				strip trailing semi
63871345SgshapiroR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
63938032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
64038032Speter
64138032Speter# null input now results from list:; syntax
64238032SpeterR$@			$@ :; <@>
64338032Speter
64438032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
64538032SpeterR$*			$: < $1 >			housekeeping <>
64638032SpeterR$+ < $* >		   < $2 >			strip excess on left
64738032SpeterR< $* > $+		   < $1 >			strip excess on right
64838032SpeterR<>			$@ < @ >			MAIL FROM:<> case
64938032SpeterR< $+ >			$: $1				remove housekeeping <>
65038032Speter
65164562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
65238032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
65338032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
65438032Speter
65538032Speter# localize and dispose of route-based addresses
65664562SgshapiroR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
65764562Sgshapirodnl',`dnl
65864562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d>
65964562SgshapiroR@ $+ , $+		$2
66064562SgshapiroR@ $+ : $+		$2
66164562Sgshapirodnl')
66238032Speter
66338032Speter# find focus for list syntax
66464562SgshapiroR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
66538032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
66638032Speter
66738032Speter# find focus for @ syntax addresses
66838032SpeterR$+ @ $+		$: $1 < @ $2 >			focus on domain
66938032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
67064562SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
67138032Speter
67238032Speter# do some sanity checking
67338032SpeterR$* < @ $* : $* > $*	$1 < @ $2 $3 > $4		nix colons in addrs
67438032Speter
67538032Speterifdef(`_NO_UUCP_', `dnl',
67638032Speter`# convert old-style addresses to a domain-based address
67764562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
67864562SgshapiroR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
67964562SgshapiroR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
68038032Speter')
68138032Speterifdef(`_USE_DECNET_SYNTAX_',
68238032Speter`# convert node::user addresses into a domain-based address
68364562SgshapiroR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
68464562SgshapiroR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
68538032Speter',
68638032Speter	`dnl')
68738032Speter# if we have % signs, take the rightmost one
68838032SpeterR$* % $*		$1 @ $2				First make them all @s.
68938032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
69064562SgshapiroR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
69138032Speter
69238032Speter# else we must be a local name
69364562SgshapiroR$*			$@ $>Canonify2 $1
69438032Speter
69538032Speter
69638032Speter################################################
69738032Speter###  Ruleset 96 -- bottom half of ruleset 3  ###
69838032Speter################################################
69938032Speter
70064562SgshapiroSCanonify2=96
70138032Speter
70238032Speter# handle special cases for local names
70338032SpeterR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
70438032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
70538032Speterifdef(`_NO_UUCP_', `dnl',
70638032Speter`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
70764562Sgshapiro
70864562Sgshapiro# check for IPv6 domain literal (save quoted form)
70964562SgshapiroR$* < @ [ IPv6 $- ] > $*	$: $2 $| $1 < @@ [ $(dequote $2 $) ] > $3	mark IPv6 addr
71064562SgshapiroR$- $| $* < @@ $=w > $*		$: $2 < @ $j . > $4		self-literal
71164562SgshapiroR$- $| $* < @@ [ $+ ] > $*	$@ $2 < @ [ IPv6 $1 ] > $4	canon IP addr
71264562Sgshapiro
71364562Sgshapiro# check for IPv4 domain literal
71438032SpeterR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [a.b.c.d]
71538032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
71638032SpeterR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
71738032Speter
71864562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl
71938032Speter# look up domains in the domain table
72038032SpeterR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
72138032Speter
72264562Sgshapiroundivert(2)dnl LOCAL_RULE_3
72338032Speter
72464562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl
72538032Speter# handle BITNET mapping
72638032SpeterR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
72738032Speter
72864562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl
72938032Speter# handle UUCP mapping
73038032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
73138032Speter
73238032Speterifdef(`_NO_UUCP_', `dnl',
73338032Speter`ifdef(`UUCP_RELAY',
73438032Speter`# pass UUCP addresses straight through
73538032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
73638032Speter`# if really UUCP, handle it immediately
73738032Speterifdef(`_CLASS_U_',
73838032Speter`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
73938032Speterifdef(`_CLASS_V_',
74038032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
74138032Speterifdef(`_CLASS_W_',
74238032Speter`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
74338032Speterifdef(`_CLASS_X_',
74438032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
74538032Speterifdef(`_CLASS_Y_',
74638032Speter`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
74738032Speter
74838032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl
74938032Speter# try UUCP traffic as a local address
75038032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
75138032SpeterR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
75238032Speter')')
75364562Sgshapiro# hostnames ending in class P are always canonical
75464562SgshapiroR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
75564562Sgshapirodnl apply the next rule only for hostnames not in class P
75664562Sgshapirodnl this even works for phrases in class P since . is in class P
75764562Sgshapirodnl which daemon flags are set?
75864562SgshapiroR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
75964562Sgshapirodnl the other rules in this section only apply if the hostname
76064562Sgshapirodnl does not end in class P hence no further checks are done here
76164562Sgshapirodnl if this ever changes make sure the lookups are "protected" again!
76264562Sgshapiroifdef(`_NO_CANONIFY_', `dnl
76364562Sgshapirodnl do not canonify unless:
76464562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection
76564562Sgshapirodnl	with class P is non-empty)
76664562Sgshapirodnl or {daemon_flags} has c set
76764562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify}
76864562SgshapiroR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
76964562Sgshapiro# pass to name server to make hostname canonical if requested
77064562SgshapiroR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
77164562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_
77264562SgshapiroR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
77364562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work
77464562SgshapiroR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
77564562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl
77664562Sgshapirodnl this should only apply to unqualified hostnames
77764562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
77864562Sgshapirodnl then $- does not work.
77964562Sgshapiro# lookup unqualified hostnames
78064562SgshapiroR$* $| $* < @ $* > $*	$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
78164562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
78264562Sgshapirodnl {daemon_flags} contains CC (do not canonify)
78371345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work
78471345Sgshapirodnl should we do this for every hostname: even unqualified?
78571345SgshapiroR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
78664562SgshapiroR$* CC $* $| $*			$: $3
78738032Speter# pass to name server to make hostname canonical
78864562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
78964562Sgshapirodnl remove {daemon_flags} for other cases
79064562SgshapiroR$* $| $*			$: $2
79138032Speter
79238032Speter# local host aliases and pseudo-domains are always canonical
79338032SpeterR$* < @ $=w > $*		$: $1 < @ $2 . > $3
79438032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
79538032Speter`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
79638032Speter`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
79764562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
79864562Sgshapirodnl virtual hosts are also canonical
79964562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
80064562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
80164562Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
80264562Sgshapiro`dnl')
80364562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added
80464562Sgshapirodnl by one of the rules before
80538032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
80638032Speter
80738032Speter
80838032Speter##################################################
80938032Speter###  Ruleset 4 -- Final Output Post-rewriting  ###
81038032Speter##################################################
81164562SgshapiroSfinal=4
81238032Speter
81371345SgshapiroR$+ :; <@>		$@ $1 :				handle <list:;>
81438032SpeterR$* <@>			$@				handle <> and list:;
81538032Speter
81638032Speter# strip trailing dot off possibly canonical name
81738032SpeterR$* < @ $+ . > $*	$1 < @ $2 > $3
81838032Speter
81964562Sgshapiro# eliminate internal code
82038032SpeterR$* < @ *LOCAL* > $*	$1 < @ $j > $2
82138032Speter
82238032Speter# externalize local domain info
82338032SpeterR$* < $+ > $*		$1 $2 $3			defocus
82438032SpeterR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
82538032SpeterR@ $*			$@ @ $1				... and exit
82638032Speter
82738032Speterifdef(`_NO_UUCP_', `dnl',
82838032Speter`# UUCP must always be presented in old form
82938032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
83038032Speter
83138032Speterifdef(`_USE_DECNET_SYNTAX_',
83238032Speter`# put DECnet back in :: form
83338032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
83438032Speter	`dnl')
83538032Speter# delete duplicate local names
83638032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
83738032Speter
83838032Speter
83938032Speter
84038032Speter##############################################################
84138032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
84238032Speter###		   (used for recursive calls)		   ###
84338032Speter##############################################################
84438032Speter
84564562SgshapiroSRecurse=97
84664562SgshapiroR$*			$: $>canonify $1
84764562SgshapiroR$*			$@ $>parse $1
84838032Speter
84938032Speter
85038032Speter######################################
85138032Speter###   Ruleset 0 -- Parse Address   ###
85238032Speter######################################
85338032Speter
85464562SgshapiroSparse=0
85538032Speter
85638032SpeterR$*			$: $>Parse0 $1		initial parsing
85738032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
85864562SgshapiroR$*			$: $>ParseLocal $1	handle local hacks
85938032SpeterR$*			$: $>Parse1 $1		final parsing
86038032Speter
86138032Speter#
86238032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
86338032Speter#	This should either return with the (possibly modified) input
86438032Speter#	or return with a #error mailer.  It should not return with a
86538032Speter#	#mailer other than the #error mailer.
86638032Speter#
86738032Speter
86838032SpeterSParse0
86938032SpeterR<@>			$@ <@>			special case error msgs
87066494SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "501 List:; syntax illegal for recipient addresses"
87164562SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
87266494SgshapiroR<@ $+>			$#error $@ 5.1.3 $: "501 User address required"
87338032SpeterR$*			$: <> $1
87438032SpeterR<> $* < @ [ $+ ] > $*	$1 < @ [ $2 ] > $3
87566494SgshapiroR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "501 Colon illegal in host name part"
87638032SpeterR<> $*			$1
87766494SgshapiroR$* < @ . $* > $*	$#error $@ 5.1.2 $: "501 Invalid host name"
87866494SgshapiroR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "501 Invalid host name"
87964562Sgshapirodnl comma only allowed before @; this check is not complete
88066494SgshapiroR$* , $~O $*		$#error $@ 5.1.2 $: "501 Invalid route address"
88138032Speter
88238032Speter# now delete the local info -- note $=O to find characters that cause forwarding
88364562SgshapiroR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
88464562SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
88538032SpeterR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
88666494SgshapiroR< @ $+ >		$#error $@ 5.1.3 $: "501 User address required"
88764562SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
88838032SpeterR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
88966494SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "501 User address required"
89038032SpeterR$* $=O $* < @ *LOCAL* >
89164562Sgshapiro			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
89238032SpeterR$* < @ *LOCAL* >	$: $1
89338032Speter
89438032Speter#
89538032Speter#  Parse1 -- the bottom half of ruleset 0.
89638032Speter#
89738032Speter
89838032SpeterSParse1
89964562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
90064562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute}
90164562SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2>',
90264562Sgshapiro`dnl')
90364562Sgshapiro
90438032Speterifdef(`_MAILER_smtp_',
90538032Speter`# handle numeric address spec
90664562Sgshapirodnl there is no check whether this is really an IP number
90764562SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
90864562SgshapiroR$* < @ [ $+ ] > $*	$1 < @ [ $2 ] : $S > $3		Add smart host to path
90964562SgshapiroR$* < @ [ IPv6 $- ] : > $*
91064562Sgshapiro		$#_SMTP_ $@ [ $(dequote $2 $) ] $: $1 < @ [IPv6 $2 ] > $3	no smarthost: send
91164562SgshapiroR$* < @ [ $+ ] : > $*	$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
91264562SgshapiroR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
91364562SgshapiroR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
91438032Speter	`dnl')
91538032Speter
91664562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
91738032Speter# handle virtual users
91864562SgshapiroR$+			$: <!> $1		Mark for lookup
91964562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
92064562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
92164562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
92264562SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
92338032SpeterR<@> $+ + $* < @ $* . >
92464562Sgshapiro			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
92538032SpeterR<@> $+ + $* < @ $* . >
92638032Speter			$: < $(virtuser $1 @ $3 $@ $1 $: @ $) > $1 + $2 < @ $3 . >
92764562Sgshapirodnl try default entry: @domain
92864562Sgshapirodnl +*@domain
92964562SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
93064562Sgshapirodnl @domain if +detail exists
93164562SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
93264562Sgshapirodnl without +detail (or no match)
93338032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
93438032SpeterR<@> $+			$: $1
93564562SgshapiroR<!> $+			$: $1
93664562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
93738032SpeterR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
93864562SgshapiroR< $+ > $+ < @ $+ >	$: $>Recurse $1',
93938032Speter`dnl')
94038032Speter
94138032Speter# short circuit local delivery so forwarded email works
94238032Speterifdef(`_MAILER_usenet_', `dnl
94364562SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
94466494Sgshapiro
94566494Sgshapiro
94638032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
94738032Speter`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
94864562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
94964562Sgshapirodnl $H empty (but @$=w.)
95038032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
95138032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
95264562Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
95338032SpeterR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
95438032Speter
95564562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
95638032Speter# not local -- try mailer table lookup
95738032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
95838032SpeterR< $+ . > $*		$: < $1 > $2			strip trailing dot
95938032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
96064562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
96164562SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
96264562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
96338032Speter`dnl')
96464562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)'
96538032Speter
96638032Speterifdef(`_NO_UUCP_', `dnl',
96738032Speter`# resolve remotely connected UUCP links (if any)
96838032Speterifdef(`_CLASS_V_',
96964562Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
97038032Speter	`dnl')
97138032Speterifdef(`_CLASS_W_',
97264562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
97338032Speter	`dnl')
97438032Speterifdef(`_CLASS_X_',
97564562Sgshapiro`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
97638032Speter	`dnl')')
97738032Speter
97838032Speter# resolve fake top level domains by forwarding to other hosts
97938032Speterifdef(`BITNET_RELAY',
98064562Sgshapiro`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
98138032Speter	`dnl')
98238032Speterifdef(`DECNET_RELAY',
98364562Sgshapiro`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
98438032Speter	`dnl')
98538032Speterifdef(`_MAILER_pop_',
98638032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
98738032Speter	`dnl')
98838032Speterifdef(`_MAILER_fax_',
98938032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
99038032Speter`ifdef(`FAX_RELAY',
99164562Sgshapiro`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
99238032Speter	`dnl')')
99338032Speter
99438032Speterifdef(`UUCP_RELAY',
99538032Speter`# forward non-local UUCP traffic to our UUCP relay
99664562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
99738032Speter`ifdef(`_MAILER_uucp_',
99838032Speter`# forward other UUCP traffic straight to UUCP
99938032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
100038032Speter	`dnl')')
100138032Speterifdef(`_MAILER_usenet_', `
100238032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
100364562SgshapiroR$+ . USENET		$#usenet $@ usenet $: $1',
100438032Speter	`dnl')
100538032Speter
100638032Speterifdef(`_LOCAL_RULES_',
100738032Speter`# figure out what should stay in our local mail system
100838032Speterundivert(1)', `dnl')
100938032Speter
101038032Speter# pass names that still have a host to a smarthost (if defined)
101164562SgshapiroR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
101238032Speter
101338032Speter# deal with other remote names
101438032Speterifdef(`_MAILER_smtp_',
101564562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
101666494Sgshapiro`R$* < @$* > $*		$#error $@ 5.1.2 $: "501 Unrecognized host name " $2')
101738032Speter
101838032Speter# handle locally delivered names
101964562SgshapiroR$=L			$#_LOCAL_ $: @ $1		special local names
102038032SpeterR$+			$#_LOCAL_ $: $1			regular local names
102138032Speter
102238032Speter###########################################################################
102338032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
102438032Speter###########################################################################
102538032Speter
102664562SgshapiroSLocal_localaddr
102764562SgshapiroSlocaladdr=5
102864562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
102964562SgshapiroR$+ $| $#$*		$#$2
103064562SgshapiroR$+ $| $*		$: $1
103138032Speter
103266494Sgshapiroifdef(`_FFR_5_', `
103366494Sgshapiro# Preserve host in a macro
103466494SgshapiroR$+			$: $(macro {LocalAddrHost} $) $1
103566494SgshapiroR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
103666494Sgshapiro
103766494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `
103838032Speter# deal with plussed users so aliases work nicely
103966494SgshapiroR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
104066494SgshapiroR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
104166494Sgshapiro')
104238032Speter# prepend an empty "forward host" on the front
104338032SpeterR$+			$: <> $1
104438032Speter
104538032Speterifdef(`LUSER_RELAY', `dnl
104638032Speter# send unrecognized local users to a relay host
104766494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `
104866494SgshapiroR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
104966494SgshapiroR< > $+			$: < ? $L > < > $(user $1 $)	look up user
105066494SgshapiroR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
105166494SgshapiroR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
105264562SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
105366494SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L')',
105438032Speter`dnl')
105538032Speter
105638032Speter# see if we have a relay or a hub
105738032SpeterR< > $+			$: < $H > $1			try hub
105838032SpeterR< > $+			$: < $R > $1			try relay
105966494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `
106066494SgshapiroR< > $+			$@ $1', `
106164562SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
106264562SgshapiroR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
106364562SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
106438032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
106566494SgshapiroR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
106638032SpeterR< > < $+ >		$@ $1				no +detail
106743730SpeterR$+			$: $1 <> $&h			add +detail back in
106843730SpeterR$+ <> + $*		$: $1 + $2			check whether +detail
106966494SgshapiroR$+ <> $*		$: $1				else discard')
107064562SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
107164562SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
107264562SgshapiroR< $- : $+ > $+		$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
107364562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
107438032Speter
107564562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
107638032Speter###################################################################
107738032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
107864562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
107938032Speter###################################################################
108038032Speter
108164562SgshapiroSMailertable=90
108264562Sgshapirodnl shift and check
108364562Sgshapirodnl %2 is not documented in cf/README
108438032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
108564562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
108664562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
108764562SgshapiroR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
108864562Sgshapirodnl is $2 always empty?
108938032SpeterR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
109064562SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
109164562Sgshapirodnl return full address
109238032SpeterR< $* > $*		$@ $2				no mailertable match',
109338032Speter`dnl')
109438032Speter
109538032Speter###################################################################
109638032Speter###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
109764562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
109864562Sgshapirodnl	<> address				-> address
109964562Sgshapirodnl	<error:d.s.n:text>			-> error
110064562Sgshapirodnl	<error:text>				-> error
110164562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
110264562Sgshapirodnl	<mailer:host> address			-> mailer host address
110364562Sgshapirodnl	<localdomain> address			-> address
110464562Sgshapirodnl	<[IPv6 number]> address			-> relay number address
110564562Sgshapirodnl	<host> address				-> relay host address
110638032Speter###################################################################
110738032Speter
110864562SgshapiroSMailerToTriple=95
110938032SpeterR< > $*				$@ $1			strip off null relay
111064562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
111138032SpeterR< error : $- $+ > $*		$#error $@ $(dequote $1 $) $: $2
111238032SpeterR< local : $* > $*		$>CanonLocal < $1 > $2
111338032SpeterR< $- : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
111438032SpeterR< $- : $+ > $*			$# $1 $@ $2 $: $3	try qualified mailer
111538032SpeterR< $=w > $*			$@ $2			delete local host
111664562SgshapiroR< [ IPv6 $+ ] > $*		$#_RELAY_ $@ $(dequote $1 $) $: $2	use unqualified mailer
111738032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
111838032Speter
111938032Speter###################################################################
112038032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
112164562Sgshapirodnl input: <user> address
112264562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
112364562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
112464562Sgshapirodnl <> user <@host> rest		-> local user@host user
112564562Sgshapirodnl <> user				-> local user user
112664562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
112764562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
112864562Sgshapirodnl <user> lp				-> local lp user
112938032Speter###################################################################
113038032Speter
113138032SpeterSCanonLocal
113243730Speter# strip local host from routed addresses
113364562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
113464562SgshapiroR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
113543730Speter
113638032Speter# strip trailing dot from any host name that may appear
113738032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
113838032Speter
113938032Speter# handle local: syntax -- use old user, either with or without host
114038032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
114138032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
114238032Speter
114338032Speter# handle local:user@host syntax -- ignore host part
114438032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
114538032Speter
114638032Speter# handle local:user syntax
114738032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
114838032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
114938032Speter
115038032Speter###################################################################
115138032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
115238032Speter###################################################################
115338032Speter
115464562SgshapiroSMasqHdr=93
115538032Speter
115664562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
115738032Speter# handle generics database
115838032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
115964562Sgshapirodnl if generics should be applied add a @ as mark
116038032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
116138032Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
116238032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
116364562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
116464562Sgshapirodnl ignore the first case for now
116564562Sgshapirodnl if it has the mark lookup full address
116664562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
116764562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
116864562Sgshapirodnl no match, try user+detail@domain
116964562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
117064562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
117164562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
117264562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
117364562Sgshapirodnl no match, remove mark
117464562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
117564562Sgshapirodnl no match, try @domain for exceptions
117664562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
117764562Sgshapirodnl workspace: ... or <match> user <@domain>
117864562Sgshapirodnl no match, try local part
117938032SpeterR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
118064562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
118164562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
118264562SgshapiroR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
118364562SgshapiroR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
118438032SpeterR< > $*			$: $1				not found',
118538032Speter`dnl')
118638032Speter
118764562Sgshapiro# do not masquerade anything in class N
118864562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
118964562Sgshapiro
119038032Speter# special case the users that should be exposed
119138032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
119238032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
119338032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
119438032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
119538032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
119638032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
119738032Speter
119838032Speter# handle domain-specific masquerading
119938032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
120038032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
120138032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
120238032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
120338032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
120438032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
120538032SpeterR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
120638032SpeterR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
120738032Speter
120838032Speter###################################################################
120938032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
121038032Speter###################################################################
121138032Speter
121264562SgshapiroSMasqEnv=94
121338032Speterifdef(`_MASQUERADE_ENVELOPE_',
121464562Sgshapiro`R$+			$@ $>MasqHdr $1',
121538032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
121638032Speter
121738032Speter###################################################################
121838032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
121938032Speter###################################################################
122038032Speter
122164562SgshapiroSParseLocal=98
122264562Sgshapiroundivert(3)dnl LOCAL_RULE_0
122338032Speter
122464562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
122564562SgshapiroSLDAPExpand
122664562Sgshapiro# do the LDAP lookups
122764562SgshapiroR<$+><$+>		$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2>
122864562Sgshapiro
122964562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
123064562Sgshapiro# return the new mailRoutingAddress
123164562SgshapiroR< $+ > < $=w > < $+ > < $+ >	$@ $>Parse0 $>canonify $1
123264562SgshapiroR< $+ > <  > < $+ > < $+ >	$@ $>Parse0 $>canonify $1
123364562Sgshapiro
123464562Sgshapiro# if mailRoutingAddress and non-local mailHost,
123564562Sgshapiro# relay to mailHost with new mailRoutingAddress
123664562SgshapiroR< $+ > < $+ > < $+ > < $+ >	$#_RELAY_ $@ $2 $: $>canonify $1
123764562Sgshapiro
123864562Sgshapiro# if no mailRoutingAddress and local mailHost,
123964562Sgshapiro# return original address
124064562SgshapiroR< > < $=w > <$+> <$+>		$@ $2
124164562Sgshapiro
124264562Sgshapiro# if no mailRoutingAddress and non-local mailHost,
124364562Sgshapiro# relay to mailHost with original address
124464562SgshapiroR< > < $+ > <$+> <$+>		$#_RELAY_ $@ $1 $: $2
124564562Sgshapiro
124664562Sgshapiro# if no mailRoutingAddress and no mailHost,
124764562Sgshapiro# try @domain
124864562SgshapiroR< > < > <$+> <$+ @ $+>		$@ $>LDAPExpand <$1> <@ $3>
124964562Sgshapiro
125064562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
125164562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
125264562Sgshapiro# user does not exist
125364562SgshapiroR< > < > <$+> <@ $+>		$#error $@ nouser $: "550 User unknown"',
125464562Sgshapiro`dnl
125564562Sgshapiro# return the original address
125664562SgshapiroR< > < > <$+> <@ $+>		$@ $1')',
125764562Sgshapiro`dnl')
125864562Sgshapiro
125964562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
126064562Sgshapiro')')
126164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
126238032Speter######################################################################
126338032Speter###  LookUpDomain -- search for domain in access database
126438032Speter###
126538032Speter###	Parameters:
126638032Speter###		<$1> -- key (domain name)
126738032Speter###		<$2> -- default (what to return if not found in db)
126864562Sgshapirodnl			must not be empty
126938032Speter###		<$3> -- passthru (additional data passed unchanged through)
127064562Sgshapiro###		<$4> -- mark (must be <(!|+) single-token>)
127164562Sgshapiro###			! does lookup only with tag
127264562Sgshapiro###			+ does lookup with and without tag
127364562Sgshapirodnl returns:		<default> <passthru>
127464562Sgshapirodnl 			<result> <passthru>
127538032Speter######################################################################
127638032Speter
127738032SpeterSLookUpDomain
127864562Sgshapirodnl remove IPv6 mark and dequote address
127964562Sgshapirodnl it is a bit ugly because it is checked on each "iteration"
128064562SgshapiroR<[IPv6 $-]> <$+> <$*> <$*>	$: <[$(dequote $1 $)]> <$2> <$3> <$4>
128164562Sgshapirodnl workspace <key> <default> <passthru> <mark>
128264562Sgshapirodnl lookup with tag (in front, no delimiter here)
128364562SgshapiroR<$*> <$+> <$*> <$- $->		$: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5>
128464562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
128564562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest
128664562SgshapiroR<?> <$+.$+> <$+> <$*> <$- $->	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4> <$5 $6>', `dnl')
128764562Sgshapirodnl lookup without tag?
128864562SgshapiroR<?> <$+> <$+> <$*> <+ $*>	$: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4>
128964562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest
129064562SgshapiroR<?> <$+.$+> <$+> <$*> <+ $*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <$4> <+ $5>', `dnl')
129164562Sgshapirodnl lookup IP address (no check is done whether it is an IP number!)
129264562SgshapiroR<?> <[$+.$-]> <$+> <$*> <$*>	$@ $>LookUpDomain <[$1]> <$3> <$4> <$5>
129364562Sgshapirodnl lookup IPv6 address
129471345SgshapiroR<?> <[$+::$-]> <$+> <$*> <$*>	$: $>LookUpDomain <[$1]> <$3> <$4> <$5>
129564562SgshapiroR<?> <[$+:$-]> <$+> <$*> <$*>	$: $>LookUpDomain <[$1]> <$3> <$4> <$5>
129664562Sgshapirodnl not found, but subdomain: try again
129764562SgshapiroR<?> <$+.$+> <$+> <$*> <$*>	$@ $>LookUpDomain <$2> <$3> <$4> <$5>
129864562Sgshapirodnl not found, no subdomain: return default
129964562SgshapiroR<?> <$+> <$+> <$*> <$*>	$@ <$2> <$3>
130064562Sgshapirodnl return result of lookup
130164562SgshapiroR<$*> <$+> <$+> <$*> <$*>	$@ <$1> <$4>
130238032Speter
130338032Speter######################################################################
130438032Speter###  LookUpAddress -- search for host address in access database
130538032Speter###
130638032Speter###	Parameters:
130738032Speter###		<$1> -- key (dot quadded host address)
130838032Speter###		<$2> -- default (what to return if not found in db)
130964562Sgshapirodnl			must not be empty
131038032Speter###		<$3> -- passthru (additional data passed through)
131164562Sgshapiro###		<$4> -- mark (must be <(!|+) single-token>)
131264562Sgshapiro###			! does lookup only with tag
131364562Sgshapiro###			+ does lookup with and without tag
131464562Sgshapirodnl	returns:	<default> <passthru>
131564562Sgshapirodnl			<result> <passthru>
131638032Speter######################################################################
131738032Speter
131838032SpeterSLookUpAddress
131964562Sgshapirodnl lookup with tag
132064562SgshapiroR<$+> <$+> <$*> <$- $+>		$: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5>
132164562Sgshapirodnl lookup without tag
132264562SgshapiroR<?> <$+> <$+> <$*> <+ $+>	$: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4>
132364562Sgshapirodnl no match; IPv6: remove last part
132471345SgshapiroR<?> <$+::$-> <$+> <$*> <$*>	$@ $>LookUpAddress <$1> <$3> <$4> <$5>
132564562SgshapiroR<?> <$+:$-> <$+> <$*> <$*>	$@ $>LookUpAddress <$1> <$3> <$4> <$5>
132664562Sgshapirodnl no match; IPv4: remove last part
132764562SgshapiroR<?> <$+.$-> <$+> <$*> <$*>	$@ $>LookUpAddress <$1> <$3> <$4> <$5>
132864562Sgshapirodnl no match: return default
132964562SgshapiroR<?> <$+> <$+> <$*> <$*>	$@ <$2> <$3>
133064562Sgshapirodnl match: return result
133164562SgshapiroR<$*> <$+> <$+> <$*> <$*>	$@ <$1> <$4>',
133238032Speter`dnl')
133338032Speter
133438032Speter######################################################################
133542575Speter###  CanonAddr --	Convert an address into a standard form for
133642575Speter###			relay checking.  Route address syntax is
133742575Speter###			crudely converted into a %-hack address.
133842575Speter###
133942575Speter###	Parameters:
134042575Speter###		$1 -- full recipient address
134142575Speter###
134242575Speter###	Returns:
134342575Speter###		parsed address, not in source route form
134464562Sgshapirodnl		user%host%host<@domain>
134564562Sgshapirodnl		host!user<@domain>
134642575Speter######################################################################
134742575Speter
134842575SpeterSCanonAddr
134964562SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
135064562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
135142575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
135242575SpeterR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
135342575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
135464562Sgshapirodnl')
135542575Speter
135642575Speter######################################################################
135738032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
135838032Speter###			$* $=m or the access database.
135938032Speter###			Check user portion for host separators.
136038032Speter###
136138032Speter###	Parameters:
136238032Speter###		$1 -- full recipient address
136338032Speter###
136438032Speter###	Returns:
136538032Speter###		parsed, non-local-relaying address
136638032Speter######################################################################
136738032Speter
136838032SpeterSParseRecipient
136964562Sgshapirodnl mark and canonify address
137042575SpeterR$*				$: <?> $>CanonAddr $1
137164562Sgshapirodnl workspace: <?> localpart<@domain[.]>
137242575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
137364562Sgshapirodnl workspace: <?> localpart<@domain>
137442575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
137538032Speter
137638032Speter# if no $=O character, no host in the user portion, we are done
137742575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
137864562Sgshapirodnl no $=O in localpart: return
137942575SpeterR<?> $*				$@ $1
138038032Speter
138164562Sgshapirodnl workspace: <?> localpart<@domain>, where localpart contains $=O
138264562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
138338032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
138438032Speter# if we relay, check username portion for user%host so host can be checked also
138542575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
138642575Speter
138742575Speterifdef(`_RELAY_MX_SERVED_', `dnl
138864562Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
138942575SpeterR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
139042575SpeterR<MX> < : $* <TEMP> : > $*	$#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
139164562Sgshapirodnl yes: mark it as <RELAY>
139242575SpeterR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
139364562Sgshapirodnl no: put old <NO> mark back
139442575SpeterR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
139542575Speter
139664562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
139764562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
139838032Speterifdef(`_RELAY_HOSTS_ONLY_',
139942575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
140064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
140164562SgshapiroR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
140242575SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
140342575Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
140464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
140564562SgshapiroR<NO> $* < @ $+ >		$: $>LookUpDomain <$2> <NO> <$1 < @ $2 >> <+To>
140642575SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
140738032Speter
140864562Sgshapiro
140942575SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
141042575SpeterR<$-> $*			$@ $2
141142575Speter
141264562Sgshapiro
141338032Speter######################################################################
141438032Speter###  check_relay -- check hostname/address on SMTP startup
141538032Speter######################################################################
141638032Speter
141738032SpeterSLocal_check_relay
141864562SgshapiroScheck`'_U_`'relay
141938032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
142038032SpeterR$* $| $* $| $#$*	$#$3
142138032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
142238032Speter
142338032SpeterSBasic_check_relay
142438032Speter# check for deferred delivery mode
142538032SpeterR$*			$: < ${deliveryMode} > $1
142638032SpeterR< d > $*		$@ deferred
142738032SpeterR< $* > $*		$: $2
142838032Speter
142964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
143066494Sgshapirodnl workspace: {client_name} $| {client_addr}
143164562SgshapiroR$+ $| $+		$: $>LookUpDomain < $1 > <?> < $2 > <+Connect>
143266494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
143364562SgshapiroR<?> <$+>		$: $>LookUpAddress < $1 > <?> < $1 > <+Connect>	no: another lookup
143466494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
143564562SgshapiroR<?> < $+ >		$: $1					found nothing
143666494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}>
143766494Sgshapirodnl or {client_addr}
143866494SgshapiroR<$={Accept}> < $* >	$@ $1				return value of lookup
143964562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
144038032SpeterR<DISCARD> $*		$#discard $: discard
144164562Sgshapirodnl error tag
144266494SgshapiroR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
144366494SgshapiroR<ERROR:$+> <$*>		$#error $: $1
144464562Sgshapirodnl generic error from access map
144566494SgshapiroR<$+> <$*>		$#error $: $1', `dnl')
144638032Speter
144764562Sgshapiroifdef(`_RBL_',`dnl
144864562Sgshapiro# DNS based IP address spam list
144938032SpeterR$*			$: $&{client_addr}
145064562SgshapiroR::ffff:$-.$-.$-.$-	$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
145164562SgshapiroR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
145264562SgshapiroR<?>OK			$: OKSOFAR
145364562SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"',
145438032Speter`dnl')
145564562Sgshapiroundivert(8)
145638032Speter
145738032Speter######################################################################
145838032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
145938032Speter######################################################################
146038032Speter
146138032SpeterSLocal_check_mail
146264562SgshapiroScheck`'_U_`'mail
146338032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
146438032SpeterR$* $| $#$*		$#$2
146538032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
146638032Speter
146738032SpeterSBasic_check_mail
146838032Speter# check for deferred delivery mode
146938032SpeterR$*			$: < ${deliveryMode} > $1
147038032SpeterR< d > $*		$@ deferred
147138032SpeterR< $* > $*		$: $2
147238032Speter
147364562Sgshapiro# authenticated?
147464562Sgshapirodnl done first: we can require authentication for every mail transaction
147564562Sgshapirodnl workspace: address as given by MAIL FROM: (sender)
147664562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
147764562SgshapiroR$* $| $#$+		$#$2
147864562Sgshapirodnl undo damage: remove result of tls_client call
147964562SgshapiroR$* $| $*		$: $1
148038032Speter
148164562Sgshapirodnl workspace: address as given by MAIL FROM:
148264562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
148338032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
148464562Sgshapirodnl do some additional checks
148564562Sgshapirodnl no user@host
148664562Sgshapirodnl no user@localhost (if nonlocal sender)
148764562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
148864562Sgshapirodnl just make sure the address has <> around it (which is required by
148964562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
149064562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
149164562Sgshapirodnl not be modified by host lookups.
149264562SgshapiroR$+			$: <?> $1
149364562SgshapiroR<?><$+>		$: <@> <$1>
149464562SgshapiroR<?>$+			$: <@> <$1>
149564562Sgshapirodnl workspace: <@> <address>
149664562Sgshapirodnl prepend daemon_flags
149764562SgshapiroR$*			$: $&{daemon_flags} $| $1
149864562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
149964562Sgshapirodnl do not allow these at all or only from local systems?
150064562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
150164562Sgshapirodnl accept unqualified sender: change mark to avoid test
150264562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
150364562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
150464562Sgshapirodnl        or:                    <? ${client_name} > <address>
150564562Sgshapirodnl        or:                    <?> <address>
150664562Sgshapirodnl remove daemon_flags
150764562SgshapiroR$* $| $*		$: $2
150838032Speter# handle case of @localhost on address
150964562SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
151064562SgshapiroR<@> < $* @ [127.0.0.1] >
151164562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
151264562SgshapiroR<@> < $* @ localhost.$m >
151364562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
151438032Speterifdef(`_NO_UUCP_', `dnl',
151564562Sgshapiro`R<@> < $* @ localhost.UUCP >
151664562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
151764562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
151864562Sgshapirodnl	or:    <@> <address>
151964562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
152064562SgshapiroR<@> $*			$: $1			no localhost as domain
152164562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
152264562Sgshapirodnl	or:    <address>
152364562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
152464562SgshapiroR<? $=w> $*		$: $2			local client: ok
152566494SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "501 Real domain name required for sender address"
152664562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
152764562SgshapiroR<?> $*			$: $1')
152864562Sgshapirodnl workspace: address (or <address>)
152964562SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
153064562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
153164562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
153264562SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
153364562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
153464562SgshapiroR<?> $* < @ $* $=P >	$: <OK> $1 < @ $2 $3 >
153564562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
153664562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
153764562Sgshapiro`R<?> $* < @ $+ >	$: <OK> $1 < @ $2 >		... unresolvable OK',
153864562Sgshapiro`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
153964562SgshapiroR<? $* <$->> $* < @ $+ >
154064562Sgshapiro			$: <$2> $3 < @ $4 >')
154164562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, OK, PERM, TEMP
154264562Sgshapirodnl mark is ? iff the address is user (wo @domain)
154338032Speter
154464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
154564562Sgshapiro# check sender address: user@address, user@, address
154664562Sgshapirodnl should we remove +ext from user?
154764562Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, OK, PERM, TEMP
154864562SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <H:$3>
154964562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
155064562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
155164562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
155264562Sgshapirodnl will only return user<@domain when "reversing" the args
155364562SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+From> $| <$3> <>
155464562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
155564562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
155664562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
155738032Speter# retransform for further use
155864562Sgshapirodnl required form:
155964562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
156064562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
156164562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
156264562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
156364562Sgshapirodnl mark is ? iff the address is user (wo @domain)
156438032Speter
156538032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
156638032Speter# handle case of no @domain on address
156764562Sgshapirodnl prepend daemon_flags
156864562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
156964562Sgshapirodnl accept unqualified sender: change mark to avoid test
157064562SgshapiroR$* u $* $| <?> $*	$: <OK> $3
157164562Sgshapirodnl remove daemon_flags
157264562SgshapiroR$* $| $*		$: $2
157338032SpeterR<?> $*			$: < ? $&{client_name} > $1
157438032SpeterR<?> $*			$@ <OK>				...local unqualed ok
157566494SgshapiroR<? $+> $*		$#error $@ 5.5.4 $: "501 Domain name required for sender address " $&f
157638032Speter							...remote is not')
157738032Speter# check results
157864562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
157938032SpeterR<OK> $*		$@ <OK>
158064562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
158164562SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "501 Domain of sender address " $&f " does not exist"
158264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
158364562SgshapiroR<$={Accept}> $*	$# $1
158438032SpeterR<DISCARD> $*		$#discard $: discard
158564562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
158664562Sgshapirodnl error tag
158764562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
158864562SgshapiroR<ERROR:$+> $*		$#error $: $1
158964562Sgshapirodnl generic error from access map
159064562SgshapiroR<$+> $*		$#error $: $1		error from access db',
159138032Speter`dnl')
159238032Speter
159338032Speter######################################################################
159438032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
159538032Speter######################################################################
159638032Speter
159738032SpeterSLocal_check_rcpt
159864562SgshapiroScheck`'_U_`'rcpt
159938032SpeterR$*			$: $1 $| $>"Local_check_rcpt" $1
160038032SpeterR$* $| $#$*		$#$2
160138032SpeterR$* $| $*		$@ $>"Basic_check_rcpt" $1
160238032Speter
160338032SpeterSBasic_check_rcpt
160438032Speter# check for deferred delivery mode
160538032SpeterR$*			$: < ${deliveryMode} > $1
160638032SpeterR< d > $*		$@ deferred
160738032SpeterR< $* > $*		$: $2
160838032Speter
160964562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
161064562Sgshapiro# require qualified recipient?
161164562SgshapiroR$+			$: <?> $1
161264562SgshapiroR<?><$+>		$: <@> <$1>
161364562SgshapiroR<?>$+			$: <@> <$1>
161464562Sgshapirodnl prepend daemon_flags
161564562SgshapiroR$*			$: $&{daemon_flags} $| $1
161664562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
161764562Sgshapirodnl do not allow these at all or only from local systems?
161864562SgshapiroR$* r $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
161964562SgshapiroR<?> < $* >		$: <$1>
162064562SgshapiroR<? $=w> < $* >		$: <$1>
162164562SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Domain name required"
162264562Sgshapirodnl remove daemon_flags for other cases
162364562SgshapiroR$* $| <@> $*		$: $2', `dnl')
162464562Sgshapiro
162538032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
162642575SpeterR$*			$: $>CanonAddr $1
162738032SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
162838032Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
162938032Speter
163042575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
163142575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
163242575Speter# unlimited bestmx
163342575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
163442575Speter`dnl
163542575Speter# limit bestmx to $=B
163643730SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
163764562SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Basic_check_rcpt" $1 $2 $3
163842575SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
163942575SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
164042575Speter
164138032Speterifdef(`_BLACKLIST_RCPT_',`dnl
164264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
164338032Speter# blacklist local users or any host from receiving mail
164438032SpeterR$*			$: <?> $1
164564562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
164664562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
164764562SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <H:$2>
164864562SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <H:$2>
164964562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
165064562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
165164562Sgshapirodnl will only return user<@domain when "reversing" the args
165264562SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+To> $| <$2> <>
165364562SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
165464562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
165564562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
165664562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
165764562Sgshapirodnl we have to filter these because otherwise they would be interpreted
165864562Sgshapirodnl as generic error message...
165964562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
166064562Sgshapirodnl that would make a lot of things easier.
166164562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
166264562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
166338032SpeterR<REJECT> $*		$#error $@ 5.2.1 $: "550 Mailbox disabled for this recipient"
166464562SgshapiroR<DISCARD> $*		$#discard $: discard
166564562Sgshapirodnl error tag
166664562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
166764562SgshapiroR<ERROR:$+> $*		$#error $: $1
166864562Sgshapirodnl generic error from access map
166964562SgshapiroR<$+> $*		$#error $: $1		error from access db
167064562SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
167138032Speter
167264562Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)')
167364562Sgshapiro# authenticated?
167464562Sgshapirodnl do this unconditionally? this requires to manage CAs carefully
167564562Sgshapirodnl just because someone has a CERT signed by a "trusted" CA
167664562Sgshapirodnl does not mean we want to allow relaying for her,
167764562Sgshapirodnl either use a subroutine or provide something more sophisticated
167864562Sgshapirodnl this could for example check the DN (maybe an access map lookup)
167964562SgshapiroR$*		$: $1 $| $>RelayAuth $1 $| $&{verify}	client authenticated?
168064562SgshapiroR$* $| $# $+		$# $2				error/ok?
168164562SgshapiroR$* $| $*		$: $1				no
168264562Sgshapiro
168364562Sgshapiro# authenticated by a trusted mechanism?
168464562SgshapiroR$*			$: $1 $| $&{auth_type}
168564562Sgshapirodnl empty ${auth_type}?
168664562SgshapiroR$* $|			$: $1
168764562Sgshapirodnl mechanism ${auth_type} accepted?
168864562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
168964562SgshapiroR$* $| $={TrustAuthMech}	$# RELAYAUTH
169064562Sgshapirodnl undo addition of ${auth_type}
169164562SgshapiroR$* $| $*		$: $1
169271345Sgshapirodnl workspace: localpart<@domain> | localpart
169364562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
169471345Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
169571345SgshapiroR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
169638032Speter# anything terminating locally is ok
169738032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
169864562SgshapiroR$+ < @ $* $=m >	$@ RELAYTO', `dnl')
169964562SgshapiroR$+ < @ $=w >		$@ RELAYTO
170038032Speterifdef(`_RELAY_HOSTS_ONLY_',
170164562Sgshapiro`R$+ < @ $=R >		$@ RELAYTO
170264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
170364562SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
170464562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
170564562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
170664562Sgshapiro`R$+ < @ $* $=R >	$@ RELAYTO
170764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
170864562SgshapiroR$+ < @ $+ >		$: $>LookUpDomain <$2> <?> <$1 < @ $2 >> <+To>',`dnl')')
170964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
171064562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
171164562SgshapiroR<RELAY> $*		$@ RELAYTO
171238032SpeterR<$*> <$*>		$: $2',`dnl')
171338032Speter
171464562Sgshapiro
171538032Speterifdef(`_RELAY_MX_SERVED_', `dnl
171638032Speter# allow relaying for hosts which we MX serve
171764562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
171864562Sgshapirodnl this must not necessarily happen if the client is checked first...
171938032SpeterR< : $* <TEMP> : > $*	$#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
172064562SgshapiroR<$* : $=w . : $*> $*	$@ RELAYTO
172142575SpeterR< : $* : > $*		$: $2',
172238032Speter`dnl')
172338032Speter
172438032Speter# check for local user (i.e. unqualified address)
172538032SpeterR$*			$: <?> $1
172642575SpeterR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
172738032Speter# local user is ok
172864562Sgshapirodnl is it really? the standard requires user@domain, not just user
172964562Sgshapirodnl but we should accept it anyway (maybe making it an option:
173064562Sgshapirodnl RequireFQDN ?)
173164562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
173264562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
173364562SgshapiroR<?> postmaster		$@ TOPOSTMASTER
173464562Sgshapiro# require qualified recipient?
173564562Sgshapirodnl prepend daemon_flags
173664562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
173764562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
173864562Sgshapirodnl do not allow these at all or only from local systems?
173964562Sgshapirodnl r flag? add client_name
174064562SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
174164562Sgshapirodnl no r flag: relay to local user (only local part)
174264562Sgshapiro# no qualified recipient required
174364562SgshapiroR$* $| <?> $+		$@ RELAYTOLOCAL
174464562Sgshapirodnl client_name is empty
174564562SgshapiroR<?> <?> $+		$@ RELAYTOLOCAL
174664562Sgshapirodnl client_name is local
174764562SgshapiroR<? $=w> <?> $+		$@ RELAYTOLOCAL
174864562Sgshapirodnl client_name is not local
174964562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
175064562Sgshapirodnl no qualified recipient required
175164562SgshapiroR<?> $+			$@ RELAYTOLOCAL')
175264562Sgshapirodnl it is a remote user: remove mark and then check client
175338032SpeterR<$+> $*		$: $2
175464562Sgshapirodnl currently the recipient address is not used below
175538032Speter
175638032Speter# anything originating locally is ok
175764562Sgshapiro# check IP address
175864562SgshapiroR$*			$: $&{client_addr}
175964562SgshapiroR$@			$@ RELAYFROM		originated locally
176064562SgshapiroR0			$@ RELAYFROM		originated locally
176164562SgshapiroR$=R $*			$@ RELAYFROM		relayable IP address
176264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
176364562SgshapiroR$*			$: $>LookUpAddress <$1> <?> <$1> <+Connect>
176464562SgshapiroR<RELAY> $* 		$@ RELAYFROM		relayable IP address
176564562SgshapiroR<$*> <$*>		$: $2', `dnl')
176664562SgshapiroR$*			$: [ $1 ]		put brackets around it...
176764562SgshapiroR$=w			$@ RELAYFROM		... and see if it is local
176864562Sgshapiro
176964562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
177064562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
177164562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
177264562Sgshapirodnl input: {client_addr} or something "broken"
177364562Sgshapirodnl just throw the input away; we do not need it.
177464562Sgshapiro# check whether FROM is allowed to use system as relay
177564562SgshapiroR$*			$: <?> $>CanonAddr $&f
177664562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
177764562Sgshapiro# check whether local FROM is ok
177864562SgshapiroR<?> $+ < @ $=w . >	$@ RELAYFROMMAIL	FROM local', `dnl')
177964562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
178064562SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
178164562SgshapiroR<?> $+ < @ $+ >	$: $1 < @ $2 > $| $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<H:$2>') <>
178264562SgshapiroR$* <RELAY>		$@ RELAYFROMMAIL	RELAY FROM sender ok', `dnl
178364562Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', `errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
178464562Sgshapiro')',
178564562Sgshapiro`dnl')
178664562Sgshapirodnl')', `dnl')
178764562Sgshapiro
178864562Sgshapiro# check client name: first: did it resolve?
178964562Sgshapirodnl input: ignored
179064562SgshapiroR$*			$: < $&{client_resolve} >
179164562SgshapiroR<TEMP>			$#error $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
179264562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
179364562SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
179464562Sgshapirodnl ${client_resolve} should be OK, so go ahead
179538032SpeterR$*			$: <?> $&{client_name}
179638032Speter# pass to name server to make hostname canonical
179764562SgshapiroR<?> $* $~P 		$:<?>  $[ $1 $2 $]
179864562SgshapiroR$* .			$1			strip trailing dots
179964562Sgshapirodnl should not be necessary since it has been done for client_addr already
180064562SgshapiroR<?>			$@ RELAYFROM
180138032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
180264562SgshapiroR<?> $* $=m		$@ RELAYFROM', `dnl')
180364562SgshapiroR<?> $=w		$@ RELAYFROM
180438032Speterifdef(`_RELAY_HOSTS_ONLY_',
180564562Sgshapiro`R<?> $=R		$@ RELAYFROM
180664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
180764562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
180864562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
180964562Sgshapiro`R<?> $* $=R			$@ RELAYFROM
181064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
181164562SgshapiroR<?> $*			$: $>LookUpDomain <$1> <?> <$1> <+Connect>',`dnl')')
181264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
181364562SgshapiroR<RELAY> $*		$@ RELAYFROM
181438032SpeterR<$*> <$*>		$: $2',`dnl')
181538032Speter
181664562Sgshapiro# anything else is bogus
181764562SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
181864562Sgshapirodivert(0)
181964562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
182064562Sgshapiro# turn a canonical address in the form user<@domain>
182164562Sgshapiro# qualify unqual. addresses with $j
182264562Sgshapirodnl it might have been only user (without <@domain>)
182364562SgshapiroSFullAddr
182464562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
182564562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
182664562SgshapiroR$+			$@ $1 <@ $j >
182738032Speter
182864562Sgshapiro# call all necessary rulesets
182964562SgshapiroScheck_rcpt
183064562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
183164562Sgshapirodnl which is the correct DSN code?
183264562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
183364562SgshapiroR$+			$: $1 $| $>checkrcpt $1
183464562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
183564562SgshapiroR$+ $| $#$*		$#$2
183664562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
183764562Sgshapiroifdef(`_SPAM_FH_',
183864562Sgshapiro`dnl lookup user@ and user@address
183964562Sgshapiroifdef(`_ACCESS_TABLE_', `',
184064562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
184164562Sgshapiro')')dnl
184264562Sgshapirodnl one of the next two rules is supposed to match
184364562Sgshapirodnl this code has been copied from BLACKLIST... etc
184464562Sgshapirodnl and simplified by omitting some < >.
184564562SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <U: $1@>
184664562SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 >
184764562Sgshapirodnl R<?>		$@ something_is_very_wrong_here
184864562Sgshapiro# lookup the addresses only with To tag
184964562SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <!To> $| <$2> <>
185064562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
185164562Sgshapirodnl', `dnl')
185264562Sgshapiroifdef(`_SPAM_FRIEND_',
185364562Sgshapiro`# is the recipient a spam friend?
185464562Sgshapiroifdef(`_SPAM_HATER_',
185564562Sgshapiro	`errprint(`*** ERROR: define either SpamHater or SpamFriend
185664562Sgshapiro')', `dnl')
185764562SgshapiroR<SPAMFRIEND> $+	$@ SPAMFRIEND
185864562SgshapiroR<$*> $+		$: $2',
185964562Sgshapiro`dnl')
186064562Sgshapiroifdef(`_SPAM_HATER_',
186164562Sgshapiro`# is the recipient no spam hater?
186264562SgshapiroR<SPAMHATER> $+		$: $1			spam hater: continue checks
186364562SgshapiroR<$*> $+		$@ NOSPAMHATER		everyone else: stop
186464562Sgshapirodnl',`dnl')
186564562Sgshapirodnl run further checks: check_mail
186664562Sgshapirodnl should we "clean up" $&f?
186764562SgshapiroR$*			$: $1 $| $>checkmail <$&f>
186864562SgshapiroR$* $| $#$*		$#$2
186964562Sgshapirodnl run further checks: check_relay
187064562SgshapiroR$*			$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
187164562SgshapiroR$* $| $#$*		$#$2
187238032SpeterR$* $| $*		$: $1
187338032Speter', `dnl')
187464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
187564562Sgshapiro######################################################################
187664562Sgshapiro###  SearchList: search a list of items in the access map
187764562Sgshapiro###	Parameters:
187864562Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
187964562Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
188064562Sgshapirodnl	avoid errorneous matches (with error messages?)
188164562Sgshapirodnl	if we can make sure that tag is always a single token
188264562Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
188364562Sgshapirodnl	to avoid errorneous matchs (first rule: H: if there
188464562Sgshapirodnl	is that mark somewhere in the list, it will be taken).
188564562Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
188664562Sgshapirodnl	the tag only, e.g.:
188764562Sgshapiro###	where "exact" is either "+" or "!":
188864562Sgshapiro###	<+ TAG>	lookup with and w/o tag
188964562Sgshapiro###	<! TAG>	lookup with tag
189064562Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
189164562Sgshapirodnl		a blank between them and the tag.
189264562Sgshapiro###	possible values for "mark" are:
189364562Sgshapiro###		H: recursive host lookup (LookUpDomain)
189464562Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
189564562Sgshapiro###		E: exact lookup, no modifications
189664562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
189764562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
189864562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
189964562Sgshapiro######################################################################
190038032Speter
190164562Sgshapiro# class with valid marks for SearchList
190264562Sgshapirodnl if A is activated: add it
190364562SgshapiroC{src}E F H U
190464562SgshapiroSSearchList
190564562Sgshapiro# mark H: lookup domain
190664562SgshapiroR<$+> $| <H:$+> <$*>		$: <$1> $| <@> $>LookUpDomain <$2> <?> <$3> <$1>
190764562SgshapiroR<$+> $| <@> <$+> <$*>		$: <$1> $| <$2> <$3>
190864562Sgshapirodnl A: NOT YET REQUIRED
190964562Sgshapirodnl R<$+> $| <A:$+> <$*>	$: <$1> $| <@> $>LookUpAddress <$2> <?> <$3> <$1>
191064562Sgshapirodnl R<$+> $| <@> <$+> <$*>	$: <$1> $| <$2> <$3>
191164562Sgshapirodnl lookup of the item with tag
191264562Sgshapirodnl this applies to F: U: E:
191364562SgshapiroR<$- $-> $| <$={src}:$+> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5>
191464562Sgshapirodnl no match, try without tag
191564562SgshapiroR<+ $-> $| <$={src}:$+> <$*>	$: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4>
191664562Sgshapirodnl do we really have to distinguish these cases?
191764562Sgshapirodnl probably yes, there might be a + in the domain part (is that allowed?)
191864562Sgshapirodnl user+detail lookups: should it be:
191964562Sgshapirodnl user+detail, user+*, user; just like aliases?
192064562SgshapiroR<$- $-> $| <F:$* + $*@$+> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@$5 $: F:$3 + $4@$5$)> <$6>
192164562SgshapiroR<+ $-> $| <F:$* + $*@$+> <$*>	$: <+ $1> $| <$(access $2@$4 $: F:$2 + $3@$4$)> <$5>
192264562Sgshapirodnl user lookups are always with trailing @
192364562Sgshapirodnl do not remove the @ from the lookup:
192464562Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
192564562SgshapiroR<$- $-> $| <U:$* + $*> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5>
192664562Sgshapirodnl no match, try without tag
192764562SgshapiroR<+ $-> $| <U:$* + $*> <$*>	$: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4>
192864562Sgshapirodnl no match, try rest of list
192964562SgshapiroR<$+> $| <$={src}:$+> <$+>	$@ $>SearchList <$1> $| <$4>
193064562Sgshapirodnl no match, list empty: return failure
193164562SgshapiroR<$+> $| <$={src}:$+> <>	$@ <?>
193264562Sgshapirodnl got result, return it
193364562SgshapiroR<$+> $| <$+> <$*>		$@ <$2>
193464562Sgshapirodnl return result from recursive invocation
193564562SgshapiroR<$+> $| <$+>			$@ <$2>', `dnl')
193638032Speter
193764562Sgshapiro# is user trusted to authenticate as someone else?
193864562Sgshapirodnl AUTH= parameter from MAIL command
193964562SgshapiroStrust_auth
194064562SgshapiroR$*			$: $&{auth_type} $| $1
194164562Sgshapiro# required by RFC 2554 section 4.
194264562SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
194364562Sgshapirodnl seems to be useful...
194464562SgshapiroR$* $| $&{auth_authen}		$@ identical
194564562SgshapiroR$* $| <$&{auth_authen}>	$@ identical
194664562Sgshapirodnl call user supplied code
194764562SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $1
194864562SgshapiroR$* $| $#$*		$#$2
194964562Sgshapirodnl default: error
195064562SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
195164562Sgshapiro
195264562Sgshapirodnl empty ruleset definition so it can be called
195364562SgshapiroSLocal_trust_auth
195464562Sgshapiro
195564562Sgshapiroifdef(`_FFR_TLS_O_T', `dnl
195664562SgshapiroSoffer_tls
195764562SgshapiroR$*		$: $>LookUpDomain <$&{client_name}> <?> <> <! TLS_OFF_TAG>
195864562SgshapiroR<?>$*		$: $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_OFF_TAG>
195964562SgshapiroR<?>$*		$: <$(access TLS_OFF_TAG: $: ? $)>
196064562SgshapiroR<?>$*		$@ OK
196164562SgshapiroR<NO> <>	$#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]"
196264562Sgshapiro
196364562SgshapiroStry_tls
196464562SgshapiroR$*		$: $>LookUpDomain <$&{server_name}> <?> <> <! TLS_TRY_TAG>
196564562SgshapiroR<?>$*		$: $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_TRY_TAG>
196664562SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG: $: ? $)>
196764562SgshapiroR<?>$*		$@ OK
196871345SgshapiroR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
196964562Sgshapiro')dnl
197064562Sgshapiro
197164562Sgshapiro# is connection with client "good" enough? (done in server)
197264562Sgshapiro# input: ${verify} $| (MAIL|STARTTLS)
197364562Sgshapirodnl MAIL: called from check_mail
197464562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
197564562SgshapiroStls_client
197664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
197764562Sgshapirodnl ignore second arg for now
197864562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
197964562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
198064562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
198164562SgshapiroR$* $| $*	$: $1 $| $>LookUpDomain <$&{client_name}> <?> <> <! TLS_CLT_TAG>
198264562SgshapiroR$* $| <?>$*	$: $1 $| $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_CLT_TAG>
198364562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
198464562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
198564562SgshapiroR$*		$@ $>"tls_connection" $1', `dnl
198664562SgshapiroR$* $| $*	$@ $>"tls_connection" $1')
198764562Sgshapiro
198864562Sgshapiro# is connection with server "good" enough? (done in client)
198964562Sgshapirodnl i.e. has the server been authenticated and is encryption active?
199064562Sgshapirodnl called from deliver() after STARTTLS command
199164562Sgshapiro# input: ${verify}
199264562SgshapiroStls_server
199364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
199464562SgshapiroR$*		$: $1 $| $>LookUpDomain <$&{server_name}> <?> <> <! TLS_SRV_TAG>
199564562SgshapiroR$* $| <?>$*	$: $1 $| $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_SRV_TAG>
199664562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
199764562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
199864562SgshapiroR$*		$@ $>"tls_connection" $1', `dnl
199964562SgshapiroR$*		$@ $>"tls_connection" $1')
200064562Sgshapiro
200164562SgshapiroStls_connection
200264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
200364562Sgshapirodnl common ruleset for tls_{client|server}
200464562Sgshapirodnl input: $&{verify} $| <ResultOfLookup> [<>]
200564562Sgshapirodnl remove optional <>
200664562SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
200764562Sgshapirodnl permanent or temporary error?
200864562SgshapiroR$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
200964562SgshapiroR$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
201064562Sgshapirodnl default case depends on TLS_PERM_ERR
201164562SgshapiroR$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
201264562Sgshapirodnl deal with TLS handshake failures: abort
201364562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
201464562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
201564562Sgshapirodnl use default error
201664562SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
201764562SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> $1
201864562SgshapiroR$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> $1
201964562Sgshapirodnl some other value in access map: accept
202064562Sgshapirodnl this also allows to override the default case (if used)
202164562SgshapiroR$* $| $*			$@ OK
202264562Sgshapiro# authentication required: give appropriate error
202364562Sgshapiro# other side did authenticate (via STARTTLS)
202464562Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> ${verify}
202564562Sgshapirodnl only verification required and it succeeded
202664562SgshapiroR<$*><VERIFY> OK		$@ OK
202764562Sgshapirodnl verification required + some level of encryption
202864562SgshapiroR<$*><VERIFY:$-> OK		$: <$1> <REQ:$2>
202964562Sgshapirodnl just some level of encryption required
203064562SgshapiroR<$*><ENCR:$-> $*		$: <$1> <REQ:$2>
203164562Sgshapirodnl verification required but ${verify} is not set
203264562SgshapiroR<$-:$+><VERIFY $*>		$#error $@ $2 $: $1 " authentication required"
203364562SgshapiroR<$-:$+><VERIFY $*> FAIL	$#error $@ $2 $: $1 " authentication failed"
203464562SgshapiroR<$-:$+><VERIFY $*> NO		$#error $@ $2 $: $1 " not authenticated"
203564562SgshapiroR<$-:$+><VERIFY $*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
203664562Sgshapirodnl some other value for ${verify}
203764562SgshapiroR<$-:$+><VERIFY $*> $+		$#error $@ $2 $: $1 " authentication failure " $4
203864562Sgshapirodnl some level of encryption required: get the maximum level
203964562SgshapiroR<$*><REQ:$->			$: <$1> <REQ:$2> $>max $&{cipher_bits} : $&{auth_ssf}
204064562Sgshapirodnl compare required bits with actual bits
204164562SgshapiroR<$*><REQ:$-> $-		$: <$1> <$2:$3> $(arith l $@ $3 $@ $2 $)
204264562SgshapiroR<$-:$+><$-:$-> TRUE		$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
204364562Sgshapiro
204464562SgshapiroSmax
204564562Sgshapirodnl compute the max of two values separated by :
204664562SgshapiroR:		$: 0
204764562SgshapiroR:$-		$: $1
204864562SgshapiroR$-:		$: $1
204964562SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
205064562SgshapiroRTRUE:$-:$-	$: $2
205164562SgshapiroR$-:$-:$-	$: $2',
205264562Sgshapiro`dnl use default error
205364562Sgshapirodnl deal with TLS handshake failures: abort
205464562SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."')
205564562Sgshapiro
205664562SgshapiroSRelayAuth
205764562Sgshapiro# authenticated?
205864562Sgshapirodnl we do not allow relaying for anyone who can present a cert
205964562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
206064562Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow
206164562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
206264562Sgshapirodnl but anyway).
206364562Sgshapirodnl so here is the trick: if the verification succeeded
206464562Sgshapirodnl we look up the cert issuer in the access map
206564562Sgshapirodnl (maybe after extracting a part with a regular expression)
206664562Sgshapirodnl if this returns RELAY we relay without further questions
206764562Sgshapirodnl if it returns SUBJECT we perform a similar check on the
206864562Sgshapirodnl cert subject.
206964562SgshapiroR$* $| OK		$: $1
207064562SgshapiroR$* $| $*		$@ NO		not authenticated
207164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
207264562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
207364562SgshapiroR$*			$: $1 $| $(CERTIssuer $&{cert_issuer} $)',
207464562Sgshapiro`R$*			$: $1 $| $&{cert_issuer}')
207564562SgshapiroR$* $| $+		$: $1 $| $(access CERTISSUER:$2 $)
207664562Sgshapirodnl use $# to stop further checks (delay_check)
207764562SgshapiroR$* $| RELAY		$# RELAYCERTISSUER
207864562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
207964562SgshapiroR$* $| SUBJECT		$: $1 $| <@> $(CERTSubject $&{cert_subject} $)',
208064562Sgshapiro`R$* $| SUBJECT		$: $1 $| <@> $&{cert_subject}')
208166494SgshapiroR$* $| <@> $+		$: $1 $| <@> $(access CERTSUBJECT:$2 $)
208264562SgshapiroR$* $| <@> RELAY	$# RELAYCERTSUBJECT
208364562SgshapiroR$* $| $*		$: $1', `dnl')
208464562Sgshapiro
208564562Sgshapiroundivert(9)dnl LOCAL_RULESETS
208664562Sgshapiroifdef(`_FFR_MILTER', `
208738032Speter#
208838032Speter######################################################################
208938032Speter######################################################################
209038032Speter#####
209164562Sgshapiro`#####			MAIL FILTER DEFINITIONS'
209264562Sgshapiro#####
209364562Sgshapiro######################################################################
209464562Sgshapiro######################################################################
209564562Sgshapiro_MAIL_FILTERS_')
209664562Sgshapiro#
209764562Sgshapiro######################################################################
209864562Sgshapiro######################################################################
209964562Sgshapiro#####
210038032Speter`#####			MAILER DEFINITIONS'
210138032Speter#####
210238032Speter######################################################################
210338032Speter######################################################################
210464562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
210566494Sgshapiro
2106