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