proto.m4 revision 90792
1divert(-1)
2#
3# Copyright (c) 1998-2001 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.628 2001/12/28 19:02:40 ca Exp $')
17
18# level CF_LEVEL config file format
19V`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley')
20divert(-1)
21
22dnl if MAILER(`local') not defined: do it ourself; be nice
23dnl maybe we should issue a warning?
24ifdef(`_MAILER_local_',`', `MAILER(local)')
25
26# do some sanity checking
27ifdef(`__OSTYPE__',,
28	`errprint(`*** ERROR: No system type defined (use OSTYPE macro)
29')')
30
31# pick our default mailers
32ifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')')
33ifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')')
34ifdef(`confRELAY_MAILER',,
35	`define(`confRELAY_MAILER',
36		`ifdef(`_MAILER_smtp_', `relay',
37			`ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')')
38ifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')')
39define(`_SMTP_', `confSMTP_MAILER')dnl		for readability only
40define(`_LOCAL_', `confLOCAL_MAILER')dnl	for readability only
41define(`_RELAY_', `confRELAY_MAILER')dnl	for readability only
42define(`_UUCP_', `confUUCP_MAILER')dnl		for readability only
43
44# back compatibility with old config files
45ifdef(`confDEF_GROUP_ID',
46`errprint(`*** confDEF_GROUP_ID is obsolete.
47    Use confDEF_USER_ID with a colon in the value instead.
48')')
49ifdef(`confREAD_TIMEOUT',
50`errprint(`*** confREAD_TIMEOUT is obsolete.
51    Use individual confTO_<timeout> parameters instead.
52')')
53ifdef(`confMESSAGE_TIMEOUT',
54	`define(`_ARG_', index(confMESSAGE_TIMEOUT, /))
55	 ifelse(_ARG_, -1,
56		`define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)',
57		`define(`confTO_QUEUERETURN',
58			substr(confMESSAGE_TIMEOUT, 0, _ARG_))
59		 define(`confTO_QUEUEWARN',
60			substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')')
61ifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,,
62`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete.
63    Use confMAX_MESSAGE_SIZE for the second part of the value.
64')')')
65
66
67# Sanity check on ldap_routing feature
68# If the user doesn't specify a new map, they better have given as a
69# default LDAP specification which has the LDAP base (and most likely the host)
70ifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(`
71WARNING: Using default FEATURE(ldap_routing) map definition(s)
72without setting confLDAP_DEFAULT_SPEC option.
73')')')dnl
74
75# clean option definitions below....
76define(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl
77
78dnl required to "rename" the check_* rulesets...
79define(`_U_',ifdef(`_DELAY_CHECKS_',`',`_'))
80dnl default relaying denied message
81ifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG',
82ifdef(`_USE_AUTH_', `"550 Relaying denied. Proper authentication required."', `"550 Relaying denied"'))')
83ifdef(`confRCPTREJ_MSG', `', `define(`confRCPTREJ_MSG', `"550 Mailbox disabled for this recipient"')')
84define(`_CODE553', `553')
85divert(0)dnl
86
87# override file safeties - setting this option compromises system security,
88# addressing the actual file configuration problem is preferred
89# need to set this before any file actions are encountered in the cf file
90_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe')
91
92# default LDAP map specification
93# need to set this now before any LDAP maps are defined
94_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost')
95
96##################
97#   local info   #
98##################
99
100# my LDAP cluster
101# need to set this before any LDAP lookups are done (including classes)
102ifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m')
103
104Cwlocalhost
105ifdef(`USE_CW_FILE',
106`# file containing names of hosts for which we receive email
107Fw`'confCW_FILE',
108	`dnl')
109
110# my official domain name
111# ... `define' this only if sendmail cannot automatically determine your domain
112ifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM')
113
114CP.
115
116ifdef(`UUCP_RELAY',
117`# UUCP relay host
118DY`'UUCP_RELAY
119CPUUCP
120
121')dnl
122ifdef(`BITNET_RELAY',
123`#  BITNET relay host
124DB`'BITNET_RELAY
125CPBITNET
126
127')dnl
128ifdef(`DECNET_RELAY',
129`define(`_USE_DECNET_SYNTAX_', 1)dnl
130# DECnet relay host
131DC`'DECNET_RELAY
132CPDECNET
133
134')dnl
135ifdef(`FAX_RELAY',
136`# FAX relay host
137DF`'FAX_RELAY
138CPFAX
139
140')dnl
141# "Smart" relay host (may be null)
142DS`'ifdef(`SMART_HOST', `SMART_HOST')
143
144ifdef(`LUSER_RELAY', `dnl
145# place to which unknown users should be forwarded
146Kuser user -m -a<>
147DL`'LUSER_RELAY',
148`dnl')
149
150# operators that cannot be in local usernames (i.e., network indicators)
151CO @ % ifdef(`_NO_UUCP_', `', `!')
152
153# a class with just dot (for identifying canonical names)
154C..
155
156# a class with just a left bracket (for identifying domain literals)
157C[[
158
159ifdef(`_ACCESS_TABLE_', `dnl
160# access_db acceptance class
161C{Accept}OK RELAY
162ifdef(`_DELAY_COMPAT_8_10_',`dnl
163ifdef(`_BLACKLIST_RCPT_',`dnl
164# possible access_db RHS for spam friends/haters
165C{SpamTag}SPAMFRIEND SPAMHATER')')',
166`dnl')
167
168dnl mark for "domain is ok" (resolved or accepted anyway)
169define(`_RES_OK_', `OKR')dnl
170ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
171# Resolve map (to check if a host exists in check_mail)
172Kresolve host -a<_RES_OK_> -T<TEMP>')
173C{ResOk}_RES_OK_
174
175ifdef(`_NEED_MACRO_MAP_', `dnl
176ifdef(`_MACRO_MAP_', `', `# macro storage map
177define(`_MACRO_MAP_', `1')dnl
178Kmacro macro')', `dnl')
179
180ifdef(`confCR_FILE', `dnl
181# Hosts for which relaying is permitted ($=R)
182FR`'confCR_FILE',
183`dnl')
184
185define(`TLS_SRV_TAG', `"TLS_Srv"')dnl
186define(`TLS_CLT_TAG', `"TLS_Clt"')dnl
187define(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl
188define(`TLS_TRY_TAG', `"Try_TLS"')dnl
189define(`SRV_FEAT_TAG', `"Srv_Features"')dnl
190dnl this may be useful in other contexts too
191ifdef(`_ARITH_MAP_', `', `# arithmetic map
192define(`_ARITH_MAP_', `1')dnl
193Karith arith')
194ifdef(`_ACCESS_TABLE_', `dnl
195ifdef(`_MACRO_MAP_', `', `# macro storage map
196define(`_MACRO_MAP_', `1')dnl
197Kmacro macro')
198# possible values for TLS_connection in access map
199C{tls}VERIFY ENCR', `dnl')
200ifdef(`_CERT_REGEX_ISSUER_', `dnl
201# extract relevant part from cert issuer
202KCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
203ifdef(`_CERT_REGEX_SUBJECT_', `dnl
204# extract relevant part from cert subject
205KCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
206
207ifdef(`LOCAL_RELAY', `dnl
208# who I send unqualified names to (null means deliver locally)
209DR`'LOCAL_RELAY')
210
211ifdef(`MAIL_HUB', `dnl
212# who gets all local email traffic ($R has precedence for unqualified names)
213DH`'MAIL_HUB')
214
215# dequoting map
216Kdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `')
217
218divert(0)dnl	# end of nullclient diversion
219# class E: names that should be exposed as from this host, even if we masquerade
220# class L: names that should be delivered locally, even if we have a relay
221# class M: domains that should be converted to $M
222# class N: domains that should not be converted to $M
223#CL root
224undivert(5)dnl
225ifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
226
227ifdef(`MASQUERADE_NAME', `dnl
228# who I masquerade as (null for no masquerading) (see also $=M)
229DM`'MASQUERADE_NAME')
230
231# my name for error messages
232ifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
233
234undivert(6)dnl LOCAL_CONFIG
235include(_CF_DIR_`m4/version.m4')
236
237###############
238#   Options   #
239###############
240ifdef(`confAUTO_REBUILD',
241`errprint(WARNING: `confAUTO_REBUILD' is no longer valid.
242	There was a potential for a denial of service attack if this is set.
243)')dnl
244
245# strip message body to 7 bits on input?
246_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
247
248# 8-bit data handling
249_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8')
250
251# wait for alias file rebuild (default units: minutes)
252_OPTION(AliasWait, `confALIAS_WAIT', `5m')
253
254# location of alias file
255_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
256
257# minimum number of free blocks on filesystem
258_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
259
260# maximum message size
261_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000')
262
263# substitution for space (blank) characters
264_OPTION(BlankSub, `confBLANK_SUB', `_')
265
266# avoid connecting to "expensive" mailers on initial submission?
267_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
268
269# checkpoint queue runs after every N successful deliveries
270_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
271
272# default delivery mode
273_OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
274
275# error message header/file
276_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
277
278# error mode
279_OPTION(ErrorMode, `confERROR_MODE', `print')
280
281# save Unix-style "From_" lines at top of header?
282_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
283
284# queue file mode (qf files)
285_OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600')
286
287# temporary file mode
288_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
289
290# match recipients against GECOS field?
291_OPTION(MatchGECOS, `confMATCH_GECOS', `False')
292
293# maximum hop count
294_OPTION(MaxHopCount, `confMAX_HOP', `25')
295
296# location of help file
297O HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
298
299# ignore dots as terminators in incoming messages?
300_OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
301
302# name resolver options
303_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
304
305# deliver MIME-encapsulated error messages?
306_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
307
308# Forward file search path
309_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
310
311# open connection cache size
312_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
313
314# open connection cache timeout
315_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
316
317# persistent host status directory
318_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
319
320# single thread deliveries (requires HostStatusDirectory)?
321_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
322
323# use Errors-To: header?
324_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
325
326# log level
327_OPTION(LogLevel, `confLOG_LEVEL', `10')
328
329# send to me too, even in an alias expansion?
330_OPTION(MeToo, `confME_TOO', `True')
331
332# verify RHS in newaliases?
333_OPTION(CheckAliases, `confCHECK_ALIASES', `False')
334
335# default messages to old style headers if no special punctuation?
336_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
337
338# SMTP daemon options
339ifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
340`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.  See cf/README for more information.
341)'dnl
342`DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
343ifelse(defn(`_DPO_'), `',
344`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet
345O DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
346ifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
347
348# SMTP client options
349ifelse(defn(`confCLIENT_OPTIONS'), `', `dnl',
350`errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid.  See cf/README for more information.
351)'dnl
352`CLIENT_OPTIONS(`confCLIENT_OPTIONS')')
353ifelse(defn(`_CPO_'), `',
354`#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_')
355
356# Modifiers to `define' {daemon_flags} for direct submissions
357_OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `')
358
359# Use as mail submission program? See sendmail/SECURITY
360_OPTION(UseMSP, `confUSE_MSP', `')
361
362# privacy flags
363_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
364
365# who (if anyone) should get extra copies of error messages
366_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
367
368# slope of queue-only function
369_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
370
371# limit on number of concurrent queue runners
372_OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `')
373
374# maximum number of queue-runners per queue-grouping with multiple queues
375_OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1')
376
377# priority of queue runners (nice(3))
378_OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `')
379
380# shall we sort the queue by hostname first?
381_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
382
383# minimum time in queue before retry
384_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
385
386# how many jobs can you process in the queue?
387_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000')
388
389# perform initial split of envelope without checking MX records
390_OPTION(FastSplit, `confFAST_SPLIT', `1')
391
392# queue directory
393O QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
394
395# key for shared memory; 0 to turn off
396_OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
397
398# timeouts (many of these)
399_OPTION(Timeout.initial, `confTO_INITIAL', `5m')
400_OPTION(Timeout.connect, `confTO_CONNECT', `5m')
401_OPTION(Timeout.aconnect, `confTO_ACONNECT', `0s')
402_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m')
403_OPTION(Timeout.helo, `confTO_HELO', `5m')
404_OPTION(Timeout.mail, `confTO_MAIL', `10m')
405_OPTION(Timeout.rcpt, `confTO_RCPT', `1h')
406_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m')
407_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h')
408_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h')
409_OPTION(Timeout.rset, `confTO_RSET', `5m')
410_OPTION(Timeout.quit, `confTO_QUIT', `2m')
411_OPTION(Timeout.misc, `confTO_MISC', `2m')
412_OPTION(Timeout.command, `confTO_COMMAND', `1h')
413_OPTION(Timeout.ident, `confTO_IDENT', `5s')
414_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s')
415_OPTION(Timeout.control, `confTO_CONTROL', `2m')
416_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d')
417_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d')
418_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d')
419_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d')
420_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
421_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
422_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
423_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
424_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
425_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
426_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
427_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
428_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
429_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
430_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
431_OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
432_OPTION(Timeout.auth, `confTO_AUTH', `10m')
433_OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
434
435# time for DeliverBy; extension disabled if less than 0
436_OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
437
438# should we not prune routes in route-addr syntax addresses?
439_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
440
441# queue up everything before forking?
442_OPTION(SuperSafe, `confSAFE_QUEUE', `True')
443
444# status file
445O StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics')
446
447# time zone handling:
448#  if undefined, use system default
449#  if defined but null, use TZ envariable passed in
450#  if defined and non-null, use that info
451ifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
452	confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
453	`O TimeZoneSpec=confTIME_ZONE')
454
455# default UID (can be username or userid:groupid)
456_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
457
458# list of locations of user database file (null means no lookup)
459_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
460
461# fallback MX host
462_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
463
464# if we are the best MX host for a site, try it directly instead of config err
465_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
466
467# load average at which we just queue messages
468_OPTION(QueueLA, `confQUEUE_LA', `8')
469
470# load average at which we refuse connections
471_OPTION(RefuseLA, `confREFUSE_LA', `12')
472
473# load average at which we delay connections; 0 means no limit
474_OPTION(DelayLA, `confDELAY_LA', `0')
475
476# maximum number of children we allow at one time
477_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12')
478
479# maximum number of new connections per second
480_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
481
482# work recipient factor
483_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
484
485# deliver each queued job in a separate process?
486_OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
487
488# work class factor
489_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
490
491# work time factor
492_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
493
494# default character set
495_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1')
496
497# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
498_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
499
500# hosts file (normally /etc/hosts)
501_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
502
503# dialup line delay on connection failure
504_OPTION(DialDelay, `confDIAL_DELAY', `10s')
505
506# action to take if there are no recipients in the message
507_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed')
508
509# chrooted environment for writing to files
510_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch')
511
512# are colons OK in addresses?
513_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
514
515# shall I avoid expanding CNAMEs (violates protocols)?
516_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
517
518# SMTP initial login message (old $e macro)
519_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
520
521# UNIX initial From header format (old $l macro)
522_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
523
524# From: lines that have embedded newlines are unwrapped onto one line
525_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
526
527# Allow HELO SMTP command that does not `include' a host name
528_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
529
530# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
531_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
532
533# delimiter (operator) characters (old $o macro)
534_OPTION(OperatorChars, `confOPERATORS', `.:@[]')
535
536# shall I avoid calling initgroups(3) because of high NIS costs?
537_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
538
539# are group-writable `:include:' and .forward files (un)trustworthy?
540# True (the default) means they are not trustworthy.
541_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
542ifdef(`confUNSAFE_GROUP_WRITES',
543`errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
544')')
545
546# where do errors that occur when sending errors get sent?
547_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
548
549# where to save bounces if all else fails
550_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
551
552# what user id do we assume for the majority of the processing?
553_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
554
555# maximum number of recipients per SMTP envelope
556_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100')
557
558# limit the rate recipients per SMTP envelope are accepted
559# once the threshold number of recipients have been rejected
560_OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `20')
561
562# shall we get local names from our installed interfaces?
563_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
564
565# Return-Receipt-To: header implies DSN request
566_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
567
568# override connection address (for testing)
569_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
570
571# Trusted user for file ownership and starting the daemon
572_OPTION(TrustedUser, `confTRUSTED_USER', `root')
573
574# Control socket for daemon management
575_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
576
577# Maximum MIME header length to protect MUAs
578_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
579
580# Maximum length of the sum of all headers
581_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
582
583# Maximum depth of alias recursion
584_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
585
586# location of pid file
587_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
588
589# Prefix string for the process title shown on 'ps' listings
590_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
591
592# Data file (df) memory-buffer file maximum size
593_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
594
595# Transcript file (xf) memory-buffer file maximum size
596_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
597
598# lookup type to find information about local mailboxes
599_OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
600
601# list of authentication mechanisms
602_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
603
604# default authentication information for outgoing connections
605_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
606
607# SMTP AUTH flags
608_OPTION(AuthOptions, `confAUTH_OPTIONS', `')
609
610# SMTP AUTH maximum encryption strength
611_OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
612
613# SMTP STARTTLS server options
614_OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
615
616# Input mail filters
617_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
618
619ifdef(`confINPUT_MAIL_FILTERS', `dnl
620# Milter options
621_OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
622_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
623_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
624_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
625_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')')
626
627# CA directory
628_OPTION(CACERTPath, `confCACERT_PATH', `')
629# CA file
630_OPTION(CACERTFile, `confCACERT', `')
631# Server Cert
632_OPTION(ServerCertFile, `confSERVER_CERT', `')
633# Server private key
634_OPTION(ServerKeyFile, `confSERVER_KEY', `')
635# Client Cert
636_OPTION(ClientCertFile, `confCLIENT_CERT', `')
637# Client private key
638_OPTION(ClientKeyFile, `confCLIENT_KEY', `')
639# DHParameters (only required if DSA/DH is used)
640_OPTION(DHParameters, `confDH_PARAMETERS', `')
641# Random data source (required for systems without /dev/urandom under OpenSSL)
642_OPTION(RandFile, `confRAND_FILE', `')
643
644############################
645`# QUEUE GROUP DEFINITIONS  #'
646############################
647_QUEUE_GROUP_
648
649###########################
650#   Message precedences   #
651###########################
652
653Pfirst-class=0
654Pspecial-delivery=100
655Plist=-30
656Pbulk=-60
657Pjunk=-100
658
659#####################
660#   Trusted users   #
661#####################
662
663# this is equivalent to setting class "t"
664ifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
665Troot
666Tdaemon
667ifdef(`_NO_UUCP_', `dnl', `Tuucp')
668ifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
669
670#########################
671#   Format of headers   #
672#########################
673
674ifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
675H?P?Return-Path: <$g>
676HReceived: confRECEIVED_HEADER
677H?D?Resent-Date: $a
678H?D?Date: $a
679H?F?Resent-From: confFROM_HEADER
680H?F?From: confFROM_HEADER
681H?x?Full-Name: $x
682# HPosted-Date: $a
683# H?l?Received-Date: $b
684H?M?Resent-Message-Id: <$t.$i@$j>
685H?M?Message-Id: <$t.$i@$j>
686
687#
688######################################################################
689######################################################################
690#####
691#####			REWRITING RULES
692#####
693######################################################################
694######################################################################
695
696############################################
697###  Ruleset 3 -- Name Canonicalization  ###
698############################################
699Scanonify=3
700
701# handle null input (translate to <@> special case)
702R$@			$@ <@>
703
704# strip group: syntax (not inside angle brackets!) and trailing semicolon
705R$*			$: $1 <@>			mark addresses
706R$* < $* > $* <@>	$: $1 < $2 > $3			unmark <addr>
707R@ $* <@>		$: @ $1				unmark @host:...
708R$* [ IPv6 : $+ ] <@>	$: $1 [ IPv6 : $2 ]		unmark IPv6 addr
709R$* :: $* <@>		$: $1 :: $2			unmark node::addr
710R:`include': $* <@>	$: :`include': $1			unmark :`include':...
711R$* : $* [ $* ]		$: $1 : $2 [ $3 ] <@>		remark if leading colon
712R$* : $* <@>		$: $2				strip colon if marked
713R$* <@>			$: $1				unmark
714R$* ;			   $1				strip trailing semi
715R$* < $+ :; > $*	$@ $2 :; <@>			catch <list:;>
716R$* < $* ; >		   $1 < $2 >			bogus bracketed semi
717
718# null input now results from list:; syntax
719R$@			$@ :; <@>
720
721# strip angle brackets -- note RFC733 heuristic to get innermost item
722R$*			$: < $1 >			housekeeping <>
723R$+ < $* >		   < $2 >			strip excess on left
724R< $* > $+		   < $1 >			strip excess on right
725R<>			$@ < @ >			MAIL FROM:<> case
726R< $+ >			$: $1				remove housekeeping <>
727
728ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
729# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
730R@ $+ , $+		@ $1 : $2			change all "," to ":"
731
732# localize and dispose of route-based addresses
733dnl XXX: IPv6 colon conflict
734ifdef(`NO_NETINET6', `dnl',
735`R@ [$+] : $+		$@ $>Canonify2 < @ [$1] > : $2	handle <route-addr>')
736R@ $+ : $+		$@ $>Canonify2 < @$1 > : $2	handle <route-addr>
737dnl',`dnl
738# strip route address <@a,@b,@c:user@d> -> <user@d>
739R@ $+ , $+		$2
740ifdef(`NO_NETINET6', `dnl',
741`R@ [ $* ] : $+		$2')
742R@ $+ : $+		$2
743dnl')
744
745# find focus for list syntax
746R $+ : $* ; @ $+	$@ $>Canonify2 $1 : $2 ; < @ $3 >	list syntax
747R $+ : $* ;		$@ $1 : $2;			list syntax
748
749# find focus for @ syntax addresses
750R$+ @ $+		$: $1 < @ $2 >			focus on domain
751R$+ < $+ @ $+ >		$1 $2 < @ $3 >			move gaze right
752R$+ < @ $+ >		$@ $>Canonify2 $1 < @ $2 >	already canonical
753
754dnl This is flagged as an error in S0; no need to silently fix it here.
755dnl # do some sanity checking
756dnl R$* < @ $~[ $* : $* > $*	$1 < @ $2 $3 > $4	nix colons in addrs
757
758ifdef(`_NO_UUCP_', `dnl',
759`# convert old-style addresses to a domain-based address
760R$- ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	resolve uucp names
761R$+ . $- ! $+		$@ $>Canonify2 $3 < @ $1 . $2 >		domain uucps
762R$+ ! $+		$@ $>Canonify2 $2 < @ $1 .UUCP >	uucp subdomains
763')
764ifdef(`_USE_DECNET_SYNTAX_',
765`# convert node::user addresses into a domain-based address
766R$- :: $+		$@ $>Canonify2 $2 < @ $1 .DECNET >	resolve DECnet names
767R$- . $- :: $+		$@ $>Canonify2 $3 < @ $1.$2 .DECNET >	numeric DECnet addr
768',
769	`dnl')
770# if we have % signs, take the rightmost one
771R$* % $*		$1 @ $2				First make them all @s.
772R$* @ $* @ $*		$1 % $2 @ $3			Undo all but the last.
773R$* @ $*		$@ $>Canonify2 $1 < @ $2 >	Insert < > and finish
774
775# else we must be a local name
776R$*			$@ $>Canonify2 $1
777
778
779################################################
780###  Ruleset 96 -- bottom half of ruleset 3  ###
781################################################
782
783SCanonify2=96
784
785# handle special cases for local names
786R$* < @ localhost > $*		$: $1 < @ $j . > $2		no domain at all
787R$* < @ localhost . $m > $*	$: $1 < @ $j . > $2		local domain
788ifdef(`_NO_UUCP_', `dnl',
789`R$* < @ localhost . UUCP > $*	$: $1 < @ $j . > $2		.UUCP domain')
790
791# check for IPv4/IPv6 domain literal
792R$* < @ [ $+ ] > $*		$: $1 < @@ [ $2 ] > $3		mark [addr]
793R$* < @@ $=w > $*		$: $1 < @ $j . > $3		self-literal
794R$* < @@ $+ > $*		$@ $1 < @ $2 > $3		canon IP addr
795
796ifdef(`_DOMAIN_TABLE_', `dnl
797# look up domains in the domain table
798R$* < @ $+ > $* 		$: $1 < @ $(domaintable $2 $) > $3', `dnl')
799
800undivert(2)dnl LOCAL_RULE_3
801
802ifdef(`_BITDOMAIN_TABLE_', `dnl
803# handle BITNET mapping
804R$* < @ $+ .BITNET > $*		$: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
805
806ifdef(`_UUDOMAIN_TABLE_', `dnl
807# handle UUCP mapping
808R$* < @ $+ .UUCP > $*		$: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
809
810ifdef(`_NO_UUCP_', `dnl',
811`ifdef(`UUCP_RELAY',
812`# pass UUCP addresses straight through
813R$* < @ $+ . UUCP > $*		$@ $1 < @ $2 . UUCP . > $3',
814`# if really UUCP, handle it immediately
815ifdef(`_CLASS_U_',
816`R$* < @ $=U . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
817ifdef(`_CLASS_V_',
818`R$* < @ $=V . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
819ifdef(`_CLASS_W_',
820`R$* < @ $=W . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
821ifdef(`_CLASS_X_',
822`R$* < @ $=X . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
823ifdef(`_CLASS_Y_',
824`R$* < @ $=Y . UUCP > $*	$@ $1 < @ $2 . UUCP . > $3', `dnl')
825
826ifdef(`_NO_CANONIFY_', `dnl', `dnl
827# try UUCP traffic as a local address
828R$* < @ $+ . UUCP > $*		$: $1 < @ $[ $2 $] . UUCP . > $3
829R$* < @ $+ . . UUCP . > $*	$@ $1 < @ $2 . > $3')
830')')
831# hostnames ending in class P are always canonical
832R$* < @ $* $=P > $*		$: $1 < @ $2 $3 . > $4
833dnl apply the next rule only for hostnames not in class P
834dnl this even works for phrases in class P since . is in class P
835dnl which daemon flags are set?
836R$* < @ $* $~P > $*		$: $&{daemon_flags} $| $1 < @ $2 $3 > $4
837dnl the other rules in this section only apply if the hostname
838dnl does not end in class P hence no further checks are done here
839dnl if this ever changes make sure the lookups are "protected" again!
840ifdef(`_NO_CANONIFY_', `dnl
841dnl do not canonify unless:
842dnl domain ends in class {Canonify} (this does not work if the intersection
843dnl	with class P is non-empty)
844dnl or {daemon_flags} has c set
845# pass to name server to make hostname canonical if in class {Canonify}
846R$* $| $* < @ $* $={Canonify} > $*	$: $2 < @ $[ $3 $4 $] > $5
847# pass to name server to make hostname canonical if requested
848R$* c $* $| $* < @ $* > $*	$: $3 < @ $[ $4 $] > $5
849dnl trailing dot? -> do not apply _CANONIFY_HOSTS_
850R$* $| $* < @ $+ . > $*		$: $2 < @ $3 . > $4
851# add a trailing dot to qualified hostnames so other rules will work
852R$* $| $* < @ $+.$+ > $*	$: $2 < @ $3.$4 . > $5
853ifdef(`_CANONIFY_HOSTS_', `dnl
854dnl this should only apply to unqualified hostnames
855dnl but if a valid character inside an unqualified hostname is an OperatorChar
856dnl then $- does not work.
857# lookup unqualified hostnames
858R$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
859dnl _NO_CANONIFY_ is not set: canonify unless:
860dnl {daemon_flags} contains CC (do not canonify)
861dnl but add a trailing dot to qualified hostnames so other rules will work
862dnl should we do this for every hostname: even unqualified?
863R$* CC $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
864R$* CC $* $| $*			$: $3
865ifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
866# do not canonify header addresses
867R$* $| $* < @ $* $~P > $*	$: $&{addr_type} $| $2 < @ $3 $4 > $5
868R$* h $* $| $* < @ $+.$+ > $*	$: $3 < @ $4.$5 . > $6
869R$* h $* $| $*			$: $3', `dnl')
870# pass to name server to make hostname canonical
871R$* $| $* < @ $* > $*		$: $2 < @ $[ $3 $] > $4')
872dnl remove {daemon_flags} for other cases
873R$* $| $*			$: $2
874
875# local host aliases and pseudo-domains are always canonical
876R$* < @ $=w > $*		$: $1 < @ $2 . > $3
877ifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
878`R$* < @ $* $=M > $*		$: $1 < @ $2 $3 . > $4',
879`R$* < @ $=M > $*		$: $1 < @ $2 . > $3')
880ifdef(`_VIRTUSER_TABLE_', `dnl
881dnl virtual hosts are also canonical
882ifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
883`R$* < @ $* $={VirtHost} > $* 	$: $1 < @ $2 $3 . > $4',
884`R$* < @ $={VirtHost} > $* 	$: $1 < @ $2 . > $3')',
885`dnl')
886ifdef(`_GENERICS_TABLE_', `dnl
887dnl hosts for genericstable are also canonical
888ifdef(`_GENERICS_ENTIRE_DOMAIN_',
889`R$* < @ $* $=G > $* 	$: $1 < @ $2 $3 . > $4',
890`R$* < @ $=G > $* 	$: $1 < @ $2 . > $3')',
891`dnl')
892dnl remove superfluous dots (maybe repeatedly) which may have been added
893dnl by one of the rules before
894R$* < @ $* . . > $*		$1 < @ $2 . > $3
895
896
897##################################################
898###  Ruleset 4 -- Final Output Post-rewriting  ###
899##################################################
900Sfinal=4
901
902R$+ :; <@>		$@ $1 :				handle <list:;>
903R$* <@>			$@				handle <> and list:;
904
905# strip trailing dot off possibly canonical name
906R$* < @ $+ . > $*	$1 < @ $2 > $3
907
908# eliminate internal code
909R$* < @ *LOCAL* > $*	$1 < @ $j > $2
910
911# externalize local domain info
912R$* < $+ > $*		$1 $2 $3			defocus
913R@ $+ : @ $+ : $+	@ $1 , @ $2 : $3		<route-addr> canonical
914R@ $*			$@ @ $1				... and exit
915
916ifdef(`_NO_UUCP_', `dnl',
917`# UUCP must always be presented in old form
918R$+ @ $- . UUCP		$2!$1				u@h.UUCP => h!u')
919
920ifdef(`_USE_DECNET_SYNTAX_',
921`# put DECnet back in :: form
922R$+ @ $+ . DECNET	$2 :: $1			u@h.DECNET => h::u',
923	`dnl')
924# delete duplicate local names
925R$+ % $=w @ $=w		$1 @ $2				u%host@host => u@host
926
927
928
929##############################################################
930###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
931###		   (used for recursive calls)		   ###
932##############################################################
933
934SRecurse=97
935R$*			$: $>canonify $1
936R$*			$@ $>parse $1
937
938
939######################################
940###   Ruleset 0 -- Parse Address   ###
941######################################
942
943Sparse=0
944
945R$*			$: $>Parse0 $1		initial parsing
946R<@>			$#_LOCAL_ $: <@>		special case error msgs
947R$*			$: $>ParseLocal $1	handle local hacks
948R$*			$: $>Parse1 $1		final parsing
949
950#
951#  Parse0 -- do initial syntax checking and eliminate local addresses.
952#	This should either return with the (possibly modified) input
953#	or return with a #error mailer.  It should not return with a
954#	#mailer other than the #error mailer.
955#
956
957SParse0
958R<@>			$@ <@>			special case error msgs
959R$* : $* ; <@>		$#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
960R@ <@ $* >		< @ $1 >		catch "@@host" bogosity
961R<@ $+>			$#error $@ 5.1.3 $: "_CODE553 User address required"
962R$+ <@>			$#error $@ 5.1.3 $: "_CODE553 Hostname required"
963R$*			$: <> $1
964dnl allow tricks like [host1]:[host2]
965R<> $* < @ [ $* ] : $+ > $*	$1 < @ [ $2 ] : $3 > $4
966R<> $* < @ [ $* ] , $+ > $*	$1 < @ [ $2 ] , $3 > $4
967dnl but no a@[b]c
968R<> $* < @ [ $* ] $+ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid address"
969R<> $* < @ [ $+ ] > $*		$1 < @ [ $2 ] > $3
970R<> $* <$* : $* > $*	$#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
971R<> $*			$1
972R$* < @ . $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
973R$* < @ $* .. $* > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid host name"
974dnl no a@b@
975R$* < @ $* @ > $*	$#error $@ 5.1.2 $: "_CODE553 Invalid route address"
976dnl no a@b@c
977R$* @ $* < @ $* > $*	$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
978dnl comma only allowed before @; this check is not complete
979R$* , $~O $*		$#error $@ 5.1.3 $: "_CODE553 Invalid route address"
980
981ifdef(`_STRICT_RFC821_', `# more RFC 821 checks
982R$* . < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
983R. $* < @ $* > $*	$#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
984dnl', `dnl')
985
986# now delete the local info -- note $=O to find characters that cause forwarding
987R$* < @ > $*		$@ $>Parse0 $>canonify $1	user@ => user
988R< @ $=w . > : $*	$@ $>Parse0 $>canonify $2	@here:... -> ...
989R$- < @ $=w . >		$: $(dequote $1 $) < @ $2 . >	dequote "foo"@here
990R< @ $+ >		$#error $@ 5.1.3 $: "_CODE553 User address required"
991R$* $=O $* < @ $=w . >	$@ $>Parse0 $>canonify $1 $2 $3	...@here -> ...
992R$- 			$: $(dequote $1 $) < @ *LOCAL* >	dequote "foo"
993R< @ *LOCAL* >		$#error $@ 5.1.3 $: "_CODE553 User address required"
994R$* $=O $* < @ *LOCAL* >
995			$@ $>Parse0 $>canonify $1 $2 $3	...@*LOCAL* -> ...
996R$* < @ *LOCAL* >	$: $1
997
998#
999#  Parse1 -- the bottom half of ruleset 0.
1000#
1001
1002SParse1
1003ifdef(`_LDAP_ROUTING_', `dnl
1004# handle LDAP routing for hosts in $={LDAPRoute}
1005R$+ < @ $={LDAPRoute} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
1006R$+ < @ $={LDAPRouteEquiv} . >	$: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
1007`dnl')
1008
1009ifdef(`_MAILER_smtp_',
1010`# handle numeric address spec
1011dnl there is no check whether this is really an IP number
1012R$* < @ [ $+ ] > $*	$: $>ParseLocal $1 < @ [ $2 ] > $3	numeric internet spec
1013R$* < @ [ $+ ] > $*	$1 < @ [ $2 ] : $S > $3		Add smart host to path
1014R$* < @ [ $+ ] : > $*		$#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3	no smarthost: send
1015R$* < @ [ $+ ] : $- : $*> $*	$#$3 $@ $4 $: $1 < @ [$2] > $5	smarthost with mailer
1016R$* < @ [ $+ ] : $+ > $*	$#_SMTP_ $@ $3 $: $1 < @ [$2] > $4	smarthost without mailer',
1017	`dnl')
1018
1019ifdef(`_VIRTUSER_TABLE_', `dnl
1020# handle virtual users
1021ifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
1022dnl this is not a documented option
1023dnl it stops looping in virtusertable mapping if input and output
1024dnl are identical, i.e., if address A is mapped to A.
1025dnl it does not deal with multi-level recursion
1026# handle full domains in RHS of virtusertable
1027R$+ < @ $+ >			$: $(macro {RecipientAddress} $) $1 < @ $2 >
1028R$+ < @ $+ > 			$: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
1029R<?> $+ $| $+			$: $1 $(macro {RecipientAddress} $@ $2 $)
1030R<?> $+ $| $*			$: $1',
1031`dnl')
1032R$+			$: <!> $1		Mark for lookup
1033dnl input: <!> local<@domain>
1034ifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
1035`R<!> $+ < @ $* $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
1036`R<!> $+ < @ $={VirtHost} . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
1037dnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
1038R<!> $+ < @ $=w . > 	$: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
1039dnl if <@> local<@domain>: no match but try lookup
1040dnl user+detail: try user++@domain if detail not empty
1041R<@> $+ + $+ < @ $* . >
1042			$: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
1043dnl user+detail: try user+*@domain
1044R<@> $+ + $* < @ $* . >
1045			$: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
1046dnl user+detail: try user@domain
1047R<@> $+ + $* < @ $* . >
1048			$: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
1049dnl try default entry: @domain
1050dnl ++@domain
1051R<@> $+ + $+ < @ $+ . >	$: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
1052dnl +*@domain
1053R<@> $+ + $* < @ $+ . >	$: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
1054dnl @domain if +detail exists
1055R<@> $+ + $* < @ $+ . >	$: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
1056dnl without +detail (or no match)
1057R<@> $+ < @ $+ . >	$: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
1058dnl no match
1059R<@> $+			$: $1
1060dnl remove mark
1061R<!> $+			$: $1
1062R< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
1063R< error : $- $+ > $* 	$#error $@ $(dequote $1 $) $: $2
1064ifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
1065# check virtuser input address against output address, if same, skip recursion
1066R< $+ > $+ < @ $+ >				$: < $1 > $2 < @ $3 > $| $1
1067# it is the same: stop now
1068R< $+ > $+ < @ $+ > $| $&{RecipientAddress}	$: $>ParseLocal $>Parse0 $>canonify $1
1069R< $+ > $+ < @ $+ > $| $* 			$: < $1 > $2 < @ $3 >
1070dnl', `dnl')
1071dnl this is not a documented option
1072dnl it performs no looping at all for virtusertable
1073ifdef(`_NO_VIRTUSER_RECURSION_',
1074`R< $+ > $+ < @ $+ >	$: $>ParseLocal $>Parse0 $>canonify $1',
1075`R< $+ > $+ < @ $+ >	$: $>Recurse $1')
1076dnl', `dnl')
1077
1078# short circuit local delivery so forwarded email works
1079ifdef(`_MAILER_usenet_', `dnl
1080R$+ . USENET < @ $=w . >	$#usenet $@ usenet $: $1	handle usenet specially', `dnl')
1081
1082
1083ifdef(`_STICKY_LOCAL_DOMAIN_',
1084`R$+ < @ $=w . >		$: < $H > $1 < @ $2 . >		first try hub
1085R< $+ > $+ < $+ >	$>MailerToTriple < $1 > $2 < $3 >	yep ....
1086dnl $H empty (but @$=w.)
1087R< > $+ + $* < $+ >	$#_LOCAL_ $: $1 + $2		plussed name?
1088R< > $+ < $+ >		$#_LOCAL_ $: @ $1			nope, local address',
1089`R$=L < @ $=w . >	$#_LOCAL_ $: @ $1			special local names
1090R$+ < @ $=w . >		$#_LOCAL_ $: $1			regular local name')
1091
1092ifdef(`_MAILER_TABLE_', `dnl
1093# not local -- try mailer table lookup
1094R$* <@ $+ > $*		$: < $2 > $1 < @ $2 > $3	extract host name
1095R< $+ . > $*		$: < $1 > $2			strip trailing dot
1096R< $+ > $*		$: < $(mailertable $1 $) > $2	lookup
1097dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
1098R< $~[ : $* > $* 	$>MailerToTriple < $1 : $2 > $3		check -- resolved?
1099R< $+ > $*		$: $>Mailertable <$1> $2		try domain',
1100`dnl')
1101undivert(4)dnl UUCP rules from `MAILER(uucp)'
1102
1103ifdef(`_NO_UUCP_', `dnl',
1104`# resolve remotely connected UUCP links (if any)
1105ifdef(`_CLASS_V_',
1106`R$* < @ $=V . UUCP . > $*		$: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
1107	`dnl')
1108ifdef(`_CLASS_W_',
1109`R$* < @ $=W . UUCP . > $*		$: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
1110	`dnl')
1111ifdef(`_CLASS_X_',
1112`R$* < @ $=X . UUCP . > $*		$: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
1113	`dnl')')
1114
1115# resolve fake top level domains by forwarding to other hosts
1116ifdef(`BITNET_RELAY',
1117`R$*<@$+.BITNET.>$*	$: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3	user@host.BITNET',
1118	`dnl')
1119ifdef(`DECNET_RELAY',
1120`R$*<@$+.DECNET.>$*	$: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3	user@host.DECNET',
1121	`dnl')
1122ifdef(`_MAILER_pop_',
1123`R$+ < @ POP. >		$#pop $: $1			user@POP',
1124	`dnl')
1125ifdef(`_MAILER_fax_',
1126`R$+ < @ $+ .FAX. >	$#fax $@ $2 $: $1		user@host.FAX',
1127`ifdef(`FAX_RELAY',
1128`R$*<@$+.FAX.>$*		$: $>MailerToTriple < $F > $1 <@$2.FAX.> $3	user@host.FAX',
1129	`dnl')')
1130
1131ifdef(`UUCP_RELAY',
1132`# forward non-local UUCP traffic to our UUCP relay
1133R$*<@$*.UUCP.>$*		$: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3	uucp mail',
1134`ifdef(`_MAILER_uucp_',
1135`# forward other UUCP traffic straight to UUCP
1136R$* < @ $+ .UUCP. > $*		$#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3	user@host.UUCP',
1137	`dnl')')
1138ifdef(`_MAILER_usenet_', `
1139# addresses sent to net.group.USENET will get forwarded to a newsgroup
1140R$+ . USENET		$#usenet $@ usenet $: $1',
1141	`dnl')
1142
1143ifdef(`_LOCAL_RULES_',
1144`# figure out what should stay in our local mail system
1145undivert(1)', `dnl')
1146
1147# pass names that still have a host to a smarthost (if defined)
1148R$* < @ $* > $*		$: $>MailerToTriple < $S > $1 < @ $2 > $3	glue on smarthost name
1149
1150# deal with other remote names
1151ifdef(`_MAILER_smtp_',
1152`R$* < @$* > $*		$#_SMTP_ $@ $2 $: $1 < @ $2 > $3	user@host.domain',
1153`R$* < @$* > $*		$#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
1154
1155# handle locally delivered names
1156R$=L			$#_LOCAL_ $: @ $1		special local names
1157R$+			$#_LOCAL_ $: $1			regular local names
1158
1159###########################################################################
1160###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
1161###########################################################################
1162
1163SLocal_localaddr
1164Slocaladdr=5
1165R$+			$: $1 $| $>"Local_localaddr" $1
1166R$+ $| $#ok		$@ $1			no change
1167R$+ $| $#$*		$#$2
1168R$+ $| $*		$: $1
1169
1170ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1171# Preserve rcpt_host in {Host}
1172R$+			$: $1 $| $&h $| $&{Host}	check h and {Host}
1173R$+ $| $|		$: $(macro {Host} $@ $) $1	no h or {Host}
1174R$+ $| $| $+		$: $1			h not set, {Host} set
1175R$+ $| +$* $| $*	$: $1			h is +detail, {Host} set
1176R$+ $| $+ $| $*		$: $(macro {Host} $@ @$2 $) $1	set {Host} to h
1177')dnl
1178
1179ifdef(`_FFR_5_', `dnl
1180# Preserve host in a macro
1181R$+			$: $(macro {LocalAddrHost} $) $1
1182R$+ @ $+		$: $(macro {LocalAddrHost} $@ @ $2 $) $1')
1183
1184ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
1185# deal with plussed users so aliases work nicely
1186R$+ + *			$#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
1187R$+ + $*		$#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
1188')
1189# prepend an empty "forward host" on the front
1190R$+			$: <> $1
1191
1192ifdef(`LUSER_RELAY', `dnl
1193# send unrecognized local users to a relay host
1194ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
1195R< > $+ + $*		$: < ? $L > <+ $2> $(user $1 $)	look up user+
1196R< > $+			$: < ? $L > < > $(user $1 $)	look up user
1197R< ? $* > < $* > $+ <>	$: < > $3 $2			found; strip $L
1198R< ? $* > < $* > $+	$: < $1 > $3 $2			not found', `
1199R< > $+ 		$: < $L > $(user $1 $)		look up user
1200R< $* > $+ <>		$: < > $2			found; strip $L')
1201ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1202R< $+ > $+		$: < $1 > $2 $&{Host}')
1203dnl')
1204
1205ifdef(`MAIL_HUB', `dnl
1206R< > $+			$: < $H > $1			try hub', `dnl')
1207ifdef(`LOCAL_RELAY', `dnl
1208R< > $+			$: < $R > $1			try relay', `dnl')
1209ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
1210R< > $+			$@ $1', `dnl
1211R< > $+			$: < > < $1 <> $&h >		nope, restore +detail
1212ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1213R< > < $+ @ $+ <> + $* >	$: < > < $1 + $3 @ $2 >	check whether +detail')
1214R< > < $+ <> + $* >	$: < > < $1 + $2 >		check whether +detail
1215R< > < $+ <> $* >	$: < > < $1 >			else discard
1216R< > < $+ + $* > $*	   < > < $1 > + $2 $3		find the user part
1217R< > < $+ > + $*	$#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')		strip the extra +
1218R< > < $+ >		$@ $1				no +detail
1219R$+			$: $1 <> $&h			add +detail back in
1220ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1221R$+ @ $+ <> + $*	$: $1 + $3 @ $2			check whether +detail')
1222R$+ <> + $*		$: $1 + $2			check whether +detail
1223R$+ <> $*		$: $1				else discard')
1224R< local : $* > $*	$: $>MailerToTriple < local : $1 > $2	no host extension
1225R< error : $* > $*	$: $>MailerToTriple < error : $1 > $2	no host extension
1226ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1227dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
1228R< $~[ : $+ > $+ @ $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
1229R< $~[ : $+ > $+	$: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
1230ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1231R< $+ > $+ @ $+		$@ $>MailerToTriple < $1 > $2 < @ $3 >')
1232R< $+ > $+		$@ $>MailerToTriple < $1 > $2 < @ $1 >
1233
1234ifdef(`_MAILER_TABLE_', `dnl
1235ifdef(`_LDAP_ROUTING_', `dnl
1236###################################################################
1237###  Ruleset LDAPMailertable -- mailertable lookup for LDAP     ###
1238dnl input: <Domain> FullAddress
1239###################################################################
1240
1241SLDAPMailertable
1242R< $+ > $*		$: < $(mailertable $1 $) > $2		lookup
1243R< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		check resolved?
1244R< $+ > $*		$: < $1 > $>Mailertable <$1> $2		try domain
1245R< $+ > $#$*		$#$2					found
1246R< $+ > $*		$#_RELAY_ $@ $1 $: $2			not found, direct relay',
1247`dnl')
1248
1249###################################################################
1250###  Ruleset 90 -- try domain part of mailertable entry 	###
1251dnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
1252###################################################################
1253
1254SMailertable=90
1255dnl shift and check
1256dnl %2 is not documented in cf/README
1257R$* <$- . $+ > $*	$: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
1258dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
1259R$* <$~[ : $* > $*	$>MailerToTriple < $2 : $3 > $4		check -- resolved?
1260R$* < . $+ > $* 	$@ $>Mailertable $1 . <$2> $3		no -- strip & try again
1261dnl is $2 always empty?
1262R$* < $* > $*		$: < $(mailertable . $@ $1$2 $) > $3	try "."
1263R< $~[ : $* > $*	$>MailerToTriple < $1 : $2 > $3		"." found?
1264dnl return full address
1265R< $* > $*		$@ $2				no mailertable match',
1266`dnl')
1267
1268###################################################################
1269###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple	###
1270dnl input: in general: <[mailer:]host> lp<@domain>rest
1271dnl	<> address				-> address
1272dnl	<error:d.s.n:text>			-> error
1273dnl	<error:text>				-> error
1274dnl	<mailer:user@host> lp<@domain>rest	-> mailer host user
1275dnl	<mailer:host> address			-> mailer host address
1276dnl	<localdomain> address			-> address
1277dnl	<host> address				-> relay host address
1278###################################################################
1279
1280SMailerToTriple=95
1281R< > $*				$@ $1			strip off null relay
1282R< error : $-.$-.$- : $+ > $* 	$#error $@ $1.$2.$3 $: $4
1283R< error : $- $+ > $*		$#error $@ $(dequote $1 $) $: $2
1284R< local : $* > $*		$>CanonLocal < $1 > $2
1285dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
1286R< $~[ : $+ @ $+ > $*<$*>$*	$# $1 $@ $3 $: $2<@$3>	use literal user
1287R< $~[ : $+ > $*		$# $1 $@ $2 $: $3	try qualified mailer
1288R< $=w > $*			$@ $2			delete local host
1289R< $+ > $*			$#_RELAY_ $@ $1 $: $2	use unqualified mailer
1290
1291###################################################################
1292###  Ruleset CanonLocal -- canonify local: syntax		###
1293dnl input: <user> address
1294dnl <x> <@host> : rest			-> Recurse rest
1295dnl <x> p1 $=O p2 <@host>		-> Recurse p1 $=O p2
1296dnl <> user <@host> rest		-> local user@host user
1297dnl <> user				-> local user user
1298dnl <user@host> lp <@domain> rest	-> <user> lp <@host> [cont]
1299dnl <user> lp <@host> rest		-> local lp@host user
1300dnl <user> lp				-> local lp user
1301###################################################################
1302
1303SCanonLocal
1304# strip local host from routed addresses
1305R< $* > < @ $+ > : $+		$@ $>Recurse $3
1306R< $* > $+ $=O $+ < @ $+ >	$@ $>Recurse $2 $3 $4
1307
1308# strip trailing dot from any host name that may appear
1309R< $* > $* < @ $* . >		$: < $1 > $2 < @ $3 >
1310
1311# handle local: syntax -- use old user, either with or without host
1312R< > $* < @ $* > $*		$#_LOCAL_ $@ $1@$2 $: $1
1313R< > $+				$#_LOCAL_ $@ $1    $: $1
1314
1315# handle local:user@host syntax -- ignore host part
1316R< $+ @ $+ > $* < @ $* >	$: < $1 > $3 < @ $4 >
1317
1318# handle local:user syntax
1319R< $+ > $* <@ $* > $*		$#_LOCAL_ $@ $2@$3 $: $1
1320R< $+ > $* 			$#_LOCAL_ $@ $2    $: $1
1321
1322###################################################################
1323###  Ruleset 93 -- convert header names to masqueraded form	###
1324###################################################################
1325
1326SMasqHdr=93
1327
1328ifdef(`_GENERICS_TABLE_', `dnl
1329# handle generics database
1330ifdef(`_GENERICS_ENTIRE_DOMAIN_',
1331dnl if generics should be applied add a @ as mark
1332`R$+ < @ $* $=G . >	$: < $1@$2$3 > $1 < @ $2$3 . > @	mark',
1333`R$+ < @ $=G . >	$: < $1@$2 > $1 < @ $2 . > @	mark')
1334R$+ < @ *LOCAL* >	$: < $1@$j > $1 < @ *LOCAL* > @	mark
1335dnl workspace: either user<@domain> or <user@domain> user <@domain> @
1336dnl ignore the first case for now
1337dnl if it has the mark lookup full address
1338dnl broken: %1 is full address not just detail
1339R< $+ > $+ < $* > @	$: < $(generics $1 $: @ $1 $) > $2 < $3 >
1340dnl workspace: ... or <match|@user@domain> user <@domain>
1341dnl no match, try user+detail@domain
1342R<@$+ + $* @ $+> $+ < @ $+ >
1343		$: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) >  $4 < @ $5 >
1344R<@$+ + $* @ $+> $+ < @ $+ >
1345		$: < $(generics $1@$3 $: $) > $4 < @ $5 >
1346dnl no match, remove mark
1347R<@$+ > $+ < @ $+ >	$: < > $2 < @ $3 >
1348dnl no match, try @domain for exceptions
1349R< > $+ < @ $+ . >	$: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
1350dnl workspace: ... or <match> user <@domain>
1351dnl no match, try local part
1352R< > $+ < @ $+ > 	$: < $(generics $1 $: $) > $1 < @ $2 >
1353R< > $+ + $* < @ $+ > 	$: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
1354R< > $+ + $* < @ $+ > 	$: < $(generics $1 $: $) > $1 + $2 < @ $3 >
1355R< $* @ $* > $* < $* >	$@ $>canonify $1 @ $2		found qualified
1356R< $+ > $* < $* >	$: $>canonify $1 @ *LOCAL*	found unqualified
1357R< > $*			$: $1				not found',
1358`dnl')
1359
1360# do not masquerade anything in class N
1361R$* < @ $* $=N . >	$@ $1 < @ $2 $3 . >
1362
1363ifdef(`MASQUERADE_NAME', `dnl
1364# special case the users that should be exposed
1365R$=E < @ *LOCAL* >	$@ $1 < @ $j . >		leave exposed
1366ifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
1367`R$=E < @ $* $=M . >	$@ $1 < @ $2 $3 . >',
1368`R$=E < @ $=M . >	$@ $1 < @ $2 . >')
1369ifdef(`_LIMITED_MASQUERADE_', `dnl',
1370`R$=E < @ $=w . >	$@ $1 < @ $2 . >')
1371
1372# handle domain-specific masquerading
1373ifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
1374`R$* < @ $* $=M . > $*	$: $1 < @ $2 $3 . @ $M > $4	convert masqueraded doms',
1375`R$* < @ $=M . > $*	$: $1 < @ $2 . @ $M > $3	convert masqueraded doms')
1376ifdef(`_LIMITED_MASQUERADE_', `dnl',
1377`R$* < @ $=w . > $*	$: $1 < @ $2 . @ $M > $3')
1378R$* < @ *LOCAL* > $*	$: $1 < @ $j . @ $M > $2
1379R$* < @ $+ @ > $*	$: $1 < @ $2 > $3		$M is null
1380R$* < @ $+ @ $+ > $*	$: $1 < @ $3 . > $4		$M is not null
1381dnl', `dnl no masquerading
1382dnl just fix *LOCAL* leftovers
1383R$* < @ *LOCAL* >	$@ $1 < @ $j . >')
1384
1385###################################################################
1386###  Ruleset 94 -- convert envelope names to masqueraded form	###
1387###################################################################
1388
1389SMasqEnv=94
1390ifdef(`_MASQUERADE_ENVELOPE_',
1391`R$+			$@ $>MasqHdr $1',
1392`R$* < @ *LOCAL* > $*	$: $1 < @ $j . > $2')
1393
1394###################################################################
1395###  Ruleset 98 -- local part of ruleset zero (can be null)	###
1396###################################################################
1397
1398SParseLocal=98
1399undivert(3)dnl LOCAL_RULE_0
1400
1401ifdef(`_LDAP_ROUTING_', `dnl
1402######################################################################
1403###  LDAPExpand: Expand address using LDAP routing
1404###
1405###	Parameters:
1406###		<$1> -- parsed address (user < @ domain . >) (pass through)
1407###		<$2> -- RFC822 address (user @ domain) (used for lookup)
1408###		<$3> -- +detail information
1409###
1410###	Returns:
1411###		Mailer triplet ($#mailer $@ host $: address)
1412###		Parsed address (user < @ domain . >)
1413######################################################################
1414
1415SLDAPExpand
1416# do the LDAP lookups
1417R<$+><$+><$*>	$: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
1418
1419# if mailRoutingAddress and local or non-existant mailHost,
1420# return the new mailRoutingAddress
1421ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
1422R<$+@$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $6 @ $2
1423R<$+@$+> <> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1 $5 @ $2')
1424R<$+> <$=w> <$+> <$+> <$*>	$@ $>Parse0 $>canonify $1
1425R<$+> <> <$+> <$+> <$*>		$@ $>Parse0 $>canonify $1
1426
1427# if mailRoutingAddress and non-local mailHost,
1428# relay to mailHost with new mailRoutingAddress
1429ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
1430ifdef(`_MAILER_TABLE_', `dnl
1431# check mailertable for host, relay from there
1432R<$+@$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
1433`R<$+@$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
1434ifdef(`_MAILER_TABLE_', `dnl
1435# check mailertable for host, relay from there
1436R<$+> <$+> <$+> <$+> <$*>	$>LDAPMailertable <$2> $>canonify $1',
1437`R<$+> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $2 $: $>canonify $1')
1438
1439# if no mailRoutingAddress and local mailHost,
1440# return original address
1441R<> <$=w> <$+> <$+> <$*>	$@ $2
1442
1443# if no mailRoutingAddress and non-local mailHost,
1444# relay to mailHost with original address
1445ifdef(`_MAILER_TABLE_', `dnl
1446# check mailertable for host, relay from there
1447R<> <$+> <$+> <$+> <$*>		$>LDAPMailertable <$1> $2',
1448`R<> <$+> <$+> <$+> <$*>	$#_RELAY_ $@ $1 $: $2')
1449
1450ifdef(`_LDAP_ROUTE_DETAIL_',
1451`# if no mailRoutingAddress and no mailHost,
1452# try without +detail
1453R<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
1454
1455# if still no mailRoutingAddress and no mailHost,
1456# try @domain
1457ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
1458R<> <> <$+> <$+ + $* @ $+> <>	$@ $>LDAPExpand <$1> <@ $4> <+$3>')
1459R<> <> <$+> <$+ @ $+> <$*>	$@ $>LDAPExpand <$1> <@ $3> <$4>
1460
1461# if no mailRoutingAddress and no mailHost and this was a domain attempt,
1462ifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
1463# user does not exist
1464R<> <> <$+> <@ $+> <$*>		$: <?> < $&{addr_type} > < $1 >
1465# only give error for envelope recipient
1466R<?> <e r> <$+>			$#error $@ nouser $: "550 User unknown"
1467R<?> <$*> <$+>			$@ $2',
1468`dnl
1469# return the original address
1470R<> <> <$+> <@ $+> <$*>		$@ $1')',
1471`dnl')
1472
1473ifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
1474')')
1475ifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
1476######################################################################
1477###  D: LookUpDomain -- search for domain in access database
1478###
1479###	Parameters:
1480###		<$1> -- key (domain name)
1481###		<$2> -- default (what to return if not found in db)
1482dnl			must not be empty
1483###		<$3> -- mark (must be <(!|+) single-token>)
1484###			! does lookup only with tag
1485###			+ does lookup with and without tag
1486###		<$4> -- passthru (additional data passed unchanged through)
1487dnl returns:		<default> <passthru>
1488dnl 			<result> <passthru>
1489######################################################################
1490
1491SD
1492dnl workspace <key> <default> <passthru> <mark>
1493dnl lookup with tag (in front, no delimiter here)
1494dnl    2    3  4    5
1495R<$*> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
1496dnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
1497dnl lookup without tag?
1498dnl   1    2      3    4
1499R<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
1500ifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
1501dnl XXX apply this also to IP addresses?
1502dnl currently it works the wrong way round for [1.2.3.4]
1503dnl   1  2    3    4  5    6
1504R<?> <$+.$+> <$+> <$- $-> <$*>	$: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
1505dnl   1  2    3      4    5
1506R<?> <$+.$+> <$+> <+ $-> <$*>	$: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
1507ifdef(`_ACCESS_SKIP_', `dnl
1508dnl found SKIP: return <default> and <passthru>
1509dnl      1    2    3  4    5
1510R<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
1511dnl not found: IPv4 net (no check is done whether it is an IP number!)
1512dnl    1  2     3    4  5    6
1513R<?> <[$+.$-]> <$+> <$- $-> <$*>	$@ $>D <[$1]> <$3> <$4 $5> <$6>
1514ifdef(`NO_NETINET6', `dnl',
1515`dnl not found: IPv6 net
1516dnl (could be merged with previous rule if we have a class containing .:)
1517dnl    1   2     3    4  5    6
1518R<?> <[$+::$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>
1519R<?> <[$+:$-]> <$+> <$- $-> <$*>	$: $>D <[$1]> <$3> <$4 $5> <$6>')
1520dnl not found, but subdomain: try again
1521dnl   1  2    3    4  5    6
1522R<?> <$+.$+> <$+> <$- $-> <$*>	$@ $>D <$2> <$3> <$4 $5> <$6>
1523ifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
1524dnl   1    2      3    4
1525R<?> <$+> <$+> <! $-> <$*>	$: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
1526dnl not found, no subdomain: return <default> and <passthru>
1527dnl   1    2    3  4    5
1528R<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
1529ifdef(`_ATMPF_', `dnl tempfail?
1530dnl            2    3    4  5    6
1531R<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
1532dnl return <result of lookup> and <passthru>
1533dnl    2    3    4  5    6
1534R<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
1535
1536######################################################################
1537###  A: LookUpAddress -- search for host address in access database
1538###
1539###	Parameters:
1540###		<$1> -- key (dot quadded host address)
1541###		<$2> -- default (what to return if not found in db)
1542dnl			must not be empty
1543###		<$3> -- mark (must be <(!|+) single-token>)
1544###			! does lookup only with tag
1545###			+ does lookup with and without tag
1546###		<$4> -- passthru (additional data passed through)
1547dnl	returns:	<default> <passthru>
1548dnl			<result> <passthru>
1549######################################################################
1550
1551SA
1552dnl lookup with tag
1553dnl    2    3  4    5
1554R<$+> <$+> <$- $-> <$*>		$: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
1555dnl lookup without tag
1556dnl   1    2      3    4
1557R<?> <$+> <$+> <+ $-> <$*>	$: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
1558dnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
1559ifdef(`_ACCESS_SKIP_', `dnl
1560dnl found SKIP: return <default> and <passthru>
1561dnl      1    2    3  4    5
1562R<SKIP> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>', `dnl')
1563ifdef(`NO_NETINET6', `dnl',
1564`dnl no match; IPv6: remove last part
1565dnl   1   2    3    4  5    6
1566R<?> <$+::$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
1567R<?> <$+:$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>')
1568dnl no match; IPv4: remove last part
1569dnl   1  2    3    4  5    6
1570R<?> <$+.$-> <$+> <$- $-> <$*>		$@ $>A <$1> <$3> <$4 $5> <$6>
1571dnl no match: return default
1572dnl   1    2    3  4    5
1573R<?> <$+> <$+> <$- $-> <$*>	$@ <$2> <$5>
1574ifdef(`_ATMPF_', `dnl tempfail?
1575dnl            2    3    4  5    6
1576R<$* _ATMPF_> <$+> <$+> <$- $-> <$*>	$@ <_ATMPF_> <$6>', `dnl')
1577dnl match: return result
1578dnl    2    3    4  5    6
1579R<$*> <$+> <$+> <$- $-> <$*>	$@ <$1> <$6>
1580dnl endif _ACCESS_TABLE_
1581divert(0)
1582######################################################################
1583###  CanonAddr --	Convert an address into a standard form for
1584###			relay checking.  Route address syntax is
1585###			crudely converted into a %-hack address.
1586###
1587###	Parameters:
1588###		$1 -- full recipient address
1589###
1590###	Returns:
1591###		parsed address, not in source route form
1592dnl		user%host%host<@domain>
1593dnl		host!user<@domain>
1594######################################################################
1595
1596SCanonAddr
1597R$*			$: $>Parse0 $>canonify $1	make domain canonical
1598ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
1599R< @ $+ > : $* @ $*	< @ $1 > : $2 % $3	change @ to % in src route
1600R$* < @ $+ > : $* : $*	$3 $1 < @ $2 > : $4	change to % hack.
1601R$* < @ $+ > : $*	$3 $1 < @ $2 >
1602dnl')
1603
1604######################################################################
1605###  ParseRecipient --	Strip off hosts in $=R as well as possibly
1606###			$* $=m or the access database.
1607###			Check user portion for host separators.
1608###
1609###	Parameters:
1610###		$1 -- full recipient address
1611###
1612###	Returns:
1613###		parsed, non-local-relaying address
1614######################################################################
1615
1616SParseRecipient
1617dnl mark and canonify address
1618R$*				$: <?> $>CanonAddr $1
1619dnl workspace: <?> localpart<@domain[.]>
1620R<?> $* < @ $* . >		<?> $1 < @ $2 >			strip trailing dots
1621dnl workspace: <?> localpart<@domain>
1622R<?> $- < @ $* >		$: <?> $(dequote $1 $) < @ $2 >	dequote local part
1623
1624# if no $=O character, no host in the user portion, we are done
1625R<?> $* $=O $* < @ $* >		$: <NO> $1 $2 $3 < @ $4>
1626dnl no $=O in localpart: return
1627R<?> $*				$@ $1
1628
1629dnl workspace: <NO> localpart<@domain>, where localpart contains $=O
1630dnl mark everything which has an "authorized" domain with <RELAY>
1631ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
1632# if we relay, check username portion for user%host so host can be checked also
1633R<NO> $* < @ $* $=m >		$: <RELAY> $1 < @ $2 $3 >', `dnl')
1634dnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
1635dnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
1636
1637dnl what if access map returns something else than RELAY?
1638dnl we are only interested in RELAY entries...
1639dnl other To: entries: blacklist recipient; generic entries?
1640dnl if it is an error we probably do not want to relay anyway
1641ifdef(`_RELAY_HOSTS_ONLY_',
1642`R<NO> $* < @ $=R >		$: <RELAY> $1 < @ $2 >
1643ifdef(`_ACCESS_TABLE_', `dnl
1644R<NO> $* < @ $+ >		$: <$(access To:$2 $: NO $)> $1 < @ $2 >
1645R<NO> $* < @ $+ >		$: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
1646`R<NO> $* < @ $* $=R >		$: <RELAY> $1 < @ $2 $3 >
1647ifdef(`_ACCESS_TABLE_', `dnl
1648R<NO> $* < @ $+ >		$: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
1649R<$+> <$+>			$: <$1> $2',`dnl')')
1650
1651
1652ifdef(`_RELAY_MX_SERVED_', `dnl
1653dnl do "we" ($=w) act as backup MX server for the destination domain?
1654R<NO> $* < @ $+ >		$: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
1655R<MX> < : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
1656dnl yes: mark it as <RELAY>
1657R<MX> < $* : $=w. : $* > < $+ >	$: <RELAY> $4
1658dnl no: put old <NO> mark back
1659R<MX> < : $* : > < $+ >		$: <NO> $2', `dnl')
1660
1661dnl do we relay to this recipient domain?
1662R<RELAY> $* < @ $* >		$@ $>ParseRecipient $1
1663dnl something else
1664R<$+> $*			$@ $2
1665
1666
1667######################################################################
1668###  check_relay -- check hostname/address on SMTP startup
1669######################################################################
1670
1671SLocal_check_relay
1672Scheck`'_U_`'relay
1673R$*			$: $1 $| $>"Local_check_relay" $1
1674R$* $| $* $| $#$*	$#$3
1675R$* $| $* $| $*		$@ $>"Basic_check_relay" $1 $| $2
1676
1677SBasic_check_relay
1678# check for deferred delivery mode
1679R$*			$: < ${deliveryMode} > $1
1680R< d > $*		$@ deferred
1681R< $* > $*		$: $2
1682
1683ifdef(`_ACCESS_TABLE_', `dnl
1684dnl workspace: {client_name} $| {client_addr}
1685R$+ $| $+		$: $>D < $1 > <?> <+ Connect> < $2 >
1686dnl workspace: <result-of-lookup> <{client_addr}>
1687R<?> <$+>		$: $>A < $1 > <?> <+ Connect> <>	no: another lookup
1688dnl workspace: <result-of-lookup> (<>|<{client_addr}>)
1689R<?> <$*>		$: OK				found nothing
1690dnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
1691R<$={Accept}> <$*>	$@ $1				return value of lookup
1692R<REJECT> <$*>		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
1693R<DISCARD> <$*>		$#discard $: discard
1694ifdef(`_FFR_QUARANTINE',
1695`R<QUARANTINE:$+> <$*>	$#error $@ quarantine $: $1', `dnl')
1696dnl error tag
1697R<ERROR:$-.$-.$-:$+> <$*>	$#error $@ $1.$2.$3 $: $4
1698R<ERROR:$+> <$*>		$#error $: $1
1699ifdef(`_ATMPF_', `R<$* _ATMPF_> <$*>		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
1700dnl generic error from access map
1701R<$+> <$*>		$#error $: $1', `dnl')
1702
1703ifdef(`_RBL_',`dnl
1704# DNS based IP address spam list
1705dnl workspace: ignored...
1706R$*			$: $&{client_addr}
1707R$-.$-.$-.$-		$: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
1708R<?>OK			$: OKSOFAR
1709R<?>$+			$#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"',
1710`dnl')
1711undivert(8)
1712
1713######################################################################
1714###  check_mail -- check SMTP ``MAIL FROM:'' command argument
1715######################################################################
1716
1717SLocal_check_mail
1718Scheck`'_U_`'mail
1719R$*			$: $1 $| $>"Local_check_mail" $1
1720R$* $| $#$*		$#$2
1721R$* $| $*		$@ $>"Basic_check_mail" $1
1722
1723SBasic_check_mail
1724# check for deferred delivery mode
1725R$*			$: < ${deliveryMode} > $1
1726R< d > $*		$@ deferred
1727R< $* > $*		$: $2
1728
1729# authenticated?
1730dnl done first: we can require authentication for every mail transaction
1731dnl workspace: address as given by MAIL FROM: (sender)
1732R$*			$: $1 $| $>"tls_client" $&{verify} $| MAIL
1733R$* $| $#$+		$#$2
1734dnl undo damage: remove result of tls_client call
1735R$* $| $*		$: $1
1736
1737dnl workspace: address as given by MAIL FROM:
1738R<>			$@ <OK>			we MUST accept <> (RFC 1123)
1739ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
1740dnl do some additional checks
1741dnl no user@host
1742dnl no user@localhost (if nonlocal sender)
1743dnl this is a pretty simple canonification, it will not catch every case
1744dnl just make sure the address has <> around it (which is required by
1745dnl the RFC anyway, maybe we should complain if they are missing...)
1746dnl dirty trick: if it is user@host, just add a dot: user@host. this will
1747dnl not be modified by host lookups.
1748R$+			$: <?> $1
1749R<?><$+>		$: <@> <$1>
1750R<?>$+			$: <@> <$1>
1751dnl workspace: <@> <address>
1752dnl prepend daemon_flags
1753R$*			$: $&{daemon_flags} $| $1
1754dnl workspace: ${daemon_flags} $| <@> <address>
1755dnl do not allow these at all or only from local systems?
1756R$* f $* $| <@> < $* @ $- >	$: < ? $&{client_name} > < $3 @ $4 >
1757dnl accept unqualified sender: change mark to avoid test
1758R$* u $* $| <@> < $* >	$: <?> < $3 >
1759dnl workspace: ${daemon_flags} $| <@> <address>
1760dnl        or:                    <? ${client_name} > <address>
1761dnl        or:                    <?> <address>
1762dnl remove daemon_flags
1763R$* $| $*		$: $2
1764# handle case of @localhost on address
1765R<@> < $* @ localhost >	$: < ? $&{client_name} > < $1 @ localhost >
1766R<@> < $* @ [127.0.0.1] >
1767			$: < ? $&{client_name} > < $1 @ [127.0.0.1] >
1768R<@> < $* @ localhost.$m >
1769			$: < ? $&{client_name} > < $1 @ localhost.$m >
1770ifdef(`_NO_UUCP_', `dnl',
1771`R<@> < $* @ localhost.UUCP >
1772			$: < ? $&{client_name} > < $1 @ localhost.UUCP >')
1773dnl workspace: < ? $&{client_name} > <user@localhost|host>
1774dnl	or:    <@> <address>
1775dnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
1776R<@> $*			$: $1			no localhost as domain
1777dnl workspace: < ? $&{client_name} > <user@localhost|host>
1778dnl	or:    <address>
1779dnl	or:    <?> <address>	(thanks to u in ${daemon_flags})
1780R<? $=w> $*		$: $2			local client: ok
1781R<? $+> <$+>		$#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
1782dnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
1783R<?> $*			$: $1')
1784dnl workspace: address (or <address>)
1785R$*			$: <?> $>CanonAddr $1		canonify sender address and mark it
1786dnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
1787dnl there is nothing behind the <@host> so no trailing $* needed
1788R<?> $* < @ $+ . >	<?> $1 < @ $2 >			strip trailing dots
1789# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
1790R<?> $* < @ $* $=P >	$: <OK> $1 < @ $2 $3 >
1791dnl workspace <mark> CanonicalAddress	where mark is ? or OK
1792ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
1793`R<?> $* < @ $+ >	$: <_RES_OK_> $1 < @ $2 >		... unresolvable OK',
1794`R<?> $* < @ $+ >	$: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
1795R<? $* <$->> $* < @ $+ >
1796			$: <$2> $3 < @ $4 >')
1797dnl workspace <mark> CanonicalAddress	where mark is ?, _RES_OK_, PERM, TEMP
1798dnl mark is ? iff the address is user (wo @domain)
1799
1800ifdef(`_ACCESS_TABLE_', `dnl
1801# check sender address: user@address, user@, address
1802dnl should we remove +ext from user?
1803dnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
1804R<$+> $+ < @ $* >	$: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
1805R<$+> $+		$: @<$1> <$2> $| <U:$2@>
1806dnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
1807dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
1808dnl will only return user<@domain when "reversing" the args
1809R@ <$+> <$*> $| <$+>	$: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
1810dnl workspace: <@><mark> <CanonicalAddress> $| <result>
1811R<@> <$+> <$*> $| <$*>	$: <$3> <$1> <$2>		reverse result
1812dnl workspace: <result> <mark> <CanonicalAddress>
1813# retransform for further use
1814dnl required form:
1815dnl <ResultOfLookup|mark> CanonicalAddress
1816R<?> <$+> <$*>		$: <$1> $2	no match
1817R<$+> <$+> <$*>		$: <$1> $3	relevant result, keep it', `dnl')
1818dnl workspace <ResultOfLookup|mark> CanonicalAddress
1819dnl mark is ? iff the address is user (wo @domain)
1820
1821ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
1822# handle case of no @domain on address
1823dnl prepend daemon_flags
1824R<?> $*			$: $&{daemon_flags} $| <?> $1
1825dnl accept unqualified sender: change mark to avoid test
1826R$* u $* $| <?> $*	$: <_RES_OK_> $3
1827dnl remove daemon_flags
1828R$* $| $*		$: $2
1829R<?> $*			$: < ? $&{client_name} > $1
1830R<?> $*			$@ <OK>				...local unqualed ok
1831R<? $+> $*		$#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
1832							...remote is not')
1833# check results
1834R<?> $*			$: @ $1		mark address: nothing known about it
1835R<$={ResOk}> $*		$@ <_RES_OK_>	domain ok: stop
1836R<TEMP> $*		$#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
1837R<PERM> $*		$#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
1838ifdef(`_ACCESS_TABLE_', `dnl
1839R<$={Accept}> $*	$# $1		accept from access map
1840R<DISCARD> $*		$#discard $: discard
1841ifdef(`_FFR_QUARANTINE',
1842`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
1843R<REJECT> $*		$#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"')
1844dnl error tag
1845R<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
1846R<ERROR:$+> $*		$#error $: $1
1847ifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
1848dnl generic error from access map
1849R<$+> $*		$#error $: $1		error from access db',
1850`dnl')
1851
1852######################################################################
1853###  check_rcpt -- check SMTP ``RCPT TO:'' command argument
1854######################################################################
1855
1856SLocal_check_rcpt
1857Scheck`'_U_`'rcpt
1858R$*			$: $1 $| $>"Local_check_rcpt" $1
1859R$* $| $#$*		$#$2
1860R$* $| $*		$@ $>"Basic_check_rcpt" $1
1861
1862SBasic_check_rcpt
1863# empty address?
1864R<>			$#error $@ nouser $: "553 User address required"
1865R$@			$#error $@ nouser $: "553 User address required"
1866# check for deferred delivery mode
1867R$*			$: < ${deliveryMode} > $1
1868R< d > $*		$@ deferred
1869R< $* > $*		$: $2
1870
1871ifdef(`_REQUIRE_QUAL_RCPT_', `dnl
1872dnl this code checks for user@host where host is not a FQHN.
1873dnl it is not activated.
1874dnl notice: code to check for a recipient without a domain name is
1875dnl available down below; look for the same macro.
1876dnl this check is done here because the name might be qualified by the
1877dnl canonicalization.
1878# require fully qualified domain part?
1879dnl very simple canonification: make sure the address is in < >
1880R$+			$: <?> $1
1881R<?> <$+>		$: <@> <$1>
1882R<?> $+			$: <@> <$1>
1883R<@> < postmaster >	$: postmaster
1884R<@> < $* @ $+ . $+ >	$: < $3 @ $4 . $5 >
1885dnl prepend daemon_flags
1886R<@> $*			$: $&{daemon_flags} $| <@> $1
1887dnl workspace: ${daemon_flags} $| <@> <address>
1888dnl do not allow these at all or only from local systems?
1889R$* r $* $| <@> < $* @ $* >	$: < ? $&{client_name} > < $3 @ $4 >
1890R<?> < $* >		$: <$1>
1891R<? $=w> < $* >		$: <$1>
1892R<? $+> <$+>		$#error $@ 5.5.4 $: "553 Fully qualified domain name required"
1893dnl remove daemon_flags for other cases
1894R$* $| <@> $*		$: $2', `dnl')
1895
1896dnl ##################################################################
1897dnl call subroutines for recipient and relay
1898dnl possible returns from subroutines:
1899dnl $#TEMP	temporary failure
1900dnl $#error	permanent failure (or temporary if from access map)
1901dnl $#other	stop processing
1902dnl RELAY	RELAYing allowed
1903dnl other	otherwise
1904######################################################################
1905R$*			$: $1 $| @ $>"Rcpt_ok" $1
1906dnl temporary failure? remove mark @ and remember
1907R$* $| @ $#TEMP $+	$: $1 $| T $2
1908dnl error or ok (stop)
1909R$* $| @ $#$*		$#$2
1910ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
1911R$* $| @ RELAY		$@ RELAY
1912dnl something else: call check sender (relay)
1913R$* $| @ $*		$: O $| $>"Relay_ok" $1
1914dnl temporary failure: call check sender (relay)
1915R$* $| T $+		$: T $2 $| $>"Relay_ok" $1
1916dnl temporary failure? return that
1917R$* $| $#TEMP $+	$#error $2
1918dnl error or ok (stop)
1919R$* $| $#$*		$#$2
1920R$* $| RELAY		$@ RELAY
1921dnl something else: return previous temp failure
1922R T $+ $| $*		$#error $1
1923# anything else is bogus
1924R$*			$#error $@ 5.7.1 $: confRELAY_MSG
1925divert(0)
1926
1927######################################################################
1928### Rcpt_ok: is the recipient ok?
1929dnl input: recipient address (RCPT TO)
1930dnl output: see explanation at call
1931######################################################################
1932SRcpt_ok
1933ifdef(`_LOOSE_RELAY_CHECK_',`dnl
1934R$*			$: $>CanonAddr $1
1935R$* < @ $* . >		$1 < @ $2 >			strip trailing dots',
1936`R$*			$: $>ParseRecipient $1		strip relayable hosts')
1937
1938ifdef(`_BESTMX_IS_LOCAL_',`dnl
1939ifelse(_BESTMX_IS_LOCAL_, `', `dnl
1940# unlimited bestmx
1941R$* < @ $* > $*			$: $1 < @ $2 @@ $(bestmx $2 $) > $3',
1942`dnl
1943# limit bestmx to $=B
1944R$* < @ $* $=B > $*		$: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
1945R$* $=O $* < @ $* @@ $=w . > $*	$@ $>"Rcpt_ok" $1 $2 $3
1946R$* < @ $* @@ $=w . > $*	$: $1 < @ $3 > $4
1947R$* < @ $* @@ $* > $*		$: $1 < @ $2 > $4')
1948
1949ifdef(`_BLACKLIST_RCPT_',`dnl
1950ifdef(`_ACCESS_TABLE_', `dnl
1951# blacklist local users or any host from receiving mail
1952R$*			$: <?> $1
1953dnl user is now tagged with @ to be consistent with check_mail
1954dnl and to distinguish users from hosts (com would be host, com@ would be user)
1955R<?> $+ < @ $=w >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
1956R<?> $+ < @ $* >	$: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
1957R<?> $+			$: <> <$1> $| <U:$1@>
1958dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
1959dnl will only return user<@domain when "reversing" the args
1960R<> <$*> $| <$+>	$: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
1961R<@> <$*> $| <$*>	$: <$2> <$1>		reverse result
1962R<?> <$*>		$: @ $1		mark address as no match
1963dnl we may have to filter here because otherwise some RHSs
1964dnl would be interpreted as generic error messages...
1965dnl error messages should be "tagged" by prefixing them with error: !
1966dnl that would make a lot of things easier.
1967R<$={Accept}> <$*>	$: @ $2		mark address as no match
1968ifdef(`_ACCESS_SKIP_', `dnl
1969R<SKIP> <$*>		$: @ $1		mark address as no match', `dnl')
1970ifdef(`_DELAY_COMPAT_8_10_',`dnl
1971dnl compatility with 8.11/8.10:
1972dnl we have to filter these because otherwise they would be interpreted
1973dnl as generic error message...
1974dnl error messages should be "tagged" by prefixing them with error: !
1975dnl that would make a lot of things easier.
1976dnl maybe we should stop checks already here (if SPAM_xyx)?
1977R<$={SpamTag}> <$*>	$: @ $2		mark address as no match')
1978R<REJECT> $*		$#error $@ 5.2.1 $: confRCPTREJ_MSG
1979R<DISCARD> $*		$#discard $: discard
1980ifdef(`_FFR_QUARANTINE',
1981`R<QUARANTINE:$+> $*	$#error $@ quarantine $: $1', `dnl')
1982dnl error tag
1983R<ERROR:$-.$-.$-:$+> $*		$#error $@ $1.$2.$3 $: $4
1984R<ERROR:$+> $*		$#error $: $1
1985ifdef(`_ATMPF_', `R<_ATMPF_> $*		$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
1986dnl generic error from access map
1987R<$+> $*		$#error $: $1		error from access db
1988R@ $*			$1		remove mark', `dnl')', `dnl')
1989
1990ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
1991# authenticated via TLS?
1992R$*			$: $1 $| $>RelayTLS	client authenticated?
1993R$* $| $# $+		$# $2			error/ok?
1994R$* $| $*		$: $1			no
1995
1996R$*			$: $1 $| $>"Local_Relay_Auth" $&{auth_type}
1997dnl workspace: localpart<@domain> $| result of Local_Relay_Auth
1998R$* $| $# $*		$# $2
1999dnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
2000R$* $| NO		$: $1
2001R$* $| $*		$: $1 $| $&{auth_type}
2002dnl workspace: localpart<@domain> [ $| ${auth_type} ]
2003dnl empty ${auth_type}?
2004R$* $|			$: $1
2005dnl mechanism ${auth_type} accepted?
2006dnl use $# to override further tests (delay_checks): see check_rcpt below
2007R$* $| $={TrustAuthMech}	$# RELAY
2008dnl remove ${auth_type}
2009R$* $| $*		$: $1
2010dnl workspace: localpart<@domain> | localpart
2011ifelse(defn(`_NO_UUCP_'), `r',
2012`R$* ! $* < @ $* >	$: <REMOTE> $2 < @ BANG_PATH >
2013R$* ! $* 		$: <REMOTE> $2 < @ BANG_PATH >', `dnl')
2014# anything terminating locally is ok
2015ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
2016R$+ < @ $* $=m >	$@ RELAY', `dnl')
2017R$+ < @ $=w >		$@ RELAY
2018ifdef(`_RELAY_HOSTS_ONLY_',
2019`R$+ < @ $=R >		$@ RELAY
2020ifdef(`_ACCESS_TABLE_', `dnl
2021R$+ < @ $+ >		$: <$(access To:$2 $: ? $)> <$1 < @ $2 >>
2022dnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
2023R<?> <$+ < @ $+ >>	$: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
2024`R$+ < @ $* $=R >	$@ RELAY
2025ifdef(`_ACCESS_TABLE_', `dnl
2026R$+ < @ $+ >		$: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')')
2027ifdef(`_ACCESS_TABLE_', `dnl
2028dnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
2029R<RELAY> $*		$@ RELAY
2030ifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2031R<$*> <$*>		$: $2',`dnl')
2032
2033
2034ifdef(`_RELAY_MX_SERVED_', `dnl
2035# allow relaying for hosts which we MX serve
2036R$+ < @ $+ >		$: < : $(mxserved $2 $) : > $1 < @ $2 >
2037dnl this must not necessarily happen if the client is checked first...
2038R< : $* <TEMP> : > $*	$#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1
2039R<$* : $=w . : $*> $*	$@ RELAY
2040R< : $* : > $*		$: $2',
2041`dnl')
2042
2043# check for local user (i.e. unqualified address)
2044R$*			$: <?> $1
2045R<?> $* < @ $+ >	$: <REMOTE> $1 < @ $2 >
2046# local user is ok
2047dnl is it really? the standard requires user@domain, not just user
2048dnl but we should accept it anyway (maybe making it an option:
2049dnl RequireFQDN ?)
2050dnl postmaster must be accepted without domain (DRUMS)
2051ifdef(`_REQUIRE_QUAL_RCPT_', `dnl
2052R<?> postmaster		$@ OK
2053# require qualified recipient?
2054dnl prepend daemon_flags
2055R<?> $+			$: $&{daemon_flags} $| <?> $1
2056dnl workspace: ${daemon_flags} $| <?> localpart
2057dnl do not allow these at all or only from local systems?
2058dnl r flag? add client_name
2059R$* r $* $| <?> $+	$: < ? $&{client_name} > <?> $3
2060dnl no r flag: relay to local user (only local part)
2061# no qualified recipient required
2062R$* $| <?> $+		$@ RELAY
2063dnl client_name is empty
2064R<?> <?> $+		$@ RELAY
2065dnl client_name is local
2066R<? $=w> <?> $+		$@ RELAY
2067dnl client_name is not local
2068R<? $+> $+		$#error $@ 5.5.4 $: "553 Domain name required"', `dnl
2069dnl no qualified recipient required
2070R<?> $+			$@ RELAY')
2071dnl it is a remote user: remove mark and then check client
2072R<$+> $*		$: $2
2073dnl currently the recipient address is not used below
2074
2075######################################################################
2076### Relay_ok: is the relay/sender ok?
2077dnl input: ignored
2078dnl output: see explanation at call
2079######################################################################
2080SRelay_ok
2081# anything originating locally is ok
2082# check IP address
2083R$*			$: $&{client_addr}
2084R$@			$@ RELAY		originated locally
2085R0			$@ RELAY		originated locally
2086R$=R $*			$@ RELAY		relayable IP address
2087ifdef(`_ACCESS_TABLE_', `dnl
2088R$*			$: $>A <$1> <?> <+ Connect> <$1>
2089R<RELAY> $* 		$@ RELAY		relayable IP address
2090ifdef(`_ATMPF_', `R<_ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2091R<$*> <$*>		$: $2', `dnl')
2092R$*			$: [ $1 ]		put brackets around it...
2093R$=w			$@ RELAY		... and see if it is local
2094
2095ifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
2096ifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
2097ifdef(`_RELAY_MAIL_FROM_', `dnl
2098dnl input: {client_addr} or something "broken"
2099dnl just throw the input away; we do not need it.
2100# check whether FROM is allowed to use system as relay
2101R$*			$: <?> $>CanonAddr $&f
2102R<?> $+ < @ $+ . >	<?> $1 < @ $2 >		remove trailing dot
2103ifdef(`_RELAY_LOCAL_FROM_', `dnl
2104# check whether local FROM is ok
2105R<?> $+ < @ $=w >	$@ RELAY		FROM local', `dnl')
2106ifdef(`_RELAY_DB_FROM_', `dnl
2107R<?> $+ < @ $+ >	$: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<D:$2>') <>
2108R<@> <RELAY>		$@ RELAY		RELAY FROM sender ok
2109ifdef(`_ATMPF_', `R<@> <_ATMPF_>		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2110', `dnl
2111ifdef(`_RELAY_DB_FROM_DOMAIN_',
2112`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
2113')',
2114`dnl')
2115dnl')', `dnl')
2116dnl notice: the rulesets above do not leave a unique workspace behind.
2117dnl it does not matter in this case because the following rule ignores
2118dnl the input. otherwise these rules must "clean up" the workspace.
2119
2120# check client name: first: did it resolve?
2121dnl input: ignored
2122R$*			$: < $&{client_resolve} >
2123R<TEMP>			$#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
2124R<FORGED>		$#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
2125R<FAIL>			$#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
2126dnl ${client_resolve} should be OK, so go ahead
2127R$*			$: <@> $&{client_name}
2128dnl should not be necessary since it has been done for client_addr already
2129R<@>			$@ RELAY
2130dnl workspace: <@> ${client_name} (not empty)
2131# pass to name server to make hostname canonical
2132R<@> $* $=P 		$:<?>  $1 $2
2133R<@> $+			$:<?>  $[ $1 $]
2134dnl workspace: <?> ${client_name} (canonified)
2135R$* .			$1			strip trailing dots
2136ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
2137R<?> $* $=m		$@ RELAY', `dnl')
2138R<?> $=w		$@ RELAY
2139ifdef(`_RELAY_HOSTS_ONLY_',
2140`R<?> $=R		$@ RELAY
2141ifdef(`_ACCESS_TABLE_', `dnl
2142R<?> $*			$: <$(access Connect:$1 $: ? $)> <$1>
2143R<?> <$*>		$: <$(access $1 $: ? $)> <$1>',`dnl')',
2144`R<?> $* $=R			$@ RELAY
2145ifdef(`_ACCESS_TABLE_', `dnl
2146R<?> $*			$: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
2147ifdef(`_ACCESS_TABLE_', `dnl
2148R<RELAY> $*		$@ RELAY
2149ifdef(`_ATMPF_', `R<$* _ATMPF_> $*		$#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2150R<$*> <$*>		$: $2',`dnl')
2151dnl end of _PROMISCUOUS_RELAY_
2152divert(0)
2153ifdef(`_DELAY_CHECKS_',`dnl
2154# turn a canonical address in the form user<@domain>
2155# qualify unqual. addresses with $j
2156dnl it might have been only user (without <@domain>)
2157SFullAddr
2158R$* <@ $+ . >		$1 <@ $2 >
2159R$* <@ $* >		$@ $1 <@ $2 >
2160R$+			$@ $1 <@ $j >
2161
2162# call all necessary rulesets
2163Scheck_rcpt
2164dnl this test should be in the Basic_check_rcpt ruleset
2165dnl which is the correct DSN code?
2166# R$@			$#error $@ 5.1.3 $: "553 Recipient address required"
2167R$+			$: $1 $| $>checkrcpt $1
2168dnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
2169R$+ $| $#$*		$#$2
2170R$+ $| $*		$: <?> $>FullAddr $>CanonAddr $1
2171ifdef(`_SPAM_FH_',
2172`dnl lookup user@ and user@address
2173ifdef(`_ACCESS_TABLE_', `',
2174`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
2175')')dnl
2176dnl one of the next two rules is supposed to match
2177dnl this code has been copied from BLACKLIST... etc
2178dnl and simplified by omitting some < >.
2179R<?> $+ < @ $=w >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
2180R<?> $+ < @ $* >	$: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
2181dnl R<?>		$@ something_is_very_wrong_here
2182# lookup the addresses only with Spam tag
2183R<> $* $| <$+>		$: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
2184R<@> $* $| $*		$: $2 $1		reverse result
2185dnl', `dnl')
2186ifdef(`_SPAM_FRIEND_',
2187`# is the recipient a spam friend?
2188ifdef(`_SPAM_HATER_',
2189	`errprint(`*** ERROR: define either SpamHater or SpamFriend
2190')', `dnl')
2191R<FRIEND> $+		$@ SPAMFRIEND
2192R<$*> $+		$: $2',
2193`dnl')
2194ifdef(`_SPAM_HATER_',
2195`# is the recipient no spam hater?
2196R<HATER> $+		$: $1			spam hater: continue checks
2197R<$*> $+		$@ NOSPAMHATER		everyone else: stop
2198dnl',`dnl')
2199dnl run further checks: check_mail
2200dnl should we "clean up" $&f?
2201ifdef(`_FFR_MAIL_MACRO',
2202`R$*			$: $1 $| $>checkmail $&{mail_from}',
2203`R$*			$: $1 $| $>checkmail <$&f>')
2204R$* $| $#$*		$#$2
2205dnl run further checks: check_relay
2206R$*			$: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
2207R$* $| $#$*		$#$2
2208R$* $| $*		$: $1
2209', `dnl')
2210
2211ifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
2212######################################################################
2213###  F: LookUpFull -- search for an entry in access database
2214###
2215###	lookup of full key (which should be an address) and
2216###	variations if +detail exists: +* and without +detail
2217###
2218###	Parameters:
2219###		<$1> -- key
2220###		<$2> -- default (what to return if not found in db)
2221dnl			must not be empty
2222###		<$3> -- mark (must be <(!|+) single-token>)
2223###			! does lookup only with tag
2224###			+ does lookup with and without tag
2225###		<$4> -- passthru (additional data passed unchanged through)
2226dnl returns:		<default> <passthru>
2227dnl 			<result> <passthru>
2228######################################################################
2229
2230SF
2231dnl workspace: <key> <def> <o tag> <thru>
2232dnl full lookup
2233dnl    2    3  4    5
2234R<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
2235dnl no match, try without tag
2236dnl   1    2      3    4
2237R<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
2238dnl no match, +detail: try +*
2239dnl   1    2    3    4    5  6    7
2240R<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
2241			$: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
2242dnl no match, +detail: try +* without tag
2243dnl   1    2    3    4      5    6
2244R<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
2245			$: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
2246dnl no match, +detail: try without +detail
2247dnl   1    2    3    4    5  6    7
2248R<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
2249			$: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
2250dnl no match, +detail: try without +detail and without tag
2251dnl   1    2    3    4      5    6
2252R<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
2253			$: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
2254dnl no match, return <default> <passthru>
2255dnl   1    2    3  4    5
2256R<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
2257ifdef(`_ATMPF_', `dnl tempfail?
2258dnl            2    3  4    5
2259R<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
2260dnl match, return <match> <passthru>
2261dnl    2    3  4    5
2262R<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
2263
2264######################################################################
2265###  E: LookUpExact -- search for an entry in access database
2266###
2267###	Parameters:
2268###		<$1> -- key
2269###		<$2> -- default (what to return if not found in db)
2270dnl			must not be empty
2271###		<$3> -- mark (must be <(!|+) single-token>)
2272###			! does lookup only with tag
2273###			+ does lookup with and without tag
2274###		<$4> -- passthru (additional data passed unchanged through)
2275dnl returns:		<default> <passthru>
2276dnl 			<result> <passthru>
2277######################################################################
2278
2279SE
2280dnl    2    3  4    5
2281R<$*> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
2282dnl no match, try without tag
2283dnl   1    2      3    4
2284R<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
2285dnl no match, return default passthru
2286dnl   1    2    3  4    5
2287R<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
2288ifdef(`_ATMPF_', `dnl tempfail?
2289dnl            2    3  4    5
2290R<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
2291dnl match, return <match> <passthru>
2292dnl    2    3  4    5
2293R<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
2294
2295######################################################################
2296###  U: LookUpUser -- search for an entry in access database
2297###
2298###	lookup of key (which should be a local part) and
2299###	variations if +detail exists: +* and without +detail
2300###
2301###	Parameters:
2302###		<$1> -- key (user@)
2303###		<$2> -- default (what to return if not found in db)
2304dnl			must not be empty
2305###		<$3> -- mark (must be <(!|+) single-token>)
2306###			! does lookup only with tag
2307###			+ does lookup with and without tag
2308###		<$4> -- passthru (additional data passed unchanged through)
2309dnl returns:		<default> <passthru>
2310dnl 			<result> <passthru>
2311######################################################################
2312
2313SU
2314dnl user lookups are always with trailing @
2315dnl    2    3  4    5
2316R<$+> <$*> <$- $-> <$*>		$: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
2317dnl no match, try without tag
2318dnl   1    2      3    4
2319R<?> <$+> <$*> <+ $-> <$*>	$: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
2320dnl do not remove the @ from the lookup:
2321dnl it is part of the +detail@ which is omitted for the lookup
2322dnl no match, +detail: try +*
2323dnl   1    2      3    4  5    6
2324R<?> <$+ + $* @> <$*> <$- $-> <$*>
2325			$: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
2326dnl no match, +detail: try +* without tag
2327dnl   1    2      3      4    5
2328R<?> <$+ + $* @> <$*> <+ $-> <$*>
2329			$: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
2330dnl no match, +detail: try without +detail
2331dnl   1    2      3    4  5    6
2332R<?> <$+ + $* @> <$*> <$- $-> <$*>
2333			$: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
2334dnl no match, +detail: try without +detail and without tag
2335dnl   1    2      3      4    5
2336R<?> <$+ + $* @> <$*> <+ $-> <$*>
2337			$: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
2338dnl no match, return <default> <passthru>
2339dnl   1    2    3  4    5
2340R<?> <$+> <$*> <$- $-> <$*>	$@ <$2> <$5>
2341ifdef(`_ATMPF_', `dnl tempfail?
2342dnl            2    3  4    5
2343R<$+ _ATMPF_> <$*> <$- $-> <$*>	$@ <_ATMPF_> <$5>', `dnl')
2344dnl match, return <match> <passthru>
2345dnl    2    3  4    5
2346R<$+> <$*> <$- $-> <$*>		$@ <$1> <$5>
2347
2348######################################################################
2349###  SearchList: search a list of items in the access map
2350###	Parameters:
2351###		<exact tag> $| <mark:address> <mark:address> ... <>
2352dnl	maybe we should have a @ (again) in front of the mark to
2353dnl	avoid errorneous matches (with error messages?)
2354dnl	if we can make sure that tag is always a single token
2355dnl	then we can omit the delimiter $|, otherwise we need it
2356dnl	to avoid errorneous matchs (first rule: D: if there
2357dnl	is that mark somewhere in the list, it will be taken).
2358dnl	moreover, we can do some tricks to enforce lookup with
2359dnl	the tag only, e.g.:
2360###	where "exact" is either "+" or "!":
2361###	<+ TAG>	lookup with and w/o tag
2362###	<! TAG>	lookup with tag
2363dnl	Warning: + and ! should be in OperatorChars (otherwise there must be
2364dnl		a blank between them and the tag.
2365###	possible values for "mark" are:
2366###		D: recursive host lookup (LookUpDomain)
2367dnl		A: recursive address lookup (LookUpAddress) [not yet required]
2368###		E: exact lookup, no modifications
2369###		F: full lookup, try user+ext@domain and user@domain
2370###		U: user lookup, try user+ext and user (input must have trailing @)
2371###	return: <RHS of lookup> or <?> (not found)
2372######################################################################
2373
2374# class with valid marks for SearchList
2375dnl if A is activated: add it
2376C{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
2377SSearchList
2378# just call the ruleset with the name of the tag... nice trick...
2379dnl       2       3    4
2380R<$+> $| <$={src}:$*> <$*>	$: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
2381dnl workspace: <o tag> $| <rest> $| <result of lookup> <>
2382dnl no match and nothing left: return
2383R<$+> $| <> $| <?> <>		$@ <?>
2384dnl no match but something left: continue
2385R<$+> $| <$+> $| <?> <>		$@ $>SearchList <$1> $| <$2>
2386dnl match: return
2387R<$+> $| <$*> $| <$+> <>	$@ <$3>
2388dnl return result from recursive invocation
2389R<$+> $| <$+>			$@ <$2>
2390dnl endif _ACCESS_TABLE_
2391divert(0)
2392
2393######################################################################
2394###  trust_auth: is user trusted to authenticate as someone else?
2395###
2396###	Parameters:
2397###		$1: AUTH= parameter from MAIL command
2398######################################################################
2399
2400dnl empty ruleset definition so it can be called
2401SLocal_trust_auth
2402Strust_auth
2403R$*			$: $&{auth_type} $| $1
2404# required by RFC 2554 section 4.
2405R$@ $| $*		$#error $@ 5.7.1 $: "550 not authenticated"
2406dnl seems to be useful...
2407R$* $| $&{auth_authen}		$@ identical
2408R$* $| <$&{auth_authen}>	$@ identical
2409dnl call user supplied code
2410R$* $| $*		$: $1 $| $>"Local_trust_auth" $1
2411R$* $| $#$*		$#$2
2412dnl default: error
2413R$*			$#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
2414
2415######################################################################
2416###  Relay_Auth: allow relaying based on authentication?
2417###
2418###	Parameters:
2419###		$1: ${auth_type}
2420######################################################################
2421SLocal_Relay_Auth
2422
2423ifdef(`_ACCESS_TABLE_', `dnl
2424######################################################################
2425###  srv_features: which features to offer to a client?
2426###	(done in server)
2427######################################################################
2428Ssrv_features
2429ifdef(`_LOCAL_SRV_FEATURES_', `dnl
2430R$*			$: $1 $| $>"Local_srv_features" $1
2431R$* $| $#$*		$#$2
2432R$* $| $*		$: $1', `dnl')
2433R$*		$: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
2434R<?>$*		$: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
2435R<?>$*		$: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
2436R<?>$*		$@ OK
2437ifdef(`_ATMPF_', `dnl tempfail?
2438R<$* _ATMPF_>$*	$#temp', `dnl')
2439R<$+>$*		$# $1
2440
2441######################################################################
2442###  try_tls: try to use STARTTLS?
2443###	(done in client)
2444######################################################################
2445Stry_tls
2446ifdef(`_LOCAL_TRY_TLS_', `dnl
2447R$*			$: $1 $| $>"Local_try_tls" $1
2448R$* $| $#$*		$#$2
2449R$* $| $*		$: $1', `dnl')
2450R$*		$: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
2451R<?>$*		$: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
2452R<?>$*		$: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
2453R<?>$*		$@ OK
2454ifdef(`_ATMPF_', `dnl tempfail?
2455R<$* _ATMPF_>$*	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2456R<NO>$*		$#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
2457  
2458######################################################################
2459###  tls_rcpt: is connection with server "good" enough?
2460###	(done in client, per recipient)
2461dnl called from deliver() before RCPT command
2462###
2463###	Parameters:
2464###		$1: recipient
2465######################################################################
2466Stls_rcpt
2467ifdef(`_LOCAL_TLS_RCPT_', `dnl
2468R$*			$: $1 $| $>"Local_tls_rcpt" $1
2469R$* $| $#$*		$#$2
2470R$* $| $*		$: $1', `dnl')
2471dnl store name of other side
2472R$*			$: $(macro {TLS_Name} $@ $&{server_name} $) $1
2473dnl canonify recipient address
2474R$+			$: <?> $>CanonAddr $1
2475dnl strip trailing dots
2476R<?> $+ < @ $+ . >	<?> $1 <@ $2 >
2477dnl full address?
2478R<?> $+ < @ $+ >	$: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
2479dnl only localpart?
2480R<?> $+			$: $1 $| <U:$1@> <E:>
2481dnl look it up
2482dnl also look up a default value via E:
2483R$* $| $+	$: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
2484dnl found nothing: stop here
2485R$* $| <?>	$@ OK
2486ifdef(`_ATMPF_', `dnl tempfail?
2487R$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2488dnl use the generic routine (for now)
2489R$* $| <$+>	$@ $>"TLS_connection" $&{verify} $| <$2>')
2490
2491######################################################################
2492###  tls_client: is connection with client "good" enough?
2493###	(done in server)
2494###
2495###	Parameters:
2496###		${verify} $| (MAIL|STARTTLS)
2497######################################################################
2498dnl MAIL: called from check_mail
2499dnl STARTTLS: called from smtp() after STARTTLS has been accepted
2500Stls_client
2501ifdef(`_LOCAL_TLS_CLIENT_', `dnl
2502R$*			$: $1 $| $>"Local_tls_client" $1
2503R$* $| $#$*		$#$2
2504R$* $| $*		$: $1', `dnl')
2505ifdef(`_ACCESS_TABLE_', `dnl
2506dnl store name of other side
2507R$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
2508dnl ignore second arg for now
2509dnl maybe use it to distinguish permanent/temporary error?
2510dnl if MAIL: permanent (STARTTLS has not been offered)
2511dnl if STARTTLS: temporary (offered but maybe failed)
2512R$* $| $*	$: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
2513R$* $| <?>$*	$: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
2514dnl do a default lookup: just TLS_CLT_TAG
2515R$* $| <?>$*	$: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
2516ifdef(`_ATMPF_', `dnl tempfail?
2517R$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2518R$*		$@ $>"TLS_connection" $1', `dnl
2519R$* $| $*	$@ $>"TLS_connection" $1')
2520
2521######################################################################
2522###  tls_server: is connection with server "good" enough?
2523###	(done in client)
2524###
2525###	Parameter:
2526###		${verify}
2527######################################################################
2528dnl i.e. has the server been authenticated and is encryption active?
2529dnl called from deliver() after STARTTLS command
2530Stls_server
2531ifdef(`_LOCAL_TLS_SERVER_', `dnl
2532R$*			$: $1 $| $>"Local_tls_server" $1
2533R$* $| $#$*		$#$2
2534R$* $| $*		$: $1', `dnl')
2535ifdef(`_ACCESS_TABLE_', `dnl
2536dnl store name of other side
2537R$*		$: $(macro {TLS_Name} $@ $&{server_name} $) $1
2538R$*		$: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
2539R$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
2540dnl do a default lookup: just TLS_SRV_TAG
2541R$* $| <?>$*	$: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
2542ifdef(`_ATMPF_', `dnl tempfail?
2543R$* $| <$* _ATMPF_>	$#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2544R$*		$@ $>"TLS_connection" $1', `dnl
2545R$*		$@ $>"TLS_connection" $1')
2546
2547######################################################################
2548###  TLS_connection: is TLS connection "good" enough?
2549###
2550###	Parameters:
2551ifdef(`_ACCESS_TABLE_', `dnl
2552###		${verify} $| <Requirement> [<>]', `dnl
2553###		${verify}')
2554###		Requirement: RHS from access map, may be ? for none.
2555dnl	syntax for Requirement:
2556dnl	[(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
2557dnl	extensions: could be a list of further requirements
2558dnl		for now: CN:string	{cn_subject} == string
2559######################################################################
2560STLS_connection
2561ifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
2562dnl deal with TLS handshake failures: abort
2563RSOFTWARE	$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
2564divert(-1)')
2565dnl common ruleset for tls_{client|server}
2566dnl input: ${verify} $| <ResultOfLookup> [<>]
2567dnl remove optional <>
2568R$* $| <$*>$*			$: $1 $| <$2>
2569dnl workspace: ${verify} $| <ResultOfLookup>
2570# create the appropriate error codes
2571dnl permanent or temporary error?
2572R$* $| <PERM + $={tls} $*>	$: $1 $| <503:5.7.0> <$2 $3>
2573R$* $| <TEMP + $={tls} $*>	$: $1 $| <403:4.7.0> <$2 $3>
2574dnl default case depends on TLS_PERM_ERR
2575R$* $| <$={tls} $*>		$: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
2576dnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
2577# deal with TLS handshake failures: abort
2578RSOFTWARE $| <$-:$+> $* 	$#error $@ $2 $: $1 " TLS handshake failed."
2579dnl no <reply:dns> i.e. not requirements in the access map
2580dnl use default error
2581RSOFTWARE $| $* 		$#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
2582R$* $| <$*> <VERIFY>		$: <$2> <VERIFY> <> $1
2583dnl separate optional requirements
2584R$* $| <$*> <VERIFY + $+>	$: <$2> <VERIFY> <$3> $1
2585R$* $| <$*> <$={tls}:$->$*	$: <$2> <$3:$4> <> $1
2586dnl separate optional requirements
2587R$* $| <$*> <$={tls}:$- + $+>$*	$: <$2> <$3:$4> <$5> $1
2588dnl some other value in access map: accept
2589dnl this also allows to override the default case (if used)
2590R$* $| $*			$@ OK
2591# authentication required: give appropriate error
2592# other side did authenticate (via STARTTLS)
2593dnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
2594dnl only verification required and it succeeded
2595R<$*><VERIFY> <> OK		$@ OK
2596dnl verification required and it succeeded but extensions are given
2597dnl change it to <SMTP:ESC> <REQ:0>  <extensions>
2598R<$*><VERIFY> <$+> OK		$: <$1> <REQ:0> <$2>
2599dnl verification required + some level of encryption
2600R<$*><VERIFY:$-> <$*> OK	$: <$1> <REQ:$2> <$3>
2601dnl just some level of encryption required
2602R<$*><ENCR:$-> <$*> $*		$: <$1> <REQ:$2> <$3>
2603dnl workspace:
2604dnl 1. <SMTP:ESC> <VERIFY [:bits]>  <[extensions]> {verify} (!= OK)
2605dnl 2. <SMTP:ESC> <REQ:bits>  <[extensions]>
2606dnl verification required but ${verify} is not set (case 1.)
2607R<$-:$+><VERIFY $*> <$*>	$#error $@ $2 $: $1 " authentication required"
2608R<$-:$+><VERIFY $*> <$*> FAIL	$#error $@ $2 $: $1 " authentication failed"
2609R<$-:$+><VERIFY $*> <$*> NO	$#error $@ $2 $: $1 " not authenticated"
2610R<$-:$+><VERIFY $*> <$*> NOT	$#error $@ $2 $: $1 " no authentication requested"
2611R<$-:$+><VERIFY $*> <$*> NONE	$#error $@ $2 $: $1 " other side does not support STARTTLS"
2612dnl some other value for ${verify}
2613R<$-:$+><VERIFY $*> <$*> $+	$#error $@ $2 $: $1 " authentication failure " $4
2614dnl some level of encryption required: get the maximum level (case 2.)
2615R<$*><REQ:$-> <$*>		$: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
2616dnl compare required bits with actual bits
2617R<$*><REQ:$-> <$*> $-		$: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
2618R<$-:$+><$-:$-> <$*> TRUE	$#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
2619dnl strength requirements fulfilled
2620dnl TLS Additional Requirements Separator
2621dnl this should be something which does not appear in the extensions itself
2622dnl @ could be part of a CN, DN, etc...
2623dnl use < > ? those are encoded in CN, DN, ...
2624define(`_TLS_ARS_', `++')dnl
2625dnl workspace:
2626dnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
2627R<$-:$+><$-:$-> <$*> $*		$: <$1:$2 _TLS_ARS_ $5>
2628dnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
2629dnl continue: check  extensions
2630R<$-:$+ _TLS_ARS_ >			$@ OK
2631dnl split extensions into own list
2632R<$-:$+ _TLS_ARS_ $+ >			$: <$1:$2> <$3>
2633R<$-:$+> < $+ _TLS_ARS_ $+ >		<$1:$2> <$3> <$4>
2634R<$-:$+> $+			$@ $>"TLS_req" $3 $| <$1:$2>
2635
2636######################################################################
2637###  TLS_req: check additional TLS requirements
2638###
2639###	Parameters: [<list> <of> <req>] $| <$-:$+>
2640###		$-: SMTP reply code
2641###		$+: Enhanced Status Code
2642dnl  further requirements for this ruleset:
2643dnl	name of "other side" is stored is {TLS_name} (client/server_name)
2644dnl
2645dnl	currently only CN[:common_name] is implemented
2646dnl	right now this is only a logical AND
2647dnl	i.e. all requirements must be true
2648dnl	how about an OR? CN must be X or CN must be Y or ..
2649dnl	use a macro to compute this as a trivial sequential
2650dnl	operations (no precedences etc)?
2651######################################################################
2652STLS_req
2653dnl no additional requirements: ok
2654R $| $+		$@ OK
2655dnl require CN: but no CN specified: use name of other side
2656R<CN> $* $| <$+>		$: <CN:$&{TLS_Name}> $1 $| <$2>
2657dnl match, check rest
2658R<CN:$&{cn_subject}> $* $| <$+>		$@ $>"TLS_req" $1 $| <$2>
2659dnl CN does not match
2660dnl  1   2      3  4
2661R<CN:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
2662dnl cert subject
2663R<CS:$&{cert_subject}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
2664dnl CS does not match
2665dnl  1   2      3  4
2666R<CS:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CERT Subject " $&{cert_subject} " does not match " $1
2667dnl match, check rest
2668R<CI:$&{cert_issuer}> $* $| <$+>	$@ $>"TLS_req" $1 $| <$2>
2669dnl CI does not match
2670dnl  1   2      3  4
2671R<CI:$+> $* $| <$-:$+>	$#error $@ $4 $: $3 " CERT Issuer " $&{cert_issuer} " does not match " $1
2672dnl return from recursive call
2673ROK			$@ OK
2674
2675######################################################################
2676###  max: return the maximum of two values separated by :
2677###
2678###	Parameters: [$-]:[$-]
2679######################################################################
2680Smax
2681R:		$: 0
2682R:$-		$: $1
2683R$-:		$: $1
2684R$-:$-		$: $(arith l $@ $1 $@ $2 $) : $1 : $2
2685RTRUE:$-:$-	$: $2
2686R$-:$-:$-	$: $2
2687dnl endif _ACCESS_TABLE_
2688divert(0)
2689
2690######################################################################
2691###  RelayTLS: allow relaying based on TLS authentication
2692###
2693###	Parameters:
2694###		none
2695######################################################################
2696SRelayTLS
2697# authenticated?
2698dnl we do not allow relaying for anyone who can present a cert
2699dnl signed by a "trusted" CA. For example, even if we put verisigns
2700dnl CA in CERTPath so we can authenticate users, we do not allow
2701dnl them to abuse our server (they might be easier to get hold of,
2702dnl but anyway).
2703dnl so here is the trick: if the verification succeeded
2704dnl we look up the cert issuer in the access map
2705dnl (maybe after extracting a part with a regular expression)
2706dnl if this returns RELAY we relay without further questions
2707dnl if it returns SUBJECT we perform a similar check on the
2708dnl cert subject.
2709ifdef(`_ACCESS_TABLE_', `dnl
2710R$*			$: <?> $&{verify}
2711R<?> OK			$: OK		authenticated: continue
2712R<?> $*			$@ NO		not authenticated
2713ifdef(`_CERT_REGEX_ISSUER_', `dnl
2714R$*			$: $(CERTIssuer $&{cert_issuer} $)',
2715`R$*			$: $&{cert_issuer}')
2716R$+			$: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
2717dnl use $# to stop further checks (delay_check)
2718RRELAY			$# RELAY
2719ifdef(`_CERT_REGEX_SUBJECT_', `dnl
2720RSUBJECT		$: <@> $(CERTSubject $&{cert_subject} $)',
2721`RSUBJECT		$: <@> $&{cert_subject}')
2722R<@> $+			$: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
2723R<@> RELAY		$# RELAY
2724R$*			$: NO', `dnl')
2725
2726######################################################################
2727###  authinfo: lookup authinfo in the access map
2728###
2729###	Parameters:
2730###		$1: {server_name}
2731###		$2: {server_addr}
2732dnl	both are currently ignored
2733dnl if it should be done via another map, we either need to restrict
2734dnl functionality (it calls D and A) or copy those rulesets (or add another
2735dnl parameter which I want to avoid, it's quite complex already)
2736######################################################################
2737dnl omit this ruleset if neither is defined?
2738dnl it causes DefaultAuthInfo to be ignored
2739dnl (which may be considered a good thing).
2740Sauthinfo
2741ifdef(`_AUTHINFO_TABLE_', `dnl
2742R$*		$: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
2743R<?>		$: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
2744R<?>		$: <$(authinfo AuthInfo: $: ? $)>
2745R<?>		$@ no				no authinfo available
2746R<$*>		$# $1
2747dnl', `dnl
2748ifdef(`_ACCESS_TABLE_', `dnl
2749R$*		$: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
2750R$* $| <?>$*	$: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
2751R$* $| <?>$*	$: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
2752R$* $| <?>$*	$@ no				no authinfo available
2753R$* $| <$*> <>	$# $2
2754dnl', `dnl')')
2755
2756undivert(9)dnl LOCAL_RULESETS
2757#
2758######################################################################
2759######################################################################
2760#####
2761`#####			MAIL FILTER DEFINITIONS'
2762#####
2763######################################################################
2764######################################################################
2765_MAIL_FILTERS_
2766#
2767######################################################################
2768######################################################################
2769#####
2770`#####			MAILER DEFINITIONS'
2771#####
2772######################################################################
2773######################################################################
2774undivert(7)dnl MAILER_DEFINITIONS
2775
2776