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