xref: /onnv-gate/usr/src/cmd/sendmail/cf/m4/proto.m4 (revision 3544:8dfb1c11a5d7)
10Sstevel@tonic-gatedivert(-1)
20Sstevel@tonic-gate#
32197Sjbeck# Copyright (c) 1998-2006 Sendmail, Inc. and its suppliers.
40Sstevel@tonic-gate#	All rights reserved.
50Sstevel@tonic-gate# Copyright (c) 1983, 1995 Eric P. Allman.  All rights reserved.
60Sstevel@tonic-gate# Copyright (c) 1988, 1993
70Sstevel@tonic-gate#	The Regents of the University of California.  All rights reserved.
80Sstevel@tonic-gate#
90Sstevel@tonic-gate# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
100Sstevel@tonic-gate# Use is subject to license terms.
110Sstevel@tonic-gate#
120Sstevel@tonic-gate# ident	"%Z%%M%	%I%	%E% SMI"
130Sstevel@tonic-gate#
140Sstevel@tonic-gate# By using this file, you agree to the terms and conditions set
150Sstevel@tonic-gate# forth in the LICENSE file which can be found at the top level of
160Sstevel@tonic-gate# the sendmail distribution.
170Sstevel@tonic-gate#
180Sstevel@tonic-gate#
190Sstevel@tonic-gatedivert(0)
200Sstevel@tonic-gate
21*3544SjbeckVERSIONID(`$Id: proto.m4,v 8.726 2007/01/04 18:27:46 ca Exp $')
220Sstevel@tonic-gate
230Sstevel@tonic-gate# level CF_LEVEL config file format
240Sstevel@tonic-gateV`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Sun')
250Sstevel@tonic-gatedivert(-1)
260Sstevel@tonic-gate
270Sstevel@tonic-gatednl if MAILER(`local') not defined: do it ourself; be nice
280Sstevel@tonic-gatednl maybe we should issue a warning?
290Sstevel@tonic-gateifdef(`_MAILER_local_',`', `MAILER(local)')
300Sstevel@tonic-gate
310Sstevel@tonic-gate# do some sanity checking
320Sstevel@tonic-gateifdef(`__OSTYPE__',,
330Sstevel@tonic-gate	`errprint(`*** ERROR: No system type defined (use OSTYPE macro)
340Sstevel@tonic-gate')')
350Sstevel@tonic-gate
360Sstevel@tonic-gate# pick our default mailers
370Sstevel@tonic-gateifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')')
380Sstevel@tonic-gateifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')')
390Sstevel@tonic-gateifdef(`confRELAY_MAILER',,
400Sstevel@tonic-gate	`define(`confRELAY_MAILER',
410Sstevel@tonic-gate		`ifdef(`_MAILER_smtp_', `relay',
420Sstevel@tonic-gate			`ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')')
430Sstevel@tonic-gateifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')')
440Sstevel@tonic-gatedefine(`_SMTP_', `confSMTP_MAILER')dnl		for readability only
450Sstevel@tonic-gatedefine(`_LOCAL_', `confLOCAL_MAILER')dnl	for readability only
460Sstevel@tonic-gatedefine(`_RELAY_', `confRELAY_MAILER')dnl	for readability only
470Sstevel@tonic-gatedefine(`_UUCP_', `confUUCP_MAILER')dnl		for readability only
480Sstevel@tonic-gate
490Sstevel@tonic-gate# back compatibility with old config files
500Sstevel@tonic-gateifdef(`confDEF_GROUP_ID',
510Sstevel@tonic-gate`errprint(`*** confDEF_GROUP_ID is obsolete.
520Sstevel@tonic-gate    Use confDEF_USER_ID with a colon in the value instead.
530Sstevel@tonic-gate')')
540Sstevel@tonic-gateifdef(`confREAD_TIMEOUT',
550Sstevel@tonic-gate`errprint(`*** confREAD_TIMEOUT is obsolete.
560Sstevel@tonic-gate    Use individual confTO_<timeout> parameters instead.
570Sstevel@tonic-gate')')
580Sstevel@tonic-gateifdef(`confMESSAGE_TIMEOUT',
590Sstevel@tonic-gate	`define(`_ARG_', index(confMESSAGE_TIMEOUT, /))
600Sstevel@tonic-gate	 ifelse(_ARG_, -1,
610Sstevel@tonic-gate		`define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)',
620Sstevel@tonic-gate		`define(`confTO_QUEUERETURN',
630Sstevel@tonic-gate			substr(confMESSAGE_TIMEOUT, 0, _ARG_))
640Sstevel@tonic-gate		 define(`confTO_QUEUEWARN',
650Sstevel@tonic-gate			substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')')
660Sstevel@tonic-gateifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,,
670Sstevel@tonic-gate`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete.
680Sstevel@tonic-gate    Use confMAX_MESSAGE_SIZE for the second part of the value.
690Sstevel@tonic-gate')')')
700Sstevel@tonic-gate
710Sstevel@tonic-gate
720Sstevel@tonic-gate# Sanity check on ldap_routing feature
730Sstevel@tonic-gate# If the user doesn't specify a new map, they better have given as a
740Sstevel@tonic-gate# default LDAP specification which has the LDAP base (and most likely the host)
750Sstevel@tonic-gateifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(`
760Sstevel@tonic-gateWARNING: Using default FEATURE(ldap_routing) map definition(s)
770Sstevel@tonic-gatewithout setting confLDAP_DEFAULT_SPEC option.
780Sstevel@tonic-gate')')')dnl
790Sstevel@tonic-gate
800Sstevel@tonic-gate# clean option definitions below....
810Sstevel@tonic-gatedefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl
820Sstevel@tonic-gate
830Sstevel@tonic-gatednl required to "rename" the check_* rulesets...
840Sstevel@tonic-gatedefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_'))
850Sstevel@tonic-gatednl default relaying denied message
860Sstevel@tonic-gateifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG',
870Sstevel@tonic-gateifdef(`_USE_AUTH_', `"550 Relaying denied. Proper authentication required."', `"550 Relaying denied"'))')
880Sstevel@tonic-gateifdef(`confRCPTREJ_MSG', `', `define(`confRCPTREJ_MSG', `"550 Mailbox disabled for this recipient"')')
890Sstevel@tonic-gatedefine(`_CODE553', `553')
900Sstevel@tonic-gatedivert(0)dnl
910Sstevel@tonic-gate
920Sstevel@tonic-gate# override file safeties - setting this option compromises system security,
930Sstevel@tonic-gate# addressing the actual file configuration problem is preferred
940Sstevel@tonic-gate# need to set this before any file actions are encountered in the cf file
950Sstevel@tonic-gate_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe')
960Sstevel@tonic-gate
970Sstevel@tonic-gate# default LDAP map specification
980Sstevel@tonic-gate# need to set this now before any LDAP maps are defined
990Sstevel@tonic-gate_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost')
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate##################
1020Sstevel@tonic-gate#   local info   #
1030Sstevel@tonic-gate##################
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate# my LDAP cluster
1060Sstevel@tonic-gate# need to set this before any LDAP lookups are done (including classes)
1070Sstevel@tonic-gateifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m')
1080Sstevel@tonic-gate
1090Sstevel@tonic-gateCwlocalhost
1100Sstevel@tonic-gateifdef(`USE_CW_FILE',
1110Sstevel@tonic-gate`# file containing names of hosts for which we receive email
1120Sstevel@tonic-gateFw`'confCW_FILE',
1130Sstevel@tonic-gate	`dnl')
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate# my official domain name
1160Sstevel@tonic-gate# ... `define' this only if sendmail cannot automatically determine your domain
1170Sstevel@tonic-gateifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM')
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate# host/domain names ending with a token in class P are canonical
1200Sstevel@tonic-gateCP.
1210Sstevel@tonic-gate
1220Sstevel@tonic-gateifdef(`UUCP_RELAY',
1230Sstevel@tonic-gate`# UUCP relay host
1240Sstevel@tonic-gateDY`'UUCP_RELAY
1250Sstevel@tonic-gateCPUUCP
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate')dnl
1280Sstevel@tonic-gateifdef(`BITNET_RELAY',
1290Sstevel@tonic-gate`#  BITNET relay host
1300Sstevel@tonic-gateDB`'BITNET_RELAY
1310Sstevel@tonic-gateCPBITNET
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate')dnl
1340Sstevel@tonic-gateifdef(`DECNET_RELAY',
1350Sstevel@tonic-gate`define(`_USE_DECNET_SYNTAX_', 1)dnl
1360Sstevel@tonic-gate# DECnet relay host
1370Sstevel@tonic-gateDC`'DECNET_RELAY
1380Sstevel@tonic-gateCPDECNET
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate')dnl
1410Sstevel@tonic-gateifdef(`FAX_RELAY',
1420Sstevel@tonic-gate`# FAX relay host
1430Sstevel@tonic-gateDF`'FAX_RELAY
1440Sstevel@tonic-gateCPFAX
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate')dnl
1470Sstevel@tonic-gate# "Smart" relay host (may be null)
1480Sstevel@tonic-gateDS`'ifdef(`SMART_HOST', `SMART_HOST')
1490Sstevel@tonic-gate
1500Sstevel@tonic-gateifdef(`LUSER_RELAY', `dnl
1510Sstevel@tonic-gate# place to which unknown users should be forwarded
1520Sstevel@tonic-gateKuser user -m -a<>
1530Sstevel@tonic-gateDL`'LUSER_RELAY',
1540Sstevel@tonic-gate`dnl')
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate# operators that cannot be in local usernames (i.e., network indicators)
1570Sstevel@tonic-gateCO @ % ifdef(`_NO_UUCP_', `', `!')
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate# a class with just dot (for identifying canonical names)
1600Sstevel@tonic-gateC..
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate# a class with just a left bracket (for identifying domain literals)
1630Sstevel@tonic-gateC[[
1640Sstevel@tonic-gate
1650Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
1660Sstevel@tonic-gate# access_db acceptance class
1670Sstevel@tonic-gateC{Accept}OK RELAY
1680Sstevel@tonic-gateifdef(`_DELAY_COMPAT_8_10_',`dnl
1690Sstevel@tonic-gateifdef(`_BLACKLIST_RCPT_',`dnl
1700Sstevel@tonic-gate# possible access_db RHS for spam friends/haters
1710Sstevel@tonic-gateC{SpamTag}SPAMFRIEND SPAMHATER')')',
1720Sstevel@tonic-gate`dnl')
1730Sstevel@tonic-gate
1740Sstevel@tonic-gatednl mark for "domain is ok" (resolved or accepted anyway)
1750Sstevel@tonic-gatedefine(`_RES_OK_', `OKR')dnl
1760Sstevel@tonic-gateifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
1770Sstevel@tonic-gate# Resolve map (to check if a host exists in check_mail)
1780Sstevel@tonic-gateKresolve host -a<_RES_OK_> -T<TEMP>')
1790Sstevel@tonic-gateC{ResOk}_RES_OK_
1800Sstevel@tonic-gate
1810Sstevel@tonic-gateifdef(`_NEED_MACRO_MAP_', `dnl
1820Sstevel@tonic-gateifdef(`_MACRO_MAP_', `', `# macro storage map
1830Sstevel@tonic-gatedefine(`_MACRO_MAP_', `1')dnl
1840Sstevel@tonic-gateKmacro macro')', `dnl')
1850Sstevel@tonic-gate
1860Sstevel@tonic-gateifdef(`confCR_FILE', `dnl
1870Sstevel@tonic-gate# Hosts for which relaying is permitted ($=R)
1880Sstevel@tonic-gateFR`'confCR_FILE',
1890Sstevel@tonic-gate`dnl')
1900Sstevel@tonic-gate
1910Sstevel@tonic-gatedefine(`TLS_SRV_TAG', `"TLS_Srv"')dnl
1920Sstevel@tonic-gatedefine(`TLS_CLT_TAG', `"TLS_Clt"')dnl
1930Sstevel@tonic-gatedefine(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl
1940Sstevel@tonic-gatedefine(`TLS_TRY_TAG', `"Try_TLS"')dnl
1950Sstevel@tonic-gatedefine(`SRV_FEAT_TAG', `"Srv_Features"')dnl
1960Sstevel@tonic-gatednl this may be useful in other contexts too
1970Sstevel@tonic-gateifdef(`_ARITH_MAP_', `', `# arithmetic map
1980Sstevel@tonic-gatedefine(`_ARITH_MAP_', `1')dnl
1990Sstevel@tonic-gateKarith arith')
2000Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
2010Sstevel@tonic-gateifdef(`_MACRO_MAP_', `', `# macro storage map
2020Sstevel@tonic-gatedefine(`_MACRO_MAP_', `1')dnl
2030Sstevel@tonic-gateKmacro macro')
2040Sstevel@tonic-gate# possible values for TLS_connection in access map
2050Sstevel@tonic-gateC{Tls}VERIFY ENCR', `dnl')
2060Sstevel@tonic-gateifdef(`_CERT_REGEX_ISSUER_', `dnl
2070Sstevel@tonic-gate# extract relevant part from cert issuer
2080Sstevel@tonic-gateKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
2090Sstevel@tonic-gateifdef(`_CERT_REGEX_SUBJECT_', `dnl
2100Sstevel@tonic-gate# extract relevant part from cert subject
2110Sstevel@tonic-gateKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
2120Sstevel@tonic-gate
2130Sstevel@tonic-gateifdef(`LOCAL_RELAY', `dnl
2140Sstevel@tonic-gate# who I send unqualified names to if `FEATURE(stickyhost)' is used
2150Sstevel@tonic-gate# (null means deliver locally)
2160Sstevel@tonic-gateDR`'LOCAL_RELAY')
2170Sstevel@tonic-gate
2180Sstevel@tonic-gateifdef(`MAIL_HUB', `dnl
2190Sstevel@tonic-gate# who gets all local email traffic
2200Sstevel@tonic-gate# ($R has precedence for unqualified names if `FEATURE(stickyhost)' is used)
2210Sstevel@tonic-gateDH`'MAIL_HUB')
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate# dequoting map
2240Sstevel@tonic-gateKdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `')
2250Sstevel@tonic-gate
2260Sstevel@tonic-gatedivert(0)dnl	# end of nullclient diversion
2270Sstevel@tonic-gate# class E: names that should be exposed as from this host, even if we masquerade
2280Sstevel@tonic-gate# class L: names that should be delivered locally, even if we have a relay
2290Sstevel@tonic-gate# class M: domains that should be converted to $M
2300Sstevel@tonic-gate# class N: domains that should not be converted to $M
2310Sstevel@tonic-gate#CL root
2320Sstevel@tonic-gateundivert(5)dnl
2330Sstevel@tonic-gateifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
2340Sstevel@tonic-gate
2350Sstevel@tonic-gateifdef(`MASQUERADE_NAME', `dnl
2360Sstevel@tonic-gate# who I masquerade as (null for no masquerading) (see also $=M)
2370Sstevel@tonic-gateDM`'MASQUERADE_NAME')
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate# my name for error messages
2400Sstevel@tonic-gateifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
2410Sstevel@tonic-gate
2420Sstevel@tonic-gateundivert(6)dnl LOCAL_CONFIG
2430Sstevel@tonic-gateinclude(_CF_DIR_`m4/version.m4')
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate###############
2460Sstevel@tonic-gate#   Options   #
2470Sstevel@tonic-gate###############
2480Sstevel@tonic-gateifdef(`confAUTO_REBUILD',
2490Sstevel@tonic-gate`errprint(WARNING: `confAUTO_REBUILD' is no longer valid.
2500Sstevel@tonic-gate	There was a potential for a denial of service attack if this is set.
2510Sstevel@tonic-gate)')dnl
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate# strip message body to 7 bits on input?
2540Sstevel@tonic-gate_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate# 8-bit data handling
2570Sstevel@tonic-gate_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8')
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate# wait for alias file rebuild (default units: minutes)
2600Sstevel@tonic-gate_OPTION(AliasWait, `confALIAS_WAIT', `5m')
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate# location of alias file
2630Sstevel@tonic-gate_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate# minimum number of free blocks on filesystem
2660Sstevel@tonic-gate_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate# maximum message size
2690Sstevel@tonic-gate_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `0')
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate# substitution for space (blank) characters
2720Sstevel@tonic-gate_OPTION(BlankSub, `confBLANK_SUB', `_')
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate# avoid connecting to "expensive" mailers on initial submission?
2750Sstevel@tonic-gate_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate# checkpoint queue runs after every N successful deliveries
2780Sstevel@tonic-gate_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate# default delivery mode
2810Sstevel@tonic-gate_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate# error message header/file
2840Sstevel@tonic-gate_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate# error mode
2870Sstevel@tonic-gate_OPTION(ErrorMode, `confERROR_MODE', `print')
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate# save Unix-style "From_" lines at top of header?
2900Sstevel@tonic-gate_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate# queue file mode (qf files)
2930Sstevel@tonic-gate_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600')
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate# temporary file mode
2960Sstevel@tonic-gate_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate# match recipients against GECOS field?
2990Sstevel@tonic-gate_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate# maximum hop count
3020Sstevel@tonic-gate_OPTION(MaxHopCount, `confMAX_HOP', `25')
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate# location of help file
3050Sstevel@tonic-gateO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate# ignore dots as terminators in incoming messages?
3080Sstevel@tonic-gate_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate# name resolver options
3110Sstevel@tonic-gate_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate# deliver MIME-encapsulated error messages?
3140Sstevel@tonic-gate_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate# Forward file search path
3170Sstevel@tonic-gate_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate# open connection cache size
3200Sstevel@tonic-gate_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate# open connection cache timeout
3230Sstevel@tonic-gate_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate# persistent host status directory
3260Sstevel@tonic-gate_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate# single thread deliveries (requires HostStatusDirectory)?
3290Sstevel@tonic-gate_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate# use Errors-To: header?
3320Sstevel@tonic-gate_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate# log level
3350Sstevel@tonic-gate_OPTION(LogLevel, `confLOG_LEVEL', `10')
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate# send to me too, even in an alias expansion?
3380Sstevel@tonic-gate_OPTION(MeToo, `confME_TOO', `True')
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate# verify RHS in newaliases?
3410Sstevel@tonic-gate_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate# default messages to old style headers if no special punctuation?
3440Sstevel@tonic-gate_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate# SMTP daemon options
3470Sstevel@tonic-gateifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
3480Sstevel@tonic-gate`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.
3490Sstevel@tonic-gate	Use `DAEMON_OPTIONS()'; see cf/README.
3500Sstevel@tonic-gate)'dnl
3510Sstevel@tonic-gate`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
3520Sstevel@tonic-gateifelse(defn(`_DPO_'), `',
3530Sstevel@tonic-gate`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet
3540Sstevel@tonic-gateO DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
3550Sstevel@tonic-gateifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate# SMTP client options
3580Sstevel@tonic-gateifelse(defn(`confCLIENT_OPTIONS'), `', `dnl',
3590Sstevel@tonic-gate`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid.  See cf/README for more information.
3600Sstevel@tonic-gate)'dnl
3610Sstevel@tonic-gate`CLIENT_OPTIONS(`confCLIENT_OPTIONS')')
3620Sstevel@tonic-gateifelse(defn(`_CPO_'), `',
3630Sstevel@tonic-gate`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_')
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate# Modifiers to `define' {daemon_flags} for direct submissions
3660Sstevel@tonic-gate_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `')
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate# Use as mail submission program? See sendmail/SECURITY
3690Sstevel@tonic-gate_OPTION(UseMSP, `confUSE_MSP', `')
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate# privacy flags
3720Sstevel@tonic-gate_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate# who (if anyone) should get extra copies of error messages
3750Sstevel@tonic-gate_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate# slope of queue-only function
3780Sstevel@tonic-gate_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate# limit on number of concurrent queue runners
3810Sstevel@tonic-gate_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `')
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate# maximum number of queue-runners per queue-grouping with multiple queues
3840Sstevel@tonic-gate_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1')
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate# priority of queue runners (nice(3))
3870Sstevel@tonic-gate_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `')
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate# shall we sort the queue by hostname first?
3900Sstevel@tonic-gate_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate# minimum time in queue before retry
3930Sstevel@tonic-gate_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate# how many jobs can you process in the queue?
396616Sjbeck_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `0')
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate# perform initial split of envelope without checking MX records
3990Sstevel@tonic-gate_OPTION(FastSplit, `confFAST_SPLIT', `1')
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate# queue directory
4020Sstevel@tonic-gateO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
4030Sstevel@tonic-gate
404*3544Sjbeck# key for shared memory; 0 to turn off, -1 to auto-select
4050Sstevel@tonic-gate_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
4060Sstevel@tonic-gate
407*3544Sjbeck# file to store auto-selected key for shared memory (SharedMemoryKey = -1)
408*3544Sjbeck_OPTION(SharedMemoryKeyFile, `confSHARED_MEMORY_KEY_FILE', `')
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate# timeouts (many of these)
4110Sstevel@tonic-gate_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
4120Sstevel@tonic-gate_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
4130Sstevel@tonic-gate_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s')
4140Sstevel@tonic-gate_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
4150Sstevel@tonic-gate_OPTION(Timeout.helo, `confTO_HELO', `5m')
4160Sstevel@tonic-gate_OPTION(Timeout.mail, `confTO_MAIL', `10m')
4170Sstevel@tonic-gate_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
4180Sstevel@tonic-gate_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
4190Sstevel@tonic-gate_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
4200Sstevel@tonic-gate_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
4210Sstevel@tonic-gate_OPTION(Timeout.rset, `confTO_RSET', `5m')
4220Sstevel@tonic-gate_OPTION(Timeout.quit, `confTO_QUIT', `2m')
4230Sstevel@tonic-gate_OPTION(Timeout.misc, `confTO_MISC', `2m')
4240Sstevel@tonic-gate_OPTION(Timeout.command, `confTO_COMMAND', `1h')
4250Sstevel@tonic-gate_OPTION(Timeout.ident, `confTO_IDENT', `5s')
4260Sstevel@tonic-gate_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
4270Sstevel@tonic-gate_OPTION(Timeout.control, `confTO_CONTROL', `2m')
4280Sstevel@tonic-gate_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
4290Sstevel@tonic-gate_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
4300Sstevel@tonic-gate_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
4310Sstevel@tonic-gate_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
4320Sstevel@tonic-gate_OPTION(Timeout.queuereturn.dsn, `confTO_QUEUERETURN_DSN', `5d')
4330Sstevel@tonic-gate_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
4340Sstevel@tonic-gate_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
4350Sstevel@tonic-gate_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
4360Sstevel@tonic-gate_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
4370Sstevel@tonic-gate_OPTION(Timeout.queuewarn.dsn, `confTO_QUEUEWARN_DSN', `4h')
4380Sstevel@tonic-gate_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
4390Sstevel@tonic-gate_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
4400Sstevel@tonic-gate_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
4410Sstevel@tonic-gate_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
4420Sstevel@tonic-gate_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
4430Sstevel@tonic-gate_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
4440Sstevel@tonic-gate_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
4450Sstevel@tonic-gate_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
4460Sstevel@tonic-gate_OPTION(Timeout.auth, `confTO_AUTH', `10m')
4470Sstevel@tonic-gate_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate# time for DeliverBy; extension disabled if less than 0
4500Sstevel@tonic-gate_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate# should we not prune routes in route-addr syntax addresses?
4530Sstevel@tonic-gate_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate# queue up everything before forking?
4560Sstevel@tonic-gate_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate# status file
459*3544Sjbeck_OPTION(StatusFile, `STATUS_FILE')
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate# time zone handling:
4620Sstevel@tonic-gate#  if undefined, use system default
4630Sstevel@tonic-gate#  if defined but null, use TZ envariable passed in
4640Sstevel@tonic-gate#  if defined and non-null, use that info
4650Sstevel@tonic-gateifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
4660Sstevel@tonic-gate	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
4670Sstevel@tonic-gate	`O TimeZoneSpec=confTIME_ZONE')
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate# default UID (can be username or userid:groupid)
4700Sstevel@tonic-gate_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate# list of locations of user database file (null means no lookup)
4730Sstevel@tonic-gate_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate# fallback MX host
4760Sstevel@tonic-gate_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate# fallback smart host
4790Sstevel@tonic-gate_OPTION(FallbackSmartHost, `confFALLBACK_SMARTHOST', `fall.back.host.net')
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate# if we are the best MX host for a site, try it directly instead of config err
4820Sstevel@tonic-gate_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate# load average at which we just queue messages
4850Sstevel@tonic-gate_OPTION(QueueLA, `confQUEUE_LA', `8')
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate# load average at which we refuse connections
4880Sstevel@tonic-gate_OPTION(RefuseLA, `confREFUSE_LA', `12')
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate# log interval when refusing connections for this long
4910Sstevel@tonic-gate_OPTION(RejectLogInterval, `confREJECT_LOG_INTERVAL', `3h')
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate# load average at which we delay connections; 0 means no limit
4940Sstevel@tonic-gate_OPTION(DelayLA, `confDELAY_LA', `0')
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate# maximum number of children we allow at one time
4970Sstevel@tonic-gate_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0')
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate# maximum number of new connections per second
5000Sstevel@tonic-gate_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate# Width of the window
5030Sstevel@tonic-gate_OPTION(ConnectionRateWindowSize, `confCONNECTION_RATE_WINDOW_SIZE', `60s')
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate# work recipient factor
5060Sstevel@tonic-gate_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate# deliver each queued job in a separate process?
5090Sstevel@tonic-gate_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate# work class factor
5120Sstevel@tonic-gate_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate# work time factor
5150Sstevel@tonic-gate_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate# default character set
5180Sstevel@tonic-gate_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `unknown-8bit')
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
5210Sstevel@tonic-gate_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate# hosts file (normally /etc/hosts)
5240Sstevel@tonic-gate_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate# dialup line delay on connection failure
527616Sjbeck_OPTION(DialDelay, `confDIAL_DELAY', `0s')
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate# action to take if there are no recipients in the message
530616Sjbeck_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `none')
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate# chrooted environment for writing to files
533616Sjbeck_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `')
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate# are colons OK in addresses?
5360Sstevel@tonic-gate_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate# shall I avoid expanding CNAMEs (violates protocols)?
5390Sstevel@tonic-gate_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate# SMTP initial login message (old $e macro)
5420Sstevel@tonic-gate_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate# UNIX initial From header format (old $l macro)
5450Sstevel@tonic-gate_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate# From: lines that have embedded newlines are unwrapped onto one line
5480Sstevel@tonic-gate_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
5490Sstevel@tonic-gate
5500Sstevel@tonic-gate# Allow HELO SMTP command that does not `include' a host name
5510Sstevel@tonic-gate_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
5540Sstevel@tonic-gate_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate# delimiter (operator) characters (old $o macro)
5570Sstevel@tonic-gate_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate# shall I avoid calling initgroups(3) because of high NIS costs?
5600Sstevel@tonic-gate_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
5610Sstevel@tonic-gate
5620Sstevel@tonic-gate# are group-writable `:include:' and .forward files (un)trustworthy?
5630Sstevel@tonic-gate# True (the default) means they are not trustworthy.
5640Sstevel@tonic-gate_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
5650Sstevel@tonic-gateifdef(`confUNSAFE_GROUP_WRITES',
5660Sstevel@tonic-gate`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
5670Sstevel@tonic-gate')')
5680Sstevel@tonic-gate
5690Sstevel@tonic-gate# where do errors that occur when sending errors get sent?
5700Sstevel@tonic-gate_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
5710Sstevel@tonic-gate
5720Sstevel@tonic-gate# where to save bounces if all else fails
5730Sstevel@tonic-gate_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate# what user id do we assume for the majority of the processing?
5760Sstevel@tonic-gate_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate# maximum number of recipients per SMTP envelope
5790Sstevel@tonic-gate_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `0')
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate# limit the rate recipients per SMTP envelope are accepted
5820Sstevel@tonic-gate# once the threshold number of recipients have been rejected
5830Sstevel@tonic-gate_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `0')
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate# shall we get local names from our installed interfaces?
5860Sstevel@tonic-gate_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate# Return-Receipt-To: header implies DSN request
5890Sstevel@tonic-gate_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
5900Sstevel@tonic-gate
5910Sstevel@tonic-gate# override connection address (for testing)
5920Sstevel@tonic-gate_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate# Trusted user for file ownership and starting the daemon
5950Sstevel@tonic-gate_OPTION(TrustedUser, `confTRUSTED_USER', `root')
5960Sstevel@tonic-gate
5970Sstevel@tonic-gate# Control socket for daemon management
5980Sstevel@tonic-gate_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
5990Sstevel@tonic-gate
6000Sstevel@tonic-gate# Maximum MIME header length to protect MUAs
6010Sstevel@tonic-gate_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `2048/1024')
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate# Maximum length of the sum of all headers
6040Sstevel@tonic-gate_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate# Maximum depth of alias recursion
6070Sstevel@tonic-gate_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
6080Sstevel@tonic-gate
6090Sstevel@tonic-gate# location of pid file
6100Sstevel@tonic-gate_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate# Prefix string for the process title shown on 'ps' listings
6130Sstevel@tonic-gate_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
6140Sstevel@tonic-gate
6150Sstevel@tonic-gate# Data file (df) memory-buffer file maximum size
6160Sstevel@tonic-gate_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate# Transcript file (xf) memory-buffer file maximum size
6190Sstevel@tonic-gate_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate# lookup type to find information about local mailboxes
6220Sstevel@tonic-gate_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
6230Sstevel@tonic-gate
6240Sstevel@tonic-gate# override compile time flag REQUIRES_DIR_FSYNC
6250Sstevel@tonic-gate_OPTION(RequiresDirfsync, `confREQUIRES_DIR_FSYNC', `true')
6260Sstevel@tonic-gate
6270Sstevel@tonic-gate# list of authentication mechanisms
6280Sstevel@tonic-gate_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate# Authentication realm
6310Sstevel@tonic-gate_OPTION(AuthRealm, `confAUTH_REALM', `')
6320Sstevel@tonic-gate
6330Sstevel@tonic-gate# default authentication information for outgoing connections
6340Sstevel@tonic-gate_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate# SMTP AUTH flags
6370Sstevel@tonic-gate_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
6380Sstevel@tonic-gate
6390Sstevel@tonic-gate# SMTP AUTH maximum encryption strength
6400Sstevel@tonic-gate_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
6410Sstevel@tonic-gate
6420Sstevel@tonic-gate# SMTP STARTTLS server options
6430Sstevel@tonic-gate_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
6440Sstevel@tonic-gate
6450Sstevel@tonic-gate# Input mail filters
6460Sstevel@tonic-gate_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
6470Sstevel@tonic-gate
6480Sstevel@tonic-gateifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl
6490Sstevel@tonic-gate# Milter options
6500Sstevel@tonic-gate_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
6510Sstevel@tonic-gate_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
6520Sstevel@tonic-gate_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
6530Sstevel@tonic-gate_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
6540Sstevel@tonic-gate_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')
6550Sstevel@tonic-gate_OPTION(Milter.macros.eom, `confMILTER_MACROS_EOM', `')')
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate# CA directory
6580Sstevel@tonic-gate_OPTION(CACertPath, `confCACERT_PATH', `')
6590Sstevel@tonic-gate# CA file
6600Sstevel@tonic-gate_OPTION(CACertFile, `confCACERT', `')
6610Sstevel@tonic-gate# Server Cert
6620Sstevel@tonic-gate_OPTION(ServerCertFile, `confSERVER_CERT', `')
6630Sstevel@tonic-gate# Server private key
6640Sstevel@tonic-gate_OPTION(ServerKeyFile, `confSERVER_KEY', `')
6650Sstevel@tonic-gate# Client Cert
6660Sstevel@tonic-gate_OPTION(ClientCertFile, `confCLIENT_CERT', `')
6670Sstevel@tonic-gate# Client private key
6680Sstevel@tonic-gate_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
6690Sstevel@tonic-gate# File containing certificate revocation lists
6700Sstevel@tonic-gate_OPTION(CRLFile, `confCRL', `')
6710Sstevel@tonic-gate# DHParameters (only required if DSA/DH is used)
6720Sstevel@tonic-gate_OPTION(DHParameters, `confDH_PARAMETERS', `')
6730Sstevel@tonic-gate# Random data source (required for systems without /dev/urandom under OpenSSL)
6740Sstevel@tonic-gate_OPTION(RandFile, `confRAND_FILE', `')
6750Sstevel@tonic-gate
676*3544Sjbeck# Maximum number of "useless" commands before slowing down
677*3544Sjbeck_OPTION(MaxNOOPCommands, `confMAX_NOOP_COMMANDS', `20')
678*3544Sjbeck
679*3544Sjbeck# Name to use for EHLO (defaults to $j)
680*3544Sjbeck_OPTION(HeloName, `confHELO_NAME')
681*3544Sjbeck
6820Sstevel@tonic-gate############################
6830Sstevel@tonic-gate`# QUEUE GROUP DEFINITIONS  #'
6840Sstevel@tonic-gate############################
6850Sstevel@tonic-gate_QUEUE_GROUP_
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate###########################
6880Sstevel@tonic-gate#   Message precedences   #
6890Sstevel@tonic-gate###########################
6900Sstevel@tonic-gate
6910Sstevel@tonic-gatePfirst-class=0
6920Sstevel@tonic-gatePspecial-delivery=100
6930Sstevel@tonic-gatePlist=-30
6940Sstevel@tonic-gatePbulk=-60
6950Sstevel@tonic-gatePjunk=-100
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate#####################
6980Sstevel@tonic-gate#   Trusted users   #
6990Sstevel@tonic-gate#####################
7000Sstevel@tonic-gate
7010Sstevel@tonic-gate# this is equivalent to setting class "t"
7020Sstevel@tonic-gateifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
7030Sstevel@tonic-gateTroot
7040Sstevel@tonic-gateTdaemon
7050Sstevel@tonic-gateifdef(`_NO_UUCP_', `dnl', `Tuucp')
7060Sstevel@tonic-gateifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate#########################
7090Sstevel@tonic-gate#   Format of headers   #
7100Sstevel@tonic-gate#########################
7110Sstevel@tonic-gate
7120Sstevel@tonic-gateifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
7130Sstevel@tonic-gateifdef(`confMESSAGEID_HEADER',, `define(`confMESSAGEID_HEADER', `<$t.$i@$j>')')dnl
7140Sstevel@tonic-gateH?P?Return-Path: <$g>
7150Sstevel@tonic-gateHReceived: confRECEIVED_HEADER
7160Sstevel@tonic-gateH?D?Resent-Date: $a
7170Sstevel@tonic-gateH?D?Date: $a
7180Sstevel@tonic-gateH?F?Resent-From: confFROM_HEADER
7190Sstevel@tonic-gateH?F?From: confFROM_HEADER
7200Sstevel@tonic-gateH?x?Full-Name: $x
7210Sstevel@tonic-gate# HPosted-Date: $a
7220Sstevel@tonic-gate# H?l?Received-Date: $b
7230Sstevel@tonic-gateH?M?Resent-Message-Id: confMESSAGEID_HEADER
7240Sstevel@tonic-gateH?M?Message-Id: confMESSAGEID_HEADER
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate#
7270Sstevel@tonic-gate######################################################################
7280Sstevel@tonic-gate######################################################################
7290Sstevel@tonic-gate#####
7300Sstevel@tonic-gate#####			REWRITING RULES
7310Sstevel@tonic-gate#####
7320Sstevel@tonic-gate######################################################################
7330Sstevel@tonic-gate######################################################################
7340Sstevel@tonic-gate
7350Sstevel@tonic-gate############################################
7360Sstevel@tonic-gate###  Ruleset 3 -- Name Canonicalization  ###
7370Sstevel@tonic-gate############################################
7380Sstevel@tonic-gateScanonify=3
7390Sstevel@tonic-gate
7400Sstevel@tonic-gate# handle null input (translate to <@> special case)
7410Sstevel@tonic-gateR$@			$@ <@>
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate# strip group: syntax (not inside angle brackets!) and trailing semicolon
7440Sstevel@tonic-gateR$*			$: $1 <@>			mark addresses
7450Sstevel@tonic-gateR$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
7460Sstevel@tonic-gateR@ $* <@>		$: @ $1				unmark @host:...
7470Sstevel@tonic-gateR$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
7480Sstevel@tonic-gateR$* :: $* <@>		$: $1 :: $2			unmark node::addr
7490Sstevel@tonic-gateR:`include': $* <@>	$: :`include': $1			unmark :`include':...
7500Sstevel@tonic-gateR$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
7510Sstevel@tonic-gateR$* : $* <@>		$: $2				strip colon if marked
7520Sstevel@tonic-gateR$* <@>			$: $1				unmark
7530Sstevel@tonic-gateR$* ;			   $1				strip trailing semi
7540Sstevel@tonic-gateR$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
7550Sstevel@tonic-gateR$* < $* ; >		   $1 < $2 >			bogus bracketed semi
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate# null input now results from list:; syntax
7580Sstevel@tonic-gateR$@			$@ :; <@>
7590Sstevel@tonic-gate
7600Sstevel@tonic-gate# strip angle brackets -- note RFC733 heuristic to get innermost item
7610Sstevel@tonic-gateR$*			$: < $1 >			housekeeping <>
7620Sstevel@tonic-gateR$+ < $* >		   < $2 >			strip excess on left
7630Sstevel@tonic-gateR< $* > $+		   < $1 >			strip excess on right
7640Sstevel@tonic-gateR<>			$@ < @ >			MAIL FROM:<> case
7650Sstevel@tonic-gateR< $+ >			$: $1				remove housekeeping <>
7660Sstevel@tonic-gate
7670Sstevel@tonic-gateifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
7680Sstevel@tonic-gate# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
7690Sstevel@tonic-gateR@ $+ , $+		@ $1 : $2			change all "," to ":"
7700Sstevel@tonic-gate
7710Sstevel@tonic-gate# localize and dispose of route-based addresses
7720Sstevel@tonic-gatednl XXX: IPv6 colon conflict
7730Sstevel@tonic-gateifdef(`NO_NETINET6', `dnl',
7740Sstevel@tonic-gate`R@ [$+] : $+		$@ $>Canonify2 < @ [$1] > : $2	handle <route-addr>')
7750Sstevel@tonic-gateR@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
7760Sstevel@tonic-gatednl',`dnl
7770Sstevel@tonic-gate# strip route address <@a,@b,@c:user@d> -> <user@d>
7780Sstevel@tonic-gateR@ $+ , $+		$2
7790Sstevel@tonic-gateifdef(`NO_NETINET6', `dnl',
7800Sstevel@tonic-gate`R@ [ $* ] : $+		$2')
7810Sstevel@tonic-gateR@ $+ : $+		$2
7820Sstevel@tonic-gatednl')
7830Sstevel@tonic-gate
7840Sstevel@tonic-gate# find focus for list syntax
7850Sstevel@tonic-gateR $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
7860Sstevel@tonic-gateR $+ : $* ;		$@ $1 : $2;			list syntax
7870Sstevel@tonic-gate
7880Sstevel@tonic-gate# find focus for @ syntax addresses
7890Sstevel@tonic-gateR$+ @ $+		$: $1 < @ $2 >			focus on domain
7900Sstevel@tonic-gateR$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
7910Sstevel@tonic-gateR$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
7920Sstevel@tonic-gate
7930Sstevel@tonic-gatednl This is flagged as an error in S0; no need to silently fix it here.
7940Sstevel@tonic-gatednl # do some sanity checking
7950Sstevel@tonic-gatednl R$* < @ $~[ $* : $* > $*	$1 < @ $2 $3 > $4	nix colons in addrs
7960Sstevel@tonic-gate
7970Sstevel@tonic-gateifdef(`_NO_UUCP_', `dnl',
7980Sstevel@tonic-gate`# convert old-style addresses to a domain-based address
7990Sstevel@tonic-gateR$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
8000Sstevel@tonic-gateR$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
8010Sstevel@tonic-gateR$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
8020Sstevel@tonic-gate')
8030Sstevel@tonic-gateifdef(`_USE_DECNET_SYNTAX_',
8040Sstevel@tonic-gate`# convert node::user addresses into a domain-based address
8050Sstevel@tonic-gateR$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
8060Sstevel@tonic-gateR$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
8070Sstevel@tonic-gate',
8080Sstevel@tonic-gate	`dnl')
8090Sstevel@tonic-gate# if we have % signs, take the rightmost one
8100Sstevel@tonic-gateR$* % $*		$1 @ $2				First make them all @s.
8110Sstevel@tonic-gateR$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
8120Sstevel@tonic-gateR$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
8130Sstevel@tonic-gate
8140Sstevel@tonic-gate# else we must be a local name
8150Sstevel@tonic-gateR$*			$@ $>Canonify2 $1
8160Sstevel@tonic-gate
8170Sstevel@tonic-gate
8180Sstevel@tonic-gate################################################
8190Sstevel@tonic-gate###  Ruleset 96 -- bottom half of ruleset 3  ###
8200Sstevel@tonic-gate################################################
8210Sstevel@tonic-gate
8220Sstevel@tonic-gateSCanonify2=96
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate# handle special cases for local names
8250Sstevel@tonic-gateR$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
8260Sstevel@tonic-gateR$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
8270Sstevel@tonic-gateifdef(`_NO_UUCP_', `dnl',
8280Sstevel@tonic-gate`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
8290Sstevel@tonic-gate
8300Sstevel@tonic-gate# check for IPv4/IPv6 domain literal
8310Sstevel@tonic-gateR$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [addr]
8320Sstevel@tonic-gateR$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
8330Sstevel@tonic-gateR$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
8340Sstevel@tonic-gate
8350Sstevel@tonic-gateifdef(`_DOMAIN_TABLE_', `dnl
8360Sstevel@tonic-gate# look up domains in the domain table
8370Sstevel@tonic-gateR$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
8380Sstevel@tonic-gate
8390Sstevel@tonic-gateundivert(2)dnl LOCAL_RULE_3
8400Sstevel@tonic-gate
8410Sstevel@tonic-gateifdef(`_BITDOMAIN_TABLE_', `dnl
8420Sstevel@tonic-gate# handle BITNET mapping
8430Sstevel@tonic-gateR$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
8440Sstevel@tonic-gate
8450Sstevel@tonic-gateifdef(`_UUDOMAIN_TABLE_', `dnl
8460Sstevel@tonic-gate# handle UUCP mapping
8470Sstevel@tonic-gateR$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
8480Sstevel@tonic-gate
8490Sstevel@tonic-gateifdef(`_NO_UUCP_', `dnl',
8500Sstevel@tonic-gate`ifdef(`UUCP_RELAY',
8510Sstevel@tonic-gate`# pass UUCP addresses straight through
8520Sstevel@tonic-gateR$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
8530Sstevel@tonic-gate`# if really UUCP, handle it immediately
8540Sstevel@tonic-gateifdef(`_CLASS_U_',
8550Sstevel@tonic-gate`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
8560Sstevel@tonic-gateifdef(`_CLASS_V_',
8570Sstevel@tonic-gate`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
8580Sstevel@tonic-gateifdef(`_CLASS_W_',
8590Sstevel@tonic-gate`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
8600Sstevel@tonic-gateifdef(`_CLASS_X_',
8610Sstevel@tonic-gate`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
8620Sstevel@tonic-gateifdef(`_CLASS_Y_',
8630Sstevel@tonic-gate`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
8640Sstevel@tonic-gate
8650Sstevel@tonic-gateifdef(`_NO_CANONIFY_', `dnl', `dnl
8660Sstevel@tonic-gate# try UUCP traffic as a local address
8670Sstevel@tonic-gateR$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
8680Sstevel@tonic-gateR$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
8690Sstevel@tonic-gate')')
8700Sstevel@tonic-gate# hostnames ending in class P are always canonical
8710Sstevel@tonic-gateR$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
8720Sstevel@tonic-gatednl apply the next rule only for hostnames not in class P
8730Sstevel@tonic-gatednl this even works for phrases in class P since . is in class P
8740Sstevel@tonic-gatednl which daemon flags are set?
8750Sstevel@tonic-gateR$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
8760Sstevel@tonic-gatednl the other rules in this section only apply if the hostname
8770Sstevel@tonic-gatednl does not end in class P hence no further checks are done here
8780Sstevel@tonic-gatednl if this ever changes make sure the lookups are "protected" again!
8790Sstevel@tonic-gateifdef(`_NO_CANONIFY_', `dnl
8800Sstevel@tonic-gatednl do not canonify unless:
8810Sstevel@tonic-gatednl domain ends in class {Canonify} (this does not work if the intersection
8820Sstevel@tonic-gatednl	with class P is non-empty)
8830Sstevel@tonic-gatednl or {daemon_flags} has c set
8840Sstevel@tonic-gate# pass to name server to make hostname canonical if in class {Canonify}
8850Sstevel@tonic-gateR$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
8860Sstevel@tonic-gate# pass to name server to make hostname canonical if requested
8870Sstevel@tonic-gateR$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
8880Sstevel@tonic-gatednl trailing dot? -> do not apply _CANONIFY_HOSTS_
8890Sstevel@tonic-gateR$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
8900Sstevel@tonic-gate# add a trailing dot to qualified hostnames so other rules will work
8910Sstevel@tonic-gateR$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
8920Sstevel@tonic-gateifdef(`_CANONIFY_HOSTS_', `dnl
8930Sstevel@tonic-gatednl this should only apply to unqualified hostnames
8940Sstevel@tonic-gatednl but if a valid character inside an unqualified hostname is an OperatorChar
8950Sstevel@tonic-gatednl then $- does not work.
8960Sstevel@tonic-gate# lookup unqualified hostnames
8970Sstevel@tonic-gateR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
8980Sstevel@tonic-gatednl _NO_CANONIFY_ is not set: canonify unless:
8990Sstevel@tonic-gatednl {daemon_flags} contains CC (do not canonify)
9000Sstevel@tonic-gatednl but add a trailing dot to qualified hostnames so other rules will work
9010Sstevel@tonic-gatednl should we do this for every hostname: even unqualified?
9020Sstevel@tonic-gateR$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
9030Sstevel@tonic-gateR$* CC $* $| $*			$: $3
9040Sstevel@tonic-gateifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
9050Sstevel@tonic-gate# do not canonify header addresses
9060Sstevel@tonic-gateR$* $| $* < @ $* $~P > $*	$: $&{addr_type} $| $2 < @ $3 $4 > $5
9070Sstevel@tonic-gateR$* h $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
9080Sstevel@tonic-gateR$* h $* $| $*			$: $3', `dnl')
9090Sstevel@tonic-gate# pass to name server to make hostname canonical
9100Sstevel@tonic-gateR$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
9110Sstevel@tonic-gatednl remove {daemon_flags} for other cases
9120Sstevel@tonic-gateR$* $| $*			$: $2
9130Sstevel@tonic-gate
9140Sstevel@tonic-gate# local host aliases and pseudo-domains are always canonical
9150Sstevel@tonic-gateR$* < @ $=w > $*		$: $1 < @ $2 . > $3
9160Sstevel@tonic-gateifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
9170Sstevel@tonic-gate`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
9180Sstevel@tonic-gate`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
9190Sstevel@tonic-gateifdef(`_VIRTUSER_TABLE_', `dnl
9200Sstevel@tonic-gatednl virtual hosts are also canonical
9210Sstevel@tonic-gateifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
9220Sstevel@tonic-gate`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
9230Sstevel@tonic-gate`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
9240Sstevel@tonic-gate`dnl')
9250Sstevel@tonic-gateifdef(`_GENERICS_TABLE_', `dnl
9260Sstevel@tonic-gatednl hosts for genericstable are also canonical
9270Sstevel@tonic-gateifdef(`_GENERICS_ENTIRE_DOMAIN_',
9280Sstevel@tonic-gate`R$* < @ $* $=G > $* 	$: $1 < @ $2 $3 . > $4',
9290Sstevel@tonic-gate`R$* < @ $=G > $* 	$: $1 < @ $2 . > $3')',
9300Sstevel@tonic-gate`dnl')
9310Sstevel@tonic-gatednl remove superfluous dots (maybe repeatedly) which may have been added
9320Sstevel@tonic-gatednl by one of the rules before
9330Sstevel@tonic-gateR$* < @ $* . . > $*		$1 < @ $2 . > $3
9340Sstevel@tonic-gate
9350Sstevel@tonic-gate
9360Sstevel@tonic-gate##################################################
9370Sstevel@tonic-gate###  Ruleset 4 -- Final Output Post-rewriting  ###
9380Sstevel@tonic-gate##################################################
9390Sstevel@tonic-gateSfinal=4
9400Sstevel@tonic-gate
9410Sstevel@tonic-gateR$+ :; <@>		$@ $1 :				handle <list:;>
9420Sstevel@tonic-gateR$* <@>			$@				handle <> and list:;
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate# strip trailing dot off possibly canonical name
9450Sstevel@tonic-gateR$* < @ $+ . > $*	$1 < @ $2 > $3
9460Sstevel@tonic-gate
9470Sstevel@tonic-gate# eliminate internal code
9480Sstevel@tonic-gateR$* < @ *LOCAL* > $*	$1 < @ $j > $2
9490Sstevel@tonic-gate
9500Sstevel@tonic-gate# externalize local domain info
9510Sstevel@tonic-gateR$* < $+ > $*		$1 $2 $3			defocus
9520Sstevel@tonic-gateR@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
9530Sstevel@tonic-gateR@ $*			$@ @ $1				... and exit
9540Sstevel@tonic-gate
9550Sstevel@tonic-gateifdef(`_NO_UUCP_', `dnl',
9560Sstevel@tonic-gate`# UUCP must always be presented in old form
9570Sstevel@tonic-gateR$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
9580Sstevel@tonic-gate
9590Sstevel@tonic-gateifdef(`_USE_DECNET_SYNTAX_',
9600Sstevel@tonic-gate`# put DECnet back in :: form
9610Sstevel@tonic-gateR$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
9620Sstevel@tonic-gate	`dnl')
9630Sstevel@tonic-gate# delete duplicate local names
9640Sstevel@tonic-gateR$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
9650Sstevel@tonic-gate
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate
9680Sstevel@tonic-gate##############################################################
9690Sstevel@tonic-gate###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
9700Sstevel@tonic-gate###		   (used for recursive calls)		   ###
9710Sstevel@tonic-gate##############################################################
9720Sstevel@tonic-gate
9730Sstevel@tonic-gateSRecurse=97
9740Sstevel@tonic-gateR$*			$: $>canonify $1
9750Sstevel@tonic-gateR$*			$@ $>parse $1
9760Sstevel@tonic-gate
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate######################################
9790Sstevel@tonic-gate###   Ruleset 0 -- Parse Address   ###
9800Sstevel@tonic-gate######################################
9810Sstevel@tonic-gate
9820Sstevel@tonic-gateSparse=0
9830Sstevel@tonic-gate
9840Sstevel@tonic-gateR$*			$: $>Parse0 $1		initial parsing
9850Sstevel@tonic-gateR<@>			$#_LOCAL_ $: <@>		special case error msgs
9860Sstevel@tonic-gateR$*			$: $>ParseLocal $1	handle local hacks
9870Sstevel@tonic-gateR$*			$: $>Parse1 $1		final parsing
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate#
9900Sstevel@tonic-gate#  Parse0 -- do initial syntax checking and eliminate local addresses.
9910Sstevel@tonic-gate#	This should either return with the (possibly modified) input
9920Sstevel@tonic-gate#	or return with a #error mailer.  It should not return with a
9930Sstevel@tonic-gate#	#mailer other than the #error mailer.
9940Sstevel@tonic-gate#
9950Sstevel@tonic-gate
9960Sstevel@tonic-gateSParse0
9970Sstevel@tonic-gateR<@>			$@ <@>			special case error msgs
9980Sstevel@tonic-gateR$* : $* ; <@>		$#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
9990Sstevel@tonic-gateR@ <@ $* >		< @ $1 >		catch "@@host" bogosity
10000Sstevel@tonic-gateR<@ $+>			$#error $@ 5.1.3 $: "_CODE553 User address required"
10010Sstevel@tonic-gateR$+ <@>			$#error $@ 5.1.3 $: "_CODE553 Hostname required"
10020Sstevel@tonic-gateR$*			$: <> $1
10030Sstevel@tonic-gatednl allow tricks like [host1]:[host2]
10040Sstevel@tonic-gateR<> $* < @ [ $* ] : $+ > $*	$1 < @ [ $2 ] : $3 > $4
10050Sstevel@tonic-gateR<> $* < @ [ $* ] , $+ > $*	$1 < @ [ $2 ] , $3 > $4
10060Sstevel@tonic-gatednl but no a@[b]c
10070Sstevel@tonic-gateR<> $* < @ [ $* ] $+ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid address"
10080Sstevel@tonic-gateR<> $* < @ [ $+ ] > $*		$1 < @ [ $2 ] > $3
10090Sstevel@tonic-gateR<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
10100Sstevel@tonic-gateR<> $*			$1
10110Sstevel@tonic-gateR$* < @ . $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
10120Sstevel@tonic-gateR$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
10130Sstevel@tonic-gatednl no a@b@
10140Sstevel@tonic-gateR$* < @ $* @ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid route address"
10150Sstevel@tonic-gatednl no a@b@c
10160Sstevel@tonic-gateR$* @ $* < @ $* > $*	$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
10170Sstevel@tonic-gatednl comma only allowed before @; this check is not complete
10180Sstevel@tonic-gateR$* , $~O $*		$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
10190Sstevel@tonic-gate
10200Sstevel@tonic-gateifdef(`_STRICT_RFC821_', `# more RFC 821 checks
10210Sstevel@tonic-gateR$* . < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
10220Sstevel@tonic-gateR. $* < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
10230Sstevel@tonic-gatednl', `dnl')
10240Sstevel@tonic-gate
10250Sstevel@tonic-gate# now delete the local info -- note $=O to find characters that cause forwarding
10260Sstevel@tonic-gateR$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
10270Sstevel@tonic-gateR< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
10280Sstevel@tonic-gateR$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
10290Sstevel@tonic-gateR< @ $+ >		$#error $@ 5.1.3 $: "_CODE553 User address required"
10300Sstevel@tonic-gateR$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
10310Sstevel@tonic-gateR$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
10320Sstevel@tonic-gateR< @ *LOCAL* >		$#error $@ 5.1.3 $: "_CODE553 User address required"
10330Sstevel@tonic-gateR$* $=O $* < @ *LOCAL* >
10340Sstevel@tonic-gate			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
10350Sstevel@tonic-gateR$* < @ *LOCAL* >	$: $1
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate#
10380Sstevel@tonic-gate#  Parse1 -- the bottom half of ruleset 0.
10390Sstevel@tonic-gate#
10400Sstevel@tonic-gate
10410Sstevel@tonic-gateSParse1
10420Sstevel@tonic-gateifdef(`_LDAP_ROUTING_', `dnl
10430Sstevel@tonic-gate# handle LDAP routing for hosts in $={LDAPRoute}
10440Sstevel@tonic-gateR$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
10450Sstevel@tonic-gateR$+ < @ $={LDAPRouteEquiv} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
10460Sstevel@tonic-gate`dnl')
10470Sstevel@tonic-gate
10480Sstevel@tonic-gateifdef(`_MAILER_smtp_',
10490Sstevel@tonic-gate`# handle numeric address spec
10500Sstevel@tonic-gatednl there is no check whether this is really an IP number
10510Sstevel@tonic-gateR$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
10520Sstevel@tonic-gateR$* < @ [ $+ ] > $*	$: $1 < @ [ $2 ] : $S > $3	Add smart host to path
10530Sstevel@tonic-gateR$* < @ [ $+ ] : > $*		$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
10540Sstevel@tonic-gateR$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
10550Sstevel@tonic-gateR$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
10560Sstevel@tonic-gate	`dnl')
10570Sstevel@tonic-gate
10580Sstevel@tonic-gateifdef(`_VIRTUSER_TABLE_', `dnl
10590Sstevel@tonic-gate# handle virtual users
10600Sstevel@tonic-gateifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
10610Sstevel@tonic-gatednl this is not a documented option
10620Sstevel@tonic-gatednl it stops looping in virtusertable mapping if input and output
10630Sstevel@tonic-gatednl are identical, i.e., if address A is mapped to A.
10640Sstevel@tonic-gatednl it does not deal with multi-level recursion
10650Sstevel@tonic-gate# handle full domains in RHS of virtusertable
10660Sstevel@tonic-gateR$+ < @ $+ >			$: $(macro {RecipientAddress} $) $1 < @ $2 >
10670Sstevel@tonic-gateR$+ < @ $+ > 			$: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
10680Sstevel@tonic-gateR<?> $+ $| $+			$: $1 $(macro {RecipientAddress} $@ $2 $)
10690Sstevel@tonic-gateR<?> $+ $| $*			$: $1',
10700Sstevel@tonic-gate`dnl')
10710Sstevel@tonic-gateR$+			$: <!> $1		Mark for lookup
10720Sstevel@tonic-gatednl input: <!> local<@domain>
10730Sstevel@tonic-gateifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
10740Sstevel@tonic-gate`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
10750Sstevel@tonic-gate`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
10760Sstevel@tonic-gatednl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
10770Sstevel@tonic-gateR<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
10780Sstevel@tonic-gatednl if <@> local<@domain>: no match but try lookup
10790Sstevel@tonic-gatednl user+detail: try user++@domain if detail not empty
10800Sstevel@tonic-gateR<@> $+ + $+ < @ $* . >
10810Sstevel@tonic-gate			$: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
10820Sstevel@tonic-gatednl user+detail: try user+*@domain
10830Sstevel@tonic-gateR<@> $+ + $* < @ $* . >
10840Sstevel@tonic-gate			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
10850Sstevel@tonic-gatednl user+detail: try user@domain
10860Sstevel@tonic-gateR<@> $+ + $* < @ $* . >
10870Sstevel@tonic-gate			$: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
10880Sstevel@tonic-gatednl try default entry: @domain
10890Sstevel@tonic-gatednl ++@domain
10900Sstevel@tonic-gateR<@> $+ + $+ < @ $+ . >	$: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
10910Sstevel@tonic-gatednl +*@domain
10920Sstevel@tonic-gateR<@> $+ + $* < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
10930Sstevel@tonic-gatednl @domain if +detail exists
10940Sstevel@tonic-gatednl if no match, change marker to prevent a second @domain lookup
10950Sstevel@tonic-gateR<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . >
10960Sstevel@tonic-gatednl without +detail
10970Sstevel@tonic-gateR<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
10980Sstevel@tonic-gatednl no match
10990Sstevel@tonic-gateR<@> $+			$: $1
11000Sstevel@tonic-gatednl remove mark
11010Sstevel@tonic-gateR<!> $+			$: $1
11020Sstevel@tonic-gateR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
11030Sstevel@tonic-gateR< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
11040Sstevel@tonic-gateifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
11050Sstevel@tonic-gate# check virtuser input address against output address, if same, skip recursion
11060Sstevel@tonic-gateR< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
11070Sstevel@tonic-gate# it is the same: stop now
11080Sstevel@tonic-gateR< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
11090Sstevel@tonic-gateR< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
11100Sstevel@tonic-gatednl', `dnl')
11110Sstevel@tonic-gatednl this is not a documented option
11120Sstevel@tonic-gatednl it performs no looping at all for virtusertable
11130Sstevel@tonic-gateifdef(`_NO_VIRTUSER_RECURSION_',
11140Sstevel@tonic-gate`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
11150Sstevel@tonic-gate`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
11160Sstevel@tonic-gatednl', `dnl')
11170Sstevel@tonic-gate
11180Sstevel@tonic-gate# short circuit local delivery so forwarded email works
11190Sstevel@tonic-gateifdef(`_MAILER_usenet_', `dnl
11200Sstevel@tonic-gateR$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
11210Sstevel@tonic-gate
11220Sstevel@tonic-gate
11230Sstevel@tonic-gateifdef(`_STICKY_LOCAL_DOMAIN_',
11240Sstevel@tonic-gate`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
11250Sstevel@tonic-gateR< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
11260Sstevel@tonic-gatednl $H empty (but @$=w.)
11270Sstevel@tonic-gateR< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
11280Sstevel@tonic-gateR< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
11290Sstevel@tonic-gate`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
11300Sstevel@tonic-gateR$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
11310Sstevel@tonic-gate
11320Sstevel@tonic-gateifdef(`_MAILER_TABLE_', `dnl
11330Sstevel@tonic-gate# not local -- try mailer table lookup
11340Sstevel@tonic-gateR$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
11350Sstevel@tonic-gateR< $+ . > $*		$: < $1 > $2			strip trailing dot
11360Sstevel@tonic-gateR< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
11370Sstevel@tonic-gatednl it is $~[ instead of $- to avoid matches on IPv6 addresses
11380Sstevel@tonic-gateR< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
11390Sstevel@tonic-gateR< $+ > $*		$: $>Mailertable <$1> $2		try domain',
11400Sstevel@tonic-gate`dnl')
11410Sstevel@tonic-gateundivert(4)dnl UUCP rules from `MAILER(uucp)'
11420Sstevel@tonic-gate
11430Sstevel@tonic-gateifdef(`_NO_UUCP_', `dnl',
11440Sstevel@tonic-gate`# resolve remotely connected UUCP links (if any)
11450Sstevel@tonic-gateifdef(`_CLASS_V_',
11460Sstevel@tonic-gate`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
11470Sstevel@tonic-gate	`dnl')
11480Sstevel@tonic-gateifdef(`_CLASS_W_',
11490Sstevel@tonic-gate`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
11500Sstevel@tonic-gate	`dnl')
11510Sstevel@tonic-gateifdef(`_CLASS_X_',
11520Sstevel@tonic-gate`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
11530Sstevel@tonic-gate	`dnl')')
11540Sstevel@tonic-gate
11550Sstevel@tonic-gate# resolve fake top level domains by forwarding to other hosts
11560Sstevel@tonic-gateifdef(`BITNET_RELAY',
11570Sstevel@tonic-gate`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
11580Sstevel@tonic-gate	`dnl')
11590Sstevel@tonic-gateifdef(`DECNET_RELAY',
11600Sstevel@tonic-gate`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
11610Sstevel@tonic-gate	`dnl')
11620Sstevel@tonic-gateifdef(`_MAILER_pop_',
11630Sstevel@tonic-gate`R$+ < @ POP. >		$#pop $: $1			user@POP',
11640Sstevel@tonic-gate	`dnl')
11650Sstevel@tonic-gateifdef(`_MAILER_fax_',
11660Sstevel@tonic-gate`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
11670Sstevel@tonic-gate`ifdef(`FAX_RELAY',
11680Sstevel@tonic-gate`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
11690Sstevel@tonic-gate	`dnl')')
11700Sstevel@tonic-gate
11710Sstevel@tonic-gateifdef(`UUCP_RELAY',
11720Sstevel@tonic-gate`# forward non-local UUCP traffic to our UUCP relay
11730Sstevel@tonic-gateR$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
11740Sstevel@tonic-gate`ifdef(`_MAILER_uucp_',
11750Sstevel@tonic-gate`# forward other UUCP traffic straight to UUCP
11760Sstevel@tonic-gateR$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
11770Sstevel@tonic-gate	`dnl')')
11780Sstevel@tonic-gateifdef(`_MAILER_usenet_', `
11790Sstevel@tonic-gate# addresses sent to net.group.USENET will get forwarded to a newsgroup
11800Sstevel@tonic-gateR$+ . USENET		$#usenet $@ usenet $: $1',
11810Sstevel@tonic-gate	`dnl')
11820Sstevel@tonic-gate
11830Sstevel@tonic-gateifdef(`_LOCAL_RULES_',
11840Sstevel@tonic-gate`# figure out what should stay in our local mail system
11850Sstevel@tonic-gateundivert(1)', `dnl')
11860Sstevel@tonic-gate
11870Sstevel@tonic-gate# pass names that still have a host to a smarthost (if defined)
11880Sstevel@tonic-gateR$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
11890Sstevel@tonic-gate
11900Sstevel@tonic-gate# deal with other remote names
11910Sstevel@tonic-gateifdef(`_MAILER_smtp_',
11920Sstevel@tonic-gate`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
11930Sstevel@tonic-gate`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate# handle locally delivered names
11960Sstevel@tonic-gateR$=L			$#_LOCAL_ $: @ $1		special local names
11970Sstevel@tonic-gateR$+			$#_LOCAL_ $: $1			regular local names
11980Sstevel@tonic-gate
11990Sstevel@tonic-gate###########################################################################
12000Sstevel@tonic-gate###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
12010Sstevel@tonic-gate###########################################################################
12020Sstevel@tonic-gate
12030Sstevel@tonic-gateSLocal_localaddr
12040Sstevel@tonic-gateSlocaladdr=5
12050Sstevel@tonic-gateR$+			$: $1 $| $>"Local_localaddr" $1
12060Sstevel@tonic-gateR$+ $| $#ok		$@ $1			no change
12070Sstevel@tonic-gateR$+ $| $#$*		$#$2
12080Sstevel@tonic-gateR$+ $| $*		$: $1
12090Sstevel@tonic-gate
12100Sstevel@tonic-gateifdef(`_PRESERVE_LUSER_HOST_', `dnl
12110Sstevel@tonic-gate# Preserve rcpt_host in {Host}
12120Sstevel@tonic-gateR$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
12130Sstevel@tonic-gateR$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
12140Sstevel@tonic-gateR$+ $| $| $+		$: $1			h not set, {Host} set
12150Sstevel@tonic-gateR$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
12160Sstevel@tonic-gateR$+ $| $* @ $+ $| $*	$: $(macro {Host} $@ @$3 $) $1	set {Host} to host in h
12170Sstevel@tonic-gateR$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
12180Sstevel@tonic-gate')dnl
12190Sstevel@tonic-gate
12200Sstevel@tonic-gateifdef(`_FFR_5_', `dnl
12210Sstevel@tonic-gate# Preserve host in a macro
12220Sstevel@tonic-gateR$+			$: $(macro {LocalAddrHost} $) $1
12230Sstevel@tonic-gateR$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
12240Sstevel@tonic-gate
12250Sstevel@tonic-gateifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
12260Sstevel@tonic-gate# deal with plussed users so aliases work nicely
12270Sstevel@tonic-gateR$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
12280Sstevel@tonic-gateR$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
12290Sstevel@tonic-gate')
12300Sstevel@tonic-gate# prepend an empty "forward host" on the front
12310Sstevel@tonic-gateR$+			$: <> $1
12320Sstevel@tonic-gate
12330Sstevel@tonic-gateifdef(`LUSER_RELAY', `dnl
12340Sstevel@tonic-gate# send unrecognized local users to a relay host
12350Sstevel@tonic-gateifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
12360Sstevel@tonic-gateR< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
12370Sstevel@tonic-gateR< > $+			$: < ? $L > < > $(user $1 $)	look up user
12380Sstevel@tonic-gateR< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
12390Sstevel@tonic-gateR< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
12400Sstevel@tonic-gateR< > $+ 		$: < $L > $(user $1 $)		look up user
12410Sstevel@tonic-gateR< $* > $+ <>		$: < > $2			found; strip $L')
12420Sstevel@tonic-gateifdef(`_PRESERVE_LUSER_HOST_', `dnl
12430Sstevel@tonic-gateR< $+ > $+		$: < $1 > $2 $&{Host}')
12440Sstevel@tonic-gatednl')
12450Sstevel@tonic-gate
12460Sstevel@tonic-gateifdef(`MAIL_HUB', `dnl
12470Sstevel@tonic-gateR< > $+			$: < $H > $1			try hub', `dnl')
12480Sstevel@tonic-gateifdef(`LOCAL_RELAY', `dnl
12490Sstevel@tonic-gateR< > $+			$: < $R > $1			try relay', `dnl')
12500Sstevel@tonic-gateifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
12510Sstevel@tonic-gateR< > $+			$@ $1', `dnl
12520Sstevel@tonic-gateR< > $+			$: < > < $1 <> $&h >		nope, restore +detail
12530Sstevel@tonic-gateifdef(`_PRESERVE_LUSER_HOST_', `dnl
12540Sstevel@tonic-gateR< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
12550Sstevel@tonic-gateR< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
12560Sstevel@tonic-gateR< > < $+ <> $* >	$: < > < $1 >			else discard
12570Sstevel@tonic-gateR< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
12580Sstevel@tonic-gateR< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
12590Sstevel@tonic-gateR< > < $+ >		$@ $1				no +detail
12600Sstevel@tonic-gateR$+			$: $1 <> $&h			add +detail back in
12610Sstevel@tonic-gateifdef(`_PRESERVE_LUSER_HOST_', `dnl
12620Sstevel@tonic-gateR$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
12630Sstevel@tonic-gateR$+ <> + $*		$: $1 + $2			check whether +detail
12640Sstevel@tonic-gateR$+ <> $*		$: $1				else discard')
12650Sstevel@tonic-gateR< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
12660Sstevel@tonic-gateR< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
12670Sstevel@tonic-gateifdef(`_PRESERVE_LUSER_HOST_', `dnl
12680Sstevel@tonic-gatednl it is $~[ instead of $- to avoid matches on IPv6 addresses
12690Sstevel@tonic-gateR< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
12700Sstevel@tonic-gateR< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
12710Sstevel@tonic-gateifdef(`_PRESERVE_LUSER_HOST_', `dnl
12720Sstevel@tonic-gateR< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
12730Sstevel@tonic-gateR< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
12740Sstevel@tonic-gate
12750Sstevel@tonic-gateifdef(`_MAILER_TABLE_', `dnl
12760Sstevel@tonic-gateifdef(`_LDAP_ROUTING_', `dnl
12770Sstevel@tonic-gate###################################################################
12780Sstevel@tonic-gate###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
12790Sstevel@tonic-gatednl input: <Domain> FullAddress
12800Sstevel@tonic-gate###################################################################
12810Sstevel@tonic-gate
12820Sstevel@tonic-gateSLDAPMailertable
12830Sstevel@tonic-gateR< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
12840Sstevel@tonic-gateR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
12850Sstevel@tonic-gateR< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
12860Sstevel@tonic-gateR< $+ > $#$*		$#$2					found
12870Sstevel@tonic-gateR< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
12880Sstevel@tonic-gate`dnl')
12890Sstevel@tonic-gate
12900Sstevel@tonic-gate###################################################################
12910Sstevel@tonic-gate###  Ruleset 90 -- try domain part of mailertable entry 	###
12920Sstevel@tonic-gatednl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
12930Sstevel@tonic-gate###################################################################
12940Sstevel@tonic-gate
12950Sstevel@tonic-gateSMailertable=90
12960Sstevel@tonic-gatednl shift and check
12970Sstevel@tonic-gatednl %2 is not documented in cf/README
12980Sstevel@tonic-gateR$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
12990Sstevel@tonic-gatednl it is $~[ instead of $- to avoid matches on IPv6 addresses
13000Sstevel@tonic-gateR$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
13010Sstevel@tonic-gateR$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
13020Sstevel@tonic-gatednl is $2 always empty?
13030Sstevel@tonic-gateR$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
13040Sstevel@tonic-gateR< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
13050Sstevel@tonic-gatednl return full address
13060Sstevel@tonic-gateR< $* > $*		$@ $2				no mailertable match',
13070Sstevel@tonic-gate`dnl')
13080Sstevel@tonic-gate
13090Sstevel@tonic-gate###################################################################
13100Sstevel@tonic-gate###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
13110Sstevel@tonic-gatednl input: in general: <[mailer:]host> lp<@domain>rest
13120Sstevel@tonic-gatednl	<> address				-> address
13130Sstevel@tonic-gatednl	<error:d.s.n:text>			-> error
13140Sstevel@tonic-gatednl	<error:keyword:text>			-> error
13150Sstevel@tonic-gatednl	<error:text>				-> error
13160Sstevel@tonic-gatednl	<mailer:user@host> lp<@domain>rest	-> mailer host user
13170Sstevel@tonic-gatednl	<mailer:host> address			-> mailer host address
13180Sstevel@tonic-gatednl	<localdomain> address			-> address
13190Sstevel@tonic-gatednl	<host> address				-> relay host address
13200Sstevel@tonic-gate###################################################################
13210Sstevel@tonic-gate
13220Sstevel@tonic-gateSMailerToTriple=95
13230Sstevel@tonic-gateR< > $*				$@ $1			strip off null relay
13240Sstevel@tonic-gateR< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
13250Sstevel@tonic-gateR< error : $- : $+ > $*		$#error $@ $(dequote $1 $) $: $2
13260Sstevel@tonic-gateR< error : $+ > $*		$#error $: $1
13270Sstevel@tonic-gateR< local : $* > $*		$>CanonLocal < $1 > $2
13280Sstevel@tonic-gatednl it is $~[ instead of $- to avoid matches on IPv6 addresses
13290Sstevel@tonic-gateR< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
13300Sstevel@tonic-gateR< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
13310Sstevel@tonic-gateR< $=w > $*			$@ $2			delete local host
13320Sstevel@tonic-gateR< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate###################################################################
13350Sstevel@tonic-gate###  Ruleset CanonLocal -- canonify local: syntax		###
13360Sstevel@tonic-gatednl input: <user> address
13370Sstevel@tonic-gatednl <x> <@host> : rest			-> Recurse rest
13380Sstevel@tonic-gatednl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
13390Sstevel@tonic-gatednl <> user <@host> rest		-> local user@host user
13400Sstevel@tonic-gatednl <> user				-> local user user
13410Sstevel@tonic-gatednl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
13420Sstevel@tonic-gatednl <user> lp <@host> rest		-> local lp@host user
13430Sstevel@tonic-gatednl <user> lp				-> local lp user
13440Sstevel@tonic-gate###################################################################
13450Sstevel@tonic-gate
13460Sstevel@tonic-gateSCanonLocal
13470Sstevel@tonic-gate# strip local host from routed addresses
13480Sstevel@tonic-gateR< $* > < @ $+ > : $+		$@ $>Recurse $3
13490Sstevel@tonic-gateR< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
13500Sstevel@tonic-gate
13510Sstevel@tonic-gate# strip trailing dot from any host name that may appear
13520Sstevel@tonic-gateR< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
13530Sstevel@tonic-gate
13540Sstevel@tonic-gate# handle local: syntax -- use old user, either with or without host
13550Sstevel@tonic-gateR< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
13560Sstevel@tonic-gateR< > $+				$#_LOCAL_ $@ $1    $: $1
13570Sstevel@tonic-gate
13580Sstevel@tonic-gate# handle local:user@host syntax -- ignore host part
13590Sstevel@tonic-gateR< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
13600Sstevel@tonic-gate
13610Sstevel@tonic-gate# handle local:user syntax
13620Sstevel@tonic-gateR< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
13630Sstevel@tonic-gateR< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
13640Sstevel@tonic-gate
13650Sstevel@tonic-gate###################################################################
13660Sstevel@tonic-gate###  Ruleset 93 -- convert header names to masqueraded form	###
13670Sstevel@tonic-gate###################################################################
13680Sstevel@tonic-gate
13690Sstevel@tonic-gateSMasqHdr=93
13700Sstevel@tonic-gate
13710Sstevel@tonic-gateifdef(`_GENERICS_TABLE_', `dnl
13720Sstevel@tonic-gate# handle generics database
13730Sstevel@tonic-gateifdef(`_GENERICS_ENTIRE_DOMAIN_',
13740Sstevel@tonic-gatednl if generics should be applied add a @ as mark
13750Sstevel@tonic-gate`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
13760Sstevel@tonic-gate`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
13770Sstevel@tonic-gateR$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
13780Sstevel@tonic-gatednl workspace: either user<@domain> or <user@domain> user <@domain> @
13790Sstevel@tonic-gatednl ignore the first case for now
13800Sstevel@tonic-gatednl if it has the mark lookup full address
13810Sstevel@tonic-gatednl broken: %1 is full address not just detail
13820Sstevel@tonic-gateR< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
13830Sstevel@tonic-gatednl workspace: ... or <match|@user@domain> user <@domain>
13840Sstevel@tonic-gatednl no match, try user+detail@domain
13850Sstevel@tonic-gateR<@$+ + $* @ $+> $+ < @ $+ >
13860Sstevel@tonic-gate		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
13870Sstevel@tonic-gateR<@$+ + $* @ $+> $+ < @ $+ >
13880Sstevel@tonic-gate		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
13890Sstevel@tonic-gatednl no match, remove mark
13900Sstevel@tonic-gateR<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
13910Sstevel@tonic-gatednl no match, try @domain for exceptions
13920Sstevel@tonic-gateR< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
13930Sstevel@tonic-gatednl workspace: ... or <match> user <@domain>
13940Sstevel@tonic-gatednl no match, try local part
13950Sstevel@tonic-gateR< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
13960Sstevel@tonic-gateR< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
13970Sstevel@tonic-gateR< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
13980Sstevel@tonic-gateR< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
13990Sstevel@tonic-gateR< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
14000Sstevel@tonic-gateR< > $*			$: $1				not found',
14010Sstevel@tonic-gate`dnl')
14020Sstevel@tonic-gate
14030Sstevel@tonic-gate# do not masquerade anything in class N
14040Sstevel@tonic-gateR$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
14050Sstevel@tonic-gate
14060Sstevel@tonic-gateifdef(`MASQUERADE_NAME', `dnl
14070Sstevel@tonic-gate# special case the users that should be exposed
14080Sstevel@tonic-gateR$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
14090Sstevel@tonic-gateifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
14100Sstevel@tonic-gate`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
14110Sstevel@tonic-gate`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
14120Sstevel@tonic-gateifdef(`_LIMITED_MASQUERADE_', `dnl',
14130Sstevel@tonic-gate`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
14140Sstevel@tonic-gate
14150Sstevel@tonic-gate# handle domain-specific masquerading
14160Sstevel@tonic-gateifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
14170Sstevel@tonic-gate`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
14180Sstevel@tonic-gate`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
14190Sstevel@tonic-gateifdef(`_LIMITED_MASQUERADE_', `dnl',
14200Sstevel@tonic-gate`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
14210Sstevel@tonic-gateR$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
14220Sstevel@tonic-gateR$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
14230Sstevel@tonic-gateR$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
14240Sstevel@tonic-gatednl', `dnl no masquerading
14250Sstevel@tonic-gatednl just fix *LOCAL* leftovers
14260Sstevel@tonic-gateR$* < @ *LOCAL* >	$@ $1 < @ $j . >')
14270Sstevel@tonic-gate
14280Sstevel@tonic-gate###################################################################
14290Sstevel@tonic-gate###  Ruleset 94 -- convert envelope names to masqueraded form	###
14300Sstevel@tonic-gate###################################################################
14310Sstevel@tonic-gate
14320Sstevel@tonic-gateSMasqEnv=94
14330Sstevel@tonic-gateifdef(`_MASQUERADE_ENVELOPE_',
14340Sstevel@tonic-gate`R$+			$@ $>MasqHdr $1',
14350Sstevel@tonic-gate`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
14360Sstevel@tonic-gate
14370Sstevel@tonic-gate###################################################################
14380Sstevel@tonic-gate###  Ruleset 98 -- local part of ruleset zero (can be null)	###
14390Sstevel@tonic-gate###################################################################
14400Sstevel@tonic-gate
14410Sstevel@tonic-gateSParseLocal=98
14420Sstevel@tonic-gateundivert(3)dnl LOCAL_RULE_0
14430Sstevel@tonic-gate
14440Sstevel@tonic-gateifdef(`_LDAP_ROUTING_', `dnl
14450Sstevel@tonic-gate######################################################################
14460Sstevel@tonic-gate###  LDAPExpand: Expand address using LDAP routing
14470Sstevel@tonic-gate###
14480Sstevel@tonic-gate###	Parameters:
14490Sstevel@tonic-gate###		<$1> -- parsed address (user < @ domain . >) (pass through)
14500Sstevel@tonic-gate###		<$2> -- RFC822 address (user @ domain) (used for lookup)
14510Sstevel@tonic-gate###		<$3> -- +detail information
14520Sstevel@tonic-gate###
14530Sstevel@tonic-gate###	Returns:
14540Sstevel@tonic-gate###		Mailer triplet ($#mailer $@ host $: address)
14550Sstevel@tonic-gate###		Parsed address (user < @ domain . >)
14560Sstevel@tonic-gate######################################################################
14570Sstevel@tonic-gate
14580Sstevel@tonic-gate# SMTP operation modes
14590Sstevel@tonic-gateC{SMTPOpModes} s d D
14600Sstevel@tonic-gate
14610Sstevel@tonic-gateSLDAPExpand
14620Sstevel@tonic-gate# do the LDAP lookups
14630Sstevel@tonic-gateR<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
14640Sstevel@tonic-gate
14650Sstevel@tonic-gate# look for temporary failures and...
14660Sstevel@tonic-gateR<$* <TMPF>> <$*> <$+> <$+> <$*>	$: $&{opMode} $| TMPF <$&{addr_type}> $| $3
14670Sstevel@tonic-gateR<$*> <$* <TMPF>> <$+> <$+> <$*>	$: $&{opMode} $| TMPF <$&{addr_type}> $| $3
14680Sstevel@tonic-gateifelse(_LDAP_ROUTE_MAPTEMP_, `_TEMPFAIL_', `dnl
14690Sstevel@tonic-gate# ... temp fail RCPT SMTP commands
14700Sstevel@tonic-gateR$={SMTPOpModes} $| TMPF <e r> $| $+	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."')
14710Sstevel@tonic-gate# ... return original address for MTA to queue up
14720Sstevel@tonic-gateR$* $| TMPF <$*> $| $+			$@ $3
14730Sstevel@tonic-gate
14740Sstevel@tonic-gate# if mailRoutingAddress and local or non-existant mailHost,
14750Sstevel@tonic-gate# return the new mailRoutingAddress
14760Sstevel@tonic-gateifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
14770Sstevel@tonic-gateR<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
14780Sstevel@tonic-gateR<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
14790Sstevel@tonic-gateR<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
14800Sstevel@tonic-gateR<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
14810Sstevel@tonic-gate
14820Sstevel@tonic-gate
14830Sstevel@tonic-gate# if mailRoutingAddress and non-local mailHost,
14840Sstevel@tonic-gate# relay to mailHost with new mailRoutingAddress
14850Sstevel@tonic-gateifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
14860Sstevel@tonic-gateifdef(`_MAILER_TABLE_', `dnl
14870Sstevel@tonic-gate# check mailertable for host, relay from there
14880Sstevel@tonic-gateR<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
14890Sstevel@tonic-gate`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
14900Sstevel@tonic-gateifdef(`_MAILER_TABLE_', `dnl
14910Sstevel@tonic-gate# check mailertable for host, relay from there
14920Sstevel@tonic-gateR<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
14930Sstevel@tonic-gate`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
14940Sstevel@tonic-gate
14950Sstevel@tonic-gate# if no mailRoutingAddress and local mailHost,
14960Sstevel@tonic-gate# return original address
14970Sstevel@tonic-gateR<> <$=w> <$+> <$+> <$*>	$@ $2
14980Sstevel@tonic-gate
14990Sstevel@tonic-gate
15000Sstevel@tonic-gate# if no mailRoutingAddress and non-local mailHost,
15010Sstevel@tonic-gate# relay to mailHost with original address
15020Sstevel@tonic-gateifdef(`_MAILER_TABLE_', `dnl
15030Sstevel@tonic-gate# check mailertable for host, relay from there
15040Sstevel@tonic-gateR<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
15050Sstevel@tonic-gate`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
15060Sstevel@tonic-gate
15070Sstevel@tonic-gateifdef(`_LDAP_ROUTE_DETAIL_',
15080Sstevel@tonic-gate`# if no mailRoutingAddress and no mailHost,
15090Sstevel@tonic-gate# try without +detail
15100Sstevel@tonic-gateR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
15110Sstevel@tonic-gate
15120Sstevel@tonic-gateifdef(`_LDAP_ROUTE_NODOMAIN_', `dnl', `
15130Sstevel@tonic-gate# if still no mailRoutingAddress and no mailHost,
15140Sstevel@tonic-gate# try @domain
15150Sstevel@tonic-gateifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
15160Sstevel@tonic-gateR<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
15170Sstevel@tonic-gateR<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>')
15180Sstevel@tonic-gate
15190Sstevel@tonic-gate# if no mailRoutingAddress and no mailHost and this was a domain attempt,
15200Sstevel@tonic-gateifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
15210Sstevel@tonic-gate# user does not exist
15220Sstevel@tonic-gateR<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
15230Sstevel@tonic-gate# only give error for envelope recipient
15240Sstevel@tonic-gateR<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
15250Sstevel@tonic-gateifdef(`_LDAP_SENDER_MUST_EXIST_', `dnl
15260Sstevel@tonic-gate# and the sender too
15270Sstevel@tonic-gateR<?> <e s> <$+>			$#error $@ nouser $: "550 User unknown"')
15280Sstevel@tonic-gateR<?> <$*> <$+>			$@ $2',
15290Sstevel@tonic-gate`dnl
15300Sstevel@tonic-gate# return the original address
15310Sstevel@tonic-gateR<> <> <$+> <@ $+> <$*>		$@ $1')',
15320Sstevel@tonic-gate`dnl')
15330Sstevel@tonic-gate
15340Sstevel@tonic-gateifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
15350Sstevel@tonic-gate')')
15360Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
15370Sstevel@tonic-gate######################################################################
15380Sstevel@tonic-gate###  D: LookUpDomain -- search for domain in access database
15390Sstevel@tonic-gate###
15400Sstevel@tonic-gate###	Parameters:
15410Sstevel@tonic-gate###		<$1> -- key (domain name)
15420Sstevel@tonic-gate###		<$2> -- default (what to return if not found in db)
15430Sstevel@tonic-gatednl			must not be empty
15440Sstevel@tonic-gate###		<$3> -- mark (must be <(!|+) single-token>)
15450Sstevel@tonic-gate###			! does lookup only with tag
15460Sstevel@tonic-gate###			+ does lookup with and without tag
15470Sstevel@tonic-gate###		<$4> -- passthru (additional data passed unchanged through)
15480Sstevel@tonic-gatednl returns:		<default> <passthru>
15490Sstevel@tonic-gatednl 			<result> <passthru>
15500Sstevel@tonic-gate######################################################################
15510Sstevel@tonic-gate
15520Sstevel@tonic-gateSD
15530Sstevel@tonic-gatednl workspace <key> <default> <passthru> <mark>
15540Sstevel@tonic-gatednl lookup with tag (in front, no delimiter here)
15550Sstevel@tonic-gatednl    2    3  4    5
15560Sstevel@tonic-gateR<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
15570Sstevel@tonic-gatednl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
15580Sstevel@tonic-gatednl lookup without tag?
15590Sstevel@tonic-gatednl   1    2      3    4
15600Sstevel@tonic-gateR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
15610Sstevel@tonic-gateifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
15620Sstevel@tonic-gatednl XXX apply this also to IP addresses?
15630Sstevel@tonic-gatednl currently it works the wrong way round for [1.2.3.4]
15640Sstevel@tonic-gatednl   1  2    3    4  5    6
15650Sstevel@tonic-gateR<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
15660Sstevel@tonic-gatednl   1  2    3      4    5
15670Sstevel@tonic-gateR<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
15680Sstevel@tonic-gateifdef(`_ACCESS_SKIP_', `dnl
15690Sstevel@tonic-gatednl found SKIP: return <default> and <passthru>
15700Sstevel@tonic-gatednl      1    2    3  4    5
15710Sstevel@tonic-gateR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
15720Sstevel@tonic-gatednl not found: IPv4 net (no check is done whether it is an IP number!)
15730Sstevel@tonic-gatednl    1  2     3    4  5    6
15740Sstevel@tonic-gateR<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
15750Sstevel@tonic-gateifdef(`NO_NETINET6', `dnl',
15760Sstevel@tonic-gate`dnl not found: IPv6 net
15770Sstevel@tonic-gatednl (could be merged with previous rule if we have a class containing .:)
15780Sstevel@tonic-gatednl    1   2     3    4  5    6
15790Sstevel@tonic-gateR<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
15800Sstevel@tonic-gateR<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
15810Sstevel@tonic-gatednl not found, but subdomain: try again
15820Sstevel@tonic-gatednl   1  2    3    4  5    6
15830Sstevel@tonic-gateR<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
15840Sstevel@tonic-gateifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
15850Sstevel@tonic-gatednl   1    2      3    4
15860Sstevel@tonic-gateR<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
15870Sstevel@tonic-gatednl not found, no subdomain: return <default> and <passthru>
15880Sstevel@tonic-gatednl   1    2    3  4    5
15890Sstevel@tonic-gateR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
15900Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
15910Sstevel@tonic-gatednl            2    3    4  5    6
15920Sstevel@tonic-gateR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
15930Sstevel@tonic-gatednl return <result of lookup> and <passthru>
15940Sstevel@tonic-gatednl    2    3    4  5    6
15950Sstevel@tonic-gateR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
15960Sstevel@tonic-gate
15970Sstevel@tonic-gate######################################################################
15980Sstevel@tonic-gate###  A: LookUpAddress -- search for host address in access database
15990Sstevel@tonic-gate###
16000Sstevel@tonic-gate###	Parameters:
16010Sstevel@tonic-gate###		<$1> -- key (dot quadded host address)
16020Sstevel@tonic-gate###		<$2> -- default (what to return if not found in db)
16030Sstevel@tonic-gatednl			must not be empty
16040Sstevel@tonic-gate###		<$3> -- mark (must be <(!|+) single-token>)
16050Sstevel@tonic-gate###			! does lookup only with tag
16060Sstevel@tonic-gate###			+ does lookup with and without tag
16070Sstevel@tonic-gate###		<$4> -- passthru (additional data passed through)
16080Sstevel@tonic-gatednl	returns:	<default> <passthru>
16090Sstevel@tonic-gatednl			<result> <passthru>
16100Sstevel@tonic-gate######################################################################
16110Sstevel@tonic-gate
16120Sstevel@tonic-gateSA
16130Sstevel@tonic-gatednl lookup with tag
16140Sstevel@tonic-gatednl    2    3  4    5
16150Sstevel@tonic-gateR<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
16160Sstevel@tonic-gatednl lookup without tag
16170Sstevel@tonic-gatednl   1    2      3    4
16180Sstevel@tonic-gateR<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
16190Sstevel@tonic-gatednl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
16200Sstevel@tonic-gateifdef(`_ACCESS_SKIP_', `dnl
16210Sstevel@tonic-gatednl found SKIP: return <default> and <passthru>
16220Sstevel@tonic-gatednl      1    2    3  4    5
16230Sstevel@tonic-gateR<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
16240Sstevel@tonic-gateifdef(`NO_NETINET6', `dnl',
16250Sstevel@tonic-gate`dnl no match; IPv6: remove last part
16260Sstevel@tonic-gatednl   1   2    3    4  5    6
16270Sstevel@tonic-gateR<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
16280Sstevel@tonic-gateR<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
16290Sstevel@tonic-gatednl no match; IPv4: remove last part
16300Sstevel@tonic-gatednl   1  2    3    4  5    6
16310Sstevel@tonic-gateR<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
16320Sstevel@tonic-gatednl no match: return default
16330Sstevel@tonic-gatednl   1    2    3  4    5
16340Sstevel@tonic-gateR<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
16350Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
16360Sstevel@tonic-gatednl            2    3    4  5    6
16370Sstevel@tonic-gateR<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
16380Sstevel@tonic-gatednl match: return result
16390Sstevel@tonic-gatednl    2    3    4  5    6
16400Sstevel@tonic-gateR<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
16410Sstevel@tonic-gatednl endif _ACCESS_TABLE_
16420Sstevel@tonic-gatedivert(0)
16430Sstevel@tonic-gate######################################################################
16440Sstevel@tonic-gate###  CanonAddr --	Convert an address into a standard form for
16450Sstevel@tonic-gate###			relay checking.  Route address syntax is
16460Sstevel@tonic-gate###			crudely converted into a %-hack address.
16470Sstevel@tonic-gate###
16480Sstevel@tonic-gate###	Parameters:
16490Sstevel@tonic-gate###		$1 -- full recipient address
16500Sstevel@tonic-gate###
16510Sstevel@tonic-gate###	Returns:
16520Sstevel@tonic-gate###		parsed address, not in source route form
16530Sstevel@tonic-gatednl		user%host%host<@domain>
16540Sstevel@tonic-gatednl		host!user<@domain>
16550Sstevel@tonic-gate######################################################################
16560Sstevel@tonic-gate
16570Sstevel@tonic-gateSCanonAddr
16580Sstevel@tonic-gateR$*			$: $>Parse0 $>canonify $1	make domain canonical
16590Sstevel@tonic-gateifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
16600Sstevel@tonic-gateR< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
16610Sstevel@tonic-gateR$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
16620Sstevel@tonic-gateR$* < @ $+ > : $*	$3 $1 < @ $2 >
16630Sstevel@tonic-gatednl')
16640Sstevel@tonic-gate
16650Sstevel@tonic-gate######################################################################
16660Sstevel@tonic-gate###  ParseRecipient --	Strip off hosts in $=R as well as possibly
16670Sstevel@tonic-gate###			$* $=m or the access database.
16680Sstevel@tonic-gate###			Check user portion for host separators.
16690Sstevel@tonic-gate###
16700Sstevel@tonic-gate###	Parameters:
16710Sstevel@tonic-gate###		$1 -- full recipient address
16720Sstevel@tonic-gate###
16730Sstevel@tonic-gate###	Returns:
16740Sstevel@tonic-gate###		parsed, non-local-relaying address
16750Sstevel@tonic-gate######################################################################
16760Sstevel@tonic-gate
16770Sstevel@tonic-gateSParseRecipient
16780Sstevel@tonic-gatednl mark and canonify address
16790Sstevel@tonic-gateR$*				$: <?> $>CanonAddr $1
16800Sstevel@tonic-gatednl workspace: <?> localpart<@domain[.]>
16810Sstevel@tonic-gateR<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
16820Sstevel@tonic-gatednl workspace: <?> localpart<@domain>
16830Sstevel@tonic-gateR<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
16840Sstevel@tonic-gate
16850Sstevel@tonic-gate# if no $=O character, no host in the user portion, we are done
16860Sstevel@tonic-gateR<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
16870Sstevel@tonic-gatednl no $=O in localpart: return
16880Sstevel@tonic-gateR<?> $*				$@ $1
16890Sstevel@tonic-gate
16900Sstevel@tonic-gatednl workspace: <NO> localpart<@domain>, where localpart contains $=O
16910Sstevel@tonic-gatednl mark everything which has an "authorized" domain with <RELAY>
16920Sstevel@tonic-gateifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
16930Sstevel@tonic-gate# if we relay, check username portion for user%host so host can be checked also
16940Sstevel@tonic-gateR<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
16950Sstevel@tonic-gatednl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
16960Sstevel@tonic-gatednl if mark is <NO> then change it to <RELAY> if domain is "authorized"
16970Sstevel@tonic-gate
16980Sstevel@tonic-gatednl what if access map returns something else than RELAY?
16990Sstevel@tonic-gatednl we are only interested in RELAY entries...
17000Sstevel@tonic-gatednl other To: entries: blacklist recipient; generic entries?
17010Sstevel@tonic-gatednl if it is an error we probably do not want to relay anyway
17020Sstevel@tonic-gateifdef(`_RELAY_HOSTS_ONLY_',
17030Sstevel@tonic-gate`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
17040Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
17050Sstevel@tonic-gateR<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
17060Sstevel@tonic-gateR<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
17070Sstevel@tonic-gate`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
17080Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
17090Sstevel@tonic-gateR<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
17100Sstevel@tonic-gateR<$+> <$+>			$: <$1> $2',`dnl')')
17110Sstevel@tonic-gate
17120Sstevel@tonic-gate
17130Sstevel@tonic-gateifdef(`_RELAY_MX_SERVED_', `dnl
17140Sstevel@tonic-gatednl do "we" ($=w) act as backup MX server for the destination domain?
17150Sstevel@tonic-gateR<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
17160Sstevel@tonic-gateR<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1
17170Sstevel@tonic-gatednl yes: mark it as <RELAY>
17180Sstevel@tonic-gateR<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
17190Sstevel@tonic-gatednl no: put old <NO> mark back
17200Sstevel@tonic-gateR<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
17210Sstevel@tonic-gate
17220Sstevel@tonic-gatednl do we relay to this recipient domain?
17230Sstevel@tonic-gateR<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
17240Sstevel@tonic-gatednl something else
17250Sstevel@tonic-gateR<$+> $*			$@ $2
17260Sstevel@tonic-gate
17270Sstevel@tonic-gate
17280Sstevel@tonic-gate######################################################################
17290Sstevel@tonic-gate###  check_relay -- check hostname/address on SMTP startup
17300Sstevel@tonic-gate######################################################################
17310Sstevel@tonic-gate
17320Sstevel@tonic-gateifdef(`_CONTROL_IMMEDIATE_',`dnl
17330Sstevel@tonic-gateScheck_relay
17340Sstevel@tonic-gateifdef(`_RATE_CONTROL_IMMEDIATE_',`dnl
17350Sstevel@tonic-gatednl workspace: ignored...
17360Sstevel@tonic-gateR$*		$: $>"RateControl" dummy', `dnl')
17370Sstevel@tonic-gateifdef(`_CONN_CONTROL_IMMEDIATE_',`dnl
17380Sstevel@tonic-gatednl workspace: ignored...
17390Sstevel@tonic-gateR$*		$: $>"ConnControl" dummy', `dnl')
17400Sstevel@tonic-gatednl')
17410Sstevel@tonic-gate
17420Sstevel@tonic-gateSLocal_check_relay
17430Sstevel@tonic-gateScheck`'_U_`'relay
17440Sstevel@tonic-gateifdef(`_USE_CLIENT_PTR_',`dnl
17450Sstevel@tonic-gateR$* $| $*		$: $&{client_ptr} $| $2', `dnl')
17460Sstevel@tonic-gateR$*			$: $1 $| $>"Local_check_relay" $1
17470Sstevel@tonic-gateR$* $| $* $| $#$*	$#$3
17480Sstevel@tonic-gateR$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
17490Sstevel@tonic-gate
17500Sstevel@tonic-gateSBasic_check_relay
17510Sstevel@tonic-gate# check for deferred delivery mode
17520Sstevel@tonic-gateR$*			$: < $&{deliveryMode} > $1
17530Sstevel@tonic-gateR< d > $*		$@ deferred
17540Sstevel@tonic-gateR< $* > $*		$: $2
17550Sstevel@tonic-gate
17560Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
17570Sstevel@tonic-gatednl workspace: {client_name} $| {client_addr}
17580Sstevel@tonic-gateR$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
17590Sstevel@tonic-gatednl workspace: <result-of-lookup> <{client_addr}>
17600Sstevel@tonic-gatednl OR $| $+ if client_name is empty
17610Sstevel@tonic-gateR   $| $+		$: $>A < $1 > <?> <+ Connect> <>	empty client_name
17620Sstevel@tonic-gatednl workspace: <result-of-lookup> <{client_addr}>
17630Sstevel@tonic-gateR<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
17640Sstevel@tonic-gatednl workspace: <result-of-lookup> (<>|<{client_addr}>)
17650Sstevel@tonic-gateR<?> <$*>		$: OK				found nothing
17660Sstevel@tonic-gatednl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
17670Sstevel@tonic-gateR<$={Accept}> <$*>	$@ $1				return value of lookup
17680Sstevel@tonic-gateR<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"')
17690Sstevel@tonic-gateR<DISCARD> <$*>		$#discard $: discard
17700Sstevel@tonic-gateR<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1
17710Sstevel@tonic-gatednl error tag
17720Sstevel@tonic-gateR<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
17730Sstevel@tonic-gateR<ERROR:$+> <$*>		$#error $: $1
17740Sstevel@tonic-gateifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
17750Sstevel@tonic-gatednl generic error from access map
17760Sstevel@tonic-gateR<$+> <$*>		$#error $: $1', `dnl')
17770Sstevel@tonic-gate
17780Sstevel@tonic-gateifdef(`_RBL_',`dnl
17790Sstevel@tonic-gate# DNS based IP address spam list
17800Sstevel@tonic-gatednl workspace: ignored...
17810Sstevel@tonic-gateR$*			$: $&{client_addr}
17820Sstevel@tonic-gateR$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
17830Sstevel@tonic-gateR<?>OK			$: OKSOFAR
17840Sstevel@tonic-gateR<?>$+			$#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"',
17850Sstevel@tonic-gate`dnl')
17860Sstevel@tonic-gateifdef(`_RATE_CONTROL_',`dnl
17870Sstevel@tonic-gateifdef(`_RATE_CONTROL_IMMEDIATE_',`', `dnl
17880Sstevel@tonic-gatednl workspace: ignored...
17890Sstevel@tonic-gateR$*		$: $>"RateControl" dummy')', `dnl')
17900Sstevel@tonic-gateifdef(`_CONN_CONTROL_',`dnl
17910Sstevel@tonic-gateifdef(`_CONN_CONTROL_IMMEDIATE_',`',`dnl
17920Sstevel@tonic-gatednl workspace: ignored...
17930Sstevel@tonic-gateR$*		$: $>"ConnControl" dummy')', `dnl')
17940Sstevel@tonic-gateundivert(8)
1795*3544Sjbeckifdef(`_REQUIRE_RDNS_', `dnl
1796*3544SjbeckR$*			$: $&{client_addr} $| $&{client_resolve}
1797*3544SjbeckR$=R $*			$@ RELAY		We relay for these
1798*3544SjbeckR$* $| OK		$@ OK			Resolves.
1799*3544SjbeckR$* $| FAIL		$#error $@ 5.7.1 $: 550 Fix reverse DNS for $1
1800*3544SjbeckR$* $| TEMP		$#error $@ 4.1.8 $: 451 Client IP address $1 does not resolve
1801*3544SjbeckR$* $| FORGED		$#error $@ 4.1.8 $: 451 Possibly forged hostname for $1
1802*3544Sjbeck', `dnl')
18030Sstevel@tonic-gate
18040Sstevel@tonic-gate######################################################################
18050Sstevel@tonic-gate###  check_mail -- check SMTP ``MAIL FROM:'' command argument
18060Sstevel@tonic-gate######################################################################
18070Sstevel@tonic-gate
18080Sstevel@tonic-gateSLocal_check_mail
18090Sstevel@tonic-gateScheck`'_U_`'mail
18100Sstevel@tonic-gateR$*			$: $1 $| $>"Local_check_mail" $1
18110Sstevel@tonic-gateR$* $| $#$*		$#$2
18120Sstevel@tonic-gateR$* $| $*		$@ $>"Basic_check_mail" $1
18130Sstevel@tonic-gate
18140Sstevel@tonic-gateSBasic_check_mail
18150Sstevel@tonic-gate# check for deferred delivery mode
18160Sstevel@tonic-gateR$*			$: < $&{deliveryMode} > $1
18170Sstevel@tonic-gateR< d > $*		$@ deferred
18180Sstevel@tonic-gateR< $* > $*		$: $2
18190Sstevel@tonic-gate
18200Sstevel@tonic-gate# authenticated?
18210Sstevel@tonic-gatednl done first: we can require authentication for every mail transaction
18220Sstevel@tonic-gatednl workspace: address as given by MAIL FROM: (sender)
18230Sstevel@tonic-gateR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
18240Sstevel@tonic-gateR$* $| $#$+		$#$2
18250Sstevel@tonic-gatednl undo damage: remove result of tls_client call
18260Sstevel@tonic-gateR$* $| $*		$: $1
18270Sstevel@tonic-gate
18280Sstevel@tonic-gatednl workspace: address as given by MAIL FROM:
18290Sstevel@tonic-gateR<>			$@ <OK>			we MUST accept <> (RFC 1123)
18300Sstevel@tonic-gateifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
18310Sstevel@tonic-gatednl do some additional checks
18320Sstevel@tonic-gatednl no user@host
18330Sstevel@tonic-gatednl no user@localhost (if nonlocal sender)
18340Sstevel@tonic-gatednl this is a pretty simple canonification, it will not catch every case
18350Sstevel@tonic-gatednl just make sure the address has <> around it (which is required by
18360Sstevel@tonic-gatednl the RFC anyway, maybe we should complain if they are missing...)
18370Sstevel@tonic-gatednl dirty trick: if it is user@host, just add a dot: user@host. this will
18380Sstevel@tonic-gatednl not be modified by host lookups.
18390Sstevel@tonic-gateR$+			$: <?> $1
18400Sstevel@tonic-gateR<?><$+>		$: <@> <$1>
18410Sstevel@tonic-gateR<?>$+			$: <@> <$1>
18420Sstevel@tonic-gatednl workspace: <@> <address>
18430Sstevel@tonic-gatednl prepend daemon_flags
18440Sstevel@tonic-gateR$*			$: $&{daemon_flags} $| $1
18450Sstevel@tonic-gatednl workspace: ${daemon_flags} $| <@> <address>
18460Sstevel@tonic-gatednl do not allow these at all or only from local systems?
18470Sstevel@tonic-gateR$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
18480Sstevel@tonic-gatednl accept unqualified sender: change mark to avoid test
18490Sstevel@tonic-gateR$* u $* $| <@> < $* >	$: <?> < $3 >
18500Sstevel@tonic-gatednl workspace: ${daemon_flags} $| <@> <address>
18510Sstevel@tonic-gatednl        or:                    <? ${client_name} > <address>
18520Sstevel@tonic-gatednl        or:                    <?> <address>
18530Sstevel@tonic-gatednl remove daemon_flags
18540Sstevel@tonic-gateR$* $| $*		$: $2
18550Sstevel@tonic-gate# handle case of @localhost on address
18560Sstevel@tonic-gateR<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
18570Sstevel@tonic-gateR<@> < $* @ [127.0.0.1] >
18580Sstevel@tonic-gate			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
18590Sstevel@tonic-gateR<@> < $* @ localhost.$m >
18600Sstevel@tonic-gate			$: < ? $&{client_name} > < $1 @ localhost.$m >
18610Sstevel@tonic-gateifdef(`_NO_UUCP_', `dnl',
18620Sstevel@tonic-gate`R<@> < $* @ localhost.UUCP >
18630Sstevel@tonic-gate			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
18640Sstevel@tonic-gatednl workspace: < ? $&{client_name} > <user@localhost|host>
18650Sstevel@tonic-gatednl	or:    <@> <address>
18660Sstevel@tonic-gatednl	or:    <?> <address>	(thanks to u in ${daemon_flags})
18670Sstevel@tonic-gateR<@> $*			$: $1			no localhost as domain
18680Sstevel@tonic-gatednl workspace: < ? $&{client_name} > <user@localhost|host>
18690Sstevel@tonic-gatednl	or:    <address>
18700Sstevel@tonic-gatednl	or:    <?> <address>	(thanks to u in ${daemon_flags})
18710Sstevel@tonic-gateR<? $=w> $*		$: $2			local client: ok
18720Sstevel@tonic-gateR<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
18730Sstevel@tonic-gatednl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
18740Sstevel@tonic-gateR<?> $*			$: $1')
18750Sstevel@tonic-gatednl workspace: address (or <address>)
18760Sstevel@tonic-gateR$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
18770Sstevel@tonic-gatednl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
18780Sstevel@tonic-gatednl there is nothing behind the <@host> so no trailing $* needed
18790Sstevel@tonic-gateR<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
18800Sstevel@tonic-gate# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
18810Sstevel@tonic-gateR<?> $* < @ $* $=P >	$: <_RES_OK_> $1 < @ $2 $3 >
18820Sstevel@tonic-gatednl workspace <mark> CanonicalAddress	where mark is ? or OK
18830Sstevel@tonic-gatednl A sender address with my local host name ($j) is safe
18840Sstevel@tonic-gateR<?> $* < @ $j >	$: <_RES_OK_> $1 < @ $j >
18850Sstevel@tonic-gateifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
18860Sstevel@tonic-gate`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
18870Sstevel@tonic-gate`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
18880Sstevel@tonic-gateR<? $* <$->> $* < @ $+ >
18890Sstevel@tonic-gate			$: <$2> $3 < @ $4 >')
18900Sstevel@tonic-gatednl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
18910Sstevel@tonic-gatednl mark is ? iff the address is user (wo @domain)
18920Sstevel@tonic-gate
18930Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
18940Sstevel@tonic-gate# check sender address: user@address, user@, address
18950Sstevel@tonic-gatednl should we remove +ext from user?
18960Sstevel@tonic-gatednl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
18970Sstevel@tonic-gateR<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
18980Sstevel@tonic-gateR<$+> $+		$: @<$1> <$2> $| <U:$2@>
18990Sstevel@tonic-gatednl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
19000Sstevel@tonic-gatednl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
19010Sstevel@tonic-gatednl will only return user<@domain when "reversing" the args
19020Sstevel@tonic-gateR@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
19030Sstevel@tonic-gatednl workspace: <@><mark> <CanonicalAddress> $| <result>
19040Sstevel@tonic-gateR<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
19050Sstevel@tonic-gatednl workspace: <result> <mark> <CanonicalAddress>
19060Sstevel@tonic-gate# retransform for further use
19070Sstevel@tonic-gatednl required form:
19080Sstevel@tonic-gatednl <ResultOfLookup|mark> CanonicalAddress
19090Sstevel@tonic-gateR<?> <$+> <$*>		$: <$1> $2	no match
19100Sstevel@tonic-gateR<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
19110Sstevel@tonic-gatednl workspace <ResultOfLookup|mark> CanonicalAddress
19120Sstevel@tonic-gatednl mark is ? iff the address is user (wo @domain)
19130Sstevel@tonic-gate
19140Sstevel@tonic-gateifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
19150Sstevel@tonic-gate# handle case of no @domain on address
19160Sstevel@tonic-gatednl prepend daemon_flags
19170Sstevel@tonic-gateR<?> $*			$: $&{daemon_flags} $| <?> $1
19180Sstevel@tonic-gatednl accept unqualified sender: change mark to avoid test
19190Sstevel@tonic-gateR$* u $* $| <?> $*	$: <_RES_OK_> $3
19200Sstevel@tonic-gatednl remove daemon_flags
19210Sstevel@tonic-gateR$* $| $*		$: $2
19220Sstevel@tonic-gateR<?> $*			$: < ? $&{client_addr} > $1
19230Sstevel@tonic-gateR<?> $*			$@ <_RES_OK_>			...local unqualed ok
19240Sstevel@tonic-gateR<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
19250Sstevel@tonic-gate							...remote is not')
19260Sstevel@tonic-gate# check results
19270Sstevel@tonic-gateR<?> $*			$: @ $1		mark address: nothing known about it
1928*3544SjbeckR<$={ResOk}> $*		$: @ $2		domain ok
19290Sstevel@tonic-gateR<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
19300Sstevel@tonic-gateR<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
19310Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
19320Sstevel@tonic-gateR<$={Accept}> $*	$# $1		accept from access map
19330Sstevel@tonic-gateR<DISCARD> $*		$#discard $: discard
19340Sstevel@tonic-gateR<QUARANTINE:$+> $*	$#error $@ quarantine $: $1
19350Sstevel@tonic-gateR<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"')
19360Sstevel@tonic-gatednl error tag
19370Sstevel@tonic-gateR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
19380Sstevel@tonic-gateR<ERROR:$+> $*		$#error $: $1
19390Sstevel@tonic-gateifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
19400Sstevel@tonic-gatednl generic error from access map
19410Sstevel@tonic-gateR<$+> $*		$#error $: $1		error from access db',
19420Sstevel@tonic-gate`dnl')
1943*3544Sjbeckdnl workspace: @ CanonicalAddress (i.e. address in canonical form localpart<@host>)
1944*3544Sjbeck
1945*3544Sjbeckifdef(`_BADMX_CHK_', `dnl
1946*3544SjbeckR@ $*<@$+>$*		$: $1<@$2>$3 $| $>BadMX $2
1947*3544SjbeckR$* $| $#$*		$#$2
1948*3544Sjbeck
1949*3544SjbeckSBadMX
1950*3544Sjbeck# Look up MX records and ferret away a copy of the original address.
1951*3544Sjbeck# input: domain part of address to check
1952*3544SjbeckR$+				$:<MX><$1><:$(mxlist $1$):><:>
1953*3544Sjbeck# workspace: <MX><domain><: mxlist-result $><:>
1954*3544SjbeckR<MX><$+><:$*<TEMP>:><$*>	$#error $@ 4.1.2 $: "450 MX lookup failure for "$1
1955*3544Sjbeck# workspace: <MX> <original destination> <unchecked mxlist> <checked mxlist>
1956*3544Sjbeck# Recursively run badmx check on each mx.
1957*3544SjbeckR<MX><$*><:$+:$*><:$*>		<MX><$1><:$3><: $4 $(badmx $2 $):>
1958*3544Sjbeck# See if any of them fail.
1959*3544SjbeckR<MX><$*><$*><$*<BADMX>:$*>	$#error $@ 5.1.2 $:"550 Illegal MX record for recipient host "$1
1960*3544Sjbeck# Reverse the mxlists so we can use the same argument order again.
1961*3544SjbeckR<MX><$*><$*><$*>		$:<MX><$1><$3><$2>
1962*3544SjbeckR<MX><$*><:$+:$*><:$*>		<MX><$1><:$3><:$4 $(dnsA $2 $) :>
1963*3544Sjbeck
1964*3544Sjbeck# Reverse the lists so we can use the same argument order again.
1965*3544SjbeckR<MX><$*><$*><$*>		$:<MX><$1><$3><$2>
1966*3544SjbeckR<MX><$*><:$+:$*><:$*>		<MX><$1><:$3><:$4 $(BadMXIP $2 $) :>
1967*3544Sjbeck
1968*3544SjbeckR<MX><$*><$*><$*<BADMXIP>:$*>	$#error $@ 5.1.2 $:"550 Invalid MX record for recipient host "$1',
1969*3544Sjbeck`dnl')
1970*3544Sjbeck
19710Sstevel@tonic-gate
19720Sstevel@tonic-gate######################################################################
19730Sstevel@tonic-gate###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
19740Sstevel@tonic-gate######################################################################
19750Sstevel@tonic-gate
19760Sstevel@tonic-gateSLocal_check_rcpt
19770Sstevel@tonic-gateScheck`'_U_`'rcpt
19780Sstevel@tonic-gateR$*			$: $1 $| $>"Local_check_rcpt" $1
19790Sstevel@tonic-gateR$* $| $#$*		$#$2
19800Sstevel@tonic-gateR$* $| $*		$@ $>"Basic_check_rcpt" $1
19810Sstevel@tonic-gate
19820Sstevel@tonic-gateSBasic_check_rcpt
19830Sstevel@tonic-gate# empty address?
19840Sstevel@tonic-gateR<>			$#error $@ nouser $: "553 User address required"
19850Sstevel@tonic-gateR$@			$#error $@ nouser $: "553 User address required"
19860Sstevel@tonic-gate# check for deferred delivery mode
19870Sstevel@tonic-gateR$*			$: < $&{deliveryMode} > $1
19880Sstevel@tonic-gateR< d > $*		$@ deferred
19890Sstevel@tonic-gateR< $* > $*		$: $2
19900Sstevel@tonic-gate
19910Sstevel@tonic-gateifdef(`_REQUIRE_QUAL_RCPT_', `dnl
19920Sstevel@tonic-gatednl this code checks for user@host where host is not a FQHN.
19930Sstevel@tonic-gatednl it is not activated.
19940Sstevel@tonic-gatednl notice: code to check for a recipient without a domain name is
19950Sstevel@tonic-gatednl available down below; look for the same macro.
19960Sstevel@tonic-gatednl this check is done here because the name might be qualified by the
19970Sstevel@tonic-gatednl canonicalization.
19980Sstevel@tonic-gate# require fully qualified domain part?
19990Sstevel@tonic-gatednl very simple canonification: make sure the address is in < >
20000Sstevel@tonic-gateR$+			$: <?> $1
20010Sstevel@tonic-gateR<?> <$+>		$: <@> <$1>
20020Sstevel@tonic-gateR<?> $+			$: <@> <$1>
20030Sstevel@tonic-gateR<@> < postmaster >	$: postmaster
20040Sstevel@tonic-gateR<@> < $* @ $+ . $+ >	$: < $1 @ $2 . $3 >
20050Sstevel@tonic-gatednl prepend daemon_flags
20060Sstevel@tonic-gateR<@> $*			$: $&{daemon_flags} $| <@> $1
20070Sstevel@tonic-gatednl workspace: ${daemon_flags} $| <@> <address>
20082197Sjbeckdnl _r_equire qual.rcpt: ok
20090Sstevel@tonic-gateR$* r $* $| <@> < $+ @ $+ >	$: < $3 @ $4 >
20100Sstevel@tonic-gatednl do not allow these at all or only from local systems?
20110Sstevel@tonic-gateR$* r $* $| <@> < $* >	$: < ? $&{client_name} > < $3 >
20120Sstevel@tonic-gateR<?> < $* >		$: <$1>
20130Sstevel@tonic-gateR<? $=w> < $* >		$: <$1>
20140Sstevel@tonic-gateR<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
20150Sstevel@tonic-gatednl remove daemon_flags for other cases
20160Sstevel@tonic-gateR$* $| <@> $*		$: $2', `dnl')
20170Sstevel@tonic-gate
20180Sstevel@tonic-gatednl ##################################################################
20190Sstevel@tonic-gatednl call subroutines for recipient and relay
20200Sstevel@tonic-gatednl possible returns from subroutines:
20210Sstevel@tonic-gatednl $#TEMP	temporary failure
20220Sstevel@tonic-gatednl $#error	permanent failure (or temporary if from access map)
20230Sstevel@tonic-gatednl $#other	stop processing
20240Sstevel@tonic-gatednl RELAY	RELAYing allowed
20250Sstevel@tonic-gatednl other	otherwise
20260Sstevel@tonic-gate######################################################################
20270Sstevel@tonic-gateR$*			$: $1 $| @ $>"Rcpt_ok" $1
20280Sstevel@tonic-gatednl temporary failure? remove mark @ and remember
20290Sstevel@tonic-gateR$* $| @ $#TEMP $+	$: $1 $| T $2
20300Sstevel@tonic-gatednl error or ok (stop)
20310Sstevel@tonic-gateR$* $| @ $#$*		$#$2
20320Sstevel@tonic-gateifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
20330Sstevel@tonic-gateR$* $| @ RELAY		$@ RELAY
20340Sstevel@tonic-gatednl something else: call check sender (relay)
20350Sstevel@tonic-gateR$* $| @ $*		$: O $| $>"Relay_ok" $1
20360Sstevel@tonic-gatednl temporary failure: call check sender (relay)
20370Sstevel@tonic-gateR$* $| T $+		$: T $2 $| $>"Relay_ok" $1
20380Sstevel@tonic-gatednl temporary failure? return that
20390Sstevel@tonic-gateR$* $| $#TEMP $+	$#error $2
20400Sstevel@tonic-gatednl error or ok (stop)
20410Sstevel@tonic-gateR$* $| $#$*		$#$2
20420Sstevel@tonic-gateR$* $| RELAY		$@ RELAY
20430Sstevel@tonic-gatednl something else: return previous temp failure
20440Sstevel@tonic-gateR T $+ $| $*		$#error $1
20450Sstevel@tonic-gate# anything else is bogus
20460Sstevel@tonic-gateR$*			$#error $@ 5.7.1 $: confRELAY_MSG
20470Sstevel@tonic-gatedivert(0)
20480Sstevel@tonic-gate
20490Sstevel@tonic-gate######################################################################
20500Sstevel@tonic-gate### Rcpt_ok: is the recipient ok?
20510Sstevel@tonic-gatednl input: recipient address (RCPT TO)
20520Sstevel@tonic-gatednl output: see explanation at call
20530Sstevel@tonic-gate######################################################################
20540Sstevel@tonic-gateSRcpt_ok
20550Sstevel@tonic-gateifdef(`_LOOSE_RELAY_CHECK_',`dnl
20560Sstevel@tonic-gateR$*			$: $>CanonAddr $1
20570Sstevel@tonic-gateR$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
20580Sstevel@tonic-gate`R$*			$: $>ParseRecipient $1		strip relayable hosts')
20590Sstevel@tonic-gate
20600Sstevel@tonic-gateifdef(`_BESTMX_IS_LOCAL_',`dnl
20610Sstevel@tonic-gateifelse(_BESTMX_IS_LOCAL_, `', `dnl
20620Sstevel@tonic-gate# unlimited bestmx
20630Sstevel@tonic-gateR$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
20640Sstevel@tonic-gate`dnl
20650Sstevel@tonic-gate# limit bestmx to $=B
20660Sstevel@tonic-gateR$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
20670Sstevel@tonic-gateR$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
20680Sstevel@tonic-gateR$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
20690Sstevel@tonic-gateR$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
20700Sstevel@tonic-gate
20710Sstevel@tonic-gateifdef(`_BLACKLIST_RCPT_',`dnl
20720Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
20730Sstevel@tonic-gate# blacklist local users or any host from receiving mail
20740Sstevel@tonic-gateR$*			$: <?> $1
20750Sstevel@tonic-gatednl user is now tagged with @ to be consistent with check_mail
20760Sstevel@tonic-gatednl and to distinguish users from hosts (com would be host, com@ would be user)
20770Sstevel@tonic-gateR<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
20780Sstevel@tonic-gateR<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
20790Sstevel@tonic-gateR<?> $+			$: <> <$1> $| <U:$1@>
20800Sstevel@tonic-gatednl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
20810Sstevel@tonic-gatednl will only return user<@domain when "reversing" the args
20820Sstevel@tonic-gateR<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
20830Sstevel@tonic-gateR<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
20840Sstevel@tonic-gateR<?> <$*>		$: @ $1		mark address as no match
20850Sstevel@tonic-gatednl we may have to filter here because otherwise some RHSs
20860Sstevel@tonic-gatednl would be interpreted as generic error messages...
20870Sstevel@tonic-gatednl error messages should be "tagged" by prefixing them with error: !
20880Sstevel@tonic-gatednl that would make a lot of things easier.
20890Sstevel@tonic-gateR<$={Accept}> <$*>	$: @ $2		mark address as no match
20900Sstevel@tonic-gateifdef(`_ACCESS_SKIP_', `dnl
20910Sstevel@tonic-gateR<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
20920Sstevel@tonic-gateifdef(`_DELAY_COMPAT_8_10_',`dnl
20930Sstevel@tonic-gatednl compatility with 8.11/8.10:
20940Sstevel@tonic-gatednl we have to filter these because otherwise they would be interpreted
20950Sstevel@tonic-gatednl as generic error message...
20960Sstevel@tonic-gatednl error messages should be "tagged" by prefixing them with error: !
20970Sstevel@tonic-gatednl that would make a lot of things easier.
20980Sstevel@tonic-gatednl maybe we should stop checks already here (if SPAM_xyx)?
20990Sstevel@tonic-gateR<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
21000Sstevel@tonic-gateR<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
21010Sstevel@tonic-gateR<DISCARD> $*		$#discard $: discard
21020Sstevel@tonic-gateR<QUARANTINE:$+> $*	$#error $@ quarantine $: $1
21030Sstevel@tonic-gatednl error tag
21040Sstevel@tonic-gateR<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
21050Sstevel@tonic-gateR<ERROR:$+> $*		$#error $: $1
21060Sstevel@tonic-gateifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
21070Sstevel@tonic-gatednl generic error from access map
21080Sstevel@tonic-gateR<$+> $*		$#error $: $1		error from access db
21090Sstevel@tonic-gateR@ $*			$1		remove mark', `dnl')', `dnl')
21100Sstevel@tonic-gate
21110Sstevel@tonic-gateifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
21120Sstevel@tonic-gate# authenticated via TLS?
21130Sstevel@tonic-gateR$*			$: $1 $| $>RelayTLS	client authenticated?
21140Sstevel@tonic-gateR$* $| $# $+		$# $2			error/ok?
21150Sstevel@tonic-gateR$* $| $*		$: $1			no
21160Sstevel@tonic-gate
21170Sstevel@tonic-gateR$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
21180Sstevel@tonic-gatednl workspace: localpart<@domain> $| result of Local_Relay_Auth
21190Sstevel@tonic-gateR$* $| $# $*		$# $2
21200Sstevel@tonic-gatednl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
21210Sstevel@tonic-gateR$* $| NO		$: $1
21220Sstevel@tonic-gateR$* $| $*		$: $1 $| $&{auth_type}
21230Sstevel@tonic-gatednl workspace: localpart<@domain> [ $| ${auth_type} ]
21240Sstevel@tonic-gatednl empty ${auth_type}?
21250Sstevel@tonic-gateR$* $|			$: $1
21260Sstevel@tonic-gatednl mechanism ${auth_type} accepted?
21270Sstevel@tonic-gatednl use $# to override further tests (delay_checks): see check_rcpt below
21280Sstevel@tonic-gateR$* $| $={TrustAuthMech}	$# RELAY
21290Sstevel@tonic-gatednl remove ${auth_type}
21300Sstevel@tonic-gateR$* $| $*		$: $1
21310Sstevel@tonic-gatednl workspace: localpart<@domain> | localpart
21320Sstevel@tonic-gateifelse(defn(`_NO_UUCP_'), `r',
21330Sstevel@tonic-gate`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
21340Sstevel@tonic-gateR$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
21350Sstevel@tonic-gate# anything terminating locally is ok
21360Sstevel@tonic-gateifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
21370Sstevel@tonic-gateR$+ < @ $* $=m >	$@ RELAY', `dnl')
21380Sstevel@tonic-gateR$+ < @ $=w >		$@ RELAY
21390Sstevel@tonic-gateifdef(`_RELAY_HOSTS_ONLY_',
21400Sstevel@tonic-gate`R$+ < @ $=R >		$@ RELAY
21410Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
21420Sstevel@tonic-gateR$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
21430Sstevel@tonic-gatednl workspace: <Result-of-lookup | ?> <localpart<@domain>>
21440Sstevel@tonic-gateR<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
21450Sstevel@tonic-gate`R$+ < @ $* $=R >	$@ RELAY
21460Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
21470Sstevel@tonic-gateifdef(`_RELAY_FULL_ADDR_', `dnl
21480Sstevel@tonic-gateR$+ < @ $+ >		$: $1 < @ $2 > $| $>SearchList <+ To> $| <F:$1@$2> <D:$2> <F:$1@> <>
21490Sstevel@tonic-gateR$+ < @ $+ > $| <$*>	$: <$3> <$1 <@ $2>>
21500Sstevel@tonic-gateR$+ < @ $+ > $| $*	$: <$3> <$1 <@ $2>>',
21510Sstevel@tonic-gate`R$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>')')')
21520Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
21530Sstevel@tonic-gatednl workspace: <Result-of-lookup | ?> <localpart<@domain>>
21540Sstevel@tonic-gateR<RELAY> $*		$@ RELAY
21550Sstevel@tonic-gateifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
21560Sstevel@tonic-gateR<$*> <$*>		$: $2',`dnl')
21570Sstevel@tonic-gate
21580Sstevel@tonic-gate
21590Sstevel@tonic-gateifdef(`_RELAY_MX_SERVED_', `dnl
21600Sstevel@tonic-gate# allow relaying for hosts which we MX serve
21610Sstevel@tonic-gateR$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
21620Sstevel@tonic-gatednl this must not necessarily happen if the client is checked first...
21630Sstevel@tonic-gateR< : $* <TEMP> : > $*	$#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1
21640Sstevel@tonic-gateR<$* : $=w . : $*> $*	$@ RELAY
21650Sstevel@tonic-gateR< : $* : > $*		$: $2',
21660Sstevel@tonic-gate`dnl')
21670Sstevel@tonic-gate
21680Sstevel@tonic-gate# check for local user (i.e. unqualified address)
21690Sstevel@tonic-gateR$*			$: <?> $1
21700Sstevel@tonic-gateR<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
21710Sstevel@tonic-gate# local user is ok
21720Sstevel@tonic-gatednl is it really? the standard requires user@domain, not just user
21730Sstevel@tonic-gatednl but we should accept it anyway (maybe making it an option:
21740Sstevel@tonic-gatednl RequireFQDN ?)
21750Sstevel@tonic-gatednl postmaster must be accepted without domain (DRUMS)
21760Sstevel@tonic-gateifdef(`_REQUIRE_QUAL_RCPT_', `dnl
21770Sstevel@tonic-gateR<?> postmaster		$@ OK
21780Sstevel@tonic-gate# require qualified recipient?
21790Sstevel@tonic-gatednl prepend daemon_flags
21800Sstevel@tonic-gateR<?> $+			$: $&{daemon_flags} $| <?> $1
21810Sstevel@tonic-gatednl workspace: ${daemon_flags} $| <?> localpart
21820Sstevel@tonic-gatednl do not allow these at all or only from local systems?
21830Sstevel@tonic-gatednl r flag? add client_name
21840Sstevel@tonic-gateR$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
21850Sstevel@tonic-gatednl no r flag: relay to local user (only local part)
21860Sstevel@tonic-gate# no qualified recipient required
21870Sstevel@tonic-gateR$* $| <?> $+		$@ RELAY
21880Sstevel@tonic-gatednl client_name is empty
21890Sstevel@tonic-gateR<?> <?> $+		$@ RELAY
21900Sstevel@tonic-gatednl client_name is local
21910Sstevel@tonic-gateR<? $=w> <?> $+		$@ RELAY
21920Sstevel@tonic-gatednl client_name is not local
21930Sstevel@tonic-gateR<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
21940Sstevel@tonic-gatednl no qualified recipient required
21950Sstevel@tonic-gateR<?> $+			$@ RELAY')
21960Sstevel@tonic-gatednl it is a remote user: remove mark and then check client
21970Sstevel@tonic-gateR<$+> $*		$: $2
21980Sstevel@tonic-gatednl currently the recipient address is not used below
21990Sstevel@tonic-gate
22000Sstevel@tonic-gate######################################################################
22010Sstevel@tonic-gate### Relay_ok: is the relay/sender ok?
22020Sstevel@tonic-gatednl input: ignored
22030Sstevel@tonic-gatednl output: see explanation at call
22040Sstevel@tonic-gate######################################################################
22050Sstevel@tonic-gateSRelay_ok
22060Sstevel@tonic-gate# anything originating locally is ok
22070Sstevel@tonic-gate# check IP address
22080Sstevel@tonic-gateR$*			$: $&{client_addr}
22090Sstevel@tonic-gateR$@			$@ RELAY		originated locally
22100Sstevel@tonic-gateR0			$@ RELAY		originated locally
22110Sstevel@tonic-gateR127.0.0.1		$@ RELAY		originated locally
22120Sstevel@tonic-gateRIPv6:::1		$@ RELAY		originated locally
22130Sstevel@tonic-gateR$=R $*			$@ RELAY		relayable IP address
22140Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
22150Sstevel@tonic-gateR$*			$: $>A <$1> <?> <+ Connect> <$1>
22160Sstevel@tonic-gateR<RELAY> $* 		$@ RELAY		relayable IP address
22170Sstevel@tonic-gateifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl
22180Sstevel@tonic-gatednl this will cause rejections in cases like:
22190Sstevel@tonic-gatednl Connect:My.Host.Domain	RELAY
22200Sstevel@tonic-gatednl Connect:My.Net		REJECT
22210Sstevel@tonic-gatednl since in check_relay client_name is checked before client_addr
22220Sstevel@tonic-gateR<REJECT> $* 		$@ REJECT		rejected IP address')
22230Sstevel@tonic-gateifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
22240Sstevel@tonic-gateR<$*> <$*>		$: $2', `dnl')
22250Sstevel@tonic-gateR$*			$: [ $1 ]		put brackets around it...
22260Sstevel@tonic-gateR$=w			$@ RELAY		... and see if it is local
22270Sstevel@tonic-gate
22280Sstevel@tonic-gateifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
22290Sstevel@tonic-gateifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
22300Sstevel@tonic-gateifdef(`_RELAY_MAIL_FROM_', `dnl
22310Sstevel@tonic-gatednl input: {client_addr} or something "broken"
22320Sstevel@tonic-gatednl just throw the input away; we do not need it.
22330Sstevel@tonic-gate# check whether FROM is allowed to use system as relay
22340Sstevel@tonic-gateR$*			$: <?> $>CanonAddr $&f
22350Sstevel@tonic-gateR<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
22360Sstevel@tonic-gateifdef(`_RELAY_LOCAL_FROM_', `dnl
22370Sstevel@tonic-gate# check whether local FROM is ok
22380Sstevel@tonic-gateR<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
22390Sstevel@tonic-gateifdef(`_RELAY_DB_FROM_', `dnl
22400Sstevel@tonic-gateR<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <>
22410Sstevel@tonic-gateR<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
22420Sstevel@tonic-gateifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
22430Sstevel@tonic-gate', `dnl
22440Sstevel@tonic-gateifdef(`_RELAY_DB_FROM_DOMAIN_',
22450Sstevel@tonic-gate`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
22460Sstevel@tonic-gate')',
22470Sstevel@tonic-gate`dnl')
22480Sstevel@tonic-gatednl')', `dnl')
22490Sstevel@tonic-gatednl notice: the rulesets above do not leave a unique workspace behind.
22500Sstevel@tonic-gatednl it does not matter in this case because the following rule ignores
22510Sstevel@tonic-gatednl the input. otherwise these rules must "clean up" the workspace.
22520Sstevel@tonic-gate
22530Sstevel@tonic-gate# check client name: first: did it resolve?
22540Sstevel@tonic-gatednl input: ignored
22550Sstevel@tonic-gateR$*			$: < $&{client_resolve} >
22560Sstevel@tonic-gateR<TEMP>			$#TEMP $@ 4.4.0 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
22570Sstevel@tonic-gateR<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
22580Sstevel@tonic-gateR<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
22590Sstevel@tonic-gatednl ${client_resolve} should be OK, so go ahead
22600Sstevel@tonic-gateR$*			$: <@> $&{client_name}
22610Sstevel@tonic-gatednl should not be necessary since it has been done for client_addr already
22620Sstevel@tonic-gatednl this rule actually may cause a problem if {client_name} resolves to ""
22630Sstevel@tonic-gatednl however, this should not happen since the forward lookup should fail
22640Sstevel@tonic-gatednl and {client_resolve} should be TEMP or FAIL.
22650Sstevel@tonic-gatednl nevertheless, removing the rule doesn't hurt.
22660Sstevel@tonic-gatednl R<@>			$@ RELAY
22670Sstevel@tonic-gatednl workspace: <@> ${client_name} (not empty)
22680Sstevel@tonic-gate# pass to name server to make hostname canonical
22690Sstevel@tonic-gateR<@> $* $=P 		$:<?>  $1 $2
22700Sstevel@tonic-gateR<@> $+			$:<?>  $[ $1 $]
22710Sstevel@tonic-gatednl workspace: <?> ${client_name} (canonified)
22720Sstevel@tonic-gateR$* .			$1			strip trailing dots
22730Sstevel@tonic-gateifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
22740Sstevel@tonic-gateR<?> $* $=m		$@ RELAY', `dnl')
22750Sstevel@tonic-gateR<?> $=w		$@ RELAY
22760Sstevel@tonic-gateifdef(`_RELAY_HOSTS_ONLY_',
22770Sstevel@tonic-gate`R<?> $=R		$@ RELAY
22780Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
22790Sstevel@tonic-gateR<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
22800Sstevel@tonic-gateR<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
22810Sstevel@tonic-gate`R<?> $* $=R			$@ RELAY
22820Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
22830Sstevel@tonic-gateR<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
22840Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
22850Sstevel@tonic-gateR<RELAY> $*		$@ RELAY
22860Sstevel@tonic-gateifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
22870Sstevel@tonic-gateR<$*> <$*>		$: $2',`dnl')
22880Sstevel@tonic-gatednl end of _PROMISCUOUS_RELAY_
22890Sstevel@tonic-gatedivert(0)
22900Sstevel@tonic-gateifdef(`_DELAY_CHECKS_',`dnl
22910Sstevel@tonic-gate# turn a canonical address in the form user<@domain>
22920Sstevel@tonic-gate# qualify unqual. addresses with $j
22930Sstevel@tonic-gatednl it might have been only user (without <@domain>)
22940Sstevel@tonic-gateSFullAddr
22950Sstevel@tonic-gateR$* <@ $+ . >		$1 <@ $2 >
22960Sstevel@tonic-gateR$* <@ $* >		$@ $1 <@ $2 >
22970Sstevel@tonic-gateR$+			$@ $1 <@ $j >
22980Sstevel@tonic-gate
22990Sstevel@tonic-gateSDelay_TLS_Clt
23000Sstevel@tonic-gate# authenticated?
23010Sstevel@tonic-gatednl code repeated here from Basic_check_mail
23020Sstevel@tonic-gatednl only called from check_rcpt in delay mode if checkrcpt returns $#
23030Sstevel@tonic-gateR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
23040Sstevel@tonic-gateR$* $| $#$+		$#$2
23050Sstevel@tonic-gatednl return result from checkrcpt
23060Sstevel@tonic-gateR$* $| $*		$# $1
23070Sstevel@tonic-gateR$*			$# $1
23080Sstevel@tonic-gate
23090Sstevel@tonic-gateSDelay_TLS_Clt2
23100Sstevel@tonic-gate# authenticated?
23110Sstevel@tonic-gatednl code repeated here from Basic_check_mail
23120Sstevel@tonic-gatednl only called from check_rcpt in delay mode if stopping due to Friend/Hater
23130Sstevel@tonic-gateR$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
23140Sstevel@tonic-gateR$* $| $#$+		$#$2
23150Sstevel@tonic-gatednl return result from friend/hater check
23160Sstevel@tonic-gateR$* $| $*		$@ $1
23170Sstevel@tonic-gateR$*			$@ $1
23180Sstevel@tonic-gate
23190Sstevel@tonic-gate# call all necessary rulesets
23200Sstevel@tonic-gateScheck_rcpt
23210Sstevel@tonic-gatednl this test should be in the Basic_check_rcpt ruleset
23220Sstevel@tonic-gatednl which is the correct DSN code?
23230Sstevel@tonic-gate# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
23240Sstevel@tonic-gate
23250Sstevel@tonic-gateR$+			$: $1 $| $>checkrcpt $1
23260Sstevel@tonic-gatednl now we can simply stop checks by returning "$# xyz" instead of just "ok"
23270Sstevel@tonic-gatednl on error (or discard) stop now
23280Sstevel@tonic-gateR$+ $| $#error $*	$#error $2
23290Sstevel@tonic-gateR$+ $| $#discard $*	$#discard $2
23300Sstevel@tonic-gatednl otherwise call tls_client; see above
23310Sstevel@tonic-gateR$+ $| $#$*		$@ $>"Delay_TLS_Clt" $2
23320Sstevel@tonic-gateR$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
23330Sstevel@tonic-gateifdef(`_SPAM_FH_',
23340Sstevel@tonic-gate`dnl lookup user@ and user@address
23350Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `',
23360Sstevel@tonic-gate`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
23370Sstevel@tonic-gate')')dnl
23380Sstevel@tonic-gatednl one of the next two rules is supposed to match
23390Sstevel@tonic-gatednl this code has been copied from BLACKLIST... etc
23400Sstevel@tonic-gatednl and simplified by omitting some < >.
23410Sstevel@tonic-gateR<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
23420Sstevel@tonic-gateR<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
23430Sstevel@tonic-gatednl R<?>		$@ something_is_very_wrong_here
23440Sstevel@tonic-gate# lookup the addresses only with Spam tag
23450Sstevel@tonic-gateR<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
23460Sstevel@tonic-gateR<@> $* $| $*		$: $2 $1		reverse result
23470Sstevel@tonic-gatednl', `dnl')
23480Sstevel@tonic-gateifdef(`_SPAM_FRIEND_',
23490Sstevel@tonic-gate`# is the recipient a spam friend?
23500Sstevel@tonic-gateifdef(`_SPAM_HATER_',
23510Sstevel@tonic-gate	`errprint(`*** ERROR: define either Hater or Friend -- not both.
23520Sstevel@tonic-gate')', `dnl')
23530Sstevel@tonic-gateR<FRIEND> $+		$@ $>"Delay_TLS_Clt2" SPAMFRIEND
23540Sstevel@tonic-gateR<$*> $+		$: $2',
23550Sstevel@tonic-gate`dnl')
23560Sstevel@tonic-gateifdef(`_SPAM_HATER_',
23570Sstevel@tonic-gate`# is the recipient no spam hater?
23580Sstevel@tonic-gateR<HATER> $+		$: $1			spam hater: continue checks
23590Sstevel@tonic-gateR<$*> $+		$@ $>"Delay_TLS_Clt2" NOSPAMHATER	everyone else: stop
23600Sstevel@tonic-gatednl',`dnl')
2361*3544Sjbeck
23620Sstevel@tonic-gatednl run further checks: check_mail
23630Sstevel@tonic-gatednl should we "clean up" $&f?
23640Sstevel@tonic-gateifdef(`_FFR_MAIL_MACRO',
23650Sstevel@tonic-gate`R$*			$: $1 $| $>checkmail $&{mail_from}',
23660Sstevel@tonic-gate`R$*			$: $1 $| $>checkmail <$&f>')
23670Sstevel@tonic-gatednl recipient (canonical format) $| result of checkmail
23680Sstevel@tonic-gateR$* $| $#$*		$#$2
23690Sstevel@tonic-gatednl run further checks: check_relay
23700Sstevel@tonic-gateR$* $| $*		$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
23710Sstevel@tonic-gateR$* $| $#$*		$#$2
23720Sstevel@tonic-gateR$* $| $*		$: $1
23730Sstevel@tonic-gate', `dnl')
23740Sstevel@tonic-gate
2375*3544Sjbeckifdef(`_BLOCK_BAD_HELO_', `dnl
2376*3544SjbeckR$*			$: $1 $| <$&{auth_authen}>	Get auth info
2377*3544Sjbeckdnl Bypass the test for users who have authenticated.
2378*3544SjbeckR$* $| <$+>		$: $1				skip if auth
2379*3544SjbeckR$* $| <$*>		$: $1 $| <$&{client_addr}> [$&s]	Get connection info
2380*3544Sjbeckdnl Bypass for local clients -- IP address starts with $=R
2381*3544SjbeckR$* $| <$=R $*> [$*]	$: $1				skip if local client
2382*3544Sjbeckdnl Bypass a "sendmail -bs" session, which use 0 for client ip address
2383*3544SjbeckR$* $| <0> [$*]		$: $1				skip if sendmail -bs
2384*3544Sjbeckdnl Reject our IP - assumes "[ip]" is in class $=w
2385*3544SjbeckR$* $| <$*> $=w		$#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2386*3544Sjbeckdnl Reject our hostname
2387*3544SjbeckR$* $| <$*> [$=w]	$#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2388*3544Sjbeckdnl Pass anything else with a "." in the domain parameter
2389*3544SjbeckR$* $| <$*> [$+.$+]	$: $1				qualified domain ok
2390*3544Sjbeckdnl Reject if there was no "." or only an initial or final "."
2391*3544SjbeckR$* $| <$*> [$*]	$#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2392*3544Sjbeckdnl Clean up the workspace
2393*3544SjbeckR$* $| $*		$: $1
2394*3544Sjbeck', `dnl')
2395*3544Sjbeck
23960Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
23970Sstevel@tonic-gate######################################################################
23980Sstevel@tonic-gate###  F: LookUpFull -- search for an entry in access database
23990Sstevel@tonic-gate###
24000Sstevel@tonic-gate###	lookup of full key (which should be an address) and
24010Sstevel@tonic-gate###	variations if +detail exists: +* and without +detail
24020Sstevel@tonic-gate###
24030Sstevel@tonic-gate###	Parameters:
24040Sstevel@tonic-gate###		<$1> -- key
24050Sstevel@tonic-gate###		<$2> -- default (what to return if not found in db)
24060Sstevel@tonic-gatednl			must not be empty
24070Sstevel@tonic-gate###		<$3> -- mark (must be <(!|+) single-token>)
24080Sstevel@tonic-gate###			! does lookup only with tag
24090Sstevel@tonic-gate###			+ does lookup with and without tag
24100Sstevel@tonic-gate###		<$4> -- passthru (additional data passed unchanged through)
24110Sstevel@tonic-gatednl returns:		<default> <passthru>
24120Sstevel@tonic-gatednl 			<result> <passthru>
24130Sstevel@tonic-gate######################################################################
24140Sstevel@tonic-gate
24150Sstevel@tonic-gateSF
24160Sstevel@tonic-gatednl workspace: <key> <def> <o tag> <thru>
24170Sstevel@tonic-gatednl full lookup
24180Sstevel@tonic-gatednl    2    3  4    5
24190Sstevel@tonic-gateR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
24200Sstevel@tonic-gatednl no match, try without tag
24210Sstevel@tonic-gatednl   1    2      3    4
24220Sstevel@tonic-gateR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
24230Sstevel@tonic-gatednl no match, +detail: try +*
24240Sstevel@tonic-gatednl   1    2    3    4    5  6    7
24250Sstevel@tonic-gateR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
24260Sstevel@tonic-gate			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
24270Sstevel@tonic-gatednl no match, +detail: try +* without tag
24280Sstevel@tonic-gatednl   1    2    3    4      5    6
24290Sstevel@tonic-gateR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
24300Sstevel@tonic-gate			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
24310Sstevel@tonic-gatednl no match, +detail: try without +detail
24320Sstevel@tonic-gatednl   1    2    3    4    5  6    7
24330Sstevel@tonic-gateR<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
24340Sstevel@tonic-gate			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
24350Sstevel@tonic-gatednl no match, +detail: try without +detail and without tag
24360Sstevel@tonic-gatednl   1    2    3    4      5    6
24370Sstevel@tonic-gateR<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
24380Sstevel@tonic-gate			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
24390Sstevel@tonic-gatednl no match, return <default> <passthru>
24400Sstevel@tonic-gatednl   1    2    3  4    5
24410Sstevel@tonic-gateR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
24420Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
24430Sstevel@tonic-gatednl            2    3  4    5
24440Sstevel@tonic-gateR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
24450Sstevel@tonic-gatednl match, return <match> <passthru>
24460Sstevel@tonic-gatednl    2    3  4    5
24470Sstevel@tonic-gateR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
24480Sstevel@tonic-gate
24490Sstevel@tonic-gate######################################################################
24500Sstevel@tonic-gate###  E: LookUpExact -- search for an entry in access database
24510Sstevel@tonic-gate###
24520Sstevel@tonic-gate###	Parameters:
24530Sstevel@tonic-gate###		<$1> -- key
24540Sstevel@tonic-gate###		<$2> -- default (what to return if not found in db)
24550Sstevel@tonic-gatednl			must not be empty
24560Sstevel@tonic-gate###		<$3> -- mark (must be <(!|+) single-token>)
24570Sstevel@tonic-gate###			! does lookup only with tag
24580Sstevel@tonic-gate###			+ does lookup with and without tag
24590Sstevel@tonic-gate###		<$4> -- passthru (additional data passed unchanged through)
24600Sstevel@tonic-gatednl returns:		<default> <passthru>
24610Sstevel@tonic-gatednl 			<result> <passthru>
24620Sstevel@tonic-gate######################################################################
24630Sstevel@tonic-gate
24640Sstevel@tonic-gateSE
24650Sstevel@tonic-gatednl    2    3  4    5
24660Sstevel@tonic-gateR<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
24670Sstevel@tonic-gatednl no match, try without tag
24680Sstevel@tonic-gatednl   1    2      3    4
24690Sstevel@tonic-gateR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
24700Sstevel@tonic-gatednl no match, return default passthru
24710Sstevel@tonic-gatednl   1    2    3  4    5
24720Sstevel@tonic-gateR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
24730Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
24740Sstevel@tonic-gatednl            2    3  4    5
24750Sstevel@tonic-gateR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
24760Sstevel@tonic-gatednl match, return <match> <passthru>
24770Sstevel@tonic-gatednl    2    3  4    5
24780Sstevel@tonic-gateR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
24790Sstevel@tonic-gate
24800Sstevel@tonic-gate######################################################################
24810Sstevel@tonic-gate###  U: LookUpUser -- search for an entry in access database
24820Sstevel@tonic-gate###
24830Sstevel@tonic-gate###	lookup of key (which should be a local part) and
24840Sstevel@tonic-gate###	variations if +detail exists: +* and without +detail
24850Sstevel@tonic-gate###
24860Sstevel@tonic-gate###	Parameters:
24870Sstevel@tonic-gate###		<$1> -- key (user@)
24880Sstevel@tonic-gate###		<$2> -- default (what to return if not found in db)
24890Sstevel@tonic-gatednl			must not be empty
24900Sstevel@tonic-gate###		<$3> -- mark (must be <(!|+) single-token>)
24910Sstevel@tonic-gate###			! does lookup only with tag
24920Sstevel@tonic-gate###			+ does lookup with and without tag
24930Sstevel@tonic-gate###		<$4> -- passthru (additional data passed unchanged through)
24940Sstevel@tonic-gatednl returns:		<default> <passthru>
24950Sstevel@tonic-gatednl 			<result> <passthru>
24960Sstevel@tonic-gate######################################################################
24970Sstevel@tonic-gate
24980Sstevel@tonic-gateSU
24990Sstevel@tonic-gatednl user lookups are always with trailing @
25000Sstevel@tonic-gatednl    2    3  4    5
25010Sstevel@tonic-gateR<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
25020Sstevel@tonic-gatednl no match, try without tag
25030Sstevel@tonic-gatednl   1    2      3    4
25040Sstevel@tonic-gateR<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
25050Sstevel@tonic-gatednl do not remove the @ from the lookup:
25060Sstevel@tonic-gatednl it is part of the +detail@ which is omitted for the lookup
25070Sstevel@tonic-gatednl no match, +detail: try +*
25080Sstevel@tonic-gatednl   1    2      3    4  5    6
25090Sstevel@tonic-gateR<?> <$+ + $* @> <$*> <$- $-> <$*>
25100Sstevel@tonic-gate			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
25110Sstevel@tonic-gatednl no match, +detail: try +* without tag
25120Sstevel@tonic-gatednl   1    2      3      4    5
25130Sstevel@tonic-gateR<?> <$+ + $* @> <$*> <+ $-> <$*>
25140Sstevel@tonic-gate			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
25150Sstevel@tonic-gatednl no match, +detail: try without +detail
25160Sstevel@tonic-gatednl   1    2      3    4  5    6
25170Sstevel@tonic-gateR<?> <$+ + $* @> <$*> <$- $-> <$*>
25180Sstevel@tonic-gate			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
25190Sstevel@tonic-gatednl no match, +detail: try without +detail and without tag
25200Sstevel@tonic-gatednl   1    2      3      4    5
25210Sstevel@tonic-gateR<?> <$+ + $* @> <$*> <+ $-> <$*>
25220Sstevel@tonic-gate			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
25230Sstevel@tonic-gatednl no match, return <default> <passthru>
25240Sstevel@tonic-gatednl   1    2    3  4    5
25250Sstevel@tonic-gateR<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
25260Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
25270Sstevel@tonic-gatednl            2    3  4    5
25280Sstevel@tonic-gateR<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
25290Sstevel@tonic-gatednl match, return <match> <passthru>
25300Sstevel@tonic-gatednl    2    3  4    5
25310Sstevel@tonic-gateR<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
25320Sstevel@tonic-gate
25330Sstevel@tonic-gate######################################################################
25340Sstevel@tonic-gate###  SearchList: search a list of items in the access map
25350Sstevel@tonic-gate###	Parameters:
25360Sstevel@tonic-gate###		<exact tag> $| <mark:address> <mark:address> ... <>
25370Sstevel@tonic-gatednl	maybe we should have a @ (again) in front of the mark to
25380Sstevel@tonic-gatednl	avoid errorneous matches (with error messages?)
25390Sstevel@tonic-gatednl	if we can make sure that tag is always a single token
25400Sstevel@tonic-gatednl	then we can omit the delimiter $|, otherwise we need it
25410Sstevel@tonic-gatednl	to avoid errorneous matchs (first rule: D: if there
25420Sstevel@tonic-gatednl	is that mark somewhere in the list, it will be taken).
25430Sstevel@tonic-gatednl	moreover, we can do some tricks to enforce lookup with
25440Sstevel@tonic-gatednl	the tag only, e.g.:
25450Sstevel@tonic-gate###	where "exact" is either "+" or "!":
25460Sstevel@tonic-gate###	<+ TAG>	lookup with and w/o tag
25470Sstevel@tonic-gate###	<! TAG>	lookup with tag
25480Sstevel@tonic-gatednl	Warning: + and ! should be in OperatorChars (otherwise there must be
25490Sstevel@tonic-gatednl		a blank between them and the tag.
25500Sstevel@tonic-gate###	possible values for "mark" are:
25510Sstevel@tonic-gate###		D: recursive host lookup (LookUpDomain)
25520Sstevel@tonic-gatednl		A: recursive address lookup (LookUpAddress) [not yet required]
25530Sstevel@tonic-gate###		E: exact lookup, no modifications
25540Sstevel@tonic-gate###		F: full lookup, try user+ext@domain and user@domain
25550Sstevel@tonic-gate###		U: user lookup, try user+ext and user (input must have trailing @)
25560Sstevel@tonic-gate###	return: <RHS of lookup> or <?> (not found)
25570Sstevel@tonic-gate######################################################################
25580Sstevel@tonic-gate
25590Sstevel@tonic-gate# class with valid marks for SearchList
25600Sstevel@tonic-gatednl if A is activated: add it
25610Sstevel@tonic-gateC{Src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
25620Sstevel@tonic-gateSSearchList
25630Sstevel@tonic-gate# just call the ruleset with the name of the tag... nice trick...
25640Sstevel@tonic-gatednl       2       3    4
25650Sstevel@tonic-gateR<$+> $| <$={Src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
25660Sstevel@tonic-gatednl workspace: <o tag> $| <rest> $| <result of lookup> <>
25670Sstevel@tonic-gatednl no match and nothing left: return
25680Sstevel@tonic-gateR<$+> $| <> $| <?> <>		$@ <?>
25690Sstevel@tonic-gatednl no match but something left: continue
25700Sstevel@tonic-gateR<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
25710Sstevel@tonic-gatednl match: return
25720Sstevel@tonic-gateR<$+> $| <$*> $| <$+> <>	$@ <$3>
25730Sstevel@tonic-gatednl return result from recursive invocation
25740Sstevel@tonic-gateR<$+> $| <$+>			$@ <$2>
25750Sstevel@tonic-gatednl endif _ACCESS_TABLE_
25760Sstevel@tonic-gatedivert(0)
25770Sstevel@tonic-gate
25780Sstevel@tonic-gate######################################################################
25790Sstevel@tonic-gate###  trust_auth: is user trusted to authenticate as someone else?
25800Sstevel@tonic-gate###
25810Sstevel@tonic-gate###	Parameters:
25820Sstevel@tonic-gate###		$1: AUTH= parameter from MAIL command
25830Sstevel@tonic-gate######################################################################
25840Sstevel@tonic-gate
25850Sstevel@tonic-gatednl empty ruleset definition so it can be called
25860Sstevel@tonic-gateSLocal_trust_auth
25870Sstevel@tonic-gateStrust_auth
25880Sstevel@tonic-gateR$*			$: $&{auth_type} $| $1
25890Sstevel@tonic-gate# required by RFC 2554 section 4.
25900Sstevel@tonic-gateR$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
25910Sstevel@tonic-gatednl seems to be useful...
25920Sstevel@tonic-gateR$* $| $&{auth_authen}		$@ identical
25930Sstevel@tonic-gateR$* $| <$&{auth_authen}>	$@ identical
25940Sstevel@tonic-gatednl call user supplied code
25950Sstevel@tonic-gateR$* $| $*		$: $1 $| $>"Local_trust_auth" $2
25960Sstevel@tonic-gateR$* $| $#$*		$#$2
25970Sstevel@tonic-gatednl default: error
25980Sstevel@tonic-gateR$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
25990Sstevel@tonic-gate
26000Sstevel@tonic-gate######################################################################
26010Sstevel@tonic-gate###  Relay_Auth: allow relaying based on authentication?
26020Sstevel@tonic-gate###
26030Sstevel@tonic-gate###	Parameters:
26040Sstevel@tonic-gate###		$1: ${auth_type}
26050Sstevel@tonic-gate######################################################################
26060Sstevel@tonic-gateSLocal_Relay_Auth
26070Sstevel@tonic-gate
26080Sstevel@tonic-gate######################################################################
26090Sstevel@tonic-gate###  srv_features: which features to offer to a client?
26100Sstevel@tonic-gate###	(done in server)
26110Sstevel@tonic-gate######################################################################
26120Sstevel@tonic-gateSsrv_features
26130Sstevel@tonic-gateifdef(`_LOCAL_SRV_FEATURES_', `dnl
26140Sstevel@tonic-gateR$*			$: $1 $| $>"Local_srv_features" $1
26150Sstevel@tonic-gateR$* $| $#$*		$#$2
26160Sstevel@tonic-gateR$* $| $*		$: $1', `dnl')
26170Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
26180Sstevel@tonic-gateR$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
26190Sstevel@tonic-gateR<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
26200Sstevel@tonic-gateR<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
26210Sstevel@tonic-gateR<?>$*		$@ OK
26220Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
26230Sstevel@tonic-gateR<$* _ATMPF_>$*	$#temp', `dnl')
26240Sstevel@tonic-gateR<$+>$*		$# $1')
26250Sstevel@tonic-gate
26260Sstevel@tonic-gate######################################################################
26270Sstevel@tonic-gate###  try_tls: try to use STARTTLS?
26280Sstevel@tonic-gate###	(done in client)
26290Sstevel@tonic-gate######################################################################
26300Sstevel@tonic-gateStry_tls
26310Sstevel@tonic-gateifdef(`_LOCAL_TRY_TLS_', `dnl
26320Sstevel@tonic-gateR$*			$: $1 $| $>"Local_try_tls" $1
26330Sstevel@tonic-gateR$* $| $#$*		$#$2
26340Sstevel@tonic-gateR$* $| $*		$: $1', `dnl')
26350Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
26360Sstevel@tonic-gateR$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
26370Sstevel@tonic-gateR<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
26380Sstevel@tonic-gateR<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
26390Sstevel@tonic-gateR<?>$*		$@ OK
26400Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
26410Sstevel@tonic-gateR<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
26420Sstevel@tonic-gateR<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"')
26430Sstevel@tonic-gate
26440Sstevel@tonic-gate######################################################################
26450Sstevel@tonic-gate###  tls_rcpt: is connection with server "good" enough?
26460Sstevel@tonic-gate###	(done in client, per recipient)
26470Sstevel@tonic-gatednl called from deliver() before RCPT command
26480Sstevel@tonic-gate###
26490Sstevel@tonic-gate###	Parameters:
26500Sstevel@tonic-gate###		$1: recipient
26510Sstevel@tonic-gate######################################################################
26520Sstevel@tonic-gateStls_rcpt
26530Sstevel@tonic-gateifdef(`_LOCAL_TLS_RCPT_', `dnl
26540Sstevel@tonic-gateR$*			$: $1 $| $>"Local_tls_rcpt" $1
26550Sstevel@tonic-gateR$* $| $#$*		$#$2
26560Sstevel@tonic-gateR$* $| $*		$: $1', `dnl')
26570Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
26580Sstevel@tonic-gatednl store name of other side
26590Sstevel@tonic-gateR$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
26600Sstevel@tonic-gatednl canonify recipient address
26610Sstevel@tonic-gateR$+			$: <?> $>CanonAddr $1
26620Sstevel@tonic-gatednl strip trailing dots
26630Sstevel@tonic-gateR<?> $+ < @ $+ . >	<?> $1 <@ $2 >
26640Sstevel@tonic-gatednl full address?
26650Sstevel@tonic-gateR<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
26660Sstevel@tonic-gatednl only localpart?
26670Sstevel@tonic-gateR<?> $+			$: $1 $| <U:$1@> <E:>
26680Sstevel@tonic-gatednl look it up
26690Sstevel@tonic-gatednl also look up a default value via E:
26700Sstevel@tonic-gateR$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
26710Sstevel@tonic-gatednl found nothing: stop here
26720Sstevel@tonic-gateR$* $| <?>	$@ OK
26730Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
26740Sstevel@tonic-gateR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
26750Sstevel@tonic-gatednl use the generic routine (for now)
26760Sstevel@tonic-gateR$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
26770Sstevel@tonic-gate
26780Sstevel@tonic-gate######################################################################
26790Sstevel@tonic-gate###  tls_client: is connection with client "good" enough?
26800Sstevel@tonic-gate###	(done in server)
26810Sstevel@tonic-gate###
26820Sstevel@tonic-gate###	Parameters:
26830Sstevel@tonic-gate###		${verify} $| (MAIL|STARTTLS)
26840Sstevel@tonic-gate######################################################################
26850Sstevel@tonic-gatednl MAIL: called from check_mail
26860Sstevel@tonic-gatednl STARTTLS: called from smtp() after STARTTLS has been accepted
26870Sstevel@tonic-gateStls_client
26880Sstevel@tonic-gateifdef(`_LOCAL_TLS_CLIENT_', `dnl
26890Sstevel@tonic-gateR$*			$: $1 $| $>"Local_tls_client" $1
26900Sstevel@tonic-gateR$* $| $#$*		$#$2
26910Sstevel@tonic-gateR$* $| $*		$: $1', `dnl')
26920Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
26930Sstevel@tonic-gatednl store name of other side
26940Sstevel@tonic-gateR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
26950Sstevel@tonic-gatednl ignore second arg for now
26960Sstevel@tonic-gatednl maybe use it to distinguish permanent/temporary error?
26970Sstevel@tonic-gatednl if MAIL: permanent (STARTTLS has not been offered)
26980Sstevel@tonic-gatednl if STARTTLS: temporary (offered but maybe failed)
26990Sstevel@tonic-gateR$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
27000Sstevel@tonic-gateR$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
27010Sstevel@tonic-gatednl do a default lookup: just TLS_CLT_TAG
27020Sstevel@tonic-gateR$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
27030Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
27040Sstevel@tonic-gateR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
27050Sstevel@tonic-gateR$*		$@ $>"TLS_connection" $1', `dnl
27060Sstevel@tonic-gateR$* $| $*	$@ $>"TLS_connection" $1')
27070Sstevel@tonic-gate
27080Sstevel@tonic-gate######################################################################
27090Sstevel@tonic-gate###  tls_server: is connection with server "good" enough?
27100Sstevel@tonic-gate###	(done in client)
27110Sstevel@tonic-gate###
27120Sstevel@tonic-gate###	Parameter:
27130Sstevel@tonic-gate###		${verify}
27140Sstevel@tonic-gate######################################################################
27150Sstevel@tonic-gatednl i.e. has the server been authenticated and is encryption active?
27160Sstevel@tonic-gatednl called from deliver() after STARTTLS command
27170Sstevel@tonic-gateStls_server
27180Sstevel@tonic-gateifdef(`_LOCAL_TLS_SERVER_', `dnl
27190Sstevel@tonic-gateR$*			$: $1 $| $>"Local_tls_server" $1
27200Sstevel@tonic-gateR$* $| $#$*		$#$2
27210Sstevel@tonic-gateR$* $| $*		$: $1', `dnl')
27220Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
27230Sstevel@tonic-gatednl store name of other side
27240Sstevel@tonic-gateR$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
27250Sstevel@tonic-gateR$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
27260Sstevel@tonic-gateR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
27270Sstevel@tonic-gatednl do a default lookup: just TLS_SRV_TAG
27280Sstevel@tonic-gateR$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
27290Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
27300Sstevel@tonic-gateR$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
27310Sstevel@tonic-gateR$*		$@ $>"TLS_connection" $1', `dnl
27320Sstevel@tonic-gateR$*		$@ $>"TLS_connection" $1')
27330Sstevel@tonic-gate
27340Sstevel@tonic-gate######################################################################
27350Sstevel@tonic-gate###  TLS_connection: is TLS connection "good" enough?
27360Sstevel@tonic-gate###
27370Sstevel@tonic-gate###	Parameters:
27380Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
27390Sstevel@tonic-gate###		${verify} $| <Requirement> [<>]', `dnl
27400Sstevel@tonic-gate###		${verify}')
27410Sstevel@tonic-gate###		Requirement: RHS from access map, may be ? for none.
27420Sstevel@tonic-gatednl	syntax for Requirement:
27430Sstevel@tonic-gatednl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
27440Sstevel@tonic-gatednl	extensions: could be a list of further requirements
27450Sstevel@tonic-gatednl		for now: CN:string	{cn_subject} == string
27460Sstevel@tonic-gate######################################################################
27470Sstevel@tonic-gateSTLS_connection
27480Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
27490Sstevel@tonic-gatednl deal with TLS handshake failures: abort
27500Sstevel@tonic-gateRSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
27510Sstevel@tonic-gatedivert(-1)')
27520Sstevel@tonic-gatednl common ruleset for tls_{client|server}
27530Sstevel@tonic-gatednl input: ${verify} $| <ResultOfLookup> [<>]
27540Sstevel@tonic-gatednl remove optional <>
27550Sstevel@tonic-gateR$* $| <$*>$*			$: $1 $| <$2>
27560Sstevel@tonic-gatednl workspace: ${verify} $| <ResultOfLookup>
27570Sstevel@tonic-gate# create the appropriate error codes
27580Sstevel@tonic-gatednl permanent or temporary error?
27590Sstevel@tonic-gateR$* $| <PERM + $={Tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
27600Sstevel@tonic-gateR$* $| <TEMP + $={Tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
27610Sstevel@tonic-gatednl default case depends on TLS_PERM_ERR
27620Sstevel@tonic-gateR$* $| <$={Tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
27630Sstevel@tonic-gatednl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
27640Sstevel@tonic-gate# deal with TLS handshake failures: abort
27650Sstevel@tonic-gateRSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
27660Sstevel@tonic-gatednl no <reply:dns> i.e. not requirements in the access map
27670Sstevel@tonic-gatednl use default error
27680Sstevel@tonic-gateRSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
2769616Sjbeck# deal with TLS protocol errors: abort
2770616SjbeckRPROTOCOL $| <$-:$+> $* 	$#error $@ $2 $: $1 " STARTTLS failed."
2771616Sjbeckdnl no <reply:dns> i.e. not requirements in the access map
2772616Sjbeckdnl use default error
2773616SjbeckRPROTOCOL $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') STARTTLS failed."
27740Sstevel@tonic-gateR$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
27750Sstevel@tonic-gatednl separate optional requirements
27760Sstevel@tonic-gateR$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
27770Sstevel@tonic-gateR$* $| <$*> <$={Tls}:$->$*	$: <$2> <$3:$4> <> $1
27780Sstevel@tonic-gatednl separate optional requirements
27790Sstevel@tonic-gateR$* $| <$*> <$={Tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
27800Sstevel@tonic-gatednl some other value in access map: accept
27810Sstevel@tonic-gatednl this also allows to override the default case (if used)
27820Sstevel@tonic-gateR$* $| $*			$@ OK
27830Sstevel@tonic-gate# authentication required: give appropriate error
27840Sstevel@tonic-gate# other side did authenticate (via STARTTLS)
27850Sstevel@tonic-gatednl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
27860Sstevel@tonic-gatednl only verification required and it succeeded
27870Sstevel@tonic-gateR<$*><VERIFY> <> OK		$@ OK
27880Sstevel@tonic-gatednl verification required and it succeeded but extensions are given
27890Sstevel@tonic-gatednl change it to <SMTP:ESC> <REQ:0>  <extensions>
27900Sstevel@tonic-gateR<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
27910Sstevel@tonic-gatednl verification required + some level of encryption
27920Sstevel@tonic-gateR<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
27930Sstevel@tonic-gatednl just some level of encryption required
27940Sstevel@tonic-gateR<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
27950Sstevel@tonic-gatednl workspace:
27960Sstevel@tonic-gatednl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
27970Sstevel@tonic-gatednl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
27980Sstevel@tonic-gatednl verification required but ${verify} is not set (case 1.)
27990Sstevel@tonic-gateR<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
28000Sstevel@tonic-gateR<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
28010Sstevel@tonic-gateR<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
28020Sstevel@tonic-gateR<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
28030Sstevel@tonic-gateR<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
28040Sstevel@tonic-gatednl some other value for ${verify}
28050Sstevel@tonic-gateR<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
28060Sstevel@tonic-gatednl some level of encryption required: get the maximum level (case 2.)
28070Sstevel@tonic-gateR<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
28080Sstevel@tonic-gatednl compare required bits with actual bits
28090Sstevel@tonic-gateR<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
28100Sstevel@tonic-gateR<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
28110Sstevel@tonic-gatednl strength requirements fulfilled
28120Sstevel@tonic-gatednl TLS Additional Requirements Separator
28130Sstevel@tonic-gatednl this should be something which does not appear in the extensions itself
28140Sstevel@tonic-gatednl @ could be part of a CN, DN, etc...
28150Sstevel@tonic-gatednl use < > ? those are encoded in CN, DN, ...
28160Sstevel@tonic-gatedefine(`_TLS_ARS_', `++')dnl
28170Sstevel@tonic-gatednl workspace:
28180Sstevel@tonic-gatednl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
28190Sstevel@tonic-gateR<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
28200Sstevel@tonic-gatednl workspace: <SMTP:ESC _TLS_ARS_ extensions>
28210Sstevel@tonic-gatednl continue: check  extensions
28220Sstevel@tonic-gateR<$-:$+ _TLS_ARS_ >			$@ OK
28230Sstevel@tonic-gatednl split extensions into own list
28240Sstevel@tonic-gateR<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
28250Sstevel@tonic-gateR<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
28260Sstevel@tonic-gateR<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
28270Sstevel@tonic-gate
28280Sstevel@tonic-gate######################################################################
28290Sstevel@tonic-gate###  TLS_req: check additional TLS requirements
28300Sstevel@tonic-gate###
28310Sstevel@tonic-gate###	Parameters: [<list> <of> <req>] $| <$-:$+>
28320Sstevel@tonic-gate###		$-: SMTP reply code
28330Sstevel@tonic-gate###		$+: Enhanced Status Code
28340Sstevel@tonic-gatednl  further requirements for this ruleset:
28350Sstevel@tonic-gatednl	name of "other side" is stored is {TLS_name} (client/server_name)
28360Sstevel@tonic-gatednl
28370Sstevel@tonic-gatednl	currently only CN[:common_name] is implemented
28380Sstevel@tonic-gatednl	right now this is only a logical AND
28390Sstevel@tonic-gatednl	i.e. all requirements must be true
28400Sstevel@tonic-gatednl	how about an OR? CN must be X or CN must be Y or ..
28410Sstevel@tonic-gatednl	use a macro to compute this as a trivial sequential
28420Sstevel@tonic-gatednl	operations (no precedences etc)?
28430Sstevel@tonic-gate######################################################################
28440Sstevel@tonic-gateSTLS_req
28450Sstevel@tonic-gatednl no additional requirements: ok
28460Sstevel@tonic-gateR $| $+		$@ OK
28470Sstevel@tonic-gatednl require CN: but no CN specified: use name of other side
28480Sstevel@tonic-gateR<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
28490Sstevel@tonic-gatednl match, check rest
28500Sstevel@tonic-gateR<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
28510Sstevel@tonic-gatednl CN does not match
28520Sstevel@tonic-gatednl  1   2      3  4
28530Sstevel@tonic-gateR<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
28540Sstevel@tonic-gatednl cert subject
28550Sstevel@tonic-gateR<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
28560Sstevel@tonic-gatednl CS does not match
28570Sstevel@tonic-gatednl  1   2      3  4
28580Sstevel@tonic-gateR<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1
28590Sstevel@tonic-gatednl match, check rest
28600Sstevel@tonic-gateR<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
28610Sstevel@tonic-gatednl CI does not match
28620Sstevel@tonic-gatednl  1   2      3  4
28630Sstevel@tonic-gateR<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1
28640Sstevel@tonic-gatednl return from recursive call
28650Sstevel@tonic-gateROK			$@ OK
28660Sstevel@tonic-gate
28670Sstevel@tonic-gate######################################################################
28680Sstevel@tonic-gate###  max: return the maximum of two values separated by :
28690Sstevel@tonic-gate###
28700Sstevel@tonic-gate###	Parameters: [$-]:[$-]
28710Sstevel@tonic-gate######################################################################
28720Sstevel@tonic-gateSmax
28730Sstevel@tonic-gateR:		$: 0
28740Sstevel@tonic-gateR:$-		$: $1
28750Sstevel@tonic-gateR$-:		$: $1
28760Sstevel@tonic-gateR$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
28770Sstevel@tonic-gateRTRUE:$-:$-	$: $2
28780Sstevel@tonic-gateR$-:$-:$-	$: $2
28790Sstevel@tonic-gatednl endif _ACCESS_TABLE_
28800Sstevel@tonic-gatedivert(0)
28810Sstevel@tonic-gate
28820Sstevel@tonic-gate######################################################################
28830Sstevel@tonic-gate###  RelayTLS: allow relaying based on TLS authentication
28840Sstevel@tonic-gate###
28850Sstevel@tonic-gate###	Parameters:
28860Sstevel@tonic-gate###		none
28870Sstevel@tonic-gate######################################################################
28880Sstevel@tonic-gateSRelayTLS
28890Sstevel@tonic-gate# authenticated?
28900Sstevel@tonic-gatednl we do not allow relaying for anyone who can present a cert
28910Sstevel@tonic-gatednl signed by a "trusted" CA. For example, even if we put verisigns
28920Sstevel@tonic-gatednl CA in CertPath so we can authenticate users, we do not allow
28930Sstevel@tonic-gatednl them to abuse our server (they might be easier to get hold of,
28940Sstevel@tonic-gatednl but anyway).
28950Sstevel@tonic-gatednl so here is the trick: if the verification succeeded
28960Sstevel@tonic-gatednl we look up the cert issuer in the access map
28970Sstevel@tonic-gatednl (maybe after extracting a part with a regular expression)
28980Sstevel@tonic-gatednl if this returns RELAY we relay without further questions
28990Sstevel@tonic-gatednl if it returns SUBJECT we perform a similar check on the
29000Sstevel@tonic-gatednl cert subject.
29010Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
29020Sstevel@tonic-gateR$*			$: <?> $&{verify}
29030Sstevel@tonic-gateR<?> OK			$: OK		authenticated: continue
29040Sstevel@tonic-gateR<?> $*			$@ NO		not authenticated
29050Sstevel@tonic-gateifdef(`_CERT_REGEX_ISSUER_', `dnl
29060Sstevel@tonic-gateR$*			$: $(CERTIssuer $&{cert_issuer} $)',
29070Sstevel@tonic-gate`R$*			$: $&{cert_issuer}')
29080Sstevel@tonic-gateR$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
29090Sstevel@tonic-gatednl use $# to stop further checks (delay_check)
29100Sstevel@tonic-gateRRELAY			$# RELAY
29110Sstevel@tonic-gateifdef(`_CERT_REGEX_SUBJECT_', `dnl
29120Sstevel@tonic-gateRSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
29130Sstevel@tonic-gate`RSUBJECT		$: <@> $&{cert_subject}')
29140Sstevel@tonic-gateR<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
29150Sstevel@tonic-gateR<@> RELAY		$# RELAY
29160Sstevel@tonic-gateR$*			$: NO', `dnl')
29170Sstevel@tonic-gate
29180Sstevel@tonic-gate######################################################################
29190Sstevel@tonic-gate###  authinfo: lookup authinfo in the access map
29200Sstevel@tonic-gate###
29210Sstevel@tonic-gate###	Parameters:
29220Sstevel@tonic-gate###		$1: {server_name}
29230Sstevel@tonic-gate###		$2: {server_addr}
29240Sstevel@tonic-gatednl	both are currently ignored
29250Sstevel@tonic-gatednl if it should be done via another map, we either need to restrict
29260Sstevel@tonic-gatednl functionality (it calls D and A) or copy those rulesets (or add another
29270Sstevel@tonic-gatednl parameter which I want to avoid, it's quite complex already)
29280Sstevel@tonic-gate######################################################################
29290Sstevel@tonic-gatednl omit this ruleset if neither is defined?
29300Sstevel@tonic-gatednl it causes DefaultAuthInfo to be ignored
29310Sstevel@tonic-gatednl (which may be considered a good thing).
29320Sstevel@tonic-gateSauthinfo
29330Sstevel@tonic-gateifdef(`_AUTHINFO_TABLE_', `dnl
29340Sstevel@tonic-gateR$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
29350Sstevel@tonic-gateR<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
29360Sstevel@tonic-gateR<?>		$: <$(authinfo AuthInfo: $: ? $)>
29370Sstevel@tonic-gateR<?>		$@ no				no authinfo available
29380Sstevel@tonic-gateR<$*>		$# $1
29390Sstevel@tonic-gatednl', `dnl
29400Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
29410Sstevel@tonic-gateR$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
29420Sstevel@tonic-gateR$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
29430Sstevel@tonic-gateR$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
29440Sstevel@tonic-gateR$* $| <?>$*	$@ no				no authinfo available
29450Sstevel@tonic-gateR$* $| <$*> <>	$# $2
29460Sstevel@tonic-gatednl', `dnl')')
29470Sstevel@tonic-gate
29480Sstevel@tonic-gateifdef(`_RATE_CONTROL_',`dnl
29490Sstevel@tonic-gate######################################################################
29500Sstevel@tonic-gate###  RateControl:
29510Sstevel@tonic-gate###	Parameters:	ignored
29520Sstevel@tonic-gate###	return: $#error or OK
29530Sstevel@tonic-gate######################################################################
29540Sstevel@tonic-gateSRateControl
29550Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
29560Sstevel@tonic-gateR$*		$: <A:$&{client_addr}> <E:>
29570Sstevel@tonic-gatednl also look up a default value via E:
29580Sstevel@tonic-gateR$+		$: $>SearchList <! ClientRate> $| $1 <>
29590Sstevel@tonic-gatednl found nothing: stop here
29600Sstevel@tonic-gateR<?>		$@ OK
29610Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
29620Sstevel@tonic-gateR<$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
29630Sstevel@tonic-gatednl use the generic routine (for now)
29640Sstevel@tonic-gateR<0>		$@ OK		no limit
29650Sstevel@tonic-gateR<$+>		$: <$1> $| $(arith l $@ $&{client_rate} $@ $1 $)
29660Sstevel@tonic-gatednl log this? Connection rate $&{client_rate} exceeds limit $1.
29670Sstevel@tonic-gateR<$+> $| FALSE	$#error $@ 4.3.2 $: _RATE_CONTROL_REPLY Connection rate limit exceeded.
29680Sstevel@tonic-gate')')
29690Sstevel@tonic-gate
29700Sstevel@tonic-gateifdef(`_CONN_CONTROL_',`dnl
29710Sstevel@tonic-gate######################################################################
29720Sstevel@tonic-gate###  ConnControl:
29730Sstevel@tonic-gate###	Parameters:	ignored
29740Sstevel@tonic-gate###	return: $#error or OK
29750Sstevel@tonic-gate######################################################################
29760Sstevel@tonic-gateSConnControl
29770Sstevel@tonic-gateifdef(`_ACCESS_TABLE_', `dnl
29780Sstevel@tonic-gateR$*		$: <A:$&{client_addr}> <E:>
29790Sstevel@tonic-gatednl also look up a default value via E:
29800Sstevel@tonic-gateR$+		$: $>SearchList <! ClientConn> $| $1 <>
29810Sstevel@tonic-gatednl found nothing: stop here
29820Sstevel@tonic-gateR<?>		$@ OK
29830Sstevel@tonic-gateifdef(`_ATMPF_', `dnl tempfail?
29840Sstevel@tonic-gateR<$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
29850Sstevel@tonic-gatednl use the generic routine (for now)
29860Sstevel@tonic-gateR<0>		$@ OK		no limit
29870Sstevel@tonic-gateR<$+>		$: <$1> $| $(arith l $@ $&{client_connections} $@ $1 $)
29880Sstevel@tonic-gatednl log this: Open connections $&{client_connections} exceeds limit $1.
29890Sstevel@tonic-gateR<$+> $| FALSE	$#error $@ 4.3.2 $: _CONN_CONTROL_REPLY Too many open connections.
29900Sstevel@tonic-gate')')
29910Sstevel@tonic-gate
29920Sstevel@tonic-gateundivert(9)dnl LOCAL_RULESETS
29930Sstevel@tonic-gate#
29940Sstevel@tonic-gate######################################################################
29950Sstevel@tonic-gate######################################################################
29960Sstevel@tonic-gate#####
29970Sstevel@tonic-gate`#####			MAIL FILTER DEFINITIONS'
29980Sstevel@tonic-gate#####
29990Sstevel@tonic-gate######################################################################
30000Sstevel@tonic-gate######################################################################
30010Sstevel@tonic-gate_MAIL_FILTERS_
30020Sstevel@tonic-gate#
30030Sstevel@tonic-gate######################################################################
30040Sstevel@tonic-gate######################################################################
30050Sstevel@tonic-gate#####
30060Sstevel@tonic-gate`#####			MAILER DEFINITIONS'
30070Sstevel@tonic-gate#####
30080Sstevel@tonic-gate######################################################################
30090Sstevel@tonic-gate######################################################################
30100Sstevel@tonic-gateundivert(7)dnl MAILER_DEFINITIONS
30110Sstevel@tonic-gate
3012