proto.m4 revision 66494
1divert(-1)
2#
3# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
4#	All rights reserved.
5# Copyright (c) 1983, 1995 Eric P. Allman.  All rights reserved.
6# Copyright (c) 1988, 1993
7#	The Regents of the University of California.  All rights reserved.
8#
9# By using this file, you agree to the terms and conditions set
10# forth in the LICENSE file which can be found at the top level of
11# the sendmail distribution.
12#
13#
14divert(0)
15
16VERSIONID(`$Id: proto.m4,v 8.446.2.5.2.29 2000/09/15 04:45:14 gshapiro Exp $')
17
18MAILER(local)dnl
19
20# level CF_LEVEL config file format
21V`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley')
22divert(-1)
23
24# do some sanity checking
25ifdef(`__OSTYPE__',,
26	`errprint(`*** ERROR: No system type defined (use OSTYPE macro)
27')')
28
29# pick our default mailers
30ifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')')
31ifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')')
32ifdef(`confRELAY_MAILER',,
33	`define(`confRELAY_MAILER',
34		`ifdef(`_MAILER_smtp_', `relay',
35			`ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')')
36ifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')')
37define(`_SMTP_', `confSMTP_MAILER')dnl		for readability only
38define(`_LOCAL_', `confLOCAL_MAILER')dnl	for readability only
39define(`_RELAY_', `confRELAY_MAILER')dnl	for readability only
40define(`_UUCP_', `confUUCP_MAILER')dnl		for readability only
41
42# back compatibility with old config files
43ifdef(`confDEF_GROUP_ID',
44`errprint(`*** confDEF_GROUP_ID is obsolete.
45    Use confDEF_USER_ID with a colon in the value instead.
46')')
47ifdef(`confREAD_TIMEOUT',
48`errprint(`*** confREAD_TIMEOUT is obsolete.
49    Use individual confTO_<timeout> parameters instead.
50')')
51ifdef(`confMESSAGE_TIMEOUT',
52	`define(`_ARG_', index(confMESSAGE_TIMEOUT, /))
53	 ifelse(_ARG_, -1,
54		`define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)',
55		`define(`confTO_QUEUERETURN',
56			substr(confMESSAGE_TIMEOUT, 0, _ARG_))
57		 define(`confTO_QUEUEWARN',
58			substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')')
59ifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,,
60`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete.
61    Use confMAX_MESSAGE_SIZE for the second part of the value.
62')')')
63
64
65# Sanity check on ldap_routing feature
66# If the user doesn't specify a new map, they better have given as a
67# default LDAP specification which has the LDAP base (and most likely the host)
68ifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(`
69WARNING: Using default FEATURE(ldap_routing) map definition(s)
70without setting confLDAP_DEFAULT_SPEC option.
71')')')dnl
72
73# clean option definitions below....
74define(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl
75
76dnl required to "rename" the check_* rulesets...
77define(`_U_',ifdef(`_DELAY_CHECKS_',`',`_'))
78dnl default relaying denied message
79ifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG', `"550 Relaying denied"')')
80divert(0)dnl
81
82# override file safeties - setting this option compromises system security,
83# addressing the actual file configuration problem is preferred
84# need to set this before any file actions are encountered in the cf file
85_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe')
86
87# default LDAP map specification
88# need to set this now before any LDAP maps are defined
89_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost')
90
91##################
92#   local info   #
93##################
94
95Cwlocalhost
96ifdef(`USE_CW_FILE',
97`# file containing names of hosts for which we receive email
98Fw`'confCW_FILE',
99	`dnl')
100
101# my official domain name
102# ... `define' this only if sendmail cannot automatically determine your domain
103ifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM')
104
105CP.
106
107ifdef(`UUCP_RELAY',
108`# UUCP relay host
109DY`'UUCP_RELAY
110CPUUCP
111
112')dnl
113ifdef(`BITNET_RELAY',
114`#  BITNET relay host
115DB`'BITNET_RELAY
116CPBITNET
117
118')dnl
119ifdef(`DECNET_RELAY',
120`define(`_USE_DECNET_SYNTAX_', 1)dnl
121# DECnet relay host
122DC`'DECNET_RELAY
123CPDECNET
124
125')dnl
126ifdef(`FAX_RELAY',
127`# FAX relay host
128DF`'FAX_RELAY
129CPFAX
130
131')dnl
132# "Smart" relay host (may be null)
133DS`'ifdef(`SMART_HOST', SMART_HOST)
134
135ifdef(`LUSER_RELAY', `dnl
136# place to which unknown users should be forwarded
137Kuser user -m -a<>
138DL`'LUSER_RELAY',
139`dnl')
140
141# operators that cannot be in local usernames (i.e., network indicators)
142CO @ % ifdef(`_NO_UUCP_', `', `!')
143
144# a class with just dot (for identifying canonical names)
145C..
146
147# a class with just a left bracket (for identifying domain literals)
148C[[
149
150ifdef(`_ACCESS_TABLE_', `dnl
151# access_db acceptance class
152C{Accept}OK RELAY
153ifdef(`_DELAY_CHECKS_',`dnl
154ifdef(`_BLACKLIST_RCPT_',`dnl
155# possible access_db RHS for spam friends/haters
156C{SpamTag}SPAMFRIEND SPAMHATER')')',
157`dnl')
158
159ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
160# Resolve map (to check if a host exists in check_mail)
161Kresolve host -a<OK> -T<TEMP>')
162
163ifdef(`_FFR_5_', `# macro storage map
164Kmacro macro')
165
166ifdef(`confCR_FILE', `dnl
167# Hosts for which relaying is permitted ($=R)
168FR`'confCR_FILE',
169`dnl')
170
171define(`TLS_SRV_TAG', `TLS_Srv')dnl
172define(`TLS_CLT_TAG', `TLS_Clt')dnl
173define(`TLS_TRY_TAG', `Try_TLS')dnl
174define(`TLS_OFF_TAG', `Offer_TLS')dnl
175dnl this may be useful in other contexts too
176ifdef(`_ARITH_MAP_', `', `# arithmetic map
177define(`_ARITH_MAP_', `1')dnl
178Karith arith')
179ifdef(`_ACCESS_TABLE_', `dnl
180# possible values for tls_connect in access map
181C{tls}VERIFY ENCR', `dnl')
182ifdef(`_CERT_REGEX_ISSUER_', `dnl
183# extract relevant part from cert issuer
184KCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
185ifdef(`_CERT_REGEX_SUBJECT_', `dnl
186# extract relevant part from cert subject
187KCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
188
189# who I send unqualified names to (null means deliver locally)
190DR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY)
191
192# who gets all local email traffic ($R has precedence for unqualified names)
193DH`'ifdef(`MAIL_HUB', MAIL_HUB)
194
195# dequoting map
196Kdequote dequote
197
198divert(0)dnl	# end of nullclient diversion
199# class E: names that should be exposed as from this host, even if we masquerade
200# class L: names that should be delivered locally, even if we have a relay
201# class M: domains that should be converted to $M
202# class N: domains that should not be converted to $M
203#CL root
204undivert(5)dnl
205ifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
206
207# who I masquerade as (null for no masquerading) (see also $=M)
208DM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME)
209
210# my name for error messages
211ifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
212
213undivert(6)dnl LOCAL_CONFIG
214include(_CF_DIR_`m4/version.m4')
215
216###############
217#   Options   #
218###############
219
220# strip message body to 7 bits on input?
221_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
222
223# 8-bit data handling
224_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `adaptive')
225
226# wait for alias file rebuild (default units: minutes)
227_OPTION(AliasWait, `confALIAS_WAIT', `5m')
228
229# location of alias file
230_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
231
232# minimum number of free blocks on filesystem
233_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
234
235# maximum message size
236_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000')
237
238# substitution for space (blank) characters
239_OPTION(BlankSub, `confBLANK_SUB', `_')
240
241# avoid connecting to "expensive" mailers on initial submission?
242_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
243
244# checkpoint queue runs after every N successful deliveries
245_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
246
247# default delivery mode
248_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
249
250# automatically rebuild the alias database?
251# NOTE: There is a potential for a denial of service attack if this is set.
252#       This option is deprecated and will be removed from a future version.
253_OPTION(AutoRebuildAliases, `confAUTO_REBUILD', `False')
254
255# error message header/file
256_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
257
258# error mode
259_OPTION(ErrorMode, `confERROR_MODE', `print')
260
261# save Unix-style "From_" lines at top of header?
262_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
263
264# temporary file mode
265_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
266
267# match recipients against GECOS field?
268_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
269
270# maximum hop count
271_OPTION(MaxHopCount, `confMAX_HOP', `17')
272
273# location of help file
274O HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
275
276# ignore dots as terminators in incoming messages?
277_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
278
279# name resolver options
280_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
281
282# deliver MIME-encapsulated error messages?
283_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
284
285# Forward file search path
286_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
287
288# open connection cache size
289_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
290
291# open connection cache timeout
292_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
293
294# persistent host status directory
295_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
296
297# single thread deliveries (requires HostStatusDirectory)?
298_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
299
300# use Errors-To: header?
301_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
302
303# log level
304_OPTION(LogLevel, `confLOG_LEVEL', `10')
305
306# send to me too, even in an alias expansion?
307_OPTION(MeToo, `confME_TOO', `True')
308
309# verify RHS in newaliases?
310_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
311
312# default messages to old style headers if no special punctuation?
313_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
314
315# SMTP daemon options
316ifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
317`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.  See cf/README for more information.
318)'dnl
319`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
320ifelse(defn(`_DPO_'), `',
321`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-IPv4, Family=inet
322O DaemonPortOptions=Name=MTA-IPv6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
323ifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
324
325# SMTP client options
326_OPTION(ClientPortOptions, `confCLIENT_OPTIONS', `Address=0.0.0.0')
327
328# privacy flags
329_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
330
331# who (if anyone) should get extra copies of error messages
332_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
333
334# slope of queue-only function
335_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
336
337# queue directory
338O QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
339
340# timeouts (many of these)
341_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
342_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
343_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
344_OPTION(Timeout.helo, `confTO_HELO', `5m')
345_OPTION(Timeout.mail, `confTO_MAIL', `10m')
346_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
347_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
348_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
349_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
350_OPTION(Timeout.rset, `confTO_RSET', `5m')
351_OPTION(Timeout.quit, `confTO_QUIT', `2m')
352_OPTION(Timeout.misc, `confTO_MISC', `2m')
353_OPTION(Timeout.command, `confTO_COMMAND', `1h')
354_OPTION(Timeout.ident, `confTO_IDENT', `5s')
355_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
356_OPTION(Timeout.control, `confTO_CONTROL', `2m')
357_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
358_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
359_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
360_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
361_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
362_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
363_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
364_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
365_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
366_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
367_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
368_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
369_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
370_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
371_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
372
373# should we not prune routes in route-addr syntax addresses?
374_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
375
376# queue up everything before forking?
377_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
378
379# status file
380O StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
381
382# time zone handling:
383#  if undefined, use system default
384#  if defined but null, use TZ envariable passed in
385#  if defined and non-null, use that info
386ifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
387	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
388	`O TimeZoneSpec=confTIME_ZONE')
389
390# default UID (can be username or userid:groupid)
391_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
392
393# list of locations of user database file (null means no lookup)
394_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
395
396# fallback MX host
397_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
398
399# if we are the best MX host for a site, try it directly instead of config err
400_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
401
402# load average at which we just queue messages
403_OPTION(QueueLA, `confQUEUE_LA', `8')
404
405# load average at which we refuse connections
406_OPTION(RefuseLA, `confREFUSE_LA', `12')
407
408# maximum number of children we allow at one time
409_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12')
410
411# maximum number of new connections per second
412_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `3')
413
414# work recipient factor
415_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
416
417# deliver each queued job in a separate process?
418_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
419
420# work class factor
421_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
422
423# work time factor
424_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
425
426# shall we sort the queue by hostname first?
427_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
428
429# minimum time in queue before retry
430_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
431
432# default character set
433_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
434
435# service switch file (ignored on Solaris, Ultrix, OSF/1, others)
436_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
437
438# hosts file (normally /etc/hosts)
439_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
440
441# dialup line delay on connection failure
442_OPTION(DialDelay, `confDIAL_DELAY', `10s')
443
444# action to take if there are no recipients in the message
445_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed')
446
447# chrooted environment for writing to files
448_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
449
450# are colons OK in addresses?
451_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
452
453# how many jobs can you process in the queue?
454_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
455
456# shall I avoid expanding CNAMEs (violates protocols)?
457_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
458
459# SMTP initial login message (old $e macro)
460_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
461
462# UNIX initial From header format (old $l macro)
463_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
464
465# From: lines that have embedded newlines are unwrapped onto one line
466_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
467
468# Allow HELO SMTP command that does not `include' a host name
469_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
470
471# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
472_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
473
474# delimiter (operator) characters (old $o macro)
475_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
476
477# shall I avoid calling initgroups(3) because of high NIS costs?
478_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
479
480# are group-writable `:include:' and .forward files (un)trustworthy?
481_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
482
483# where do errors that occur when sending errors get sent?
484_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
485
486# where to save bounces if all else fails
487_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
488
489# what user id do we assume for the majority of the processing?
490_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
491
492# maximum number of recipients per SMTP envelope
493_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
494
495# shall we get local names from our installed interfaces?
496_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
497
498# Return-Receipt-To: header implies DSN request
499_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
500
501# override connection address (for testing)
502_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
503
504# Trusted user for file ownership and starting the daemon
505_OPTION(TrustedUser, `confTRUSTED_USER', `root')
506
507# Control socket for daemon management
508_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
509
510# Maximum MIME header length to protect MUAs
511_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
512
513# Maximum length of the sum of all headers
514_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
515
516# Maximum depth of alias recursion
517_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
518
519# location of pid file
520_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
521
522# Prefix string for the process title shown on 'ps' listings
523_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
524
525# Data file (df) memory-buffer file maximum size
526_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
527
528# Transcript file (xf) memory-buffer file maximum size
529_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
530
531# list of authentication mechanisms
532_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
533
534# default authentication information for outgoing connections
535_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
536
537# SMTP AUTH flags
538_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
539
540ifdef(`_FFR_MILTER', `
541# Input mail filters
542_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
543
544# Milter options
545_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
546_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
547_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
548_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')')
549
550# CA directory
551_OPTION(CACERTPath, `confCACERT_PATH', `')
552# CA file
553_OPTION(CACERTFile, `confCACERT', `')
554# Server Cert
555_OPTION(ServerCertFile, `confSERVER_CERT', `')
556# Server private key
557_OPTION(ServerKeyFile, `confSERVER_KEY', `')
558# Client Cert
559_OPTION(ClientCertFile, `confCLIENT_CERT', `')
560# Client private key
561_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
562# DHParameters (only required if DSA/DH is used)
563_OPTION(DHParameters, `confDH_PARAMETERS', `')
564# Random data source (required for systems without /dev/urandom under OpenSSL)
565_OPTION(RandFile, `confRAND_FILE', `')
566
567ifdef(`confQUEUE_FILE_MODE',
568`# queue file mode (qf files)
569O QueueFileMode=confQUEUE_FILE_MODE
570')
571
572###########################
573#   Message precedences   #
574###########################
575
576Pfirst-class=0
577Pspecial-delivery=100
578Plist=-30
579Pbulk=-60
580Pjunk=-100
581
582#####################
583#   Trusted users   #
584#####################
585
586# this is equivalent to setting class "t"
587ifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
588Troot
589Tdaemon
590ifdef(`_NO_UUCP_', `dnl', `Tuucp')
591ifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
592
593#########################
594#   Format of headers   #
595#########################
596
597ifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
598H?P?Return-Path: <$g>
599HReceived: confRECEIVED_HEADER
600H?D?Resent-Date: $a
601H?D?Date: $a
602H?F?Resent-From: confFROM_HEADER
603H?F?From: confFROM_HEADER
604H?x?Full-Name: $x
605# HPosted-Date: $a
606# H?l?Received-Date: $b
607H?M?Resent-Message-Id: <$t.$i@$j>
608H?M?Message-Id: <$t.$i@$j>
609
610#
611######################################################################
612######################################################################
613#####
614#####			REWRITING RULES
615#####
616######################################################################
617######################################################################
618
619############################################
620###  Ruleset 3 -- Name Canonicalization  ###
621############################################
622Scanonify=3
623
624# handle null input (translate to <@> special case)
625R$@			$@ <@>
626
627# strip group: syntax (not inside angle brackets!) and trailing semicolon
628R$*			$: $1 <@>			mark addresses
629R$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
630R@ $* <@>		$: @ $1				unmark @host:...
631R$* :: $* <@>		$: $1 :: $2			unmark node::addr
632R:`include': $* <@>	$: :`include': $1			unmark :`include':...
633R$* [ IPv6 $- ] <@>	$: $1 [ IPv6 $2 ]		unmark IPv6 addr
634R$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
635R$* : $* <@>		$: $2				strip colon if marked
636R$* <@>			$: $1				unmark
637R$* ;			   $1				strip trailing semi
638R$* < $* ; >		   $1 < $2 >			bogus bracketed semi
639
640# null input now results from list:; syntax
641R$@			$@ :; <@>
642
643# strip angle brackets -- note RFC733 heuristic to get innermost item
644R$*			$: < $1 >			housekeeping <>
645R$+ < $* >		   < $2 >			strip excess on left
646R< $* > $+		   < $1 >			strip excess on right
647R<>			$@ < @ >			MAIL FROM:<> case
648R< $+ >			$: $1				remove housekeeping <>
649
650ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
651# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
652R@ $+ , $+		@ $1 : $2			change all "," to ":"
653
654# localize and dispose of route-based addresses
655R@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
656dnl',`dnl
657# strip route address <@a,@b,@c:user@d> -> <user@d>
658R@ $+ , $+		$2
659R@ $+ : $+		$2
660dnl')
661
662# find focus for list syntax
663R $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
664R $+ : $* ;		$@ $1 : $2;			list syntax
665
666# find focus for @ syntax addresses
667R$+ @ $+		$: $1 < @ $2 >			focus on domain
668R$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
669R$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
670
671# do some sanity checking
672R$* < @ $* : $* > $*	$1 < @ $2 $3 > $4		nix colons in addrs
673
674ifdef(`_NO_UUCP_', `dnl',
675`# convert old-style addresses to a domain-based address
676R$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
677R$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
678R$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
679')
680ifdef(`_USE_DECNET_SYNTAX_',
681`# convert node::user addresses into a domain-based address
682R$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
683R$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
684',
685	`dnl')
686# if we have % signs, take the rightmost one
687R$* % $*		$1 @ $2				First make them all @s.
688R$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
689R$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
690
691# else we must be a local name
692R$*			$@ $>Canonify2 $1
693
694
695################################################
696###  Ruleset 96 -- bottom half of ruleset 3  ###
697################################################
698
699SCanonify2=96
700
701# handle special cases for local names
702R$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
703R$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
704ifdef(`_NO_UUCP_', `dnl',
705`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
706
707# check for IPv6 domain literal (save quoted form)
708R$* < @ [ IPv6 $- ] > $*	$: $2 $| $1 < @@ [ $(dequote $2 $) ] > $3	mark IPv6 addr
709R$- $| $* < @@ $=w > $*		$: $2 < @ $j . > $4		self-literal
710R$- $| $* < @@ [ $+ ] > $*	$@ $2 < @ [ IPv6 $1 ] > $4	canon IP addr
711
712# check for IPv4 domain literal
713R$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [a.b.c.d]
714R$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
715R$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
716
717ifdef(`_DOMAIN_TABLE_', `dnl
718# look up domains in the domain table
719R$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
720
721undivert(2)dnl LOCAL_RULE_3
722
723ifdef(`_BITDOMAIN_TABLE_', `dnl
724# handle BITNET mapping
725R$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
726
727ifdef(`_UUDOMAIN_TABLE_', `dnl
728# handle UUCP mapping
729R$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
730
731ifdef(`_NO_UUCP_', `dnl',
732`ifdef(`UUCP_RELAY',
733`# pass UUCP addresses straight through
734R$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
735`# if really UUCP, handle it immediately
736ifdef(`_CLASS_U_',
737`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
738ifdef(`_CLASS_V_',
739`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
740ifdef(`_CLASS_W_',
741`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
742ifdef(`_CLASS_X_',
743`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
744ifdef(`_CLASS_Y_',
745`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
746
747ifdef(`_NO_CANONIFY_', `dnl', `dnl
748# try UUCP traffic as a local address
749R$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
750R$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
751')')
752# hostnames ending in class P are always canonical
753R$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
754dnl apply the next rule only for hostnames not in class P
755dnl this even works for phrases in class P since . is in class P
756dnl which daemon flags are set?
757R$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
758dnl the other rules in this section only apply if the hostname
759dnl does not end in class P hence no further checks are done here
760dnl if this ever changes make sure the lookups are "protected" again!
761ifdef(`_NO_CANONIFY_', `dnl
762dnl do not canonify unless:
763dnl domain ends in class {Canonify} (this does not work if the intersection
764dnl	with class P is non-empty)
765dnl or {daemon_flags} has c set
766# pass to name server to make hostname canonical if in class {Canonify}
767R$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
768# pass to name server to make hostname canonical if requested
769R$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
770dnl trailing dot? -> do not apply _CANONIFY_HOSTS_
771R$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
772# add a trailing dot to qualified hostnames so other rules will work
773R$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
774ifdef(`_CANONIFY_HOSTS_', `dnl
775dnl this should only apply to unqualified hostnames
776dnl but if a valid character inside an unqualified hostname is an OperatorChar
777dnl then $- does not work.
778# lookup unqualified hostnames
779R$* $| $* < @ $* > $*	$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
780dnl _NO_CANONIFY_ is not set: canonify unless:
781dnl {daemon_flags} contains CC (do not canonify)
782R$* CC $* $| $*			$: $3
783# pass to name server to make hostname canonical
784R$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
785dnl remove {daemon_flags} for other cases
786R$* $| $*			$: $2
787
788# local host aliases and pseudo-domains are always canonical
789R$* < @ $=w > $*		$: $1 < @ $2 . > $3
790ifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
791`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
792`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
793ifdef(`_VIRTUSER_TABLE_', `dnl
794dnl virtual hosts are also canonical
795ifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
796`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
797`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
798`dnl')
799dnl remove superfluous dots (maybe repeatedly) which may have been added
800dnl by one of the rules before
801R$* < @ $* . . > $*		$1 < @ $2 . > $3
802
803
804##################################################
805###  Ruleset 4 -- Final Output Post-rewriting  ###
806##################################################
807Sfinal=4
808
809R$* <@>			$@				handle <> and list:;
810
811# strip trailing dot off possibly canonical name
812R$* < @ $+ . > $*	$1 < @ $2 > $3
813
814# eliminate internal code
815R$* < @ *LOCAL* > $*	$1 < @ $j > $2
816
817# externalize local domain info
818R$* < $+ > $*		$1 $2 $3			defocus
819R@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
820R@ $*			$@ @ $1				... and exit
821
822ifdef(`_NO_UUCP_', `dnl',
823`# UUCP must always be presented in old form
824R$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
825
826ifdef(`_USE_DECNET_SYNTAX_',
827`# put DECnet back in :: form
828R$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
829	`dnl')
830# delete duplicate local names
831R$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
832
833
834
835##############################################################
836###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
837###		   (used for recursive calls)		   ###
838##############################################################
839
840SRecurse=97
841R$*			$: $>canonify $1
842R$*			$@ $>parse $1
843
844
845######################################
846###   Ruleset 0 -- Parse Address   ###
847######################################
848
849Sparse=0
850
851R$*			$: $>Parse0 $1		initial parsing
852R<@>			$#_LOCAL_ $: <@>		special case error msgs
853R$*			$: $>ParseLocal $1	handle local hacks
854R$*			$: $>Parse1 $1		final parsing
855
856#
857#  Parse0 -- do initial syntax checking and eliminate local addresses.
858#	This should either return with the (possibly modified) input
859#	or return with a #error mailer.  It should not return with a
860#	#mailer other than the #error mailer.
861#
862
863SParse0
864R<@>			$@ <@>			special case error msgs
865R$* : $* ; <@>		$#error $@ 5.1.3 $: "501 List:; syntax illegal for recipient addresses"
866R@ <@ $* >		< @ $1 >		catch "@@host" bogosity
867R<@ $+>			$#error $@ 5.1.3 $: "501 User address required"
868R$*			$: <> $1
869R<> $* < @ [ $+ ] > $*	$1 < @ [ $2 ] > $3
870R<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "501 Colon illegal in host name part"
871R<> $*			$1
872R$* < @ . $* > $*	$#error $@ 5.1.2 $: "501 Invalid host name"
873R$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "501 Invalid host name"
874dnl comma only allowed before @; this check is not complete
875R$* , $~O $*		$#error $@ 5.1.2 $: "501 Invalid route address"
876
877# now delete the local info -- note $=O to find characters that cause forwarding
878R$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
879R< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
880R$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
881R< @ $+ >		$#error $@ 5.1.3 $: "501 User address required"
882R$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
883R$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
884R< @ *LOCAL* >		$#error $@ 5.1.3 $: "501 User address required"
885R$* $=O $* < @ *LOCAL* >
886			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
887R$* < @ *LOCAL* >	$: $1
888
889#
890#  Parse1 -- the bottom half of ruleset 0.
891#
892
893SParse1
894ifdef(`_LDAP_ROUTING_', `dnl
895# handle LDAP routing for hosts in $={LDAPRoute}
896R$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2>',
897`dnl')
898
899ifdef(`_MAILER_smtp_',
900`# handle numeric address spec
901dnl there is no check whether this is really an IP number
902R$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
903R$* < @ [ $+ ] > $*	$1 < @ [ $2 ] : $S > $3		Add smart host to path
904R$* < @ [ IPv6 $- ] : > $*
905		$#_SMTP_ $@ [ $(dequote $2 $) ] $: $1 < @ [IPv6 $2 ] > $3	no smarthost: send
906R$* < @ [ $+ ] : > $*	$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
907R$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
908R$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
909	`dnl')
910
911ifdef(`_VIRTUSER_TABLE_', `dnl
912# handle virtual users
913R$+			$: <!> $1		Mark for lookup
914ifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
915`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
916`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
917R<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
918R<@> $+ + $* < @ $* . >
919			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
920R<@> $+ + $* < @ $* . >
921			$: < $(virtuser $1 @ $3 $@ $1 $: @ $) > $1 + $2 < @ $3 . >
922dnl try default entry: @domain
923dnl +*@domain
924R<@> $+ + $+ < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
925dnl @domain if +detail exists
926R<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . >
927dnl without +detail (or no match)
928R<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
929R<@> $+			$: $1
930R<!> $+			$: $1
931R< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
932R< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
933R< $+ > $+ < @ $+ >	$: $>Recurse $1',
934`dnl')
935
936# short circuit local delivery so forwarded email works
937ifdef(`_MAILER_usenet_', `dnl
938R$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
939
940
941ifdef(`_STICKY_LOCAL_DOMAIN_',
942`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
943R< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
944dnl $H empty (but @$=w.)
945R< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
946R< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
947`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
948R$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
949
950ifdef(`_MAILER_TABLE_', `dnl
951# not local -- try mailer table lookup
952R$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
953R< $+ . > $*		$: < $1 > $2			strip trailing dot
954R< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
955dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
956R< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
957R< $+ > $*		$: $>Mailertable <$1> $2		try domain',
958`dnl')
959undivert(4)dnl UUCP rules from `MAILER(uucp)'
960
961ifdef(`_NO_UUCP_', `dnl',
962`# resolve remotely connected UUCP links (if any)
963ifdef(`_CLASS_V_',
964`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
965	`dnl')
966ifdef(`_CLASS_W_',
967`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
968	`dnl')
969ifdef(`_CLASS_X_',
970`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
971	`dnl')')
972
973# resolve fake top level domains by forwarding to other hosts
974ifdef(`BITNET_RELAY',
975`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
976	`dnl')
977ifdef(`DECNET_RELAY',
978`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
979	`dnl')
980ifdef(`_MAILER_pop_',
981`R$+ < @ POP. >		$#pop $: $1			user@POP',
982	`dnl')
983ifdef(`_MAILER_fax_',
984`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
985`ifdef(`FAX_RELAY',
986`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
987	`dnl')')
988
989ifdef(`UUCP_RELAY',
990`# forward non-local UUCP traffic to our UUCP relay
991R$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
992`ifdef(`_MAILER_uucp_',
993`# forward other UUCP traffic straight to UUCP
994R$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
995	`dnl')')
996ifdef(`_MAILER_usenet_', `
997# addresses sent to net.group.USENET will get forwarded to a newsgroup
998R$+ . USENET		$#usenet $@ usenet $: $1',
999	`dnl')
1000
1001ifdef(`_LOCAL_RULES_',
1002`# figure out what should stay in our local mail system
1003undivert(1)', `dnl')
1004
1005# pass names that still have a host to a smarthost (if defined)
1006R$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
1007
1008# deal with other remote names
1009ifdef(`_MAILER_smtp_',
1010`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
1011`R$* < @$* > $*		$#error $@ 5.1.2 $: "501 Unrecognized host name " $2')
1012
1013# handle locally delivered names
1014R$=L			$#_LOCAL_ $: @ $1		special local names
1015R$+			$#_LOCAL_ $: $1			regular local names
1016
1017###########################################################################
1018###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
1019###########################################################################
1020
1021SLocal_localaddr
1022Slocaladdr=5
1023R$+			$: $1 $| $>"Local_localaddr" $1
1024R$+ $| $#$*		$#$2
1025R$+ $| $*		$: $1
1026
1027ifdef(`_FFR_5_', `
1028# Preserve host in a macro
1029R$+			$: $(macro {LocalAddrHost} $) $1
1030R$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
1031
1032ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `
1033# deal with plussed users so aliases work nicely
1034R$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
1035R$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
1036')
1037# prepend an empty "forward host" on the front
1038R$+			$: <> $1
1039
1040ifdef(`LUSER_RELAY', `dnl
1041# send unrecognized local users to a relay host
1042ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `
1043R< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
1044R< > $+			$: < ? $L > < > $(user $1 $)	look up user
1045R< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
1046R< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
1047R< > $+ 		$: < $L > $(user $1 $)		look up user
1048R< $* > $+ <>		$: < > $2			found; strip $L')',
1049`dnl')
1050
1051# see if we have a relay or a hub
1052R< > $+			$: < $H > $1			try hub
1053R< > $+			$: < $R > $1			try relay
1054ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `
1055R< > $+			$@ $1', `
1056R< > $+			$: < > < $1 <> $&h >		nope, restore +detail
1057R< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
1058R< > < $+ <> $* >	$: < > < $1 >			else discard
1059R< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
1060R< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
1061R< > < $+ >		$@ $1				no +detail
1062R$+			$: $1 <> $&h			add +detail back in
1063R$+ <> + $*		$: $1 + $2			check whether +detail
1064R$+ <> $*		$: $1				else discard')
1065R< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
1066R< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
1067R< $- : $+ > $+		$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
1068R< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
1069
1070ifdef(`_MAILER_TABLE_', `dnl
1071###################################################################
1072###  Ruleset 90 -- try domain part of mailertable entry 	###
1073dnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
1074###################################################################
1075
1076SMailertable=90
1077dnl shift and check
1078dnl %2 is not documented in cf/README
1079R$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
1080dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
1081R$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
1082R$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
1083dnl is $2 always empty?
1084R$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
1085R< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
1086dnl return full address
1087R< $* > $*		$@ $2				no mailertable match',
1088`dnl')
1089
1090###################################################################
1091###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
1092dnl input: in general: <[mailer:]host> lp<@domain>rest
1093dnl	<> address				-> address
1094dnl	<error:d.s.n:text>			-> error
1095dnl	<error:text>				-> error
1096dnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
1097dnl	<mailer:host> address			-> mailer host address
1098dnl	<localdomain> address			-> address
1099dnl	<[IPv6 number]> address			-> relay number address
1100dnl	<host> address				-> relay host address
1101###################################################################
1102
1103SMailerToTriple=95
1104R< > $*				$@ $1			strip off null relay
1105R< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
1106R< error : $- $+ > $*		$#error $@ $(dequote $1 $) $: $2
1107R< local : $* > $*		$>CanonLocal < $1 > $2
1108R< $- : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
1109R< $- : $+ > $*			$# $1 $@ $2 $: $3	try qualified mailer
1110R< $=w > $*			$@ $2			delete local host
1111R< [ IPv6 $+ ] > $*		$#_RELAY_ $@ $(dequote $1 $) $: $2	use unqualified mailer
1112R< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
1113
1114###################################################################
1115###  Ruleset CanonLocal -- canonify local: syntax		###
1116dnl input: <user> address
1117dnl <x> <@host> : rest			-> Recurse rest
1118dnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
1119dnl <> user <@host> rest		-> local user@host user
1120dnl <> user				-> local user user
1121dnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
1122dnl <user> lp <@host> rest		-> local lp@host user
1123dnl <user> lp				-> local lp user
1124###################################################################
1125
1126SCanonLocal
1127# strip local host from routed addresses
1128R< $* > < @ $+ > : $+		$@ $>Recurse $3
1129R< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
1130
1131# strip trailing dot from any host name that may appear
1132R< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
1133
1134# handle local: syntax -- use old user, either with or without host
1135R< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
1136R< > $+				$#_LOCAL_ $@ $1    $: $1
1137
1138# handle local:user@host syntax -- ignore host part
1139R< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
1140
1141# handle local:user syntax
1142R< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
1143R< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
1144
1145###################################################################
1146###  Ruleset 93 -- convert header names to masqueraded form	###
1147###################################################################
1148
1149SMasqHdr=93
1150
1151ifdef(`_GENERICS_TABLE_', `dnl
1152# handle generics database
1153ifdef(`_GENERICS_ENTIRE_DOMAIN_',
1154dnl if generics should be applied add a @ as mark
1155`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
1156`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
1157R$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
1158dnl workspace: either user<@domain> or <user@domain> user <@domain> @
1159dnl ignore the first case for now
1160dnl if it has the mark lookup full address
1161R< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
1162dnl workspace: ... or <match|@user@domain> user <@domain>
1163dnl no match, try user+detail@domain
1164R<@$+ + $* @ $+> $+ < @ $+ >
1165		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
1166R<@$+ + $* @ $+> $+ < @ $+ >
1167		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
1168dnl no match, remove mark
1169R<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
1170dnl no match, try @domain for exceptions
1171R< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
1172dnl workspace: ... or <match> user <@domain>
1173dnl no match, try local part
1174R< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
1175R< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
1176R< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
1177R< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
1178R< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
1179R< > $*			$: $1				not found',
1180`dnl')
1181
1182# do not masquerade anything in class N
1183R$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
1184
1185# special case the users that should be exposed
1186R$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
1187ifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
1188`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
1189`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
1190ifdef(`_LIMITED_MASQUERADE_', `dnl',
1191`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
1192
1193# handle domain-specific masquerading
1194ifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
1195`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
1196`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
1197ifdef(`_LIMITED_MASQUERADE_', `dnl',
1198`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
1199R$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
1200R$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
1201R$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
1202
1203###################################################################
1204###  Ruleset 94 -- convert envelope names to masqueraded form	###
1205###################################################################
1206
1207SMasqEnv=94
1208ifdef(`_MASQUERADE_ENVELOPE_',
1209`R$+			$@ $>MasqHdr $1',
1210`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
1211
1212###################################################################
1213###  Ruleset 98 -- local part of ruleset zero (can be null)	###
1214###################################################################
1215
1216SParseLocal=98
1217undivert(3)dnl LOCAL_RULE_0
1218
1219ifdef(`_LDAP_ROUTING_', `dnl
1220SLDAPExpand
1221# do the LDAP lookups
1222R<$+><$+>		$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2>
1223
1224# if mailRoutingAddress and local or non-existant mailHost,
1225# return the new mailRoutingAddress
1226R< $+ > < $=w > < $+ > < $+ >	$@ $>Parse0 $>canonify $1
1227R< $+ > <  > < $+ > < $+ >	$@ $>Parse0 $>canonify $1
1228
1229# if mailRoutingAddress and non-local mailHost,
1230# relay to mailHost with new mailRoutingAddress
1231R< $+ > < $+ > < $+ > < $+ >	$#_RELAY_ $@ $2 $: $>canonify $1
1232
1233# if no mailRoutingAddress and local mailHost,
1234# return original address
1235R< > < $=w > <$+> <$+>		$@ $2
1236
1237# if no mailRoutingAddress and non-local mailHost,
1238# relay to mailHost with original address
1239R< > < $+ > <$+> <$+>		$#_RELAY_ $@ $1 $: $2
1240
1241# if no mailRoutingAddress and no mailHost,
1242# try @domain
1243R< > < > <$+> <$+ @ $+>		$@ $>LDAPExpand <$1> <@ $3>
1244
1245# if no mailRoutingAddress and no mailHost and this was a domain attempt,
1246ifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
1247# user does not exist
1248R< > < > <$+> <@ $+>		$#error $@ nouser $: "550 User unknown"',
1249`dnl
1250# return the original address
1251R< > < > <$+> <@ $+>		$@ $1')',
1252`dnl')
1253
1254ifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
1255')')
1256ifdef(`_ACCESS_TABLE_', `dnl
1257######################################################################
1258###  LookUpDomain -- search for domain in access database
1259###
1260###	Parameters:
1261###		<$1> -- key (domain name)
1262###		<$2> -- default (what to return if not found in db)
1263dnl			must not be empty
1264###		<$3> -- passthru (additional data passed unchanged through)
1265###		<$4> -- mark (must be <(!|+) single-token>)
1266###			! does lookup only with tag
1267###			+ does lookup with and without tag
1268dnl returns:		<default> <passthru>
1269dnl 			<result> <passthru>
1270######################################################################
1271
1272SLookUpDomain
1273dnl remove IPv6 mark and dequote address
1274dnl it is a bit ugly because it is checked on each "iteration"
1275R<[IPv6 $-]> <$+> <$*> <$*>	$: <[$(dequote $1 $)]> <$2> <$3> <$4>
1276dnl workspace <key> <default> <passthru> <mark>
1277dnl lookup with tag (in front, no delimiter here)
1278R<$*> <$+> <$*> <$- $->		$: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5>
1279dnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
1280ifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest
1281R<?> <$+.$+> <$+> <$*> <$- $->	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4> <$5 $6>', `dnl')
1282dnl lookup without tag?
1283R<?> <$+> <$+> <$*> <+ $*>	$: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4>
1284ifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest
1285R<?> <$+.$+> <$+> <$*> <+ $*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <$4> <+ $5>', `dnl')
1286dnl lookup IP address (no check is done whether it is an IP number!)
1287R<?> <[$+.$-]> <$+> <$*> <$*>	$@ $>LookUpDomain <[$1]> <$3> <$4> <$5>
1288dnl lookup IPv6 address
1289R<?> <[$+:$-]> <$+> <$*> <$*>	$: $>LookUpDomain <[$1]> <$3> <$4> <$5>
1290dnl not found, but subdomain: try again
1291R<?> <$+.$+> <$+> <$*> <$*>	$@ $>LookUpDomain <$2> <$3> <$4> <$5>
1292dnl not found, no subdomain: return default
1293R<?> <$+> <$+> <$*> <$*>	$@ <$2> <$3>
1294dnl return result of lookup
1295R<$*> <$+> <$+> <$*> <$*>	$@ <$1> <$4>
1296
1297######################################################################
1298###  LookUpAddress -- search for host address in access database
1299###
1300###	Parameters:
1301###		<$1> -- key (dot quadded host address)
1302###		<$2> -- default (what to return if not found in db)
1303dnl			must not be empty
1304###		<$3> -- passthru (additional data passed through)
1305###		<$4> -- mark (must be <(!|+) single-token>)
1306###			! does lookup only with tag
1307###			+ does lookup with and without tag
1308dnl	returns:	<default> <passthru>
1309dnl			<result> <passthru>
1310######################################################################
1311
1312SLookUpAddress
1313dnl lookup with tag
1314R<$+> <$+> <$*> <$- $+>		$: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5>
1315dnl lookup without tag
1316R<?> <$+> <$+> <$*> <+ $+>	$: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4>
1317dnl no match; IPv6: remove last part
1318R<?> <$+:$-> <$+> <$*> <$*>	$@ $>LookUpAddress <$1> <$3> <$4> <$5>
1319dnl no match; IPv4: remove last part
1320R<?> <$+.$-> <$+> <$*> <$*>	$@ $>LookUpAddress <$1> <$3> <$4> <$5>
1321dnl no match: return default
1322R<?> <$+> <$+> <$*> <$*>	$@ <$2> <$3>
1323dnl match: return result
1324R<$*> <$+> <$+> <$*> <$*>	$@ <$1> <$4>',
1325`dnl')
1326
1327######################################################################
1328###  CanonAddr --	Convert an address into a standard form for
1329###			relay checking.  Route address syntax is
1330###			crudely converted into a %-hack address.
1331###
1332###	Parameters:
1333###		$1 -- full recipient address
1334###
1335###	Returns:
1336###		parsed address, not in source route form
1337dnl		user%host%host<@domain>
1338dnl		host!user<@domain>
1339######################################################################
1340
1341SCanonAddr
1342R$*			$: $>Parse0 $>canonify $1	make domain canonical
1343ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
1344R< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
1345R$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
1346R$* < @ $+ > : $*	$3 $1 < @ $2 >
1347dnl')
1348
1349######################################################################
1350###  ParseRecipient --	Strip off hosts in $=R as well as possibly
1351###			$* $=m or the access database.
1352###			Check user portion for host separators.
1353###
1354###	Parameters:
1355###		$1 -- full recipient address
1356###
1357###	Returns:
1358###		parsed, non-local-relaying address
1359######################################################################
1360
1361SParseRecipient
1362dnl mark and canonify address
1363R$*				$: <?> $>CanonAddr $1
1364dnl workspace: <?> localpart<@domain[.]>
1365R<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
1366dnl workspace: <?> localpart<@domain>
1367R<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
1368
1369# if no $=O character, no host in the user portion, we are done
1370R<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
1371dnl no $=O in localpart: return
1372R<?> $*				$@ $1
1373
1374dnl workspace: <?> localpart<@domain>, where localpart contains $=O
1375dnl mark everything which has an "authorized" domain with <RELAY>
1376ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
1377# if we relay, check username portion for user%host so host can be checked also
1378R<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
1379
1380ifdef(`_RELAY_MX_SERVED_', `dnl
1381dnl do "we" ($=w) act as backup MX server for the destination domain?
1382R<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
1383R<MX> < : $* <TEMP> : > $*	$#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
1384dnl yes: mark it as <RELAY>
1385R<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
1386dnl no: put old <NO> mark back
1387R<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
1388
1389dnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
1390dnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
1391ifdef(`_RELAY_HOSTS_ONLY_',
1392`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
1393ifdef(`_ACCESS_TABLE_', `dnl
1394R<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
1395R<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
1396`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
1397ifdef(`_ACCESS_TABLE_', `dnl
1398R<NO> $* < @ $+ >		$: $>LookUpDomain <$2> <NO> <$1 < @ $2 >> <+To>
1399R<$+> <$+>			$: <$1> $2',`dnl')')
1400
1401
1402R<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
1403R<$-> $*			$@ $2
1404
1405
1406######################################################################
1407###  check_relay -- check hostname/address on SMTP startup
1408######################################################################
1409
1410SLocal_check_relay
1411Scheck`'_U_`'relay
1412R$*			$: $1 $| $>"Local_check_relay" $1
1413R$* $| $* $| $#$*	$#$3
1414R$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
1415
1416SBasic_check_relay
1417# check for deferred delivery mode
1418R$*			$: < ${deliveryMode} > $1
1419R< d > $*		$@ deferred
1420R< $* > $*		$: $2
1421
1422ifdef(`_ACCESS_TABLE_', `dnl
1423dnl workspace: {client_name} $| {client_addr}
1424R$+ $| $+		$: $>LookUpDomain < $1 > <?> < $2 > <+Connect>
1425dnl workspace: <result-of-lookup> <{client_addr}>
1426R<?> <$+>		$: $>LookUpAddress < $1 > <?> < $1 > <+Connect>	no: another lookup
1427dnl workspace: <result-of-lookup> <{client_addr}>
1428R<?> < $+ >		$: $1					found nothing
1429dnl workspace: <result-of-lookup> <{client_addr}>
1430dnl or {client_addr}
1431R<$={Accept}> < $* >	$@ $1				return value of lookup
1432R<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
1433R<DISCARD> $*		$#discard $: discard
1434dnl error tag
1435R<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
1436R<ERROR:$+> <$*>		$#error $: $1
1437dnl generic error from access map
1438R<$+> <$*>		$#error $: $1', `dnl')
1439
1440ifdef(`_RBL_',`dnl
1441# DNS based IP address spam list
1442R$*			$: $&{client_addr}
1443R::ffff:$-.$-.$-.$-	$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
1444R$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
1445R<?>OK			$: OKSOFAR
1446R<?>$+			$#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"',
1447`dnl')
1448undivert(8)
1449
1450######################################################################
1451###  check_mail -- check SMTP ``MAIL FROM:'' command argument
1452######################################################################
1453
1454SLocal_check_mail
1455Scheck`'_U_`'mail
1456R$*			$: $1 $| $>"Local_check_mail" $1
1457R$* $| $#$*		$#$2
1458R$* $| $*		$@ $>"Basic_check_mail" $1
1459
1460SBasic_check_mail
1461# check for deferred delivery mode
1462R$*			$: < ${deliveryMode} > $1
1463R< d > $*		$@ deferred
1464R< $* > $*		$: $2
1465
1466# authenticated?
1467dnl done first: we can require authentication for every mail transaction
1468dnl workspace: address as given by MAIL FROM: (sender)
1469R$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
1470R$* $| $#$+		$#$2
1471dnl undo damage: remove result of tls_client call
1472R$* $| $*		$: $1
1473
1474dnl workspace: address as given by MAIL FROM:
1475R<>			$@ <OK>			we MUST accept <> (RFC 1123)
1476ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
1477dnl do some additional checks
1478dnl no user@host
1479dnl no user@localhost (if nonlocal sender)
1480dnl this is a pretty simple canonification, it will not catch every case
1481dnl just make sure the address has <> around it (which is required by
1482dnl the RFC anyway, maybe we should complain if they are missing...)
1483dnl dirty trick: if it is user@host, just add a dot: user@host. this will
1484dnl not be modified by host lookups.
1485R$+			$: <?> $1
1486R<?><$+>		$: <@> <$1>
1487R<?>$+			$: <@> <$1>
1488dnl workspace: <@> <address>
1489dnl prepend daemon_flags
1490R$*			$: $&{daemon_flags} $| $1
1491dnl workspace: ${daemon_flags} $| <@> <address>
1492dnl do not allow these at all or only from local systems?
1493R$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
1494dnl accept unqualified sender: change mark to avoid test
1495R$* u $* $| <@> < $* >	$: <?> < $3 >
1496dnl workspace: ${daemon_flags} $| <@> <address>
1497dnl        or:                    <? ${client_name} > <address>
1498dnl        or:                    <?> <address>
1499dnl remove daemon_flags
1500R$* $| $*		$: $2
1501# handle case of @localhost on address
1502R<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
1503R<@> < $* @ [127.0.0.1] >
1504			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
1505R<@> < $* @ localhost.$m >
1506			$: < ? $&{client_name} > < $1 @ localhost.$m >
1507ifdef(`_NO_UUCP_', `dnl',
1508`R<@> < $* @ localhost.UUCP >
1509			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
1510dnl workspace: < ? $&{client_name} > <user@localhost|host>
1511dnl	or:    <@> <address>
1512dnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
1513R<@> $*			$: $1			no localhost as domain
1514dnl workspace: < ? $&{client_name} > <user@localhost|host>
1515dnl	or:    <address>
1516dnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
1517R<? $=w> $*		$: $2			local client: ok
1518R<? $+> <$+>		$#error $@ 5.5.4 $: "501 Real domain name required for sender address"
1519dnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
1520R<?> $*			$: $1')
1521dnl workspace: address (or <address>)
1522R$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
1523dnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
1524dnl there is nothing behind the <@host> so no trailing $* needed
1525R<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
1526# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
1527R<?> $* < @ $* $=P >	$: <OK> $1 < @ $2 $3 >
1528dnl workspace <mark> CanonicalAddress	where mark is ? or OK
1529ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
1530`R<?> $* < @ $+ >	$: <OK> $1 < @ $2 >		... unresolvable OK',
1531`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
1532R<? $* <$->> $* < @ $+ >
1533			$: <$2> $3 < @ $4 >')
1534dnl workspace <mark> CanonicalAddress	where mark is ?, OK, PERM, TEMP
1535dnl mark is ? iff the address is user (wo @domain)
1536
1537ifdef(`_ACCESS_TABLE_', `dnl
1538# check sender address: user@address, user@, address
1539dnl should we remove +ext from user?
1540dnl workspace: <mark> CanonicalAddress where mark is: ?, OK, PERM, TEMP
1541R<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <H:$3>
1542R<$+> $+		$: @<$1> <$2> $| <U:$2@>
1543dnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
1544dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
1545dnl will only return user<@domain when "reversing" the args
1546R@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+From> $| <$3> <>
1547dnl workspace: <@><mark> <CanonicalAddress> $| <result>
1548R<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
1549dnl workspace: <result> <mark> <CanonicalAddress>
1550# retransform for further use
1551dnl required form:
1552dnl <ResultOfLookup|mark> CanonicalAddress
1553R<?> <$+> <$*>		$: <$1> $2	no match
1554R<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
1555dnl workspace <ResultOfLookup|mark> CanonicalAddress
1556dnl mark is ? iff the address is user (wo @domain)
1557
1558ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
1559# handle case of no @domain on address
1560dnl prepend daemon_flags
1561R<?> $*			$: $&{daemon_flags} $| <?> $1
1562dnl accept unqualified sender: change mark to avoid test
1563R$* u $* $| <?> $*	$: <OK> $3
1564dnl remove daemon_flags
1565R$* $| $*		$: $2
1566R<?> $*			$: < ? $&{client_name} > $1
1567R<?> $*			$@ <OK>				...local unqualed ok
1568R<? $+> $*		$#error $@ 5.5.4 $: "501 Domain name required for sender address " $&f
1569							...remote is not')
1570# check results
1571R<?> $*			$: @ $1		mark address: nothing known about it
1572R<OK> $*		$@ <OK>
1573R<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
1574R<PERM> $*		$#error $@ 5.1.8 $: "501 Domain of sender address " $&f " does not exist"
1575ifdef(`_ACCESS_TABLE_', `dnl
1576R<$={Accept}> $*	$# $1
1577R<DISCARD> $*		$#discard $: discard
1578R<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
1579dnl error tag
1580R<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
1581R<ERROR:$+> $*		$#error $: $1
1582dnl generic error from access map
1583R<$+> $*		$#error $: $1		error from access db',
1584`dnl')
1585
1586######################################################################
1587###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
1588######################################################################
1589
1590SLocal_check_rcpt
1591Scheck`'_U_`'rcpt
1592R$*			$: $1 $| $>"Local_check_rcpt" $1
1593R$* $| $#$*		$#$2
1594R$* $| $*		$@ $>"Basic_check_rcpt" $1
1595
1596SBasic_check_rcpt
1597# check for deferred delivery mode
1598R$*			$: < ${deliveryMode} > $1
1599R< d > $*		$@ deferred
1600R< $* > $*		$: $2
1601
1602ifdef(`_REQUIRE_QUAL_RCPT_', `dnl
1603# require qualified recipient?
1604R$+			$: <?> $1
1605R<?><$+>		$: <@> <$1>
1606R<?>$+			$: <@> <$1>
1607dnl prepend daemon_flags
1608R$*			$: $&{daemon_flags} $| $1
1609dnl workspace: ${daemon_flags} $| <@> <address>
1610dnl do not allow these at all or only from local systems?
1611R$* r $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
1612R<?> < $* >		$: <$1>
1613R<? $=w> < $* >		$: <$1>
1614R<? $+> <$+>		$#error $@ 5.5.4 $: "553 Domain name required"
1615dnl remove daemon_flags for other cases
1616R$* $| <@> $*		$: $2', `dnl')
1617
1618ifdef(`_LOOSE_RELAY_CHECK_',`dnl
1619R$*			$: $>CanonAddr $1
1620R$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
1621`R$*			$: $>ParseRecipient $1		strip relayable hosts')
1622
1623ifdef(`_BESTMX_IS_LOCAL_',`dnl
1624ifelse(_BESTMX_IS_LOCAL_, `', `dnl
1625# unlimited bestmx
1626R$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
1627`dnl
1628# limit bestmx to $=B
1629R$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
1630R$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Basic_check_rcpt" $1 $2 $3
1631R$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
1632R$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
1633
1634ifdef(`_BLACKLIST_RCPT_',`dnl
1635ifdef(`_ACCESS_TABLE_', `dnl
1636# blacklist local users or any host from receiving mail
1637R$*			$: <?> $1
1638dnl user is now tagged with @ to be consistent with check_mail
1639dnl and to distinguish users from hosts (com would be host, com@ would be user)
1640R<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <H:$2>
1641R<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <H:$2>
1642R<?> $+			$: <> <$1> $| <U:$1@>
1643dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
1644dnl will only return user<@domain when "reversing" the args
1645R<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+To> $| <$2> <>
1646R<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
1647R<?> <$*>		$: @ $1		mark address as no match
1648R<$={Accept}> <$*>	$: @ $2		mark address as no match
1649ifdef(`_DELAY_CHECKS_',`dnl
1650dnl we have to filter these because otherwise they would be interpreted
1651dnl as generic error message...
1652dnl error messages should be "tagged" by prefixing them with error: !
1653dnl that would make a lot of things easier.
1654dnl maybe we should stop checks already here (if SPAM_xyx)?
1655R<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
1656R<REJECT> $*		$#error $@ 5.2.1 $: "550 Mailbox disabled for this recipient"
1657R<DISCARD> $*		$#discard $: discard
1658dnl error tag
1659R<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
1660R<ERROR:$+> $*		$#error $: $1
1661dnl generic error from access map
1662R<$+> $*		$#error $: $1		error from access db
1663R@ $*			$1		remove mark', `dnl')', `dnl')
1664
1665ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)')
1666# authenticated?
1667dnl do this unconditionally? this requires to manage CAs carefully
1668dnl just because someone has a CERT signed by a "trusted" CA
1669dnl does not mean we want to allow relaying for her,
1670dnl either use a subroutine or provide something more sophisticated
1671dnl this could for example check the DN (maybe an access map lookup)
1672R$*		$: $1 $| $>RelayAuth $1 $| $&{verify}	client authenticated?
1673R$* $| $# $+		$# $2				error/ok?
1674R$* $| $*		$: $1				no
1675
1676# authenticated by a trusted mechanism?
1677R$*			$: $1 $| $&{auth_type}
1678dnl empty ${auth_type}?
1679R$* $|			$: $1
1680dnl mechanism ${auth_type} accepted?
1681dnl use $# to override further tests (delay_checks): see check_rcpt below
1682R$* $| $={TrustAuthMech}	$# RELAYAUTH
1683dnl undo addition of ${auth_type}
1684R$* $| $*		$: $1
1685dnl workspace: localpart<@domain>
1686ifelse(defn(`_NO_UUCP_'), `r',
1687`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
1688# anything terminating locally is ok
1689ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
1690R$+ < @ $* $=m >	$@ RELAYTO', `dnl')
1691R$+ < @ $=w >		$@ RELAYTO
1692ifdef(`_RELAY_HOSTS_ONLY_',
1693`R$+ < @ $=R >		$@ RELAYTO
1694ifdef(`_ACCESS_TABLE_', `dnl
1695R$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
1696dnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
1697R<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
1698`R$+ < @ $* $=R >	$@ RELAYTO
1699ifdef(`_ACCESS_TABLE_', `dnl
1700R$+ < @ $+ >		$: $>LookUpDomain <$2> <?> <$1 < @ $2 >> <+To>',`dnl')')
1701ifdef(`_ACCESS_TABLE_', `dnl
1702dnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
1703R<RELAY> $*		$@ RELAYTO
1704R<$*> <$*>		$: $2',`dnl')
1705
1706
1707ifdef(`_RELAY_MX_SERVED_', `dnl
1708# allow relaying for hosts which we MX serve
1709R$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
1710dnl this must not necessarily happen if the client is checked first...
1711R< : $* <TEMP> : > $*	$#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
1712R<$* : $=w . : $*> $*	$@ RELAYTO
1713R< : $* : > $*		$: $2',
1714`dnl')
1715
1716# check for local user (i.e. unqualified address)
1717R$*			$: <?> $1
1718R<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
1719# local user is ok
1720dnl is it really? the standard requires user@domain, not just user
1721dnl but we should accept it anyway (maybe making it an option:
1722dnl RequireFQDN ?)
1723dnl postmaster must be accepted without domain (DRUMS)
1724ifdef(`_REQUIRE_QUAL_RCPT_', `dnl
1725R<?> postmaster		$@ TOPOSTMASTER
1726# require qualified recipient?
1727dnl prepend daemon_flags
1728R<?> $+			$: $&{daemon_flags} $| <?> $1
1729dnl workspace: ${daemon_flags} $| <?> localpart
1730dnl do not allow these at all or only from local systems?
1731dnl r flag? add client_name
1732R$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
1733dnl no r flag: relay to local user (only local part)
1734# no qualified recipient required
1735R$* $| <?> $+		$@ RELAYTOLOCAL
1736dnl client_name is empty
1737R<?> <?> $+		$@ RELAYTOLOCAL
1738dnl client_name is local
1739R<? $=w> <?> $+		$@ RELAYTOLOCAL
1740dnl client_name is not local
1741R<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
1742dnl no qualified recipient required
1743R<?> $+			$@ RELAYTOLOCAL')
1744dnl it is a remote user: remove mark and then check client
1745R<$+> $*		$: $2
1746dnl currently the recipient address is not used below
1747
1748# anything originating locally is ok
1749# check IP address
1750R$*			$: $&{client_addr}
1751R$@			$@ RELAYFROM		originated locally
1752R0			$@ RELAYFROM		originated locally
1753R$=R $*			$@ RELAYFROM		relayable IP address
1754ifdef(`_ACCESS_TABLE_', `dnl
1755R$*			$: $>LookUpAddress <$1> <?> <$1> <+Connect>
1756R<RELAY> $* 		$@ RELAYFROM		relayable IP address
1757R<$*> <$*>		$: $2', `dnl')
1758R$*			$: [ $1 ]		put brackets around it...
1759R$=w			$@ RELAYFROM		... and see if it is local
1760
1761ifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
1762ifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
1763ifdef(`_RELAY_MAIL_FROM_', `dnl
1764dnl input: {client_addr} or something "broken"
1765dnl just throw the input away; we do not need it.
1766# check whether FROM is allowed to use system as relay
1767R$*			$: <?> $>CanonAddr $&f
1768ifdef(`_RELAY_LOCAL_FROM_', `dnl
1769# check whether local FROM is ok
1770R<?> $+ < @ $=w . >	$@ RELAYFROMMAIL	FROM local', `dnl')
1771ifdef(`_RELAY_DB_FROM_', `dnl
1772R<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
1773R<?> $+ < @ $+ >	$: $1 < @ $2 > $| $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<H:$2>') <>
1774R$* <RELAY>		$@ RELAYFROMMAIL	RELAY FROM sender ok', `dnl
1775ifdef(`_RELAY_DB_FROM_DOMAIN_', `errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
1776')',
1777`dnl')
1778dnl')', `dnl')
1779
1780# check client name: first: did it resolve?
1781dnl input: ignored
1782R$*			$: < $&{client_resolve} >
1783R<TEMP>			$#error $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
1784R<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
1785R<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
1786dnl ${client_resolve} should be OK, so go ahead
1787R$*			$: <?> $&{client_name}
1788# pass to name server to make hostname canonical
1789R<?> $* $~P 		$:<?>  $[ $1 $2 $]
1790R$* .			$1			strip trailing dots
1791dnl should not be necessary since it has been done for client_addr already
1792R<?>			$@ RELAYFROM
1793ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
1794R<?> $* $=m		$@ RELAYFROM', `dnl')
1795R<?> $=w		$@ RELAYFROM
1796ifdef(`_RELAY_HOSTS_ONLY_',
1797`R<?> $=R		$@ RELAYFROM
1798ifdef(`_ACCESS_TABLE_', `dnl
1799R<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
1800R<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
1801`R<?> $* $=R			$@ RELAYFROM
1802ifdef(`_ACCESS_TABLE_', `dnl
1803R<?> $*			$: $>LookUpDomain <$1> <?> <$1> <+Connect>',`dnl')')
1804ifdef(`_ACCESS_TABLE_', `dnl
1805R<RELAY> $*		$@ RELAYFROM
1806R<$*> <$*>		$: $2',`dnl')
1807
1808# anything else is bogus
1809R$*			$#error $@ 5.7.1 $: confRELAY_MSG
1810divert(0)
1811ifdef(`_DELAY_CHECKS_',`dnl
1812# turn a canonical address in the form user<@domain>
1813# qualify unqual. addresses with $j
1814dnl it might have been only user (without <@domain>)
1815SFullAddr
1816R$* <@ $+ . >		$1 <@ $2 >
1817R$* <@ $* >		$@ $1 <@ $2 >
1818R$+			$@ $1 <@ $j >
1819
1820# call all necessary rulesets
1821Scheck_rcpt
1822dnl this test should be in the Basic_check_rcpt ruleset
1823dnl which is the correct DSN code?
1824# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
1825R$+			$: $1 $| $>checkrcpt $1
1826dnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
1827R$+ $| $#$*		$#$2
1828R$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
1829ifdef(`_SPAM_FH_',
1830`dnl lookup user@ and user@address
1831ifdef(`_ACCESS_TABLE_', `',
1832`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
1833')')dnl
1834dnl one of the next two rules is supposed to match
1835dnl this code has been copied from BLACKLIST... etc
1836dnl and simplified by omitting some < >.
1837R<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <U: $1@>
1838R<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 >
1839dnl R<?>		$@ something_is_very_wrong_here
1840# lookup the addresses only with To tag
1841R<> $* $| <$+>		$: <@> $1 $| $>SearchList <!To> $| <$2> <>
1842R<@> $* $| $*		$: $2 $1		reverse result
1843dnl', `dnl')
1844ifdef(`_SPAM_FRIEND_',
1845`# is the recipient a spam friend?
1846ifdef(`_SPAM_HATER_',
1847	`errprint(`*** ERROR: define either SpamHater or SpamFriend
1848')', `dnl')
1849R<SPAMFRIEND> $+	$@ SPAMFRIEND
1850R<$*> $+		$: $2',
1851`dnl')
1852ifdef(`_SPAM_HATER_',
1853`# is the recipient no spam hater?
1854R<SPAMHATER> $+		$: $1			spam hater: continue checks
1855R<$*> $+		$@ NOSPAMHATER		everyone else: stop
1856dnl',`dnl')
1857dnl run further checks: check_mail
1858dnl should we "clean up" $&f?
1859R$*			$: $1 $| $>checkmail <$&f>
1860R$* $| $#$*		$#$2
1861dnl run further checks: check_relay
1862R$*			$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
1863R$* $| $#$*		$#$2
1864R$* $| $*		$: $1
1865', `dnl')
1866ifdef(`_ACCESS_TABLE_', `dnl
1867######################################################################
1868###  SearchList: search a list of items in the access map
1869###	Parameters:
1870###		<exact tag> $| <mark:address> <mark:address> ... <>
1871dnl	maybe we should have a @ (again) in front of the mark to
1872dnl	avoid errorneous matches (with error messages?)
1873dnl	if we can make sure that tag is always a single token
1874dnl	then we can omit the delimiter $|, otherwise we need it
1875dnl	to avoid errorneous matchs (first rule: H: if there
1876dnl	is that mark somewhere in the list, it will be taken).
1877dnl	moreover, we can do some tricks to enforce lookup with
1878dnl	the tag only, e.g.:
1879###	where "exact" is either "+" or "!":
1880###	<+ TAG>	lookup with and w/o tag
1881###	<! TAG>	lookup with tag
1882dnl	Warning: + and ! should be in OperatorChars (otherwise there must be
1883dnl		a blank between them and the tag.
1884###	possible values for "mark" are:
1885###		H: recursive host lookup (LookUpDomain)
1886dnl		A: recursive address lookup (LookUpAddress) [not yet required]
1887###		E: exact lookup, no modifications
1888###		F: full lookup, try user+ext@domain and user@domain
1889###		U: user lookup, try user+ext and user (input must have trailing @)
1890###	return: <RHS of lookup> or <?> (not found)
1891######################################################################
1892
1893# class with valid marks for SearchList
1894dnl if A is activated: add it
1895C{src}E F H U
1896SSearchList
1897# mark H: lookup domain
1898R<$+> $| <H:$+> <$*>		$: <$1> $| <@> $>LookUpDomain <$2> <?> <$3> <$1>
1899R<$+> $| <@> <$+> <$*>		$: <$1> $| <$2> <$3>
1900dnl A: NOT YET REQUIRED
1901dnl R<$+> $| <A:$+> <$*>	$: <$1> $| <@> $>LookUpAddress <$2> <?> <$3> <$1>
1902dnl R<$+> $| <@> <$+> <$*>	$: <$1> $| <$2> <$3>
1903dnl lookup of the item with tag
1904dnl this applies to F: U: E:
1905R<$- $-> $| <$={src}:$+> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5>
1906dnl no match, try without tag
1907R<+ $-> $| <$={src}:$+> <$*>	$: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4>
1908dnl do we really have to distinguish these cases?
1909dnl probably yes, there might be a + in the domain part (is that allowed?)
1910dnl user+detail lookups: should it be:
1911dnl user+detail, user+*, user; just like aliases?
1912R<$- $-> $| <F:$* + $*@$+> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@$5 $: F:$3 + $4@$5$)> <$6>
1913R<+ $-> $| <F:$* + $*@$+> <$*>	$: <+ $1> $| <$(access $2@$4 $: F:$2 + $3@$4$)> <$5>
1914dnl user lookups are always with trailing @
1915dnl do not remove the @ from the lookup:
1916dnl it is part of the +detail@ which is omitted for the lookup
1917R<$- $-> $| <U:$* + $*> <$*>	$: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5>
1918dnl no match, try without tag
1919R<+ $-> $| <U:$* + $*> <$*>	$: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4>
1920dnl no match, try rest of list
1921R<$+> $| <$={src}:$+> <$+>	$@ $>SearchList <$1> $| <$4>
1922dnl no match, list empty: return failure
1923R<$+> $| <$={src}:$+> <>	$@ <?>
1924dnl got result, return it
1925R<$+> $| <$+> <$*>		$@ <$2>
1926dnl return result from recursive invocation
1927R<$+> $| <$+>			$@ <$2>', `dnl')
1928
1929# is user trusted to authenticate as someone else?
1930dnl AUTH= parameter from MAIL command
1931Strust_auth
1932R$*			$: $&{auth_type} $| $1
1933# required by RFC 2554 section 4.
1934R$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
1935dnl seems to be useful...
1936R$* $| $&{auth_authen}		$@ identical
1937R$* $| <$&{auth_authen}>	$@ identical
1938dnl call user supplied code
1939R$* $| $*		$: $1 $| $>"Local_trust_auth" $1
1940R$* $| $#$*		$#$2
1941dnl default: error
1942R$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
1943
1944dnl empty ruleset definition so it can be called
1945SLocal_trust_auth
1946
1947ifdef(`_FFR_TLS_O_T', `dnl
1948Soffer_tls
1949R$*		$: $>LookUpDomain <$&{client_name}> <?> <> <! TLS_OFF_TAG>
1950R<?>$*		$: $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_OFF_TAG>
1951R<?>$*		$: <$(access TLS_OFF_TAG: $: ? $)>
1952R<?>$*		$@ OK
1953R<NO> <>	$#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]"
1954
1955Stry_tls
1956R$*		$: $>LookUpDomain <$&{server_name}> <?> <> <! TLS_TRY_TAG>
1957R<?>$*		$: $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_TRY_TAG>
1958R<?>$*		$: <$(access TLS_TRY_TAG: $: ? $)>
1959R<?>$*		$@ OK
1960R<NO> <>	$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
1961')dnl
1962
1963# is connection with client "good" enough? (done in server)
1964# input: ${verify} $| (MAIL|STARTTLS)
1965dnl MAIL: called from check_mail
1966dnl STARTTLS: called from smtp() after STARTTLS has been accepted
1967Stls_client
1968ifdef(`_ACCESS_TABLE_', `dnl
1969dnl ignore second arg for now
1970dnl maybe use it to distinguish permanent/temporary error?
1971dnl if MAIL: permanent (STARTTLS has not been offered)
1972dnl if STARTTLS: temporary (offered but maybe failed)
1973R$* $| $*	$: $1 $| $>LookUpDomain <$&{client_name}> <?> <> <! TLS_CLT_TAG>
1974R$* $| <?>$*	$: $1 $| $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_CLT_TAG>
1975dnl do a default lookup: just TLS_CLT_TAG
1976R$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
1977R$*		$@ $>"tls_connection" $1', `dnl
1978R$* $| $*	$@ $>"tls_connection" $1')
1979
1980# is connection with server "good" enough? (done in client)
1981dnl i.e. has the server been authenticated and is encryption active?
1982dnl called from deliver() after STARTTLS command
1983# input: ${verify}
1984Stls_server
1985ifdef(`_ACCESS_TABLE_', `dnl
1986R$*		$: $1 $| $>LookUpDomain <$&{server_name}> <?> <> <! TLS_SRV_TAG>
1987R$* $| <?>$*	$: $1 $| $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_SRV_TAG>
1988dnl do a default lookup: just TLS_SRV_TAG
1989R$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
1990R$*		$@ $>"tls_connection" $1', `dnl
1991R$*		$@ $>"tls_connection" $1')
1992
1993Stls_connection
1994ifdef(`_ACCESS_TABLE_', `dnl
1995dnl common ruleset for tls_{client|server}
1996dnl input: $&{verify} $| <ResultOfLookup> [<>]
1997dnl remove optional <>
1998R$* $| <$*>$*			$: $1 $| <$2>
1999dnl permanent or temporary error?
2000R$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
2001R$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
2002dnl default case depends on TLS_PERM_ERR
2003R$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
2004dnl deal with TLS handshake failures: abort
2005RSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
2006dnl no <reply:dns> i.e. not requirements in the access map
2007dnl use default error
2008RSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
2009R$* $| <$*> <VERIFY>		$: <$2> <VERIFY> $1
2010R$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> $1
2011dnl some other value in access map: accept
2012dnl this also allows to override the default case (if used)
2013R$* $| $*			$@ OK
2014# authentication required: give appropriate error
2015# other side did authenticate (via STARTTLS)
2016dnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> ${verify}
2017dnl only verification required and it succeeded
2018R<$*><VERIFY> OK		$@ OK
2019dnl verification required + some level of encryption
2020R<$*><VERIFY:$-> OK		$: <$1> <REQ:$2>
2021dnl just some level of encryption required
2022R<$*><ENCR:$-> $*		$: <$1> <REQ:$2>
2023dnl verification required but ${verify} is not set
2024R<$-:$+><VERIFY $*>		$#error $@ $2 $: $1 " authentication required"
2025R<$-:$+><VERIFY $*> FAIL	$#error $@ $2 $: $1 " authentication failed"
2026R<$-:$+><VERIFY $*> NO		$#error $@ $2 $: $1 " not authenticated"
2027R<$-:$+><VERIFY $*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
2028dnl some other value for ${verify}
2029R<$-:$+><VERIFY $*> $+		$#error $@ $2 $: $1 " authentication failure " $4
2030dnl some level of encryption required: get the maximum level
2031R<$*><REQ:$->			$: <$1> <REQ:$2> $>max $&{cipher_bits} : $&{auth_ssf}
2032dnl compare required bits with actual bits
2033R<$*><REQ:$-> $-		$: <$1> <$2:$3> $(arith l $@ $3 $@ $2 $)
2034R<$-:$+><$-:$-> TRUE		$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
2035
2036Smax
2037dnl compute the max of two values separated by :
2038R:		$: 0
2039R:$-		$: $1
2040R$-:		$: $1
2041R$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
2042RTRUE:$-:$-	$: $2
2043R$-:$-:$-	$: $2',
2044`dnl use default error
2045dnl deal with TLS handshake failures: abort
2046RSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."')
2047
2048SRelayAuth
2049# authenticated?
2050dnl we do not allow relaying for anyone who can present a cert
2051dnl signed by a "trusted" CA. For example, even if we put verisigns
2052dnl CA in CERTPath so we can authenticate users, we do not allow
2053dnl them to abuse our server (they might be easier to get hold of,
2054dnl but anyway).
2055dnl so here is the trick: if the verification succeeded
2056dnl we look up the cert issuer in the access map
2057dnl (maybe after extracting a part with a regular expression)
2058dnl if this returns RELAY we relay without further questions
2059dnl if it returns SUBJECT we perform a similar check on the
2060dnl cert subject.
2061R$* $| OK		$: $1
2062R$* $| $*		$@ NO		not authenticated
2063ifdef(`_ACCESS_TABLE_', `dnl
2064ifdef(`_CERT_REGEX_ISSUER_', `dnl
2065R$*			$: $1 $| $(CERTIssuer $&{cert_issuer} $)',
2066`R$*			$: $1 $| $&{cert_issuer}')
2067R$* $| $+		$: $1 $| $(access CERTISSUER:$2 $)
2068dnl use $# to stop further checks (delay_check)
2069R$* $| RELAY		$# RELAYCERTISSUER
2070ifdef(`_CERT_REGEX_SUBJECT_', `dnl
2071R$* $| SUBJECT		$: $1 $| <@> $(CERTSubject $&{cert_subject} $)',
2072`R$* $| SUBJECT		$: $1 $| <@> $&{cert_subject}')
2073R$* $| <@> $+		$: $1 $| <@> $(access CERTSUBJECT:$2 $)
2074R$* $| <@> RELAY	$# RELAYCERTSUBJECT
2075R$* $| $*		$: $1', `dnl')
2076
2077undivert(9)dnl LOCAL_RULESETS
2078ifdef(`_FFR_MILTER', `
2079#
2080######################################################################
2081######################################################################
2082#####
2083`#####			MAIL FILTER DEFINITIONS'
2084#####
2085######################################################################
2086######################################################################
2087_MAIL_FILTERS_')
2088#
2089######################################################################
2090######################################################################
2091#####
2092`#####			MAILER DEFINITIONS'
2093#####
2094######################################################################
2095######################################################################
2096undivert(7)dnl MAILER_DEFINITIONS
2097
2098