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