proto.m4 revision 64562
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
1664562SgshapiroVERSIONID(`$Id: proto.m4,v 8.446.2.5.2.12 2000/07/19 21:41:19 gshapiro Exp $')
1738032Speter
1838032SpeterMAILER(local)dnl
1938032Speter
2064562Sgshapiro# level CF_LEVEL config file format
2164562SgshapiroV`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley')
2238032Speterdivert(-1)
2338032Speter
2438032Speter# do some sanity checking
2538032Speterifdef(`__OSTYPE__',,
2664562Sgshapiro	`errprint(`*** ERROR: No system type defined (use OSTYPE macro)
2764562Sgshapiro')')
2838032Speter
2938032Speter# pick our default mailers
3038032Speterifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')')
3138032Speterifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')')
3238032Speterifdef(`confRELAY_MAILER',,
3338032Speter	`define(`confRELAY_MAILER',
3438032Speter		`ifdef(`_MAILER_smtp_', `relay',
3538032Speter			`ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')')
3638032Speterifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')')
3738032Speterdefine(`_SMTP_', `confSMTP_MAILER')dnl		for readability only
3838032Speterdefine(`_LOCAL_', `confLOCAL_MAILER')dnl	for readability only
3938032Speterdefine(`_RELAY_', `confRELAY_MAILER')dnl	for readability only
4038032Speterdefine(`_UUCP_', `confUUCP_MAILER')dnl		for readability only
4138032Speter
4238032Speter# back compatibility with old config files
4338032Speterifdef(`confDEF_GROUP_ID',
4464562Sgshapiro`errprint(`*** confDEF_GROUP_ID is obsolete.
4564562Sgshapiro    Use confDEF_USER_ID with a colon in the value instead.
4664562Sgshapiro')')
4738032Speterifdef(`confREAD_TIMEOUT',
4864562Sgshapiro`errprint(`*** confREAD_TIMEOUT is obsolete.
4964562Sgshapiro    Use individual confTO_<timeout> parameters instead.
5064562Sgshapiro')')
5138032Speterifdef(`confMESSAGE_TIMEOUT',
5238032Speter	`define(`_ARG_', index(confMESSAGE_TIMEOUT, /))
5338032Speter	 ifelse(_ARG_, -1,
5438032Speter		`define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)',
5538032Speter		`define(`confTO_QUEUERETURN',
5638032Speter			substr(confMESSAGE_TIMEOUT, 0, _ARG_))
5738032Speter		 define(`confTO_QUEUEWARN',
5838032Speter			substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')')
5938032Speterifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,,
6064562Sgshapiro`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete.
6164562Sgshapiro    Use confMAX_MESSAGE_SIZE for the second part of the value.
6264562Sgshapiro')')')
6338032Speter
6464562Sgshapiro
6564562Sgshapiro# Sanity check on ldap_routing feature
6664562Sgshapiro# If the user doesn't specify a new map, they better have given as a
6764562Sgshapiro# default LDAP specification which has the LDAP base (and most likely the host)
6864562Sgshapiroifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(`
6964562SgshapiroWARNING: Using default FEATURE(ldap_routing) map definition(s)
7064562Sgshapirowithout setting confLDAP_DEFAULT_SPEC option.
7164562Sgshapiro')')')dnl
7264562Sgshapiro
7338032Speter# clean option definitions below....
7464562Sgshapirodefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl
7538032Speter
7664562Sgshapirodnl required to "rename" the check_* rulesets...
7764562Sgshapirodefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_'))
7864562Sgshapirodnl default relaying denied message
7964562Sgshapiroifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG', `"550 Relaying denied"')')
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
16338032Speterifdef(`confCR_FILE', `dnl
16438032Speter# Hosts that will permit relaying ($=R)
16538032SpeterFR`'confCR_FILE',
16638032Speter`dnl')
16738032Speter
16864562Sgshapirodefine(`TLS_SRV_TAG', `TLS_Srv')dnl
16964562Sgshapirodefine(`TLS_CLT_TAG', `TLS_Clt')dnl
17064562Sgshapirodefine(`TLS_TRY_TAG', `Try_TLS')dnl
17164562Sgshapirodefine(`TLS_OFF_TAG', `Offer_TLS')dnl
17264562Sgshapirodnl this may be useful in other contexts too
17364562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map
17464562Sgshapirodefine(`_ARITH_MAP_', `1')dnl
17564562SgshapiroKarith arith')
17664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
17764562Sgshapiro# possible values for tls_connect in access map
17864562SgshapiroC{tls}VERIFY ENCR', `dnl')
17964562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
18064562Sgshapiro# extract relevant part from cert issuer
18164562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
18264562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
18364562Sgshapiro# extract relevant part from cert subject
18464562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
18564562Sgshapiro
18638032Speter# who I send unqualified names to (null means deliver locally)
18738032SpeterDR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY)
18838032Speter
18938032Speter# who gets all local email traffic ($R has precedence for unqualified names)
19038032SpeterDH`'ifdef(`MAIL_HUB', MAIL_HUB)
19138032Speter
19238032Speter# dequoting map
19338032SpeterKdequote dequote
19438032Speter
19538032Speterdivert(0)dnl	# end of nullclient diversion
19638032Speter# class E: names that should be exposed as from this host, even if we masquerade
19764562Sgshapiro# class L: names that should be delivered locally, even if we have a relay
19838032Speter# class M: domains that should be converted to $M
19964562Sgshapiro# class N: domains that should not be converted to $M
20038032Speter#CL root
20138032Speterundivert(5)dnl
20264562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
20338032Speter
20438032Speter# who I masquerade as (null for no masquerading) (see also $=M)
20538032SpeterDM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME)
20638032Speter
20738032Speter# my name for error messages
20838032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
20938032Speter
21064562Sgshapiroundivert(6)dnl LOCAL_CONFIG
21138032Speterinclude(_CF_DIR_`m4/version.m4')
21238032Speter
21338032Speter###############
21438032Speter#   Options   #
21538032Speter###############
21638032Speter
21738032Speter# strip message body to 7 bits on input?
21864562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
21938032Speter
22038032Speter# 8-bit data handling
22164562Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `adaptive')
22238032Speter
22338032Speter# wait for alias file rebuild (default units: minutes)
22464562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m')
22538032Speter
22638032Speter# location of alias file
22764562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
22864562Sgshapiro
22938032Speter# minimum number of free blocks on filesystem
23064562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
23138032Speter
23238032Speter# maximum message size
23364562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000')
23438032Speter
23538032Speter# substitution for space (blank) characters
23664562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_')
23738032Speter
23838032Speter# avoid connecting to "expensive" mailers on initial submission?
23964562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
24038032Speter
24138032Speter# checkpoint queue runs after every N successful deliveries
24264562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
24338032Speter
24438032Speter# default delivery mode
24564562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
24638032Speter
24738032Speter# automatically rebuild the alias database?
24864562Sgshapiro# NOTE: There is a potential for a denial of service attack if this is set.
24964562Sgshapiro#       This option is deprecated and will be removed from a future version.
25064562Sgshapiro_OPTION(AutoRebuildAliases, `confAUTO_REBUILD', `False')
25138032Speter
25238032Speter# error message header/file
25364562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
25438032Speter
25538032Speter# error mode
25664562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print')
25738032Speter
25838032Speter# save Unix-style "From_" lines at top of header?
25964562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
26038032Speter
26138032Speter# temporary file mode
26264562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
26338032Speter
26438032Speter# match recipients against GECOS field?
26564562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
26638032Speter
26738032Speter# maximum hop count
26864562Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `17')
26938032Speter
27038032Speter# location of help file
27164562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
27238032Speter
27338032Speter# ignore dots as terminators in incoming messages?
27464562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
27538032Speter
27638032Speter# name resolver options
27764562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
27838032Speter
27938032Speter# deliver MIME-encapsulated error messages?
28064562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
28138032Speter
28238032Speter# Forward file search path
28364562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
28438032Speter
28538032Speter# open connection cache size
28664562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
28738032Speter
28838032Speter# open connection cache timeout
28964562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
29038032Speter
29138032Speter# persistent host status directory
29264562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
29338032Speter
29438032Speter# single thread deliveries (requires HostStatusDirectory)?
29564562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
29638032Speter
29738032Speter# use Errors-To: header?
29864562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
29938032Speter
30038032Speter# log level
30164562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10')
30238032Speter
30338032Speter# send to me too, even in an alias expansion?
30464562Sgshapiro_OPTION(MeToo, `confME_TOO', `True')
30538032Speter
30638032Speter# verify RHS in newaliases?
30764562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
30838032Speter
30938032Speter# default messages to old style headers if no special punctuation?
31064562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
31138032Speter
31238032Speter# SMTP daemon options
31364562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
31464562Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.  See cf/README for more information.
31564562Sgshapiro)'dnl
31664562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
31764562Sgshapiroifelse(defn(`_DPO_'), `', `O DaemonPortOptions=Name=MTA', `_DPO_')
31864562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
31938032Speter
32064562Sgshapiro# SMTP client options
32164562Sgshapiro_OPTION(ClientPortOptions, `confCLIENT_OPTIONS', `Address=0.0.0.0')
32264562Sgshapiro
32338032Speter# privacy flags
32464562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
32538032Speter
32638032Speter# who (if anyone) should get extra copies of error messages
32764562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
32838032Speter
32938032Speter# slope of queue-only function
33064562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
33138032Speter
33238032Speter# queue directory
33364562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
33438032Speter
33538032Speter# timeouts (many of these)
33664562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
33764562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
33864562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
33964562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m')
34064562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m')
34164562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
34264562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
34364562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
34464562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
34564562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m')
34664562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m')
34764562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m')
34864562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h')
34964562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s')
35064562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
35164562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m')
35264562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
35364562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
35464562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
35564562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
35664562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
35764562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
35864562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
35964562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
36064562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
36164562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
36264562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
36364562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
36464562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
36564562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
36664562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
36738032Speter
36838032Speter# should we not prune routes in route-addr syntax addresses?
36964562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
37038032Speter
37138032Speter# queue up everything before forking?
37264562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
37338032Speter
37438032Speter# status file
37564562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
37638032Speter
37738032Speter# time zone handling:
37838032Speter#  if undefined, use system default
37938032Speter#  if defined but null, use TZ envariable passed in
38038032Speter#  if defined and non-null, use that info
38138032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
38238032Speter	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
38338032Speter	`O TimeZoneSpec=confTIME_ZONE')
38438032Speter
38538032Speter# default UID (can be username or userid:groupid)
38664562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
38738032Speter
38838032Speter# list of locations of user database file (null means no lookup)
38964562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
39038032Speter
39138032Speter# fallback MX host
39264562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
39338032Speter
39438032Speter# if we are the best MX host for a site, try it directly instead of config err
39564562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
39638032Speter
39738032Speter# load average at which we just queue messages
39864562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8')
39938032Speter
40038032Speter# load average at which we refuse connections
40164562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12')
40238032Speter
40338032Speter# maximum number of children we allow at one time
40464562Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12')
40538032Speter
40638032Speter# maximum number of new connections per second
40764562Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `3')
40838032Speter
40938032Speter# work recipient factor
41064562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
41138032Speter
41238032Speter# deliver each queued job in a separate process?
41364562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
41438032Speter
41538032Speter# work class factor
41664562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
41738032Speter
41838032Speter# work time factor
41964562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
42038032Speter
42138032Speter# shall we sort the queue by hostname first?
42264562Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
42338032Speter
42438032Speter# minimum time in queue before retry
42564562Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
42638032Speter
42738032Speter# default character set
42864562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
42938032Speter
43038032Speter# service switch file (ignored on Solaris, Ultrix, OSF/1, others)
43164562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
43238032Speter
43338032Speter# hosts file (normally /etc/hosts)
43464562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
43538032Speter
43638032Speter# dialup line delay on connection failure
43764562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s')
43838032Speter
43938032Speter# action to take if there are no recipients in the message
44064562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed')
44138032Speter
44238032Speter# chrooted environment for writing to files
44364562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
44438032Speter
44538032Speter# are colons OK in addresses?
44664562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
44738032Speter
44838032Speter# how many jobs can you process in the queue?
44964562Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
45038032Speter
45138032Speter# shall I avoid expanding CNAMEs (violates protocols)?
45264562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
45338032Speter
45438032Speter# SMTP initial login message (old $e macro)
45564562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
45638032Speter
45738032Speter# UNIX initial From header format (old $l macro)
45864562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
45938032Speter
46038032Speter# From: lines that have embedded newlines are unwrapped onto one line
46164562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
46238032Speter
46338032Speter# Allow HELO SMTP command that does not `include' a host name
46464562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
46538032Speter
46638032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
46764562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
46838032Speter
46938032Speter# delimiter (operator) characters (old $o macro)
47064562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
47138032Speter
47238032Speter# shall I avoid calling initgroups(3) because of high NIS costs?
47364562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
47438032Speter
47538032Speter# are group-writable `:include:' and .forward files (un)trustworthy?
47664562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
47738032Speter
47838032Speter# where do errors that occur when sending errors get sent?
47964562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
48038032Speter
48164562Sgshapiro# where to save bounces if all else fails
48264562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
48364562Sgshapiro
48438032Speter# what user id do we assume for the majority of the processing?
48564562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
48638032Speter
48738032Speter# maximum number of recipients per SMTP envelope
48864562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
48938032Speter
49038032Speter# shall we get local names from our installed interfaces?
49164562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
49238032Speter
49364562Sgshapiro# Return-Receipt-To: header implies DSN request
49464562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
49564562Sgshapiro
49664562Sgshapiro# override connection address (for testing)
49764562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
49864562Sgshapiro
49964562Sgshapiro# Trusted user for file ownership and starting the daemon
50064562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root')
50164562Sgshapiro
50264562Sgshapiro# Control socket for daemon management
50364562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
50464562Sgshapiro
50564562Sgshapiro# Maximum MIME header length to protect MUAs
50664562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
50764562Sgshapiro
50864562Sgshapiro# Maximum length of the sum of all headers
50964562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
51064562Sgshapiro
51164562Sgshapiro# Maximum depth of alias recursion
51264562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
51364562Sgshapiro
51464562Sgshapiro# location of pid file
51564562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
51664562Sgshapiro
51764562Sgshapiro# Prefix string for the process title shown on 'ps' listings
51864562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
51964562Sgshapiro
52064562Sgshapiro# Data file (df) memory-buffer file maximum size
52164562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
52264562Sgshapiro
52364562Sgshapiro# Transcript file (xf) memory-buffer file maximum size
52464562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
52564562Sgshapiro
52664562Sgshapiro# list of authentication mechanisms
52764562Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
52864562Sgshapiro
52964562Sgshapiro# default authentication information for outgoing connections
53064562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
53164562Sgshapiro
53264562Sgshapiro# SMTP AUTH flags
53364562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
53464562Sgshapiro
53564562Sgshapiroifdef(`_FFR_MILTER', `
53664562Sgshapiro# Input mail filters
53764562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
53864562Sgshapiro
53964562Sgshapiro# Milter options
54064562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
54164562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
54264562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
54364562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')')
54464562Sgshapiro
54564562Sgshapiro# CA directory
54664562Sgshapiro_OPTION(CACERTPath, `confCACERT_PATH', `')
54764562Sgshapiro# CA file
54864562Sgshapiro_OPTION(CACERTFile, `confCACERT', `')
54964562Sgshapiro# Server Cert
55064562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `')
55164562Sgshapiro# Server private key
55264562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `')
55364562Sgshapiro# Client Cert
55464562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `')
55564562Sgshapiro# Client private key
55664562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
55764562Sgshapiro# DHParameters (only required if DSA/DH is used)
55864562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `')
55964562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL)
56064562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `')
56164562Sgshapiro
56264562Sgshapiroifdef(`confQUEUE_FILE_MODE',
56364562Sgshapiro`# queue file mode (qf files)
56464562SgshapiroO QueueFileMode=confQUEUE_FILE_MODE
56542575Speter')
56642575Speter
56738032Speter###########################
56838032Speter#   Message precedences   #
56938032Speter###########################
57038032Speter
57138032SpeterPfirst-class=0
57238032SpeterPspecial-delivery=100
57338032SpeterPlist=-30
57438032SpeterPbulk=-60
57538032SpeterPjunk=-100
57638032Speter
57738032Speter#####################
57838032Speter#   Trusted users   #
57938032Speter#####################
58038032Speter
58138032Speter# this is equivalent to setting class "t"
58264562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
58338032SpeterTroot
58438032SpeterTdaemon
58538032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp')
58638032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
58738032Speter
58838032Speter#########################
58938032Speter#   Format of headers   #
59038032Speter#########################
59138032Speter
59238032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
59338032SpeterH?P?Return-Path: <$g>
59438032SpeterHReceived: confRECEIVED_HEADER
59538032SpeterH?D?Resent-Date: $a
59638032SpeterH?D?Date: $a
59738032SpeterH?F?Resent-From: confFROM_HEADER
59838032SpeterH?F?From: confFROM_HEADER
59938032SpeterH?x?Full-Name: $x
60038032Speter# HPosted-Date: $a
60138032Speter# H?l?Received-Date: $b
60238032SpeterH?M?Resent-Message-Id: <$t.$i@$j>
60338032SpeterH?M?Message-Id: <$t.$i@$j>
60464562Sgshapiro
60538032Speter#
60638032Speter######################################################################
60738032Speter######################################################################
60838032Speter#####
60938032Speter#####			REWRITING RULES
61038032Speter#####
61138032Speter######################################################################
61238032Speter######################################################################
61338032Speter
61438032Speter############################################
61538032Speter###  Ruleset 3 -- Name Canonicalization  ###
61638032Speter############################################
61764562SgshapiroScanonify=3
61838032Speter
61938032Speter# handle null input (translate to <@> special case)
62038032SpeterR$@			$@ <@>
62138032Speter
62238032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon
62338032SpeterR$*			$: $1 <@>			mark addresses
62438032SpeterR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
62538032SpeterR@ $* <@>		$: @ $1				unmark @host:...
62638032SpeterR$* :: $* <@>		$: $1 :: $2			unmark node::addr
62738032SpeterR:`include': $* <@>	$: :`include': $1			unmark :`include':...
62864562SgshapiroR$* [ IPv6 $- ] <@>	$: $1 [ IPv6 $2 ]		unmark IPv6 addr
62938032SpeterR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
63038032SpeterR$* : $* <@>		$: $2				strip colon if marked
63138032SpeterR$* <@>			$: $1				unmark
63238032SpeterR$* ;			   $1				strip trailing semi
63338032SpeterR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
63438032Speter
63538032Speter# null input now results from list:; syntax
63638032SpeterR$@			$@ :; <@>
63738032Speter
63838032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item
63938032SpeterR$*			$: < $1 >			housekeeping <>
64038032SpeterR$+ < $* >		   < $2 >			strip excess on left
64138032SpeterR< $* > $+		   < $1 >			strip excess on right
64238032SpeterR<>			$@ < @ >			MAIL FROM:<> case
64338032SpeterR< $+ >			$: $1				remove housekeeping <>
64438032Speter
64564562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
64638032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
64738032SpeterR@ $+ , $+		@ $1 : $2			change all "," to ":"
64838032Speter
64938032Speter# localize and dispose of route-based addresses
65064562SgshapiroR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
65164562Sgshapirodnl',`dnl
65264562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d>
65364562SgshapiroR@ $+ , $+		$2
65464562SgshapiroR@ $+ : $+		$2
65564562Sgshapirodnl')
65638032Speter
65738032Speter# find focus for list syntax
65864562SgshapiroR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
65938032SpeterR $+ : $* ;		$@ $1 : $2;			list syntax
66038032Speter
66138032Speter# find focus for @ syntax addresses
66238032SpeterR$+ @ $+		$: $1 < @ $2 >			focus on domain
66338032SpeterR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
66464562SgshapiroR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
66538032Speter
66638032Speter# do some sanity checking
66738032SpeterR$* < @ $* : $* > $*	$1 < @ $2 $3 > $4		nix colons in addrs
66838032Speter
66938032Speterifdef(`_NO_UUCP_', `dnl',
67038032Speter`# convert old-style addresses to a domain-based address
67164562SgshapiroR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
67264562SgshapiroR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
67364562SgshapiroR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
67438032Speter')
67538032Speterifdef(`_USE_DECNET_SYNTAX_',
67638032Speter`# convert node::user addresses into a domain-based address
67764562SgshapiroR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
67864562SgshapiroR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
67938032Speter',
68038032Speter	`dnl')
68138032Speter# if we have % signs, take the rightmost one
68238032SpeterR$* % $*		$1 @ $2				First make them all @s.
68338032SpeterR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
68464562SgshapiroR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
68538032Speter
68638032Speter# else we must be a local name
68764562SgshapiroR$*			$@ $>Canonify2 $1
68838032Speter
68938032Speter
69038032Speter################################################
69138032Speter###  Ruleset 96 -- bottom half of ruleset 3  ###
69238032Speter################################################
69338032Speter
69464562SgshapiroSCanonify2=96
69538032Speter
69638032Speter# handle special cases for local names
69738032SpeterR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
69838032SpeterR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
69938032Speterifdef(`_NO_UUCP_', `dnl',
70038032Speter`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
70164562Sgshapiro
70264562Sgshapiro# check for IPv6 domain literal (save quoted form)
70364562SgshapiroR$* < @ [ IPv6 $- ] > $*	$: $2 $| $1 < @@ [ $(dequote $2 $) ] > $3	mark IPv6 addr
70464562SgshapiroR$- $| $* < @@ $=w > $*		$: $2 < @ $j . > $4		self-literal
70564562SgshapiroR$- $| $* < @@ [ $+ ] > $*	$@ $2 < @ [ IPv6 $1 ] > $4	canon IP addr
70664562Sgshapiro
70764562Sgshapiro# check for IPv4 domain literal
70838032SpeterR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [a.b.c.d]
70938032SpeterR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
71038032SpeterR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
71138032Speter
71264562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl
71338032Speter# look up domains in the domain table
71438032SpeterR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
71538032Speter
71664562Sgshapiroundivert(2)dnl LOCAL_RULE_3
71738032Speter
71864562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl
71938032Speter# handle BITNET mapping
72038032SpeterR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
72138032Speter
72264562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl
72338032Speter# handle UUCP mapping
72438032SpeterR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
72538032Speter
72638032Speterifdef(`_NO_UUCP_', `dnl',
72738032Speter`ifdef(`UUCP_RELAY',
72838032Speter`# pass UUCP addresses straight through
72938032SpeterR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
73038032Speter`# if really UUCP, handle it immediately
73138032Speterifdef(`_CLASS_U_',
73238032Speter`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
73338032Speterifdef(`_CLASS_V_',
73438032Speter`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
73538032Speterifdef(`_CLASS_W_',
73638032Speter`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
73738032Speterifdef(`_CLASS_X_',
73838032Speter`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
73938032Speterifdef(`_CLASS_Y_',
74038032Speter`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
74138032Speter
74238032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl
74338032Speter# try UUCP traffic as a local address
74438032SpeterR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
74538032SpeterR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
74638032Speter')')
74764562Sgshapiro# hostnames ending in class P are always canonical
74864562SgshapiroR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
74964562Sgshapirodnl apply the next rule only for hostnames not in class P
75064562Sgshapirodnl this even works for phrases in class P since . is in class P
75164562Sgshapirodnl which daemon flags are set?
75264562SgshapiroR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
75364562Sgshapirodnl the other rules in this section only apply if the hostname
75464562Sgshapirodnl does not end in class P hence no further checks are done here
75564562Sgshapirodnl if this ever changes make sure the lookups are "protected" again!
75664562Sgshapiroifdef(`_NO_CANONIFY_', `dnl
75764562Sgshapirodnl do not canonify unless:
75864562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection
75964562Sgshapirodnl	with class P is non-empty)
76064562Sgshapirodnl or {daemon_flags} has c set
76164562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify}
76264562SgshapiroR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
76364562Sgshapiro# pass to name server to make hostname canonical if requested
76464562SgshapiroR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
76564562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_
76664562SgshapiroR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
76764562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work
76864562SgshapiroR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
76964562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl
77064562Sgshapirodnl this should only apply to unqualified hostnames
77164562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar
77264562Sgshapirodnl then $- does not work.
77364562Sgshapiro# lookup unqualified hostnames
77464562SgshapiroR$* $| $* < @ $* > $*	$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
77564562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless:
77664562Sgshapirodnl {daemon_flags} contains CC (do not canonify)
77764562SgshapiroR$* CC $* $| $*			$: $3
77838032Speter# pass to name server to make hostname canonical
77964562SgshapiroR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
78064562Sgshapirodnl remove {daemon_flags} for other cases
78164562SgshapiroR$* $| $*			$: $2
78238032Speter
78338032Speter# local host aliases and pseudo-domains are always canonical
78438032SpeterR$* < @ $=w > $*		$: $1 < @ $2 . > $3
78538032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
78638032Speter`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
78738032Speter`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
78864562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
78964562Sgshapirodnl virtual hosts are also canonical
79064562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
79164562Sgshapiro`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
79264562Sgshapiro`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
79364562Sgshapiro`dnl')
79464562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added
79564562Sgshapirodnl by one of the rules before
79638032SpeterR$* < @ $* . . > $*		$1 < @ $2 . > $3
79738032Speter
79838032Speter
79938032Speter##################################################
80038032Speter###  Ruleset 4 -- Final Output Post-rewriting  ###
80138032Speter##################################################
80264562SgshapiroSfinal=4
80338032Speter
80438032SpeterR$* <@>			$@				handle <> and list:;
80538032Speter
80638032Speter# strip trailing dot off possibly canonical name
80738032SpeterR$* < @ $+ . > $*	$1 < @ $2 > $3
80838032Speter
80964562Sgshapiro# eliminate internal code
81038032SpeterR$* < @ *LOCAL* > $*	$1 < @ $j > $2
81138032Speter
81238032Speter# externalize local domain info
81338032SpeterR$* < $+ > $*		$1 $2 $3			defocus
81438032SpeterR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
81538032SpeterR@ $*			$@ @ $1				... and exit
81638032Speter
81738032Speterifdef(`_NO_UUCP_', `dnl',
81838032Speter`# UUCP must always be presented in old form
81938032SpeterR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
82038032Speter
82138032Speterifdef(`_USE_DECNET_SYNTAX_',
82238032Speter`# put DECnet back in :: form
82338032SpeterR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
82438032Speter	`dnl')
82538032Speter# delete duplicate local names
82638032SpeterR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
82738032Speter
82838032Speter
82938032Speter
83038032Speter##############################################################
83138032Speter###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
83238032Speter###		   (used for recursive calls)		   ###
83338032Speter##############################################################
83438032Speter
83564562SgshapiroSRecurse=97
83664562SgshapiroR$*			$: $>canonify $1
83764562SgshapiroR$*			$@ $>parse $1
83838032Speter
83938032Speter
84038032Speter######################################
84138032Speter###   Ruleset 0 -- Parse Address   ###
84238032Speter######################################
84338032Speter
84464562SgshapiroSparse=0
84538032Speter
84638032SpeterR$*			$: $>Parse0 $1		initial parsing
84738032SpeterR<@>			$#_LOCAL_ $: <@>		special case error msgs
84864562SgshapiroR$*			$: $>ParseLocal $1	handle local hacks
84938032SpeterR$*			$: $>Parse1 $1		final parsing
85038032Speter
85138032Speter#
85238032Speter#  Parse0 -- do initial syntax checking and eliminate local addresses.
85338032Speter#	This should either return with the (possibly modified) input
85438032Speter#	or return with a #error mailer.  It should not return with a
85538032Speter#	#mailer other than the #error mailer.
85638032Speter#
85738032Speter
85838032SpeterSParse0
85938032SpeterR<@>			$@ <@>			special case error msgs
86064562SgshapiroR$* : $* ; <@>		$#error $@ 5.1.3 $: "553 List:; syntax illegal for recipient addresses"
86164562SgshapiroR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
86264562SgshapiroR<@ $+>			$#error $@ 5.1.3 $: "553 User address required"
86338032SpeterR$*			$: <> $1
86438032SpeterR<> $* < @ [ $+ ] > $*	$1 < @ [ $2 ] > $3
86564562SgshapiroR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "553 Colon illegal in host name part"
86638032SpeterR<> $*			$1
86764562SgshapiroR$* < @ . $* > $*	$#error $@ 5.1.2 $: "553 Invalid host name"
86864562SgshapiroR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "553 Invalid host name"
86964562Sgshapirodnl comma only allowed before @; this check is not complete
87064562SgshapiroR$* , $~O $*		$#error $@ 5.1.2 $: "553 Invalid route address"
87138032Speter
87238032Speter# now delete the local info -- note $=O to find characters that cause forwarding
87364562SgshapiroR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
87464562SgshapiroR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
87538032SpeterR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
87664562SgshapiroR< @ $+ >		$#error $@ 5.1.3 $: "553 User address required"
87764562SgshapiroR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
87838032SpeterR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
87964562SgshapiroR< @ *LOCAL* >		$#error $@ 5.1.3 $: "553 User address required"
88038032SpeterR$* $=O $* < @ *LOCAL* >
88164562Sgshapiro			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
88238032SpeterR$* < @ *LOCAL* >	$: $1
88338032Speter
88438032Speter#
88538032Speter#  Parse1 -- the bottom half of ruleset 0.
88638032Speter#
88738032Speter
88838032SpeterSParse1
88964562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
89064562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute}
89164562SgshapiroR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2>',
89264562Sgshapiro`dnl')
89364562Sgshapiro
89464562Sgshapiro
89538032Speterifdef(`_MAILER_smtp_',
89638032Speter`# handle numeric address spec
89764562Sgshapirodnl there is no check whether this is really an IP number
89864562SgshapiroR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
89964562SgshapiroR$* < @ [ $+ ] > $*	$1 < @ [ $2 ] : $S > $3		Add smart host to path
90064562SgshapiroR$* < @ [ IPv6 $- ] : > $*
90164562Sgshapiro		$#_SMTP_ $@ [ $(dequote $2 $) ] $: $1 < @ [IPv6 $2 ] > $3	no smarthost: send
90264562SgshapiroR$* < @ [ $+ ] : > $*	$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
90364562SgshapiroR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
90464562SgshapiroR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
90538032Speter	`dnl')
90638032Speter
90764562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl
90838032Speter# handle virtual users
90964562SgshapiroR$+			$: <!> $1		Mark for lookup
91064562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
91164562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
91264562Sgshapiro`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
91364562SgshapiroR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
91438032SpeterR<@> $+ + $* < @ $* . >
91564562Sgshapiro			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
91638032SpeterR<@> $+ + $* < @ $* . >
91738032Speter			$: < $(virtuser $1 @ $3 $@ $1 $: @ $) > $1 + $2 < @ $3 . >
91864562Sgshapirodnl try default entry: @domain
91964562Sgshapirodnl +*@domain
92064562SgshapiroR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
92164562Sgshapirodnl @domain if +detail exists
92264562SgshapiroR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
92364562Sgshapirodnl without +detail (or no match)
92438032SpeterR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
92538032SpeterR<@> $+			$: $1
92664562SgshapiroR<!> $+			$: $1
92764562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
92838032SpeterR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
92964562SgshapiroR< $+ > $+ < @ $+ >	$: $>Recurse $1',
93038032Speter`dnl')
93138032Speter
93238032Speter# short circuit local delivery so forwarded email works
93338032Speterifdef(`_MAILER_usenet_', `dnl
93464562SgshapiroR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
93538032Speterifdef(`_STICKY_LOCAL_DOMAIN_',
93638032Speter`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
93764562SgshapiroR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
93864562Sgshapirodnl $H empty (but @$=w.)
93938032SpeterR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
94038032SpeterR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
94164562Sgshapiro`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
94238032SpeterR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
94338032Speter
94464562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
94538032Speter# not local -- try mailer table lookup
94638032SpeterR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
94738032SpeterR< $+ . > $*		$: < $1 > $2			strip trailing dot
94838032SpeterR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
94964562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
95064562SgshapiroR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
95164562SgshapiroR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
95238032Speter`dnl')
95364562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)'
95438032Speter
95538032Speterifdef(`_NO_UUCP_', `dnl',
95638032Speter`# resolve remotely connected UUCP links (if any)
95738032Speterifdef(`_CLASS_V_',
95864562Sgshapiro`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
95938032Speter	`dnl')
96038032Speterifdef(`_CLASS_W_',
96164562Sgshapiro`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
96238032Speter	`dnl')
96338032Speterifdef(`_CLASS_X_',
96464562Sgshapiro`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
96538032Speter	`dnl')')
96638032Speter
96738032Speter# resolve fake top level domains by forwarding to other hosts
96838032Speterifdef(`BITNET_RELAY',
96964562Sgshapiro`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
97038032Speter	`dnl')
97138032Speterifdef(`DECNET_RELAY',
97264562Sgshapiro`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
97338032Speter	`dnl')
97438032Speterifdef(`_MAILER_pop_',
97538032Speter`R$+ < @ POP. >		$#pop $: $1			user@POP',
97638032Speter	`dnl')
97738032Speterifdef(`_MAILER_fax_',
97838032Speter`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
97938032Speter`ifdef(`FAX_RELAY',
98064562Sgshapiro`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
98138032Speter	`dnl')')
98238032Speter
98338032Speterifdef(`UUCP_RELAY',
98438032Speter`# forward non-local UUCP traffic to our UUCP relay
98564562SgshapiroR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
98638032Speter`ifdef(`_MAILER_uucp_',
98738032Speter`# forward other UUCP traffic straight to UUCP
98838032SpeterR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
98938032Speter	`dnl')')
99038032Speterifdef(`_MAILER_usenet_', `
99138032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup
99264562SgshapiroR$+ . USENET		$#usenet $@ usenet $: $1',
99338032Speter	`dnl')
99438032Speter
99538032Speterifdef(`_LOCAL_RULES_',
99638032Speter`# figure out what should stay in our local mail system
99738032Speterundivert(1)', `dnl')
99838032Speter
99938032Speter# pass names that still have a host to a smarthost (if defined)
100064562SgshapiroR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
100138032Speter
100238032Speter# deal with other remote names
100338032Speterifdef(`_MAILER_smtp_',
100464562Sgshapiro`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
100564562Sgshapiro`R$* < @$* > $*		$#error $@ 5.1.2 $: "553 Unrecognized host name " $2')
100638032Speter
100738032Speter# handle locally delivered names
100864562SgshapiroR$=L			$#_LOCAL_ $: @ $1		special local names
100938032SpeterR$+			$#_LOCAL_ $: $1			regular local names
101038032Speter
101138032Speter###########################################################################
101238032Speter###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
101338032Speter###########################################################################
101438032Speter
101564562SgshapiroSLocal_localaddr
101664562SgshapiroSlocaladdr=5
101764562SgshapiroR$+			$: $1 $| $>"Local_localaddr" $1
101864562SgshapiroR$+ $| $#$*		$#$2
101964562SgshapiroR$+ $| $*		$: $1
102038032Speter
102138032Speter# deal with plussed users so aliases work nicely
102238032SpeterR$+ + *			$#_LOCAL_ $@ $&h $: $1
102338032SpeterR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *
102438032Speter
102538032Speter# prepend an empty "forward host" on the front
102638032SpeterR$+			$: <> $1
102738032Speter
102838032Speterifdef(`LUSER_RELAY', `dnl
102938032Speter# send unrecognized local users to a relay host
103064562SgshapiroR< > $+ 		$: < $L > $(user $1 $)		look up user
103164562SgshapiroR< $* > $+ <>		$: < > $2			found; strip $L',
103238032Speter`dnl')
103338032Speter
103438032Speter# see if we have a relay or a hub
103538032SpeterR< > $+			$: < $H > $1			try hub
103638032SpeterR< > $+			$: < $R > $1			try relay
103764562SgshapiroR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
103864562SgshapiroR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
103964562SgshapiroR< > < $+ <> $* >	$: < > < $1 >			else discard
104038032SpeterR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
104138032SpeterR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1		strip the extra +
104238032SpeterR< > < $+ >		$@ $1				no +detail
104343730SpeterR$+			$: $1 <> $&h			add +detail back in
104443730SpeterR$+ <> + $*		$: $1 + $2			check whether +detail
104543730SpeterR$+ <> $*		$: $1				else discard
104664562SgshapiroR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
104764562SgshapiroR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
104864562SgshapiroR< $- : $+ > $+		$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
104964562SgshapiroR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
105038032Speter
105164562Sgshapiroifdef(`_MAILER_TABLE_', `dnl
105238032Speter###################################################################
105338032Speter###  Ruleset 90 -- try domain part of mailertable entry 	###
105464562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
105538032Speter###################################################################
105638032Speter
105764562SgshapiroSMailertable=90
105864562Sgshapirodnl shift and check
105964562Sgshapirodnl %2 is not documented in cf/README
106038032SpeterR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
106164562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses
106264562SgshapiroR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
106364562SgshapiroR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
106464562Sgshapirodnl is $2 always empty?
106538032SpeterR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
106664562SgshapiroR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
106764562Sgshapirodnl return full address
106838032SpeterR< $* > $*		$@ $2				no mailertable match',
106938032Speter`dnl')
107038032Speter
107138032Speter###################################################################
107238032Speter###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
107364562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest
107464562Sgshapirodnl	<> address				-> address
107564562Sgshapirodnl	<error:d.s.n:text>			-> error
107664562Sgshapirodnl	<error:text>				-> error
107764562Sgshapirodnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
107864562Sgshapirodnl	<mailer:host> address			-> mailer host address
107964562Sgshapirodnl	<localdomain> address			-> address
108064562Sgshapirodnl	<[IPv6 number]> address			-> relay number address
108164562Sgshapirodnl	<host> address				-> relay host address
108238032Speter###################################################################
108338032Speter
108464562SgshapiroSMailerToTriple=95
108538032SpeterR< > $*				$@ $1			strip off null relay
108664562SgshapiroR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
108738032SpeterR< error : $- $+ > $*		$#error $@ $(dequote $1 $) $: $2
108838032SpeterR< local : $* > $*		$>CanonLocal < $1 > $2
108938032SpeterR< $- : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
109038032SpeterR< $- : $+ > $*			$# $1 $@ $2 $: $3	try qualified mailer
109138032SpeterR< $=w > $*			$@ $2			delete local host
109264562SgshapiroR< [ IPv6 $+ ] > $*		$#_RELAY_ $@ $(dequote $1 $) $: $2	use unqualified mailer
109338032SpeterR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
109438032Speter
109538032Speter###################################################################
109638032Speter###  Ruleset CanonLocal -- canonify local: syntax		###
109764562Sgshapirodnl input: <user> address
109864562Sgshapirodnl <x> <@host> : rest			-> Recurse rest
109964562Sgshapirodnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
110064562Sgshapirodnl <> user <@host> rest		-> local user@host user
110164562Sgshapirodnl <> user				-> local user user
110264562Sgshapirodnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
110364562Sgshapirodnl <user> lp <@host> rest		-> local lp@host user
110464562Sgshapirodnl <user> lp				-> local lp user
110538032Speter###################################################################
110638032Speter
110738032SpeterSCanonLocal
110843730Speter# strip local host from routed addresses
110964562SgshapiroR< $* > < @ $+ > : $+		$@ $>Recurse $3
111064562SgshapiroR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
111143730Speter
111238032Speter# strip trailing dot from any host name that may appear
111338032SpeterR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
111438032Speter
111538032Speter# handle local: syntax -- use old user, either with or without host
111638032SpeterR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
111738032SpeterR< > $+				$#_LOCAL_ $@ $1    $: $1
111838032Speter
111938032Speter# handle local:user@host syntax -- ignore host part
112038032SpeterR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
112138032Speter
112238032Speter# handle local:user syntax
112338032SpeterR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
112438032SpeterR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
112538032Speter
112638032Speter###################################################################
112738032Speter###  Ruleset 93 -- convert header names to masqueraded form	###
112838032Speter###################################################################
112938032Speter
113064562SgshapiroSMasqHdr=93
113138032Speter
113264562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl
113338032Speter# handle generics database
113438032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_',
113564562Sgshapirodnl if generics should be applied add a @ as mark
113638032Speter`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
113738032Speter`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
113838032SpeterR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
113964562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @
114064562Sgshapirodnl ignore the first case for now
114164562Sgshapirodnl if it has the mark lookup full address
114264562SgshapiroR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
114364562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain>
114464562Sgshapirodnl no match, try user+detail@domain
114564562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
114664562Sgshapiro		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
114764562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ >
114864562Sgshapiro		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
114964562Sgshapirodnl no match, remove mark
115064562SgshapiroR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
115164562Sgshapirodnl no match, try @domain for exceptions
115264562SgshapiroR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
115364562Sgshapirodnl workspace: ... or <match> user <@domain>
115464562Sgshapirodnl no match, try local part
115538032SpeterR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
115664562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
115764562SgshapiroR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
115864562SgshapiroR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
115964562SgshapiroR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
116038032SpeterR< > $*			$: $1				not found',
116138032Speter`dnl')
116238032Speter
116364562Sgshapiro# do not masquerade anything in class N
116464562SgshapiroR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
116564562Sgshapiro
116638032Speter# special case the users that should be exposed
116738032SpeterR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
116838032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
116938032Speter`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
117038032Speter`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
117138032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
117238032Speter`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
117338032Speter
117438032Speter# handle domain-specific masquerading
117538032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
117638032Speter`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
117738032Speter`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
117838032Speterifdef(`_LIMITED_MASQUERADE_', `dnl',
117938032Speter`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
118038032SpeterR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
118138032SpeterR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
118238032SpeterR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
118338032Speter
118438032Speter###################################################################
118538032Speter###  Ruleset 94 -- convert envelope names to masqueraded form	###
118638032Speter###################################################################
118738032Speter
118864562SgshapiroSMasqEnv=94
118938032Speterifdef(`_MASQUERADE_ENVELOPE_',
119064562Sgshapiro`R$+			$@ $>MasqHdr $1',
119138032Speter`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
119238032Speter
119338032Speter###################################################################
119438032Speter###  Ruleset 98 -- local part of ruleset zero (can be null)	###
119538032Speter###################################################################
119638032Speter
119764562SgshapiroSParseLocal=98
119864562Sgshapiroundivert(3)dnl LOCAL_RULE_0
119938032Speter
120064562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl
120164562SgshapiroSLDAPExpand
120264562Sgshapiro# do the LDAP lookups
120364562SgshapiroR<$+><$+>		$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2>
120464562Sgshapiro
120564562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost,
120664562Sgshapiro# return the new mailRoutingAddress
120764562SgshapiroR< $+ > < $=w > < $+ > < $+ >	$@ $>Parse0 $>canonify $1
120864562SgshapiroR< $+ > <  > < $+ > < $+ >	$@ $>Parse0 $>canonify $1
120964562Sgshapiro
121064562Sgshapiro# if mailRoutingAddress and non-local mailHost,
121164562Sgshapiro# relay to mailHost with new mailRoutingAddress
121264562SgshapiroR< $+ > < $+ > < $+ > < $+ >	$#_RELAY_ $@ $2 $: $>canonify $1
121364562Sgshapiro
121464562Sgshapiro# if no mailRoutingAddress and local mailHost,
121564562Sgshapiro# return original address
121664562SgshapiroR< > < $=w > <$+> <$+>		$@ $2
121764562Sgshapiro
121864562Sgshapiro# if no mailRoutingAddress and non-local mailHost,
121964562Sgshapiro# relay to mailHost with original address
122064562SgshapiroR< > < $+ > <$+> <$+>		$#_RELAY_ $@ $1 $: $2
122164562Sgshapiro
122264562Sgshapiro# if no mailRoutingAddress and no mailHost,
122364562Sgshapiro# try @domain
122464562SgshapiroR< > < > <$+> <$+ @ $+>		$@ $>LDAPExpand <$1> <@ $3>
122564562Sgshapiro
122664562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt,
122764562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
122864562Sgshapiro# user does not exist
122964562SgshapiroR< > < > <$+> <@ $+>		$#error $@ nouser $: "550 User unknown"',
123064562Sgshapiro`dnl
123164562Sgshapiro# return the original address
123264562SgshapiroR< > < > <$+> <@ $+>		$@ $1')',
123364562Sgshapiro`dnl')
123464562Sgshapiro
123564562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
123664562Sgshapiro')')
123764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
123838032Speter######################################################################
123938032Speter###  LookUpDomain -- search for domain in access database
124038032Speter###
124138032Speter###	Parameters:
124238032Speter###		<$1> -- key (domain name)
124338032Speter###		<$2> -- default (what to return if not found in db)
124464562Sgshapirodnl			must not be empty
124538032Speter###		<$3> -- passthru (additional data passed unchanged through)
124664562Sgshapiro###		<$4> -- mark (must be <(!|+) single-token>)
124764562Sgshapiro###			! does lookup only with tag
124864562Sgshapiro###			+ does lookup with and without tag
124964562Sgshapirodnl returns:		<default> <passthru>
125064562Sgshapirodnl 			<result> <passthru>
125138032Speter######################################################################
125238032Speter
125338032SpeterSLookUpDomain
125464562Sgshapirodnl remove IPv6 mark and dequote address
125564562Sgshapirodnl it is a bit ugly because it is checked on each "iteration"
125664562SgshapiroR<[IPv6 $-]> <$+> <$*> <$*>	$: <[$(dequote $1 $)]> <$2> <$3> <$4>
125764562Sgshapirodnl workspace <key> <default> <passthru> <mark>
125864562Sgshapirodnl lookup with tag (in front, no delimiter here)
125964562SgshapiroR<$*> <$+> <$*> <$- $->		$: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5>
126064562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
126164562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest
126264562SgshapiroR<?> <$+.$+> <$+> <$*> <$- $->	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4> <$5 $6>', `dnl')
126364562Sgshapirodnl lookup without tag?
126464562SgshapiroR<?> <$+> <$+> <$*> <+ $*>	$: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4>
126564562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest
126664562SgshapiroR<?> <$+.$+> <$+> <$*> <+ $*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <$4> <+ $5>', `dnl')
126764562Sgshapirodnl lookup IP address (no check is done whether it is an IP number!)
126864562SgshapiroR<?> <[$+.$-]> <$+> <$*> <$*>	$@ $>LookUpDomain <[$1]> <$3> <$4> <$5>
126964562Sgshapirodnl lookup IPv6 address
127064562SgshapiroR<?> <[$+:$-]> <$+> <$*> <$*>	$: $>LookUpDomain <[$1]> <$3> <$4> <$5>
127164562Sgshapirodnl not found, but subdomain: try again
127264562SgshapiroR<?> <$+.$+> <$+> <$*> <$*>	$@ $>LookUpDomain <$2> <$3> <$4> <$5>
127364562Sgshapirodnl not found, no subdomain: return default
127464562SgshapiroR<?> <$+> <$+> <$*> <$*>	$@ <$2> <$3>
127564562Sgshapirodnl return result of lookup
127664562SgshapiroR<$*> <$+> <$+> <$*> <$*>	$@ <$1> <$4>
127738032Speter
127838032Speter######################################################################
127938032Speter###  LookUpAddress -- search for host address in access database
128038032Speter###
128138032Speter###	Parameters:
128238032Speter###		<$1> -- key (dot quadded host address)
128338032Speter###		<$2> -- default (what to return if not found in db)
128464562Sgshapirodnl			must not be empty
128538032Speter###		<$3> -- passthru (additional data passed through)
128664562Sgshapiro###		<$4> -- mark (must be <(!|+) single-token>)
128764562Sgshapiro###			! does lookup only with tag
128864562Sgshapiro###			+ does lookup with and without tag
128964562Sgshapirodnl	returns:	<default> <passthru>
129064562Sgshapirodnl			<result> <passthru>
129138032Speter######################################################################
129238032Speter
129338032SpeterSLookUpAddress
129464562Sgshapirodnl lookup with tag
129564562SgshapiroR<$+> <$+> <$*> <$- $+>		$: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5>
129664562Sgshapirodnl lookup without tag
129764562SgshapiroR<?> <$+> <$+> <$*> <+ $+>	$: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4>
129864562Sgshapirodnl no match; IPv6: remove last part
129964562SgshapiroR<?> <$+:$-> <$+> <$*> <$*>	$@ $>LookUpAddress <$1> <$3> <$4> <$5>
130064562Sgshapirodnl no match; IPv4: remove last part
130164562SgshapiroR<?> <$+.$-> <$+> <$*> <$*>	$@ $>LookUpAddress <$1> <$3> <$4> <$5>
130264562Sgshapirodnl no match: return default
130364562SgshapiroR<?> <$+> <$+> <$*> <$*>	$@ <$2> <$3>
130464562Sgshapirodnl match: return result
130564562SgshapiroR<$*> <$+> <$+> <$*> <$*>	$@ <$1> <$4>',
130638032Speter`dnl')
130738032Speter
130838032Speter######################################################################
130942575Speter###  CanonAddr --	Convert an address into a standard form for
131042575Speter###			relay checking.  Route address syntax is
131142575Speter###			crudely converted into a %-hack address.
131242575Speter###
131342575Speter###	Parameters:
131442575Speter###		$1 -- full recipient address
131542575Speter###
131642575Speter###	Returns:
131742575Speter###		parsed address, not in source route form
131864562Sgshapirodnl		user%host%host<@domain>
131964562Sgshapirodnl		host!user<@domain>
132042575Speter######################################################################
132142575Speter
132242575SpeterSCanonAddr
132364562SgshapiroR$*			$: $>Parse0 $>canonify $1	make domain canonical
132464562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
132542575SpeterR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
132642575SpeterR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
132742575SpeterR$* < @ $+ > : $*	$3 $1 < @ $2 >
132864562Sgshapirodnl')
132942575Speter
133042575Speter######################################################################
133138032Speter###  ParseRecipient --	Strip off hosts in $=R as well as possibly
133238032Speter###			$* $=m or the access database.
133338032Speter###			Check user portion for host separators.
133438032Speter###
133538032Speter###	Parameters:
133638032Speter###		$1 -- full recipient address
133738032Speter###
133838032Speter###	Returns:
133938032Speter###		parsed, non-local-relaying address
134038032Speter######################################################################
134138032Speter
134238032SpeterSParseRecipient
134364562Sgshapirodnl mark and canonify address
134442575SpeterR$*				$: <?> $>CanonAddr $1
134564562Sgshapirodnl workspace: <?> localpart<@domain[.]>
134642575SpeterR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
134764562Sgshapirodnl workspace: <?> localpart<@domain>
134842575SpeterR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
134938032Speter
135038032Speter# if no $=O character, no host in the user portion, we are done
135142575SpeterR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
135264562Sgshapirodnl no $=O in localpart: return
135342575SpeterR<?> $*				$@ $1
135438032Speter
135564562Sgshapirodnl workspace: <?> localpart<@domain>, where localpart contains $=O
135664562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY>
135738032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
135838032Speter# if we relay, check username portion for user%host so host can be checked also
135942575SpeterR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
136042575Speter
136142575Speterifdef(`_RELAY_MX_SERVED_', `dnl
136264562Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain?
136342575SpeterR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
136442575SpeterR<MX> < : $* <TEMP> : > $*	$#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
136564562Sgshapirodnl yes: mark it as <RELAY>
136642575SpeterR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
136764562Sgshapirodnl no: put old <NO> mark back
136842575SpeterR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
136942575Speter
137064562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
137164562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
137238032Speterifdef(`_RELAY_HOSTS_ONLY_',
137342575Speter`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
137464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
137564562SgshapiroR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
137642575SpeterR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
137742575Speter`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
137864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
137964562SgshapiroR<NO> $* < @ $+ >		$: $>LookUpDomain <$2> <NO> <$1 < @ $2 >> <+To>
138042575SpeterR<$+> <$+>			$: <$1> $2',`dnl')')
138138032Speter
138264562Sgshapiro
138342575SpeterR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
138442575SpeterR<$-> $*			$@ $2
138542575Speter
138664562Sgshapiro
138738032Speter######################################################################
138838032Speter###  check_relay -- check hostname/address on SMTP startup
138938032Speter######################################################################
139038032Speter
139138032SpeterSLocal_check_relay
139264562SgshapiroScheck`'_U_`'relay
139338032SpeterR$*			$: $1 $| $>"Local_check_relay" $1
139438032SpeterR$* $| $* $| $#$*	$#$3
139538032SpeterR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
139638032Speter
139738032SpeterSBasic_check_relay
139838032Speter# check for deferred delivery mode
139938032SpeterR$*			$: < ${deliveryMode} > $1
140038032SpeterR< d > $*		$@ deferred
140138032SpeterR< $* > $*		$: $2
140238032Speter
140364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
140464562SgshapiroR$+ $| $+		$: $>LookUpDomain < $1 > <?> < $2 > <+Connect>
140564562SgshapiroR<?> <$+>		$: $>LookUpAddress < $1 > <?> < $1 > <+Connect>	no: another lookup
140664562SgshapiroR<?> < $+ >		$: $1					found nothing
140764562SgshapiroR<$={Accept}> < $* >	$@ $1
140864562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
140938032SpeterR<DISCARD> $*		$#discard $: discard
141064562Sgshapirodnl error tag
141164562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
141264562SgshapiroR<ERROR:$+> $*		$#error $: $1
141364562Sgshapirodnl generic error from access map
141464562SgshapiroR<$+> $*		$#error $: $1', `dnl')
141538032Speter
141664562Sgshapiroifdef(`_RBL_',`dnl
141764562Sgshapiro# DNS based IP address spam list
141838032SpeterR$*			$: $&{client_addr}
141964562SgshapiroR::ffff:$-.$-.$-.$-	$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
142064562SgshapiroR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
142164562SgshapiroR<?>OK			$: OKSOFAR
142264562SgshapiroR<?>$+			$#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"',
142338032Speter`dnl')
142464562Sgshapiroundivert(8)
142538032Speter
142638032Speter######################################################################
142738032Speter###  check_mail -- check SMTP ``MAIL FROM:'' command argument
142838032Speter######################################################################
142938032Speter
143038032SpeterSLocal_check_mail
143164562SgshapiroScheck`'_U_`'mail
143238032SpeterR$*			$: $1 $| $>"Local_check_mail" $1
143338032SpeterR$* $| $#$*		$#$2
143438032SpeterR$* $| $*		$@ $>"Basic_check_mail" $1
143538032Speter
143638032SpeterSBasic_check_mail
143738032Speter# check for deferred delivery mode
143838032SpeterR$*			$: < ${deliveryMode} > $1
143938032SpeterR< d > $*		$@ deferred
144038032SpeterR< $* > $*		$: $2
144138032Speter
144264562Sgshapiro# authenticated?
144364562Sgshapirodnl done first: we can require authentication for every mail transaction
144464562Sgshapirodnl workspace: address as given by MAIL FROM: (sender)
144564562SgshapiroR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
144664562SgshapiroR$* $| $#$+		$#$2
144764562Sgshapirodnl undo damage: remove result of tls_client call
144864562SgshapiroR$* $| $*		$: $1
144938032Speter
145064562Sgshapirodnl workspace: address as given by MAIL FROM:
145164562SgshapiroR<>			$@ <OK>			we MUST accept <> (RFC 1123)
145238032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
145364562Sgshapirodnl do some additional checks
145464562Sgshapirodnl no user@host
145564562Sgshapirodnl no user@localhost (if nonlocal sender)
145664562Sgshapirodnl this is a pretty simple canonification, it will not catch every case
145764562Sgshapirodnl just make sure the address has <> around it (which is required by
145864562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...)
145964562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will
146064562Sgshapirodnl not be modified by host lookups.
146164562SgshapiroR$+			$: <?> $1
146264562SgshapiroR<?><$+>		$: <@> <$1>
146364562SgshapiroR<?>$+			$: <@> <$1>
146464562Sgshapirodnl workspace: <@> <address>
146564562Sgshapirodnl prepend daemon_flags
146664562SgshapiroR$*			$: $&{daemon_flags} $| $1
146764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
146864562Sgshapirodnl do not allow these at all or only from local systems?
146964562SgshapiroR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
147064562Sgshapirodnl accept unqualified sender: change mark to avoid test
147164562SgshapiroR$* u $* $| <@> < $* >	$: <?> < $3 >
147264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
147364562Sgshapirodnl        or:                    <? ${client_name} > <address>
147464562Sgshapirodnl        or:                    <?> <address>
147564562Sgshapirodnl remove daemon_flags
147664562SgshapiroR$* $| $*		$: $2
147738032Speter# handle case of @localhost on address
147864562SgshapiroR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
147964562SgshapiroR<@> < $* @ [127.0.0.1] >
148064562Sgshapiro			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
148164562SgshapiroR<@> < $* @ localhost.$m >
148264562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.$m >
148338032Speterifdef(`_NO_UUCP_', `dnl',
148464562Sgshapiro`R<@> < $* @ localhost.UUCP >
148564562Sgshapiro			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
148664562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
148764562Sgshapirodnl	or:    <@> <address>
148864562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
148964562SgshapiroR<@> $*			$: $1			no localhost as domain
149064562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host>
149164562Sgshapirodnl	or:    <address>
149264562Sgshapirodnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
149364562SgshapiroR<? $=w> $*		$: $2			local client: ok
149464562SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Real domain name required"
149564562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
149664562SgshapiroR<?> $*			$: $1')
149764562Sgshapirodnl workspace: address (or <address>)
149864562SgshapiroR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
149964562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
150064562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed
150164562SgshapiroR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
150264562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
150364562SgshapiroR<?> $* < @ $* $=P >	$: <OK> $1 < @ $2 $3 >
150464562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ? or OK
150564562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
150664562Sgshapiro`R<?> $* < @ $+ >	$: <OK> $1 < @ $2 >		... unresolvable OK',
150764562Sgshapiro`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
150864562SgshapiroR<? $* <$->> $* < @ $+ >
150964562Sgshapiro			$: <$2> $3 < @ $4 >')
151064562Sgshapirodnl workspace <mark> CanonicalAddress	where mark is ?, OK, PERM, TEMP
151164562Sgshapirodnl mark is ? iff the address is user (wo @domain)
151238032Speter
151364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
151464562Sgshapiro# check sender address: user@address, user@, address
151564562Sgshapirodnl should we remove +ext from user?
151664562Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, OK, PERM, TEMP
151764562SgshapiroR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <H:$3>
151864562SgshapiroR<$+> $+		$: @<$1> <$2> $| <U:$2@>
151964562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
152064562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
152164562Sgshapirodnl will only return user<@domain when "reversing" the args
152264562SgshapiroR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+From> $| <$3> <>
152364562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result>
152464562SgshapiroR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
152564562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress>
152638032Speter# retransform for further use
152764562Sgshapirodnl required form:
152864562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress
152964562SgshapiroR<?> <$+> <$*>		$: <$1> $2	no match
153064562SgshapiroR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
153164562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress
153264562Sgshapirodnl mark is ? iff the address is user (wo @domain)
153338032Speter
153438032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
153538032Speter# handle case of no @domain on address
153664562Sgshapirodnl prepend daemon_flags
153764562SgshapiroR<?> $*			$: $&{daemon_flags} $| <?> $1
153864562Sgshapirodnl accept unqualified sender: change mark to avoid test
153964562SgshapiroR$* u $* $| <?> $*	$: <OK> $3
154064562Sgshapirodnl remove daemon_flags
154164562SgshapiroR$* $| $*		$: $2
154238032SpeterR<?> $*			$: < ? $&{client_name} > $1
154338032SpeterR<?> $*			$@ <OK>				...local unqualed ok
154438032SpeterR<? $+> $*		$#error $@ 5.5.4 $: "553 Domain name required"
154538032Speter							...remote is not')
154638032Speter# check results
154764562SgshapiroR<?> $*			$: @ $1		mark address: nothing known about it
154838032SpeterR<OK> $*		$@ <OK>
154964562SgshapiroR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
155064562SgshapiroR<PERM> $*		$#error $@ 5.1.8 $: "501 Domain of sender address " $&f " does not exist"
155164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
155264562SgshapiroR<$={Accept}> $*	$# $1
155338032SpeterR<DISCARD> $*		$#discard $: discard
155464562SgshapiroR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
155564562Sgshapirodnl error tag
155664562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
155764562SgshapiroR<ERROR:$+> $*		$#error $: $1
155864562Sgshapirodnl generic error from access map
155964562SgshapiroR<$+> $*		$#error $: $1		error from access db',
156038032Speter`dnl')
156138032Speter
156238032Speter######################################################################
156338032Speter###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
156438032Speter######################################################################
156538032Speter
156638032SpeterSLocal_check_rcpt
156764562SgshapiroScheck`'_U_`'rcpt
156838032SpeterR$*			$: $1 $| $>"Local_check_rcpt" $1
156938032SpeterR$* $| $#$*		$#$2
157038032SpeterR$* $| $*		$@ $>"Basic_check_rcpt" $1
157138032Speter
157238032SpeterSBasic_check_rcpt
157338032Speter# check for deferred delivery mode
157438032SpeterR$*			$: < ${deliveryMode} > $1
157538032SpeterR< d > $*		$@ deferred
157638032SpeterR< $* > $*		$: $2
157738032Speter
157864562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
157964562Sgshapiro# require qualified recipient?
158064562SgshapiroR$+			$: <?> $1
158164562SgshapiroR<?><$+>		$: <@> <$1>
158264562SgshapiroR<?>$+			$: <@> <$1>
158364562Sgshapirodnl prepend daemon_flags
158464562SgshapiroR$*			$: $&{daemon_flags} $| $1
158564562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address>
158664562Sgshapirodnl do not allow these at all or only from local systems?
158764562SgshapiroR$* r $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
158864562SgshapiroR<?> < $* >		$: <$1>
158964562SgshapiroR<? $=w> < $* >		$: <$1>
159064562SgshapiroR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Domain name required"
159164562Sgshapirodnl remove daemon_flags for other cases
159264562SgshapiroR$* $| <@> $*		$: $2', `dnl')
159364562Sgshapiro
159438032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl
159542575SpeterR$*			$: $>CanonAddr $1
159638032SpeterR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
159738032Speter`R$*			$: $>ParseRecipient $1		strip relayable hosts')
159838032Speter
159942575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl
160042575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl
160142575Speter# unlimited bestmx
160242575SpeterR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
160342575Speter`dnl
160442575Speter# limit bestmx to $=B
160543730SpeterR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
160664562SgshapiroR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Basic_check_rcpt" $1 $2 $3
160742575SpeterR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
160842575SpeterR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
160942575Speter
161038032Speterifdef(`_BLACKLIST_RCPT_',`dnl
161164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
161238032Speter# blacklist local users or any host from receiving mail
161338032SpeterR$*			$: <?> $1
161464562Sgshapirodnl user is now tagged with @ to be consistent with check_mail
161564562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user)
161664562SgshapiroR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <H:$2>
161764562SgshapiroR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <H:$2>
161864562SgshapiroR<?> $+			$: <> <$1> $| <U:$1@>
161964562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
162064562Sgshapirodnl will only return user<@domain when "reversing" the args
162164562SgshapiroR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+To> $| <$2> <>
162264562SgshapiroR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
162364562SgshapiroR<?> <$*>		$: @ $1		mark address as no match
162464562SgshapiroR<$={Accept}> <$*>	$: @ $2		mark address as no match
162564562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
162664562Sgshapirodnl we have to filter these because otherwise they would be interpreted
162764562Sgshapirodnl as generic error message...
162864562Sgshapirodnl error messages should be "tagged" by prefixing them with error: !
162964562Sgshapirodnl that would make a lot of things easier.
163064562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)?
163164562SgshapiroR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
163238032SpeterR<REJECT> $*		$#error $@ 5.2.1 $: "550 Mailbox disabled for this recipient"
163364562SgshapiroR<DISCARD> $*		$#discard $: discard
163464562Sgshapirodnl error tag
163564562SgshapiroR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
163664562SgshapiroR<ERROR:$+> $*		$#error $: $1
163764562Sgshapirodnl generic error from access map
163864562SgshapiroR<$+> $*		$#error $: $1		error from access db
163964562SgshapiroR@ $*			$1		remove mark', `dnl')', `dnl')
164038032Speter
164164562Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)')
164264562Sgshapiro# authenticated?
164364562Sgshapirodnl do this unconditionally? this requires to manage CAs carefully
164464562Sgshapirodnl just because someone has a CERT signed by a "trusted" CA
164564562Sgshapirodnl does not mean we want to allow relaying for her,
164664562Sgshapirodnl either use a subroutine or provide something more sophisticated
164764562Sgshapirodnl this could for example check the DN (maybe an access map lookup)
164864562SgshapiroR$*		$: $1 $| $>RelayAuth $1 $| $&{verify}	client authenticated?
164964562SgshapiroR$* $| $# $+		$# $2				error/ok?
165064562SgshapiroR$* $| $*		$: $1				no
165164562Sgshapiro
165264562Sgshapiro# authenticated by a trusted mechanism?
165364562SgshapiroR$*			$: $1 $| $&{auth_type}
165464562Sgshapirodnl empty ${auth_type}?
165564562SgshapiroR$* $|			$: $1
165664562Sgshapirodnl mechanism ${auth_type} accepted?
165764562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below
165864562SgshapiroR$* $| $={TrustAuthMech}	$# RELAYAUTH
165964562Sgshapirodnl undo addition of ${auth_type}
166064562SgshapiroR$* $| $*		$: $1
166164562Sgshapirodnl workspace: localpart<@domain>
166264562Sgshapiroifelse(defn(`_NO_UUCP_'), `r',
166364562Sgshapiro`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
166438032Speter# anything terminating locally is ok
166538032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
166664562SgshapiroR$+ < @ $* $=m >	$@ RELAYTO', `dnl')
166764562SgshapiroR$+ < @ $=w >		$@ RELAYTO
166838032Speterifdef(`_RELAY_HOSTS_ONLY_',
166964562Sgshapiro`R$+ < @ $=R >		$@ RELAYTO
167064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
167164562SgshapiroR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
167264562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
167364562SgshapiroR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
167464562Sgshapiro`R$+ < @ $* $=R >	$@ RELAYTO
167564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
167664562SgshapiroR$+ < @ $+ >		$: $>LookUpDomain <$2> <?> <$1 < @ $2 >> <+To>',`dnl')')
167764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
167864562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
167964562SgshapiroR<RELAY> $*		$@ RELAYTO
168038032SpeterR<$*> <$*>		$: $2',`dnl')
168138032Speter
168264562Sgshapiro
168338032Speterifdef(`_RELAY_MX_SERVED_', `dnl
168438032Speter# allow relaying for hosts which we MX serve
168564562SgshapiroR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
168664562Sgshapirodnl this must not necessarily happen if the client is checked first...
168738032SpeterR< : $* <TEMP> : > $*	$#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
168864562SgshapiroR<$* : $=w . : $*> $*	$@ RELAYTO
168942575SpeterR< : $* : > $*		$: $2',
169038032Speter`dnl')
169138032Speter
169238032Speter# check for local user (i.e. unqualified address)
169338032SpeterR$*			$: <?> $1
169442575SpeterR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
169538032Speter# local user is ok
169664562Sgshapirodnl is it really? the standard requires user@domain, not just user
169764562Sgshapirodnl but we should accept it anyway (maybe making it an option:
169864562Sgshapirodnl RequireFQDN ?)
169964562Sgshapirodnl postmaster must be accepted without domain (DRUMS)
170064562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl
170164562SgshapiroR<?> postmaster		$@ TOPOSTMASTER
170264562Sgshapiro# require qualified recipient?
170364562Sgshapirodnl prepend daemon_flags
170464562SgshapiroR<?> $+			$: $&{daemon_flags} $| <?> $1
170564562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart
170664562Sgshapirodnl do not allow these at all or only from local systems?
170764562Sgshapirodnl r flag? add client_name
170864562SgshapiroR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
170964562Sgshapirodnl no r flag: relay to local user (only local part)
171064562Sgshapiro# no qualified recipient required
171164562SgshapiroR$* $| <?> $+		$@ RELAYTOLOCAL
171264562Sgshapirodnl client_name is empty
171364562SgshapiroR<?> <?> $+		$@ RELAYTOLOCAL
171464562Sgshapirodnl client_name is local
171564562SgshapiroR<? $=w> <?> $+		$@ RELAYTOLOCAL
171664562Sgshapirodnl client_name is not local
171764562SgshapiroR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
171864562Sgshapirodnl no qualified recipient required
171964562SgshapiroR<?> $+			$@ RELAYTOLOCAL')
172064562Sgshapirodnl it is a remote user: remove mark and then check client
172138032SpeterR<$+> $*		$: $2
172264562Sgshapirodnl currently the recipient address is not used below
172338032Speter
172438032Speter# anything originating locally is ok
172564562Sgshapiro# check IP address
172664562SgshapiroR$*			$: $&{client_addr}
172764562SgshapiroR$@			$@ RELAYFROM		originated locally
172864562SgshapiroR0			$@ RELAYFROM		originated locally
172964562SgshapiroR$=R $*			$@ RELAYFROM		relayable IP address
173064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
173164562SgshapiroR$*			$: $>LookUpAddress <$1> <?> <$1> <+Connect>
173264562SgshapiroR<RELAY> $* 		$@ RELAYFROM		relayable IP address
173364562SgshapiroR<$*> <$*>		$: $2', `dnl')
173464562SgshapiroR$*			$: [ $1 ]		put brackets around it...
173564562SgshapiroR$=w			$@ RELAYFROM		... and see if it is local
173664562Sgshapiro
173764562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
173864562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
173964562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl
174064562Sgshapirodnl input: {client_addr} or something "broken"
174164562Sgshapirodnl just throw the input away; we do not need it.
174264562Sgshapiro# check whether FROM is allowed to use system as relay
174364562SgshapiroR$*			$: <?> $>CanonAddr $&f
174464562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl
174564562Sgshapiro# check whether local FROM is ok
174664562SgshapiroR<?> $+ < @ $=w . >	$@ RELAYFROMMAIL	FROM local', `dnl')
174764562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl
174864562SgshapiroR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
174964562SgshapiroR<?> $+ < @ $+ >	$: $1 < @ $2 > $| $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<H:$2>') <>
175064562SgshapiroR$* <RELAY>		$@ RELAYFROMMAIL	RELAY FROM sender ok', `dnl
175164562Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', `errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
175264562Sgshapiro')',
175364562Sgshapiro`dnl')
175464562Sgshapirodnl')', `dnl')
175564562Sgshapiro
175664562Sgshapiro# check client name: first: did it resolve?
175764562Sgshapirodnl input: ignored
175864562SgshapiroR$*			$: < $&{client_resolve} >
175964562SgshapiroR<TEMP>			$#error $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
176064562SgshapiroR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
176164562SgshapiroR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
176264562Sgshapirodnl ${client_resolve} should be OK, so go ahead
176338032SpeterR$*			$: <?> $&{client_name}
176438032Speter# pass to name server to make hostname canonical
176564562SgshapiroR<?> $* $~P 		$:<?>  $[ $1 $2 $]
176664562SgshapiroR$* .			$1			strip trailing dots
176764562Sgshapirodnl should not be necessary since it has been done for client_addr already
176864562SgshapiroR<?>			$@ RELAYFROM
176938032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
177064562SgshapiroR<?> $* $=m		$@ RELAYFROM', `dnl')
177164562SgshapiroR<?> $=w		$@ RELAYFROM
177238032Speterifdef(`_RELAY_HOSTS_ONLY_',
177364562Sgshapiro`R<?> $=R		$@ RELAYFROM
177464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
177564562SgshapiroR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
177664562SgshapiroR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
177764562Sgshapiro`R<?> $* $=R			$@ RELAYFROM
177864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
177964562SgshapiroR<?> $*			$: $>LookUpDomain <$1> <?> <$1> <+Connect>',`dnl')')
178064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
178164562SgshapiroR<RELAY> $*		$@ RELAYFROM
178238032SpeterR<$*> <$*>		$: $2',`dnl')
178338032Speter
178464562Sgshapiro# anything else is bogus
178564562SgshapiroR$*			$#error $@ 5.7.1 $: confRELAY_MSG
178664562Sgshapirodivert(0)
178764562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl
178864562Sgshapiro# turn a canonical address in the form user<@domain>
178964562Sgshapiro# qualify unqual. addresses with $j
179064562Sgshapirodnl it might have been only user (without <@domain>)
179164562SgshapiroSFullAddr
179264562SgshapiroR$* <@ $+ . >		$1 <@ $2 >
179364562SgshapiroR$* <@ $* >		$@ $1 <@ $2 >
179464562SgshapiroR$+			$@ $1 <@ $j >
179538032Speter
179664562Sgshapiro# call all necessary rulesets
179764562SgshapiroScheck_rcpt
179864562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset
179964562Sgshapirodnl which is the correct DSN code?
180064562Sgshapiro# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
180164562SgshapiroR$+			$: $1 $| $>checkrcpt $1
180264562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
180364562SgshapiroR$+ $| $#$*		$#$2
180464562SgshapiroR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
180564562Sgshapiroifdef(`_SPAM_FH_',
180664562Sgshapiro`dnl lookup user@ and user@address
180764562Sgshapiroifdef(`_ACCESS_TABLE_', `',
180864562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
180964562Sgshapiro')')dnl
181064562Sgshapirodnl one of the next two rules is supposed to match
181164562Sgshapirodnl this code has been copied from BLACKLIST... etc
181264562Sgshapirodnl and simplified by omitting some < >.
181364562SgshapiroR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <U: $1@>
181464562SgshapiroR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 >
181564562Sgshapirodnl R<?>		$@ something_is_very_wrong_here
181664562Sgshapiro# lookup the addresses only with To tag
181764562SgshapiroR<> $* $| <$+>		$: <@> $1 $| $>SearchList <!To> $| <$2> <>
181864562SgshapiroR<@> $* $| $*		$: $2 $1		reverse result
181964562Sgshapirodnl', `dnl')
182064562Sgshapiroifdef(`_SPAM_FRIEND_',
182164562Sgshapiro`# is the recipient a spam friend?
182264562Sgshapiroifdef(`_SPAM_HATER_',
182364562Sgshapiro	`errprint(`*** ERROR: define either SpamHater or SpamFriend
182464562Sgshapiro')', `dnl')
182564562SgshapiroR<SPAMFRIEND> $+	$@ SPAMFRIEND
182664562SgshapiroR<$*> $+		$: $2',
182764562Sgshapiro`dnl')
182864562Sgshapiroifdef(`_SPAM_HATER_',
182964562Sgshapiro`# is the recipient no spam hater?
183064562SgshapiroR<SPAMHATER> $+		$: $1			spam hater: continue checks
183164562SgshapiroR<$*> $+		$@ NOSPAMHATER		everyone else: stop
183264562Sgshapirodnl',`dnl')
183364562Sgshapirodnl run further checks: check_mail
183464562Sgshapirodnl should we "clean up" $&f?
183564562SgshapiroR$*			$: $1 $| $>checkmail <$&f>
183664562SgshapiroR$* $| $#$*		$#$2
183764562Sgshapirodnl run further checks: check_relay
183864562SgshapiroR$*			$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
183964562SgshapiroR$* $| $#$*		$#$2
184038032SpeterR$* $| $*		$: $1
184138032Speter', `dnl')
184264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
184364562Sgshapiro######################################################################
184464562Sgshapiro###  SearchList: search a list of items in the access map
184564562Sgshapiro###	Parameters:
184664562Sgshapiro###		<exact tag> $| <mark:address> <mark:address> ... <>
184764562Sgshapirodnl	maybe we should have a @ (again) in front of the mark to
184864562Sgshapirodnl	avoid errorneous matches (with error messages?)
184964562Sgshapirodnl	if we can make sure that tag is always a single token
185064562Sgshapirodnl	then we can omit the delimiter $|, otherwise we need it
185164562Sgshapirodnl	to avoid errorneous matchs (first rule: H: if there
185264562Sgshapirodnl	is that mark somewhere in the list, it will be taken).
185364562Sgshapirodnl	moreover, we can do some tricks to enforce lookup with
185464562Sgshapirodnl	the tag only, e.g.:
185564562Sgshapiro###	where "exact" is either "+" or "!":
185664562Sgshapiro###	<+ TAG>	lookup with and w/o tag
185764562Sgshapiro###	<! TAG>	lookup with tag
185864562Sgshapirodnl	Warning: + and ! should be in OperatorChars (otherwise there must be
185964562Sgshapirodnl		a blank between them and the tag.
186064562Sgshapiro###	possible values for "mark" are:
186164562Sgshapiro###		H: recursive host lookup (LookUpDomain)
186264562Sgshapirodnl		A: recursive address lookup (LookUpAddress) [not yet required]
186364562Sgshapiro###		E: exact lookup, no modifications
186464562Sgshapiro###		F: full lookup, try user+ext@domain and user@domain
186564562Sgshapiro###		U: user lookup, try user+ext and user (input must have trailing @)
186664562Sgshapiro###	return: <RHS of lookup> or <?> (not found)
186764562Sgshapiro######################################################################
186838032Speter
186964562Sgshapiro# class with valid marks for SearchList
187064562Sgshapirodnl if A is activated: add it
187164562SgshapiroC{src}E F H U
187264562SgshapiroSSearchList
187364562Sgshapiro# mark H: lookup domain
187464562SgshapiroR<$+> $| <H:$+> <$*>		$: <$1> $| <@> $>LookUpDomain <$2> <?> <$3> <$1>
187564562SgshapiroR<$+> $| <@> <$+> <$*>		$: <$1> $| <$2> <$3>
187664562Sgshapirodnl A: NOT YET REQUIRED
187764562Sgshapirodnl R<$+> $| <A:$+> <$*>	$: <$1> $| <@> $>LookUpAddress <$2> <?> <$3> <$1>
187864562Sgshapirodnl R<$+> $| <@> <$+> <$*>	$: <$1> $| <$2> <$3>
187964562Sgshapirodnl lookup of the item with tag
188064562Sgshapirodnl this applies to F: U: E:
188164562SgshapiroR<$- $-> $| <$={src}:$+> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5>
188264562Sgshapirodnl no match, try without tag
188364562SgshapiroR<+ $-> $| <$={src}:$+> <$*>	$: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4>
188464562Sgshapirodnl do we really have to distinguish these cases?
188564562Sgshapirodnl probably yes, there might be a + in the domain part (is that allowed?)
188664562Sgshapirodnl user+detail lookups: should it be:
188764562Sgshapirodnl user+detail, user+*, user; just like aliases?
188864562SgshapiroR<$- $-> $| <F:$* + $*@$+> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@$5 $: F:$3 + $4@$5$)> <$6>
188964562SgshapiroR<+ $-> $| <F:$* + $*@$+> <$*>	$: <+ $1> $| <$(access $2@$4 $: F:$2 + $3@$4$)> <$5>
189064562Sgshapirodnl user lookups are always with trailing @
189164562Sgshapirodnl do not remove the @ from the lookup:
189264562Sgshapirodnl it is part of the +detail@ which is omitted for the lookup
189364562SgshapiroR<$- $-> $| <U:$* + $*> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5>
189464562Sgshapirodnl no match, try without tag
189564562SgshapiroR<+ $-> $| <U:$* + $*> <$*>	$: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4>
189664562Sgshapirodnl no match, try rest of list
189764562SgshapiroR<$+> $| <$={src}:$+> <$+>	$@ $>SearchList <$1> $| <$4>
189864562Sgshapirodnl no match, list empty: return failure
189964562SgshapiroR<$+> $| <$={src}:$+> <>	$@ <?>
190064562Sgshapirodnl got result, return it
190164562SgshapiroR<$+> $| <$+> <$*>		$@ <$2>
190264562Sgshapirodnl return result from recursive invocation
190364562SgshapiroR<$+> $| <$+>			$@ <$2>', `dnl')
190438032Speter
190564562Sgshapiro# is user trusted to authenticate as someone else?
190664562Sgshapirodnl AUTH= parameter from MAIL command
190764562SgshapiroStrust_auth
190864562SgshapiroR$*			$: $&{auth_type} $| $1
190964562Sgshapiro# required by RFC 2554 section 4.
191064562SgshapiroR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
191164562Sgshapirodnl seems to be useful...
191264562SgshapiroR$* $| $&{auth_authen}		$@ identical
191364562SgshapiroR$* $| <$&{auth_authen}>	$@ identical
191464562Sgshapirodnl call user supplied code
191564562SgshapiroR$* $| $*		$: $1 $| $>"Local_trust_auth" $1
191664562SgshapiroR$* $| $#$*		$#$2
191764562Sgshapirodnl default: error
191864562SgshapiroR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
191964562Sgshapiro
192064562Sgshapirodnl empty ruleset definition so it can be called
192164562SgshapiroSLocal_trust_auth
192264562Sgshapiro
192364562Sgshapiroifdef(`_FFR_TLS_O_T', `dnl
192464562SgshapiroSoffer_tls
192564562SgshapiroR$*		$: $>LookUpDomain <$&{client_name}> <?> <> <! TLS_OFF_TAG>
192664562SgshapiroR<?>$*		$: $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_OFF_TAG>
192764562SgshapiroR<?>$*		$: <$(access TLS_OFF_TAG: $: ? $)>
192864562SgshapiroR<?>$*		$@ OK
192964562SgshapiroR<NO> <>	$#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]"
193064562Sgshapiro
193164562SgshapiroStry_tls
193264562SgshapiroR$*		$: $>LookUpDomain <$&{server_name}> <?> <> <! TLS_TRY_TAG>
193364562SgshapiroR<?>$*		$: $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_TRY_TAG>
193464562SgshapiroR<?>$*		$: <$(access TLS_TRY_TAG: $: ? $)>
193564562SgshapiroR<?>$*		$@ OK
193664562SgshapiroR<NO> <>	$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
193764562Sgshapiro')dnl
193864562Sgshapiro
193964562Sgshapiro# is connection with client "good" enough? (done in server)
194064562Sgshapiro# input: ${verify} $| (MAIL|STARTTLS)
194164562Sgshapirodnl MAIL: called from check_mail
194264562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted
194364562SgshapiroStls_client
194464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
194564562Sgshapirodnl ignore second arg for now
194664562Sgshapirodnl maybe use it to distinguish permanent/temporary error?
194764562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered)
194864562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed)
194964562SgshapiroR$* $| $*	$: $1 $| $>LookUpDomain <$&{client_name}> <?> <> <! TLS_CLT_TAG>
195064562SgshapiroR$* $| <?>$*	$: $1 $| $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_CLT_TAG>
195164562Sgshapirodnl do a default lookup: just TLS_CLT_TAG
195264562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
195364562SgshapiroR$*		$@ $>"tls_connection" $1', `dnl
195464562SgshapiroR$* $| $*	$@ $>"tls_connection" $1')
195564562Sgshapiro
195664562Sgshapiro# is connection with server "good" enough? (done in client)
195764562Sgshapirodnl i.e. has the server been authenticated and is encryption active?
195864562Sgshapirodnl called from deliver() after STARTTLS command
195964562Sgshapiro# input: ${verify}
196064562SgshapiroStls_server
196164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
196264562SgshapiroR$*		$: $1 $| $>LookUpDomain <$&{server_name}> <?> <> <! TLS_SRV_TAG>
196364562SgshapiroR$* $| <?>$*	$: $1 $| $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_SRV_TAG>
196464562Sgshapirodnl do a default lookup: just TLS_SRV_TAG
196564562SgshapiroR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
196664562SgshapiroR$*		$@ $>"tls_connection" $1', `dnl
196764562SgshapiroR$*		$@ $>"tls_connection" $1')
196864562Sgshapiro
196964562SgshapiroStls_connection
197064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
197164562Sgshapirodnl common ruleset for tls_{client|server}
197264562Sgshapirodnl input: $&{verify} $| <ResultOfLookup> [<>]
197364562Sgshapirodnl remove optional <>
197464562SgshapiroR$* $| <$*>$*			$: $1 $| <$2>
197564562Sgshapirodnl permanent or temporary error?
197664562SgshapiroR$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
197764562SgshapiroR$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
197864562Sgshapirodnl default case depends on TLS_PERM_ERR
197964562SgshapiroR$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
198064562Sgshapirodnl deal with TLS handshake failures: abort
198164562SgshapiroRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
198264562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map
198364562Sgshapirodnl use default error
198464562SgshapiroRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
198564562SgshapiroR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> $1
198664562SgshapiroR$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> $1
198764562Sgshapirodnl some other value in access map: accept
198864562Sgshapirodnl this also allows to override the default case (if used)
198964562SgshapiroR$* $| $*			$@ OK
199064562Sgshapiro# authentication required: give appropriate error
199164562Sgshapiro# other side did authenticate (via STARTTLS)
199264562Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> ${verify}
199364562Sgshapirodnl only verification required and it succeeded
199464562SgshapiroR<$*><VERIFY> OK		$@ OK
199564562Sgshapirodnl verification required + some level of encryption
199664562SgshapiroR<$*><VERIFY:$-> OK		$: <$1> <REQ:$2>
199764562Sgshapirodnl just some level of encryption required
199864562SgshapiroR<$*><ENCR:$-> $*		$: <$1> <REQ:$2>
199964562Sgshapirodnl verification required but ${verify} is not set
200064562SgshapiroR<$-:$+><VERIFY $*>		$#error $@ $2 $: $1 " authentication required"
200164562SgshapiroR<$-:$+><VERIFY $*> FAIL	$#error $@ $2 $: $1 " authentication failed"
200264562SgshapiroR<$-:$+><VERIFY $*> NO		$#error $@ $2 $: $1 " not authenticated"
200364562SgshapiroR<$-:$+><VERIFY $*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
200464562Sgshapirodnl some other value for ${verify}
200564562SgshapiroR<$-:$+><VERIFY $*> $+		$#error $@ $2 $: $1 " authentication failure " $4
200664562Sgshapirodnl some level of encryption required: get the maximum level
200764562SgshapiroR<$*><REQ:$->			$: <$1> <REQ:$2> $>max $&{cipher_bits} : $&{auth_ssf}
200864562Sgshapirodnl compare required bits with actual bits
200964562SgshapiroR<$*><REQ:$-> $-		$: <$1> <$2:$3> $(arith l $@ $3 $@ $2 $)
201064562SgshapiroR<$-:$+><$-:$-> TRUE		$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
201164562Sgshapiro
201264562SgshapiroSmax
201364562Sgshapirodnl compute the max of two values separated by :
201464562SgshapiroR:		$: 0
201564562SgshapiroR:$-		$: $1
201664562SgshapiroR$-:		$: $1
201764562SgshapiroR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
201864562SgshapiroRTRUE:$-:$-	$: $2
201964562SgshapiroR$-:$-:$-	$: $2',
202064562Sgshapiro`dnl use default error
202164562Sgshapirodnl deal with TLS handshake failures: abort
202264562SgshapiroRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."')
202364562Sgshapiro
202464562SgshapiroSRelayAuth
202564562Sgshapiro# authenticated?
202664562Sgshapirodnl we do not allow relaying for anyone who can present a cert
202764562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns
202864562Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow
202964562Sgshapirodnl them to abuse our server (they might be easier to get hold of,
203064562Sgshapirodnl but anyway).
203164562Sgshapirodnl so here is the trick: if the verification succeeded
203264562Sgshapirodnl we look up the cert issuer in the access map
203364562Sgshapirodnl (maybe after extracting a part with a regular expression)
203464562Sgshapirodnl if this returns RELAY we relay without further questions
203564562Sgshapirodnl if it returns SUBJECT we perform a similar check on the
203664562Sgshapirodnl cert subject.
203764562SgshapiroR$* $| OK		$: $1
203864562SgshapiroR$* $| $*		$@ NO		not authenticated
203964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl
204064562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl
204164562SgshapiroR$*			$: $1 $| $(CERTIssuer $&{cert_issuer} $)',
204264562Sgshapiro`R$*			$: $1 $| $&{cert_issuer}')
204364562SgshapiroR$* $| $+		$: $1 $| $(access CERTISSUER:$2 $)
204464562Sgshapirodnl use $# to stop further checks (delay_check)
204564562SgshapiroR$* $| RELAY		$# RELAYCERTISSUER
204664562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl
204764562SgshapiroR$* $| SUBJECT		$: $1 $| <@> $(CERTSubject $&{cert_subject} $)',
204864562Sgshapiro`R$* $| SUBJECT		$: $1 $| <@> $&{cert_subject}')
204964562SgshapiroR$* $| <@> $+		$: $1 $| <@> $(access CERTSUBJECT:$&{cert_subject} $)
205064562SgshapiroR$* $| <@> RELAY	$# RELAYCERTSUBJECT
205164562SgshapiroR$* $| $*		$: $1', `dnl')
205264562Sgshapiro
205364562Sgshapiroundivert(9)dnl LOCAL_RULESETS
205464562Sgshapiroifdef(`_FFR_MILTER', `
205538032Speter#
205638032Speter######################################################################
205738032Speter######################################################################
205838032Speter#####
205964562Sgshapiro`#####			MAIL FILTER DEFINITIONS'
206064562Sgshapiro#####
206164562Sgshapiro######################################################################
206264562Sgshapiro######################################################################
206364562Sgshapiro_MAIL_FILTERS_')
206464562Sgshapiro#
206564562Sgshapiro######################################################################
206664562Sgshapiro######################################################################
206764562Sgshapiro#####
206838032Speter`#####			MAILER DEFINITIONS'
206938032Speter#####
207038032Speter######################################################################
207138032Speter######################################################################
207264562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS
2073