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