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