3 # Copyright (c) 1998-2009 Sendmail, Inc. and its suppliers.
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.
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.
16 VERSIONID(`$Id: proto.m4,v 8.741 2009/12/11 00:04:53 ca Exp $')
18 # level CF_LEVEL config file format
19 V`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley')
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)')
26 # do some sanity checking
28 `errprint(`*** ERROR: No system type defined (use OSTYPE macro)
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
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.
49 ifdef(`confREAD_TIMEOUT',
50 `errprint(`*** confREAD_TIMEOUT is obsolete.
51 Use individual confTO_<timeout> parameters instead.
53 ifdef(`confMESSAGE_TIMEOUT',
54 `define(`_ARG_', index(confMESSAGE_TIMEOUT, /))
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.
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.
75 # clean option definitions below....
76 define(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl
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')
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')
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')
101 # need to set this before any LDAP lookups are done (including classes)
102 ifdef(`confLDAP_CLUSTER', `D{sendmailMTACluster}`'confLDAP_CLUSTER', `#D{sendmailMTACluster}$m')
106 `# file containing names of hosts for which we receive email
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')
114 # host/domain names ending with a token in class P are canonical
123 ifdef(`BITNET_RELAY',
129 ifdef(`DECNET_RELAY',
130 `define(`_USE_DECNET_SYNTAX_', 1)dnl
142 # "Smart" relay host (may be null)
143 DS`'ifdef(`SMART_HOST', `SMART_HOST')
145 ifdef(`LUSER_RELAY', `dnl
146 # place to which unknown users should be forwarded
151 # operators that cannot be in local usernames (i.e., network indicators)
152 CO @ % ifdef(`_NO_UUCP_', `', `!')
154 # a class with just dot (for identifying canonical names)
157 # a class with just a left bracket (for identifying domain literals)
160 ifdef(`_ACCESS_TABLE_', `dnl
161 # access_db acceptance class
163 ifdef(`_DELAY_COMPAT_8_10_',`dnl
164 ifdef(`_BLACKLIST_RCPT_',`dnl
165 # possible access_db RHS for spam friends/haters
166 C{SpamTag}SPAMFRIEND SPAMHATER')')',
169 dnl mark for "domain is ok" (resolved or accepted anyway)
170 define(`_RES_OK_', `OKR')dnl
171 ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl
172 # Resolve map (to check if a host exists in check_mail)
173 Kresolve host -a<_RES_OK_> -T<TEMP>')
176 ifdef(`_NEED_MACRO_MAP_', `dnl
177 ifdef(`_MACRO_MAP_', `', `# macro storage map
178 define(`_MACRO_MAP_', `1')dnl
179 Kmacro macro')', `dnl')
181 ifdef(`confCR_FILE', `dnl
182 # Hosts for which relaying is permitted ($=R)
186 define(`TLS_SRV_TAG', `"TLS_Srv"')dnl
187 define(`TLS_CLT_TAG', `"TLS_Clt"')dnl
188 define(`TLS_RCPT_TAG', `"TLS_Rcpt"')dnl
189 define(`TLS_TRY_TAG', `"Try_TLS"')dnl
190 define(`SRV_FEAT_TAG', `"Srv_Features"')dnl
191 dnl this may be useful in other contexts too
192 ifdef(`_ARITH_MAP_', `', `# arithmetic map
193 define(`_ARITH_MAP_', `1')dnl
195 ifdef(`_ACCESS_TABLE_', `dnl
196 ifdef(`_MACRO_MAP_', `', `# macro storage map
197 define(`_MACRO_MAP_', `1')dnl
199 # possible values for TLS_connection in access map
200 C{Tls}VERIFY ENCR', `dnl')
201 ifdef(`_CERT_REGEX_ISSUER_', `dnl
202 # extract relevant part from cert issuer
203 KCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl')
204 ifdef(`_CERT_REGEX_SUBJECT_', `dnl
205 # extract relevant part from cert subject
206 KCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl')
208 ifdef(`LOCAL_RELAY', `dnl
209 # who I send unqualified names to if `FEATURE(stickyhost)' is used
210 # (null means deliver locally)
213 ifdef(`MAIL_HUB', `dnl
214 # who gets all local email traffic
215 # ($R has precedence for unqualified names if `FEATURE(stickyhost)' is used)
219 Kdequote dequote`'ifdef(`confDEQUOTE_OPTS', ` confDEQUOTE_OPTS', `')
221 divert(0)dnl # end of nullclient diversion
222 # class E: names that should be exposed as from this host, even if we masquerade
223 # class L: names that should be delivered locally, even if we have a relay
224 # class M: domains that should be converted to $M
225 # class N: domains that should not be converted to $M
228 ifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl')
230 ifdef(`MASQUERADE_NAME', `dnl
231 # who I masquerade as (null for no masquerading) (see also $=M)
232 DM`'MASQUERADE_NAME')
234 # my name for error messages
235 ifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON')
237 undivert(6)dnl LOCAL_CONFIG
238 include(_CF_DIR_`m4/version.m4')
243 ifdef(`confAUTO_REBUILD',
244 `errprint(WARNING: `confAUTO_REBUILD' is no longer valid.
245 There was a potential for a denial of service attack if this is set.
248 # strip message body to 7 bits on input?
249 _OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False')
251 # 8-bit data handling
252 _OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8')
254 # wait for alias file rebuild (default units: minutes)
255 _OPTION(AliasWait, `confALIAS_WAIT', `5m')
257 # location of alias file
258 _OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases')
260 # minimum number of free blocks on filesystem
261 _OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100')
263 # maximum message size
264 _OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `0')
266 # substitution for space (blank) characters
267 _OPTION(BlankSub, `confBLANK_SUB', `_')
269 # avoid connecting to "expensive" mailers on initial submission?
270 _OPTION(HoldExpensive, `confCON_EXPENSIVE', `False')
272 # checkpoint queue runs after every N successful deliveries
273 _OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10')
275 # default delivery mode
276 _OPTION(DeliveryMode, `confDELIVERY_MODE', `background')
278 # error message header/file
279 _OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header')
282 _OPTION(ErrorMode, `confERROR_MODE', `print')
284 # save Unix-style "From_" lines at top of header?
285 _OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False')
287 # queue file mode (qf files)
288 _OPTION(QueueFileMode, `confQUEUE_FILE_MODE', `0600')
290 # temporary file mode
291 _OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600')
293 # match recipients against GECOS field?
294 _OPTION(MatchGECOS, `confMATCH_GECOS', `False')
297 _OPTION(MaxHopCount, `confMAX_HOP', `25')
299 # location of help file
300 O HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile')
302 # ignore dots as terminators in incoming messages?
303 _OPTION(IgnoreDots, `confIGNORE_DOTS', `False')
305 # name resolver options
306 _OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY')
308 # deliver MIME-encapsulated error messages?
309 _OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True')
311 # Forward file search path
312 _OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward')
314 # open connection cache size
315 _OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2')
317 # open connection cache timeout
318 _OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m')
320 # persistent host status directory
321 _OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat')
323 # single thread deliveries (requires HostStatusDirectory)?
324 _OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False')
326 # use Errors-To: header?
327 _OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False')
330 _OPTION(LogLevel, `confLOG_LEVEL', `10')
332 # send to me too, even in an alias expansion?
333 _OPTION(MeToo, `confME_TOO', `True')
335 # verify RHS in newaliases?
336 _OPTION(CheckAliases, `confCHECK_ALIASES', `False')
338 # default messages to old style headers if no special punctuation?
339 _OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False')
341 # SMTP daemon options
342 ifelse(defn(`confDAEMON_OPTIONS'), `', `dnl',
343 `errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid.
344 Use `DAEMON_OPTIONS()'; see cf/README.
346 `DAEMON_OPTIONS(`confDAEMON_OPTIONS')')
347 ifelse(defn(`_DPO_'), `',
348 `ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-v4, Family=inet
349 O DaemonPortOptions=Name=MTA-v6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_')
350 ifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E')
352 # SMTP client options
353 ifelse(defn(`confCLIENT_OPTIONS'), `', `dnl',
354 `errprint(WARNING: `confCLIENT_OPTIONS' is no longer valid. See cf/README for more information.
356 `CLIENT_OPTIONS(`confCLIENT_OPTIONS')')
357 ifelse(defn(`_CPO_'), `',
358 `#O ClientPortOptions=Family=inet, Address=0.0.0.0', `_CPO_')
360 # Modifiers to `define' {daemon_flags} for direct submissions
361 _OPTION(DirectSubmissionModifiers, `confDIRECT_SUBMISSION_MODIFIERS', `')
363 # Use as mail submission program? See sendmail/SECURITY
364 _OPTION(UseMSP, `confUSE_MSP', `')
367 _OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings')
369 # who (if anyone) should get extra copies of error messages
370 _OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster')
372 # slope of queue-only function
373 _OPTION(QueueFactor, `confQUEUE_FACTOR', `600000')
375 # limit on number of concurrent queue runners
376 _OPTION(MaxQueueChildren, `confMAX_QUEUE_CHILDREN', `')
378 # maximum number of queue-runners per queue-grouping with multiple queues
379 _OPTION(MaxRunnersPerQueue, `confMAX_RUNNERS_PER_QUEUE', `1')
381 # priority of queue runners (nice(3))
382 _OPTION(NiceQueueRun, `confNICE_QUEUE_RUN', `')
384 # shall we sort the queue by hostname first?
385 _OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority')
387 # minimum time in queue before retry
388 _OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m')
390 # how many jobs can you process in the queue?
391 _OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `0')
393 # perform initial split of envelope without checking MX records
394 _OPTION(FastSplit, `confFAST_SPLIT', `1')
397 O QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue')
399 # key for shared memory; 0 to turn off, -1 to auto-select
400 _OPTION(SharedMemoryKey, `confSHARED_MEMORY_KEY', `0')
402 # file to store auto-selected key for shared memory (SharedMemoryKey = -1)
403 _OPTION(SharedMemoryKeyFile, `confSHARED_MEMORY_KEY_FILE', `')
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 _OPTION(Timeout.queuereturn.dsn, `confTO_QUEUERETURN_DSN', `5d')
428 _OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h')
429 _OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h')
430 _OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h')
431 _OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h')
432 _OPTION(Timeout.queuewarn.dsn, `confTO_QUEUEWARN_DSN', `4h')
433 _OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m')
434 _OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s')
435 _OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s')
436 _OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s')
437 _OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4')
438 _OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4')
439 _OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4')
440 _OPTION(Timeout.lhlo, `confTO_LHLO', `2m')
441 _OPTION(Timeout.auth, `confTO_AUTH', `10m')
442 _OPTION(Timeout.starttls, `confTO_STARTTLS', `1h')
444 # time for DeliverBy; extension disabled if less than 0
445 _OPTION(DeliverByMin, `confDELIVER_BY_MIN', `0')
447 # should we not prune routes in route-addr syntax addresses?
448 _OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False')
450 # queue up everything before forking?
451 _OPTION(SuperSafe, `confSAFE_QUEUE', `True')
454 _OPTION(StatusFile, `STATUS_FILE')
456 # time zone handling:
457 # if undefined, use system default
458 # if defined but null, use TZ envariable passed in
459 # if defined and non-null, use that info
460 ifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=',
461 confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=',
462 `O TimeZoneSpec=confTIME_ZONE')
464 # default UID (can be username or userid:groupid)
465 _OPTION(DefaultUser, `confDEF_USER_ID', `mailnull')
467 # list of locations of user database file (null means no lookup)
468 _OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb')
471 _OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net')
473 # fallback smart host
474 _OPTION(FallbackSmartHost, `confFALLBACK_SMARTHOST', `fall.back.host.net')
476 # if we are the best MX host for a site, try it directly instead of config err
477 _OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False')
479 # load average at which we just queue messages
480 _OPTION(QueueLA, `confQUEUE_LA', `8')
482 # load average at which we refuse connections
483 _OPTION(RefuseLA, `confREFUSE_LA', `12')
485 # log interval when refusing connections for this long
486 _OPTION(RejectLogInterval, `confREJECT_LOG_INTERVAL', `3h')
488 # load average at which we delay connections; 0 means no limit
489 _OPTION(DelayLA, `confDELAY_LA', `0')
491 # maximum number of children we allow at one time
492 _OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `0')
494 # maximum number of new connections per second
495 _OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0')
497 # Width of the window
498 _OPTION(ConnectionRateWindowSize, `confCONNECTION_RATE_WINDOW_SIZE', `60s')
500 # work recipient factor
501 _OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000')
503 # deliver each queued job in a separate process?
504 _OPTION(ForkEachJob, `confSEPARATE_PROC', `False')
507 _OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800')
510 _OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000')
512 # default character set
513 _OPTION(DefaultCharSet, `confDEF_CHAR_SET', `unknown-8bit')
515 # service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
516 _OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch')
518 # hosts file (normally /etc/hosts)
519 _OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts')
521 # dialup line delay on connection failure
522 _OPTION(DialDelay, `confDIAL_DELAY', `0s')
524 # action to take if there are no recipients in the message
525 _OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `none')
527 # chrooted environment for writing to files
528 _OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `')
530 # are colons OK in addresses?
531 _OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True')
533 # shall I avoid expanding CNAMEs (violates protocols)?
534 _OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False')
536 # SMTP initial login message (old $e macro)
537 _OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b')
539 # UNIX initial From header format (old $l macro)
540 _OPTION(UnixFromLine, `confFROM_LINE', `From $g $d')
542 # From: lines that have embedded newlines are unwrapped onto one line
543 _OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False')
545 # Allow HELO SMTP command that does not `include' a host name
546 _OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False')
548 # Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
549 _OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
551 # delimiter (operator) characters (old $o macro)
552 _OPTION(OperatorChars, `confOPERATORS', `.:@[]')
554 # shall I avoid calling initgroups(3) because of high NIS costs?
555 _OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False')
557 # are group-writable `:include:' and .forward files (un)trustworthy?
558 # True (the default) means they are not trustworthy.
559 _OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True')
560 ifdef(`confUNSAFE_GROUP_WRITES',
561 `errprint(`WARNING: confUNSAFE_GROUP_WRITES is deprecated; use confDONT_BLAME_SENDMAIL.
564 # where do errors that occur when sending errors get sent?
565 _OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster')
567 # issue temporary errors (4xy) instead of permanent errors (5xy)?
568 _OPTION(SoftBounce, `confSOFT_BOUNCE', `False')
570 # where to save bounces if all else fails
571 _OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter')
573 # what user id do we assume for the majority of the processing?
574 _OPTION(RunAsUser, `confRUN_AS_USER', `sendmail')
576 # maximum number of recipients per SMTP envelope
577 _OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `0')
579 # limit the rate recipients per SMTP envelope are accepted
580 # once the threshold number of recipients have been rejected
581 _OPTION(BadRcptThrottle, `confBAD_RCPT_THROTTLE', `0')
584 # shall we get local names from our installed interfaces?
585 _OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False')
587 # Return-Receipt-To: header implies DSN request
588 _OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False')
590 # override connection address (for testing)
591 _OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0')
593 # Trusted user for file ownership and starting the daemon
594 _OPTION(TrustedUser, `confTRUSTED_USER', `root')
596 # Control socket for daemon management
597 _OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control')
599 # Maximum MIME header length to protect MUAs
600 _OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0')
602 # Maximum length of the sum of all headers
603 _OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768')
605 # Maximum depth of alias recursion
606 _OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10')
608 # location of pid file
609 _OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid')
611 # Prefix string for the process title shown on 'ps' listings
612 _OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix')
614 # Data file (df) memory-buffer file maximum size
615 _OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096')
617 # Transcript file (xf) memory-buffer file maximum size
618 _OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096')
620 # lookup type to find information about local mailboxes
621 _OPTION(MailboxDatabase, `confMAILBOX_DATABASE', `pw')
623 # override compile time flag REQUIRES_DIR_FSYNC
624 _OPTION(RequiresDirfsync, `confREQUIRES_DIR_FSYNC', `true')
626 # list of authentication mechanisms
627 _OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5')
629 # Authentication realm
630 _OPTION(AuthRealm, `confAUTH_REALM', `')
632 # default authentication information for outgoing connections
633 _OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info')
636 _OPTION(AuthOptions, `confAUTH_OPTIONS', `')
638 # SMTP AUTH maximum encryption strength
639 _OPTION(AuthMaxBits, `confAUTH_MAX_BITS', `')
641 # SMTP STARTTLS server options
642 _OPTION(TLSSrvOptions, `confTLS_SRV_OPTIONS', `')
646 _OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `')
648 ifelse(len(X`'_MAIL_FILTERS_DEF), `1', `dnl', `dnl
650 _OPTION(Milter.LogLevel, `confMILTER_LOG_LEVEL', `')
651 _OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `')
652 _OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `')
653 _OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `')
654 _OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')
655 _OPTION(Milter.macros.eom, `confMILTER_MACROS_EOM', `')
656 _OPTION(Milter.macros.eoh, `confMILTER_MACROS_EOH', `')
657 _OPTION(Milter.macros.data, `confMILTER_MACROS_DATA', `')')
660 _OPTION(CACertPath, `confCACERT_PATH', `')
662 _OPTION(CACertFile, `confCACERT', `')
664 _OPTION(ServerCertFile, `confSERVER_CERT', `')
666 _OPTION(ServerKeyFile, `confSERVER_KEY', `')
668 _OPTION(ClientCertFile, `confCLIENT_CERT', `')
670 _OPTION(ClientKeyFile, `confCLIENT_KEY', `')
671 # File containing certificate revocation lists
672 _OPTION(CRLFile, `confCRL', `')
673 # DHParameters (only required if DSA/DH is used)
674 _OPTION(DHParameters, `confDH_PARAMETERS', `')
675 # Random data source (required for systems without /dev/urandom under OpenSSL)
676 _OPTION(RandFile, `confRAND_FILE', `')
678 # Maximum number of "useless" commands before slowing down
679 _OPTION(MaxNOOPCommands, `confMAX_NOOP_COMMANDS', `20')
681 # Name to use for EHLO (defaults to $j)
682 _OPTION(HeloName, `confHELO_NAME')
684 ############################
685 `# QUEUE GROUP DEFINITIONS #'
686 ############################
689 ###########################
690 # Message precedences #
691 ###########################
694 Pspecial-delivery=100
699 #####################
701 #####################
703 # this is equivalent to setting class "t"
704 ifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users')
707 ifdef(`_NO_UUCP_', `dnl', `Tuucp')
708 ifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl')
710 #########################
711 # Format of headers #
712 #########################
714 ifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl
715 ifdef(`confMESSAGEID_HEADER',, `define(`confMESSAGEID_HEADER', `<$t.$i@$j>')')dnl
716 H?P?Return-Path: <$g>
717 HReceived: confRECEIVED_HEADER
720 H?F?Resent-From: confFROM_HEADER
721 H?F?From: confFROM_HEADER
724 # H?l?Received-Date: $b
725 H?M?Resent-Message-Id: confMESSAGEID_HEADER
726 H?M?Message-Id: confMESSAGEID_HEADER
729 ######################################################################
730 ######################################################################
732 ##### REWRITING RULES
734 ######################################################################
735 ######################################################################
737 ############################################
738 ### Ruleset 3 -- Name Canonicalization ###
739 ############################################
742 # handle null input (translate to <@> special case)
745 # strip group: syntax (not inside angle brackets!) and trailing semicolon
746 R$* $: $1 <@> mark addresses
747 R$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr>
748 R@ $* <@> $: @ $1 unmark @host:...
749 R$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr
750 R$* :: $* <@> $: $1 :: $2 unmark node::addr
751 R:`include': $* <@> $: :`include': $1 unmark :`include':...
752 R$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon
753 R$* : $* <@> $: $2 strip colon if marked
755 R$* ; $1 strip trailing semi
756 R$* < $+ :; > $* $@ $2 :; <@> catch <list:;>
757 R$* < $* ; > $1 < $2 > bogus bracketed semi
759 # null input now results from list:; syntax
762 # strip angle brackets -- note RFC733 heuristic to get innermost item
763 R$* $: < $1 > housekeeping <>
764 R$+ < $* > < $2 > strip excess on left
765 R< $* > $+ < $1 > strip excess on right
766 R<> $@ < @ > MAIL FROM:<> case
767 R< $+ > $: $1 remove housekeeping <>
769 ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
770 # make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later
771 R@ $+ , $+ @ $1 : $2 change all "," to ":"
773 # localize and dispose of route-based addresses
774 dnl XXX: IPv6 colon conflict
775 ifdef(`NO_NETINET6', `dnl',
776 `R@ [$+] : $+ $@ $>Canonify2 < @ [$1] > : $2 handle <route-addr>')
777 R@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr>
779 # strip route address <@a,@b,@c:user@d> -> <user@d>
781 ifdef(`NO_NETINET6', `dnl',
786 # find focus for list syntax
787 R $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax
788 R $+ : $* ; $@ $1 : $2; list syntax
790 # find focus for @ syntax addresses
791 R$+ @ $+ $: $1 < @ $2 > focus on domain
792 R$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right
793 R$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical
795 dnl This is flagged as an error in S0; no need to silently fix it here.
796 dnl # do some sanity checking
797 dnl R$* < @ $~[ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs
799 ifdef(`_NO_UUCP_', `dnl',
800 `# convert old-style addresses to a domain-based address
801 R$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names
802 R$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps
803 R$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains
805 ifdef(`_USE_DECNET_SYNTAX_',
806 `# convert node::user addresses into a domain-based address
807 R$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names
808 R$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr
811 # if we have % signs, take the rightmost one
812 R$* % $* $1 @ $2 First make them all @s.
813 R$* @ $* @ $* $1 % $2 @ $3 Undo all but the last.
814 R$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish
816 # else we must be a local name
817 R$* $@ $>Canonify2 $1
820 ################################################
821 ### Ruleset 96 -- bottom half of ruleset 3 ###
822 ################################################
826 # handle special cases for local names
827 R$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all
828 R$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain
829 ifdef(`_NO_UUCP_', `dnl',
830 `R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain')
832 # check for IPv4/IPv6 domain literal
833 R$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [addr]
834 R$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal
835 R$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr
837 ifdef(`_DOMAIN_TABLE_', `dnl
838 # look up domains in the domain table
839 R$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl')
841 undivert(2)dnl LOCAL_RULE_3
843 ifdef(`_BITDOMAIN_TABLE_', `dnl
844 # handle BITNET mapping
845 R$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl')
847 ifdef(`_UUDOMAIN_TABLE_', `dnl
848 # handle UUCP mapping
849 R$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl')
851 ifdef(`_NO_UUCP_', `dnl',
853 `# pass UUCP addresses straight through
854 R$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3',
855 `# if really UUCP, handle it immediately
857 `R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl')
859 `R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl')
861 `R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl')
863 `R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl')
865 `R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl')
867 ifdef(`_NO_CANONIFY_', `dnl', `dnl
868 # try UUCP traffic as a local address
869 R$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3
870 R$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3')
872 # hostnames ending in class P are always canonical
873 R$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4
874 dnl apply the next rule only for hostnames not in class P
875 dnl this even works for phrases in class P since . is in class P
876 dnl which daemon flags are set?
877 R$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4
878 dnl the other rules in this section only apply if the hostname
879 dnl does not end in class P hence no further checks are done here
880 dnl if this ever changes make sure the lookups are "protected" again!
881 ifdef(`_NO_CANONIFY_', `dnl
882 dnl do not canonify unless:
883 dnl domain ends in class {Canonify} (this does not work if the intersection
884 dnl with class P is non-empty)
885 dnl or {daemon_flags} has c set
886 # pass to name server to make hostname canonical if in class {Canonify}
887 R$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5
888 # pass to name server to make hostname canonical if requested
889 R$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5
890 dnl trailing dot? -> do not apply _CANONIFY_HOSTS_
891 R$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4
892 # add a trailing dot to qualified hostnames so other rules will work
893 R$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5
894 ifdef(`_CANONIFY_HOSTS_', `dnl
895 dnl this should only apply to unqualified hostnames
896 dnl but if a valid character inside an unqualified hostname is an OperatorChar
897 dnl then $- does not work.
898 # lookup unqualified hostnames
899 R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl
900 dnl _NO_CANONIFY_ is not set: canonify unless:
901 dnl {daemon_flags} contains CC (do not canonify)
902 dnl but add a trailing dot to qualified hostnames so other rules will work
903 dnl should we do this for every hostname: even unqualified?
904 R$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6
905 R$* CC $* $| $* $: $3
906 ifdef(`_FFR_NOCANONIFY_HEADERS', `dnl
907 # do not canonify header addresses
908 R$* $| $* < @ $* $~P > $* $: $&{addr_type} $| $2 < @ $3 $4 > $5
909 R$* h $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6
910 R$* h $* $| $* $: $3', `dnl')
911 # pass to name server to make hostname canonical
912 R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4')
913 dnl remove {daemon_flags} for other cases
916 # local host aliases and pseudo-domains are always canonical
917 R$* < @ $=w > $* $: $1 < @ $2 . > $3
918 ifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
919 `R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4',
920 `R$* < @ $=M > $* $: $1 < @ $2 . > $3')
921 ifdef(`_VIRTUSER_TABLE_', `dnl
922 dnl virtual hosts are also canonical
923 ifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
924 `R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4',
925 `R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')',
927 ifdef(`_GENERICS_TABLE_', `dnl
928 dnl hosts for genericstable are also canonical
929 ifdef(`_GENERICS_ENTIRE_DOMAIN_',
930 `R$* < @ $* $=G > $* $: $1 < @ $2 $3 . > $4',
931 `R$* < @ $=G > $* $: $1 < @ $2 . > $3')',
933 dnl remove superfluous dots (maybe repeatedly) which may have been added
934 dnl by one of the rules before
935 R$* < @ $* . . > $* $1 < @ $2 . > $3
938 ##################################################
939 ### Ruleset 4 -- Final Output Post-rewriting ###
940 ##################################################
943 R$+ :; <@> $@ $1 : handle <list:;>
944 R$* <@> $@ handle <> and list:;
946 # strip trailing dot off possibly canonical name
947 R$* < @ $+ . > $* $1 < @ $2 > $3
949 # eliminate internal code
950 R$* < @ *LOCAL* > $* $1 < @ $j > $2
952 # externalize local domain info
953 R$* < $+ > $* $1 $2 $3 defocus
954 R@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical
955 R@ $* $@ @ $1 ... and exit
957 ifdef(`_NO_UUCP_', `dnl',
958 `# UUCP must always be presented in old form
959 R$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u')
961 ifdef(`_USE_DECNET_SYNTAX_',
962 `# put DECnet back in :: form
963 R$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u',
965 # delete duplicate local names
966 R$+ % $=w @ $=w $1 @ $2 u%host@host => u@host
970 ##############################################################
971 ### Ruleset 97 -- recanonicalize and call ruleset zero ###
972 ### (used for recursive calls) ###
973 ##############################################################
980 ######################################
981 ### Ruleset 0 -- Parse Address ###
982 ######################################
986 R$* $: $>Parse0 $1 initial parsing
987 R<@> $#_LOCAL_ $: <@> special case error msgs
988 R$* $: $>ParseLocal $1 handle local hacks
989 R$* $: $>Parse1 $1 final parsing
992 # Parse0 -- do initial syntax checking and eliminate local addresses.
993 # This should either return with the (possibly modified) input
994 # or return with a #error mailer. It should not return with a
995 # #mailer other than the #error mailer.
999 R<@> $@ <@> special case error msgs
1000 R$* : $* ; <@> $#error $@ 5.1.3 $: "_CODE553 List:; syntax illegal for recipient addresses"
1001 R@ <@ $* > < @ $1 > catch "@@host" bogosity
1002 R<@ $+> $#error $@ 5.1.3 $: "_CODE553 User address required"
1003 R$+ <@> $#error $@ 5.1.3 $: "_CODE553 Hostname required"
1005 dnl allow tricks like [host1]:[host2]
1006 R<> $* < @ [ $* ] : $+ > $* $1 < @ [ $2 ] : $3 > $4
1007 R<> $* < @ [ $* ] , $+ > $* $1 < @ [ $2 ] , $3 > $4
1009 R<> $* < @ [ $* ] $+ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid address"
1010 R<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3
1011 R<> $* <$* : $* > $* $#error $@ 5.1.3 $: "_CODE553 Colon illegal in host name part"
1013 R$* < @ . $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name"
1014 R$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "_CODE553 Invalid host name"
1016 R$* < @ $* @ > $* $#error $@ 5.1.2 $: "_CODE553 Invalid route address"
1018 R$* @ $* < @ $* > $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address"
1019 dnl comma only allowed before @; this check is not complete
1020 R$* , $~O $* $#error $@ 5.1.3 $: "_CODE553 Invalid route address"
1022 ifdef(`_STRICT_RFC821_', `# more RFC 821 checks
1023 R$* . < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not end with a dot"
1024 R. $* < @ $* > $* $#error $@ 5.1.2 $: "_CODE553 Local part must not begin with a dot"
1027 # now delete the local info -- note $=O to find characters that cause forwarding
1028 R$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user
1029 R< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ...
1030 R$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here
1031 R< @ $+ > $#error $@ 5.1.3 $: "_CODE553 User address required"
1032 R$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ...
1033 R$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo"
1034 R< @ *LOCAL* > $#error $@ 5.1.3 $: "_CODE553 User address required"
1035 R$* $=O $* < @ *LOCAL* >
1036 $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ...
1037 R$* < @ *LOCAL* > $: $1
1040 # Parse1 -- the bottom half of ruleset 0.
1044 ifdef(`_LDAP_ROUTING_', `dnl
1045 # handle LDAP routing for hosts in $={LDAPRoute}
1046 R$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2> <>
1047 R$+ < @ $={LDAPRouteEquiv} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $M> <>',
1050 ifdef(`_MAILER_smtp_',
1051 `# handle numeric address spec
1052 dnl there is no check whether this is really an IP number
1053 R$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec
1054 R$* < @ [ $+ ] > $* $: $1 < @ [ $2 ] : $S > $3 Add smart host to path
1055 R$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send
1056 R$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer
1057 R$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer',
1060 ifdef(`_VIRTUSER_TABLE_', `dnl
1061 # handle virtual users
1062 ifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
1063 dnl this is not a documented option
1064 dnl it stops looping in virtusertable mapping if input and output
1065 dnl are identical, i.e., if address A is mapped to A.
1066 dnl it does not deal with multi-level recursion
1067 # handle full domains in RHS of virtusertable
1068 R$+ < @ $+ > $: $(macro {RecipientAddress} $) $1 < @ $2 >
1069 R$+ < @ $+ > $: <?> $1 < @ $2 > $| $>final $1 < @ $2 >
1070 R<?> $+ $| $+ $: $1 $(macro {RecipientAddress} $@ $2 $)
1071 R<?> $+ $| $* $: $1',
1073 R$+ $: <!> $1 Mark for lookup
1074 dnl input: <!> local<@domain>
1075 ifdef(`_VIRTUSER_ENTIRE_DOMAIN_',
1076 `R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >',
1077 `R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >')
1078 dnl input: <result-of-lookup | @> local<@domain> | <!> local<@domain>
1079 R<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
1080 dnl if <@> local<@domain>: no match but try lookup
1081 dnl user+detail: try user++@domain if detail not empty
1082 R<@> $+ + $+ < @ $* . >
1083 $: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
1084 dnl user+detail: try user+*@domain
1085 R<@> $+ + $* < @ $* . >
1086 $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
1087 dnl user+detail: try user@domain
1088 R<@> $+ + $* < @ $* . >
1089 $: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
1090 dnl try default entry: @domain
1092 R<@> $+ + $+ < @ $+ . > $: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
1094 R<@> $+ + $* < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
1095 dnl @domain if +detail exists
1096 dnl if no match, change marker to prevent a second @domain lookup
1097 R<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . >
1099 R<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
1104 R< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4
1105 R< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2
1106 ifdef(`_VIRTUSER_STOP_ONE_LEVEL_RECURSION_',`dnl
1107 # check virtuser input address against output address, if same, skip recursion
1108 R< $+ > $+ < @ $+ > $: < $1 > $2 < @ $3 > $| $1
1109 # it is the same: stop now
1110 R< $+ > $+ < @ $+ > $| $&{RecipientAddress} $: $>ParseLocal $>Parse0 $>canonify $1
1111 R< $+ > $+ < @ $+ > $| $* $: < $1 > $2 < @ $3 >
1113 dnl this is not a documented option
1114 dnl it performs no looping at all for virtusertable
1115 ifdef(`_NO_VIRTUSER_RECURSION_',
1116 `R< $+ > $+ < @ $+ > $: $>ParseLocal $>Parse0 $>canonify $1',
1117 `R< $+ > $+ < @ $+ > $: $>Recurse $1')
1120 # short circuit local delivery so forwarded email works
1121 ifdef(`_MAILER_usenet_', `dnl
1122 R$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl')
1125 ifdef(`_STICKY_LOCAL_DOMAIN_',
1126 `R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub
1127 R< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep ....
1128 dnl $H empty (but @$=w.)
1129 R< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name?
1130 R< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address',
1131 `R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names
1132 R$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name')
1134 ifdef(`_MAILER_TABLE_', `dnl
1135 # not local -- try mailer table lookup
1136 R$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name
1137 R< $+ . > $* $: < $1 > $2 strip trailing dot
1138 R< $+ > $* $: < $(mailertable $1 $) > $2 lookup
1139 dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
1140 R< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved?
1141 R< $+ > $* $: $>Mailertable <$1> $2 try domain',
1143 undivert(4)dnl UUCP rules from `MAILER(uucp)'
1145 ifdef(`_NO_UUCP_', `dnl',
1146 `# resolve remotely connected UUCP links (if any)
1148 `R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3',
1151 `R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3',
1154 `R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3',
1157 # resolve fake top level domains by forwarding to other hosts
1158 ifdef(`BITNET_RELAY',
1159 `R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET',
1161 ifdef(`DECNET_RELAY',
1162 `R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET',
1164 ifdef(`_MAILER_pop_',
1165 `R$+ < @ POP. > $#pop $: $1 user@POP',
1167 ifdef(`_MAILER_fax_',
1168 `R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX',
1170 `R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX',
1174 `# forward non-local UUCP traffic to our UUCP relay
1175 R$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail',
1176 `ifdef(`_MAILER_uucp_',
1177 `# forward other UUCP traffic straight to UUCP
1178 R$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP',
1180 ifdef(`_MAILER_usenet_', `
1181 # addresses sent to net.group.USENET will get forwarded to a newsgroup
1182 R$+ . USENET $#usenet $@ usenet $: $1',
1185 ifdef(`_LOCAL_RULES_',
1186 `# figure out what should stay in our local mail system
1187 undivert(1)', `dnl')
1189 # pass names that still have a host to a smarthost (if defined)
1190 R$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name
1192 # deal with other remote names
1193 ifdef(`_MAILER_smtp_',
1194 `R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain',
1195 `R$* < @$* > $* $#error $@ 5.1.2 $: "_CODE553 Unrecognized host name " $2')
1197 # handle locally delivered names
1198 R$=L $#_LOCAL_ $: @ $1 special local names
1199 R$+ $#_LOCAL_ $: $1 regular local names
1201 ###########################################################################
1202 ### Ruleset 5 -- special rewriting after aliases have been expanded ###
1203 ###########################################################################
1207 R$+ $: $1 $| $>"Local_localaddr" $1
1208 R$+ $| $#ok $@ $1 no change
1212 ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1213 # Preserve rcpt_host in {Host}
1214 R$+ $: $1 $| $&h $| $&{Host} check h and {Host}
1215 R$+ $| $| $: $(macro {Host} $@ $) $1 no h or {Host}
1216 R$+ $| $| $+ $: $1 h not set, {Host} set
1217 R$+ $| +$* $| $* $: $1 h is +detail, {Host} set
1218 R$+ $| $* @ $+ $| $* $: $(macro {Host} $@ @$3 $) $1 set {Host} to host in h
1219 R$+ $| $+ $| $* $: $(macro {Host} $@ @$2 $) $1 set {Host} to h
1222 ifdef(`_FFR_5_', `dnl
1223 # Preserve host in a macro
1224 R$+ $: $(macro {LocalAddrHost} $) $1
1225 R$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1')
1227 ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', `dnl
1228 # deal with plussed users so aliases work nicely
1229 R$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
1230 R$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}')
1232 # prepend an empty "forward host" on the front
1235 ifdef(`LUSER_RELAY', `dnl
1236 # send unrecognized local users to a relay host
1237 ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
1238 R< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+
1239 R< > $+ $: < ? $L > < > $(user $1 $) look up user
1240 R< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L
1241 R< ? $* > < $* > $+ $: < $1 > $3 $2 not found', `
1242 R< > $+ $: < $L > $(user $1 $) look up user
1243 R< $* > $+ <> $: < > $2 found; strip $L')
1244 ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1245 R< $+ > $+ $: < $1 > $2 $&{Host}')
1248 ifdef(`MAIL_HUB', `dnl
1249 R< > $+ $: < $H > $1 try hub', `dnl')
1250 ifdef(`LOCAL_RELAY', `dnl
1251 R< > $+ $: < $R > $1 try relay', `dnl')
1252 ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `dnl
1253 R< > $+ $@ $1', `dnl
1254 R< > $+ $: < > < $1 <> $&h > nope, restore +detail
1255 ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1256 R< > < $+ @ $+ <> + $* > $: < > < $1 + $3 @ $2 > check whether +detail')
1257 R< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail
1258 R< > < $+ <> $* > $: < > < $1 > else discard
1259 R< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part
1260 R< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra +
1261 R< > < $+ > $@ $1 no +detail
1262 R$+ $: $1 <> $&h add +detail back in
1263 ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1264 R$+ @ $+ <> + $* $: $1 + $3 @ $2 check whether +detail')
1265 R$+ <> + $* $: $1 + $2 check whether +detail
1266 R$+ <> $* $: $1 else discard')
1267 R< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension
1268 R< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension
1269 ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1270 dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
1271 R< $~[ : $+ > $+ @ $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $4 >')
1272 R< $~[ : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
1273 ifdef(`_PRESERVE_LUSER_HOST_', `dnl
1274 R< $+ > $+ @ $+ $@ $>MailerToTriple < $1 > $2 < @ $3 >')
1275 R< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 >
1277 ifdef(`_MAILER_TABLE_', `dnl
1278 ifdef(`_LDAP_ROUTING_', `dnl
1279 ###################################################################
1280 ### Ruleset LDAPMailertable -- mailertable lookup for LDAP ###
1281 dnl input: <Domain> FullAddress
1282 ###################################################################
1285 R< $+ > $* $: < $(mailertable $1 $) > $2 lookup
1286 R< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check resolved?
1287 R< $+ > $* $: < $1 > $>Mailertable <$1> $2 try domain
1288 R< $+ > $#$* $#$2 found
1289 R< $+ > $* $#_RELAY_ $@ $1 $: $2 not found, direct relay',
1292 ###################################################################
1293 ### Ruleset 90 -- try domain part of mailertable entry ###
1294 dnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress
1295 ###################################################################
1299 dnl %2 is not documented in cf/README
1300 R$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
1301 dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
1302 R$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved?
1303 R$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again
1304 dnl is $2 always empty?
1305 R$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "."
1306 R< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found?
1307 dnl return full address
1308 R< $* > $* $@ $2 no mailertable match',
1311 ###################################################################
1312 ### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ###
1313 dnl input: in general: <[mailer:]host> lp<@domain>rest
1314 dnl <> address -> address
1315 dnl <error:d.s.n:text> -> error
1316 dnl <error:keyword:text> -> error
1317 dnl <error:text> -> error
1318 dnl <mailer:user@host> lp<@domain>rest -> mailer host user
1319 dnl <mailer:host> address -> mailer host address
1320 dnl <localdomain> address -> address
1321 dnl <host> address -> relay host address
1322 ###################################################################
1325 R< > $* $@ $1 strip off null relay
1326 R< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4
1327 R< error : $- : $+ > $* $#error $@ $(dequote $1 $) $: $2
1328 R< error : $+ > $* $#error $: $1
1329 R< local : $* > $* $>CanonLocal < $1 > $2
1330 dnl it is $~[ instead of $- to avoid matches on IPv6 addresses
1331 R< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user
1332 R< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer
1333 R< $=w > $* $@ $2 delete local host
1334 R< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer
1336 ###################################################################
1337 ### Ruleset CanonLocal -- canonify local: syntax ###
1338 dnl input: <user> address
1339 dnl <x> <@host> : rest -> Recurse rest
1340 dnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2
1341 dnl <> user <@host> rest -> local user@host user
1342 dnl <> user -> local user user
1343 dnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont]
1344 dnl <user> lp <@host> rest -> local lp@host user
1345 dnl <user> lp -> local lp user
1346 ###################################################################
1349 # strip local host from routed addresses
1350 R< $* > < @ $+ > : $+ $@ $>Recurse $3
1351 R< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4
1353 # strip trailing dot from any host name that may appear
1354 R< $* > $* < @ $* . > $: < $1 > $2 < @ $3 >
1356 # handle local: syntax -- use old user, either with or without host
1357 R< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1
1358 R< > $+ $#_LOCAL_ $@ $1 $: $1
1360 # handle local:user@host syntax -- ignore host part
1361 R< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 >
1363 # handle local:user syntax
1364 R< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1
1365 R< $+ > $* $#_LOCAL_ $@ $2 $: $1
1367 ###################################################################
1368 ### Ruleset 93 -- convert header names to masqueraded form ###
1369 ###################################################################
1373 ifdef(`_GENERICS_TABLE_', `dnl
1374 # handle generics database
1375 ifdef(`_GENERICS_ENTIRE_DOMAIN_',
1376 dnl if generics should be applied add a @ as mark
1377 `R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark',
1378 `R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark')
1379 R$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark
1380 dnl workspace: either user<@domain> or <user@domain> user <@domain> @
1381 dnl ignore the first case for now
1382 dnl if it has the mark lookup full address
1383 dnl broken: %1 is full address not just detail
1384 R< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 >
1385 dnl workspace: ... or <match|@user@domain> user <@domain>
1386 dnl no match, try user+detail@domain
1387 R<@$+ + $* @ $+> $+ < @ $+ >
1388 $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 >
1389 R<@$+ + $* @ $+> $+ < @ $+ >
1390 $: < $(generics $1@$3 $: $) > $4 < @ $5 >
1391 dnl no match, remove mark
1392 R<@$+ > $+ < @ $+ > $: < > $2 < @ $3 >
1393 dnl no match, try @domain for exceptions
1394 R< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . >
1395 dnl workspace: ... or <match> user <@domain>
1396 dnl no match, try local part
1397 R< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 >
1398 R< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 >
1399 R< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 >
1400 R< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified
1401 R< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified
1402 R< > $* $: $1 not found',
1405 # do not masquerade anything in class N
1406 R$* < @ $* $=N . > $@ $1 < @ $2 $3 . >
1408 ifdef(`MASQUERADE_NAME', `dnl
1409 # special case the users that should be exposed
1410 R$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed
1411 ifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
1412 `R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >',
1413 `R$=E < @ $=M . > $@ $1 < @ $2 . >')
1414 ifdef(`_LIMITED_MASQUERADE_', `dnl',
1415 `R$=E < @ $=w . > $@ $1 < @ $2 . >')
1417 # handle domain-specific masquerading
1418 ifdef(`_MASQUERADE_ENTIRE_DOMAIN_',
1419 `R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms',
1420 `R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms')
1421 ifdef(`_LIMITED_MASQUERADE_', `dnl',
1422 `R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3')
1423 R$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2
1424 R$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null
1425 R$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null
1426 dnl', `dnl no masquerading
1427 dnl just fix *LOCAL* leftovers
1428 R$* < @ *LOCAL* > $@ $1 < @ $j . >')
1430 ###################################################################
1431 ### Ruleset 94 -- convert envelope names to masqueraded form ###
1432 ###################################################################
1435 ifdef(`_MASQUERADE_ENVELOPE_',
1436 `R$+ $@ $>MasqHdr $1',
1437 `R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2')
1439 ###################################################################
1440 ### Ruleset 98 -- local part of ruleset zero (can be null) ###
1441 ###################################################################
1444 undivert(3)dnl LOCAL_RULE_0
1446 ifdef(`_LDAP_ROUTING_', `dnl
1447 ######################################################################
1448 ### LDAPExpand: Expand address using LDAP routing
1451 ### <$1> -- parsed address (user < @ domain . >) (pass through)
1452 ### <$2> -- RFC822 address (user @ domain) (used for lookup)
1453 ### <$3> -- +detail information
1456 ### Mailer triplet ($#mailer $@ host $: address)
1457 ### Parsed address (user < @ domain . >)
1458 ######################################################################
1460 # SMTP operation modes
1461 C{SMTPOpModes} s d D
1464 # do the LDAP lookups
1465 R<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3>
1467 # look for temporary failures and...
1468 R<$* <TMPF>> <$*> <$+> <$+> <$*> $: $&{opMode} $| TMPF <$&{addr_type}> $| $3
1469 R<$*> <$* <TMPF>> <$+> <$+> <$*> $: $&{opMode} $| TMPF <$&{addr_type}> $| $3
1470 ifelse(_LDAP_ROUTE_MAPTEMP_, `_TEMPFAIL_', `dnl
1471 # ... temp fail RCPT SMTP commands
1472 R$={SMTPOpModes} $| TMPF <e r> $| $+ $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."')
1473 # ... return original address for MTA to queue up
1474 R$* $| TMPF <$*> $| $+ $@ $3
1476 # if mailRoutingAddress and local or non-existant mailHost,
1477 # return the new mailRoutingAddress
1478 ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
1479 R<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2
1480 R<$+@$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $5 @ $2')
1481 R<$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1
1482 R<$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1
1485 # if mailRoutingAddress and non-local mailHost,
1486 # relay to mailHost with new mailRoutingAddress
1487 ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
1488 ifdef(`_MAILER_TABLE_', `dnl
1489 # check mailertable for host, relay from there
1490 R<$+@$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$3> $>canonify $1 $6 @ $2',
1491 `R<$+@$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')')
1492 ifdef(`_MAILER_TABLE_', `dnl
1493 # check mailertable for host, relay from there
1494 R<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1',
1495 `R<$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $2 $: $>canonify $1')
1497 # if no mailRoutingAddress and local mailHost,
1498 # return original address
1499 R<> <$=w> <$+> <$+> <$*> $@ $2
1502 # if no mailRoutingAddress and non-local mailHost,
1503 # relay to mailHost with original address
1504 ifdef(`_MAILER_TABLE_', `dnl
1505 # check mailertable for host, relay from there
1506 R<> <$+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2',
1507 `R<> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $1 $: $2')
1509 ifdef(`_LDAP_ROUTE_DETAIL_',
1510 `# if no mailRoutingAddress and no mailHost,
1511 # try without +detail
1512 R<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl
1514 ifdef(`_LDAP_ROUTE_NODOMAIN_', `
1515 # pretend we did the @domain lookup
1516 R<> <> <$+> <$+ @ $+> <$*> $: <> <> <$1> <@ $3> <$4>', `
1517 # if still no mailRoutingAddress and no mailHost,
1519 ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl
1520 R<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <@ $4> <+$3>')
1521 R<> <> <$+> <$+ @ $+> <$*> $@ $>LDAPExpand <$1> <@ $3> <$4>')
1523 # if no mailRoutingAddress and no mailHost and this was a domain attempt,
1524 ifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl
1525 # user does not exist
1526 R<> <> <$+> <@ $+> <$*> $: <?> < $&{addr_type} > < $1 >
1527 # only give error for envelope recipient
1528 R<?> <e r> <$+> $#error $@ nouser $: "550 User unknown"
1529 ifdef(`_LDAP_SENDER_MUST_EXIST_', `dnl
1530 # and the sender too
1531 R<?> <e s> <$+> $#error $@ nouser $: "550 User unknown"')
1532 R<?> <$*> <$+> $@ $2',
1534 # return the original address
1535 R<> <> <$+> <@ $+> <$*> $@ $1')',
1538 ifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode.
1540 ifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
1541 ######################################################################
1542 ### D: LookUpDomain -- search for domain in access database
1545 ### <$1> -- key (domain name)
1546 ### <$2> -- default (what to return if not found in db)
1547 dnl must not be empty
1548 ### <$3> -- mark (must be <(!|+) single-token>)
1549 ### ! does lookup only with tag
1550 ### + does lookup with and without tag
1551 ### <$4> -- passthru (additional data passed unchanged through)
1552 dnl returns: <default> <passthru>
1553 dnl <result> <passthru>
1554 ######################################################################
1557 dnl workspace <key> <default> <passthru> <mark>
1558 dnl lookup with tag (in front, no delimiter here)
1560 R<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
1561 dnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark>
1562 dnl lookup without tag?
1564 R<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
1565 ifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest
1566 dnl XXX apply this also to IP addresses?
1567 dnl currently it works the wrong way round for [1.2.3.4]
1569 R<?> <$+.$+> <$+> <$- $-> <$*> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6>
1571 R<?> <$+.$+> <$+> <+ $-> <$*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl')
1572 ifdef(`_ACCESS_SKIP_', `dnl
1573 dnl found SKIP: return <default> and <passthru>
1575 R<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl')
1576 dnl not found: IPv4 net (no check is done whether it is an IP number!)
1578 R<?> <[$+.$-]> <$+> <$- $-> <$*> $@ $>D <[$1]> <$3> <$4 $5> <$6>
1579 ifdef(`NO_NETINET6', `dnl',
1580 `dnl not found: IPv6 net
1581 dnl (could be merged with previous rule if we have a class containing .:)
1583 R<?> <[$+::$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>
1584 R<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>')
1585 dnl not found, but subdomain: try again
1587 R<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6>
1588 ifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag:
1590 R<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl')
1591 dnl not found, no subdomain: return <default> and <passthru>
1593 R<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>
1594 ifdef(`_ATMPF_', `dnl tempfail?
1596 R<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl')
1597 dnl return <result of lookup> and <passthru>
1599 R<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6>
1601 ######################################################################
1602 ### A: LookUpAddress -- search for host address in access database
1605 ### <$1> -- key (dot quadded host address)
1606 ### <$2> -- default (what to return if not found in db)
1607 dnl must not be empty
1608 ### <$3> -- mark (must be <(!|+) single-token>)
1609 ### ! does lookup only with tag
1610 ### + does lookup with and without tag
1611 ### <$4> -- passthru (additional data passed through)
1612 dnl returns: <default> <passthru>
1613 dnl <result> <passthru>
1614 ######################################################################
1619 R<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
1620 dnl lookup without tag
1622 R<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
1623 dnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru>
1624 ifdef(`_ACCESS_SKIP_', `dnl
1625 dnl found SKIP: return <default> and <passthru>
1627 R<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl')
1628 ifdef(`NO_NETINET6', `dnl',
1629 `dnl no match; IPv6: remove last part
1631 R<?> <$+::$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>
1632 R<?> <$+:$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>')
1633 dnl no match; IPv4: remove last part
1635 R<?> <$+.$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>
1636 dnl no match: return default
1638 R<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>
1639 ifdef(`_ATMPF_', `dnl tempfail?
1641 R<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl')
1642 dnl match: return result
1644 R<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6>
1645 dnl endif _ACCESS_TABLE_
1647 ######################################################################
1648 ### CanonAddr -- Convert an address into a standard form for
1649 ### relay checking. Route address syntax is
1650 ### crudely converted into a %-hack address.
1653 ### $1 -- full recipient address
1656 ### parsed address, not in source route form
1657 dnl user%host%host<@domain>
1658 dnl host!user<@domain>
1659 ######################################################################
1662 R$* $: $>Parse0 $>canonify $1 make domain canonical
1663 ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl
1664 R< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route
1665 R$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack.
1666 R$* < @ $+ > : $* $3 $1 < @ $2 >
1669 ######################################################################
1670 ### ParseRecipient -- Strip off hosts in $=R as well as possibly
1671 ### $* $=m or the access database.
1672 ### Check user portion for host separators.
1675 ### $1 -- full recipient address
1678 ### parsed, non-local-relaying address
1679 ######################################################################
1682 dnl mark and canonify address
1683 R$* $: <?> $>CanonAddr $1
1684 dnl workspace: <?> localpart<@domain[.]>
1685 R<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots
1686 dnl workspace: <?> localpart<@domain>
1687 R<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part
1689 # if no $=O character, no host in the user portion, we are done
1690 R<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4>
1691 dnl no $=O in localpart: return
1694 dnl workspace: <NO> localpart<@domain>, where localpart contains $=O
1695 dnl mark everything which has an "authorized" domain with <RELAY>
1696 ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
1697 # if we relay, check username portion for user%host so host can be checked also
1698 R<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl')
1699 dnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O
1700 dnl if mark is <NO> then change it to <RELAY> if domain is "authorized"
1702 dnl what if access map returns something else than RELAY?
1703 dnl we are only interested in RELAY entries...
1704 dnl other To: entries: blacklist recipient; generic entries?
1705 dnl if it is an error we probably do not want to relay anyway
1706 ifdef(`_RELAY_HOSTS_ONLY_',
1707 `R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 >
1708 ifdef(`_ACCESS_TABLE_', `dnl
1709 R<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 >
1710 R<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')',
1711 `R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 >
1712 ifdef(`_ACCESS_TABLE_', `dnl
1713 R<NO> $* < @ $+ > $: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
1714 R<$+> <$+> $: <$1> $2',`dnl')')
1717 ifdef(`_RELAY_MX_SERVED_', `dnl
1718 dnl do "we" ($=w) act as backup MX server for the destination domain?
1719 R<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > >
1720 R<MX> < : $* <TEMP> : > $* $#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1
1721 dnl yes: mark it as <RELAY>
1722 R<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4
1723 dnl no: put old <NO> mark back
1724 R<MX> < : $* : > < $+ > $: <NO> $2', `dnl')
1726 dnl do we relay to this recipient domain?
1727 R<RELAY> $* < @ $* > $@ $>ParseRecipient $1
1732 ######################################################################
1733 ### check_relay -- check hostname/address on SMTP startup
1734 ######################################################################
1736 ifdef(`_CONTROL_IMMEDIATE_',`dnl
1738 ifdef(`_RATE_CONTROL_IMMEDIATE_',`dnl
1739 dnl workspace: ignored...
1740 R$* $: $>"RateControl" dummy', `dnl')
1741 ifdef(`_CONN_CONTROL_IMMEDIATE_',`dnl
1742 dnl workspace: ignored...
1743 R$* $: $>"ConnControl" dummy', `dnl')
1748 ifdef(`_USE_CLIENT_PTR_',`dnl
1749 R$* $| $* $: $&{client_ptr} $| $2', `dnl')
1750 R$* $: $1 $| $>"Local_check_relay" $1
1751 R$* $| $* $| $#$* $#$3
1752 R$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2
1755 # check for deferred delivery mode
1756 R$* $: < $&{deliveryMode} > $1
1757 R< d > $* $@ deferred
1760 ifdef(`_ACCESS_TABLE_', `dnl
1761 dnl workspace: {client_name} $| {client_addr}
1762 R$+ $| $+ $: $>D < $1 > <?> <+ Connect> < $2 >
1763 dnl workspace: <result-of-lookup> <{client_addr}>
1764 dnl OR $| $+ if client_name is empty
1765 R $| $+ $: $>A < $1 > <?> <+ Connect> <> empty client_name
1766 dnl workspace: <result-of-lookup> <{client_addr}>
1767 R<?> <$+> $: $>A < $1 > <?> <+ Connect> <> no: another lookup
1768 dnl workspace: <result-of-lookup> (<>|<{client_addr}>)
1769 R<?> <$*> $: OK found nothing
1770 dnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK
1771 R<$={Accept}> <$*> $@ $1 return value of lookup
1772 R<REJECT> <$*> $#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"')
1773 R<DISCARD> <$*> $#discard $: discard
1774 R<QUARANTINE:$+> <$*> $#error $@ quarantine $: $1
1776 R<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4
1777 R<ERROR:$+> <$*> $#error $: $1
1778 ifdef(`_ATMPF_', `R<$* _ATMPF_> <$*> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
1779 dnl generic error from access map
1780 R<$+> <$*> $#error $: $1', `dnl')
1783 # DNS based IP address spam list
1784 dnl workspace: ignored...
1785 R$* $: $&{client_addr}
1786 R$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $)
1788 R<?>$+ $#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"',
1790 ifdef(`_RATE_CONTROL_',`dnl
1791 ifdef(`_RATE_CONTROL_IMMEDIATE_',`', `dnl
1792 dnl workspace: ignored...
1793 R$* $: $>"RateControl" dummy')', `dnl')
1794 ifdef(`_CONN_CONTROL_',`dnl
1795 ifdef(`_CONN_CONTROL_IMMEDIATE_',`',`dnl
1796 dnl workspace: ignored...
1797 R$* $: $>"ConnControl" dummy')', `dnl')
1799 ifdef(`_REQUIRE_RDNS_', `dnl
1800 R$* $: $&{client_addr} $| $&{client_resolve}
1801 R$=R $* $@ RELAY We relay for these
1802 R$* $| OK $@ OK Resolves.
1803 R$* $| FAIL $#error $@ 5.7.1 $: 550 Fix reverse DNS for $1
1804 R$* $| TEMP $#error $@ 4.1.8 $: 451 Client IP address $1 does not resolve
1805 R$* $| FORGED $#error $@ 4.1.8 $: 451 Possibly forged hostname for $1
1808 ######################################################################
1809 ### check_mail -- check SMTP ``MAIL FROM:'' command argument
1810 ######################################################################
1814 R$* $: $1 $| $>"Local_check_mail" $1
1816 R$* $| $* $@ $>"Basic_check_mail" $1
1819 # check for deferred delivery mode
1820 R$* $: < $&{deliveryMode} > $1
1821 R< d > $* $@ deferred
1825 dnl done first: we can require authentication for every mail transaction
1826 dnl workspace: address as given by MAIL FROM: (sender)
1827 R$* $: $1 $| $>"tls_client" $&{verify} $| MAIL
1829 dnl undo damage: remove result of tls_client call
1832 dnl workspace: address as given by MAIL FROM:
1833 R<> $@ <OK> we MUST accept <> (RFC 1123)
1834 ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
1835 dnl do some additional checks
1837 dnl no user@localhost (if nonlocal sender)
1838 dnl this is a pretty simple canonification, it will not catch every case
1839 dnl just make sure the address has <> around it (which is required by
1840 dnl the RFC anyway, maybe we should complain if they are missing...)
1841 dnl dirty trick: if it is user@host, just add a dot: user@host. this will
1842 dnl not be modified by host lookups.
1844 R<?><$+> $: <@> <$1>
1846 dnl workspace: <@> <address>
1847 dnl prepend daemon_flags
1848 R$* $: $&{daemon_flags} $| $1
1849 dnl workspace: ${daemon_flags} $| <@> <address>
1850 dnl do not allow these at all or only from local systems?
1851 R$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 >
1852 dnl accept unqualified sender: change mark to avoid test
1853 R$* u $* $| <@> < $* > $: <?> < $3 >
1854 dnl workspace: ${daemon_flags} $| <@> <address>
1855 dnl or: <? ${client_name} > <address>
1856 dnl or: <?> <address>
1857 dnl remove daemon_flags
1859 # handle case of @localhost on address
1860 R<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost >
1861 R<@> < $* @ [127.0.0.1] >
1862 $: < ? $&{client_name} > < $1 @ [127.0.0.1] >
1863 R<@> < $* @ localhost.$m >
1864 $: < ? $&{client_name} > < $1 @ localhost.$m >
1865 ifdef(`_NO_UUCP_', `dnl',
1866 `R<@> < $* @ localhost.UUCP >
1867 $: < ? $&{client_name} > < $1 @ localhost.UUCP >')
1868 dnl workspace: < ? $&{client_name} > <user@localhost|host>
1869 dnl or: <@> <address>
1870 dnl or: <?> <address> (thanks to u in ${daemon_flags})
1871 R<@> $* $: $1 no localhost as domain
1872 dnl workspace: < ? $&{client_name} > <user@localhost|host>
1874 dnl or: <?> <address> (thanks to u in ${daemon_flags})
1875 R<? $=w> $* $: $2 local client: ok
1876 R<? $+> <$+> $#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address"
1877 dnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags})
1879 dnl workspace: address (or <address>)
1880 R$* $: <?> $>CanonAddr $1 canonify sender address and mark it
1881 dnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>)
1882 dnl there is nothing behind the <@host> so no trailing $* needed
1883 R<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots
1884 # handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
1885 R<?> $* < @ $* $=P > $: <_RES_OK_> $1 < @ $2 $3 >
1886 dnl workspace <mark> CanonicalAddress where mark is ? or OK
1887 dnl A sender address with my local host name ($j) is safe
1888 R<?> $* < @ $j > $: <_RES_OK_> $1 < @ $j >
1889 ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',
1890 `R<?> $* < @ $+ > $: <_RES_OK_> $1 < @ $2 > ... unresolvable OK',
1891 `R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 >
1892 R<? $* <$->> $* < @ $+ >
1893 $: <$2> $3 < @ $4 >')
1894 dnl workspace <mark> CanonicalAddress where mark is ?, _RES_OK_, PERM, TEMP
1895 dnl mark is ? iff the address is user (wo @domain)
1897 ifdef(`_ACCESS_TABLE_', `dnl
1898 # check sender address: user@address, user@, address
1899 dnl should we remove +ext from user?
1900 dnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP
1901 R<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
1902 R<$+> $+ $: @<$1> <$2> $| <U:$2@>
1903 dnl workspace: @<mark> <CanonicalAddress> $| <@type:address> ....
1904 dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
1905 dnl will only return user<@domain when "reversing" the args
1906 R@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
1907 dnl workspace: <@><mark> <CanonicalAddress> $| <result>
1908 R<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result
1909 dnl workspace: <result> <mark> <CanonicalAddress>
1910 # retransform for further use
1912 dnl <ResultOfLookup|mark> CanonicalAddress
1913 R<?> <$+> <$*> $: <$1> $2 no match
1914 R<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl')
1915 dnl workspace <ResultOfLookup|mark> CanonicalAddress
1916 dnl mark is ? iff the address is user (wo @domain)
1918 ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl
1919 # handle case of no @domain on address
1920 dnl prepend daemon_flags
1921 R<?> $* $: $&{daemon_flags} $| <?> $1
1922 dnl accept unqualified sender: change mark to avoid test
1923 R$* u $* $| <?> $* $: <_RES_OK_> $3
1924 dnl remove daemon_flags
1926 R<?> $* $: < ? $&{client_addr} > $1
1927 R<?> $* $@ <_RES_OK_> ...local unqualed ok
1928 R<? $+> $* $#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f
1931 R<?> $* $: @ $1 mark address: nothing known about it
1932 R<$={ResOk}> $* $: @ $2 domain ok
1933 R<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
1934 R<PERM> $* $#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist"
1935 ifdef(`_ACCESS_TABLE_', `dnl
1936 R<$={Accept}> $* $# $1 accept from access map
1937 R<DISCARD> $* $#discard $: discard
1938 R<QUARANTINE:$+> $* $#error $@ quarantine $: $1
1939 R<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: confREJECT_MSG', `$@ 5.7.1 $: "550 Access denied"')
1941 R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4
1942 R<ERROR:$+> $* $#error $: $1
1943 ifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
1944 dnl generic error from access map
1945 R<$+> $* $#error $: $1 error from access db',
1947 dnl workspace: @ CanonicalAddress (i.e. address in canonical form localpart<@host>)
1949 ifdef(`_BADMX_CHK_', `dnl
1950 R@ $*<@$+>$* $: $1<@$2>$3 $| $>BadMX $2
1954 # Look up MX records and ferret away a copy of the original address.
1955 # input: domain part of address to check
1956 R$+ $:<MX><$1><:$(mxlist $1$):><:>
1957 # workspace: <MX><domain><: mxlist-result $><:>
1958 R<MX><$+><:$*<TEMP>:><$*> $#error $@ 4.1.2 $: "450 MX lookup failure for "$1
1959 # workspace: <MX> <original destination> <unchecked mxlist> <checked mxlist>
1960 # Recursively run badmx check on each mx.
1961 R<MX><$*><:$+:$*><:$*> <MX><$1><:$3><: $4 $(badmx $2 $):>
1962 # See if any of them fail.
1963 R<MX><$*><$*><$*<BADMX>:$*> $#error $@ 5.1.2 $:"550 Illegal MX record for host "$1
1964 # Reverse the mxlists so we can use the same argument order again.
1965 R<MX><$*><$*><$*> $:<MX><$1><$3><$2>
1966 R<MX><$*><:$+:$*><:$*> <MX><$1><:$3><:$4 $(dnsA $2 $) :>
1968 # Reverse the lists so we can use the same argument order again.
1969 R<MX><$*><$*><$*> $:<MX><$1><$3><$2>
1970 R<MX><$*><:$+:$*><:$*> <MX><$1><:$3><:$4 $(BadMXIP $2 $) :>
1972 R<MX><$*><$*><$*<BADMXIP>:$*> $#error $@ 5.1.2 $:"550 Invalid MX record for host "$1',
1976 ######################################################################
1977 ### check_rcpt -- check SMTP ``RCPT TO:'' command argument
1978 ######################################################################
1982 R$* $: $1 $| $>"Local_check_rcpt" $1
1984 R$* $| $* $@ $>"Basic_check_rcpt" $1
1988 R<> $#error $@ nouser $: "553 User address required"
1989 R$@ $#error $@ nouser $: "553 User address required"
1990 # check for deferred delivery mode
1991 R$* $: < $&{deliveryMode} > $1
1992 R< d > $* $@ deferred
1995 ifdef(`_REQUIRE_QUAL_RCPT_', `dnl
1996 dnl this code checks for user@host where host is not a FQHN.
1997 dnl it is not activated.
1998 dnl notice: code to check for a recipient without a domain name is
1999 dnl available down below; look for the same macro.
2000 dnl this check is done here because the name might be qualified by the
2001 dnl canonicalization.
2002 # require fully qualified domain part?
2003 dnl very simple canonification: make sure the address is in < >
2005 R<?> <$+> $: <@> <$1>
2007 R<@> < postmaster > $: postmaster
2008 R<@> < $* @ $+ . $+ > $: < $1 @ $2 . $3 >
2009 dnl prepend daemon_flags
2010 R<@> $* $: $&{daemon_flags} $| <@> $1
2011 dnl workspace: ${daemon_flags} $| <@> <address>
2012 dnl _r_equire qual.rcpt: ok
2013 R$* r $* $| <@> < $+ @ $+ > $: < $3 @ $4 >
2014 dnl do not allow these at all or only from local systems?
2015 R$* r $* $| <@> < $* > $: < ? $&{client_name} > < $3 >
2017 R<? $=w> < $* > $: <$1>
2018 R<? $+> <$+> $#error $@ 5.5.4 $: "553 Fully qualified domain name required"
2019 dnl remove daemon_flags for other cases
2020 R$* $| <@> $* $: $2', `dnl')
2022 dnl ##################################################################
2023 dnl call subroutines for recipient and relay
2024 dnl possible returns from subroutines:
2025 dnl $#TEMP temporary failure
2026 dnl $#error permanent failure (or temporary if from access map)
2027 dnl $#other stop processing
2028 dnl RELAY RELAYing allowed
2030 ######################################################################
2031 R$* $: $1 $| @ $>"Rcpt_ok" $1
2032 dnl temporary failure? remove mark @ and remember
2033 R$* $| @ $#TEMP $+ $: $1 $| T $2
2034 dnl error or ok (stop)
2036 ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
2037 R$* $| @ RELAY $@ RELAY
2038 dnl something else: call check sender (relay)
2039 R$* $| @ $* $: O $| $>"Relay_ok" $1
2040 dnl temporary failure: call check sender (relay)
2041 R$* $| T $+ $: T $2 $| $>"Relay_ok" $1
2042 dnl temporary failure? return that
2043 R$* $| $#TEMP $+ $#error $2
2044 dnl error or ok (stop)
2046 R$* $| RELAY $@ RELAY
2047 dnl something else: return previous temp failure
2048 R T $+ $| $* $#error $1
2049 # anything else is bogus
2050 R$* $#error $@ 5.7.1 $: confRELAY_MSG
2053 ######################################################################
2054 ### Rcpt_ok: is the recipient ok?
2055 dnl input: recipient address (RCPT TO)
2056 dnl output: see explanation at call
2057 ######################################################################
2059 ifdef(`_LOOSE_RELAY_CHECK_',`dnl
2060 R$* $: $>CanonAddr $1
2061 R$* < @ $* . > $1 < @ $2 > strip trailing dots',
2062 `R$* $: $>ParseRecipient $1 strip relayable hosts')
2064 ifdef(`_BESTMX_IS_LOCAL_',`dnl
2065 ifelse(_BESTMX_IS_LOCAL_, `', `dnl
2067 R$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3',
2069 # limit bestmx to $=B
2070 R$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4')
2071 R$* $=O $* < @ $* @@ $=w . > $* $@ $>"Rcpt_ok" $1 $2 $3
2072 R$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4
2073 R$* < @ $* @@ $* > $* $: $1 < @ $2 > $4')
2075 ifdef(`_BLACKLIST_RCPT_',`dnl
2076 ifdef(`_ACCESS_TABLE_', `dnl
2077 # blacklist local users or any host from receiving mail
2079 dnl user is now tagged with @ to be consistent with check_mail
2080 dnl and to distinguish users from hosts (com would be host, com@ would be user)
2081 R<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
2082 R<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
2083 R<?> $+ $: <> <$1> $| <U:$1@>
2084 dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>>
2085 dnl will only return user<@domain when "reversing" the args
2086 R<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
2087 R<@> <$*> $| <$*> $: <$2> <$1> reverse result
2088 R<?> <$*> $: @ $1 mark address as no match
2089 dnl we may have to filter here because otherwise some RHSs
2090 dnl would be interpreted as generic error messages...
2091 dnl error messages should be "tagged" by prefixing them with error: !
2092 dnl that would make a lot of things easier.
2093 R<$={Accept}> <$*> $: @ $2 mark address as no match
2094 ifdef(`_ACCESS_SKIP_', `dnl
2095 R<SKIP> <$*> $: @ $1 mark address as no match', `dnl')
2096 ifdef(`_DELAY_COMPAT_8_10_',`dnl
2097 dnl compatility with 8.11/8.10:
2098 dnl we have to filter these because otherwise they would be interpreted
2099 dnl as generic error message...
2100 dnl error messages should be "tagged" by prefixing them with error: !
2101 dnl that would make a lot of things easier.
2102 dnl maybe we should stop checks already here (if SPAM_xyx)?
2103 R<$={SpamTag}> <$*> $: @ $2 mark address as no match')
2104 R<REJECT> $* $#error $@ 5.2.1 $: confRCPTREJ_MSG
2105 R<DISCARD> $* $#discard $: discard
2106 R<QUARANTINE:$+> $* $#error $@ quarantine $: $1
2108 R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4
2109 R<ERROR:$+> $* $#error $: $1
2110 ifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2111 dnl generic error from access map
2112 R<$+> $* $#error $: $1 error from access db
2113 R@ $* $1 remove mark', `dnl')', `dnl')
2115 ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl')
2116 # authenticated via TLS?
2117 R$* $: $1 $| $>RelayTLS client authenticated?
2118 R$* $| $# $+ $# $2 error/ok?
2121 R$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type}
2122 dnl workspace: localpart<@domain> $| result of Local_Relay_Auth
2124 dnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech}
2126 R$* $| $* $: $1 $| $&{auth_type}
2127 dnl workspace: localpart<@domain> [ $| ${auth_type} ]
2128 dnl empty ${auth_type}?
2130 dnl mechanism ${auth_type} accepted?
2131 dnl use $# to override further tests (delay_checks): see check_rcpt below
2132 R$* $| $={TrustAuthMech} $# RELAY
2133 dnl remove ${auth_type}
2135 dnl workspace: localpart<@domain> | localpart
2136 ifelse(defn(`_NO_UUCP_'), `r',
2137 `R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH >
2138 R$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl')
2139 # anything terminating locally is ok
2140 ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
2141 R$+ < @ $* $=m > $@ RELAY', `dnl')
2142 R$+ < @ $=w > $@ RELAY
2143 ifdef(`_RELAY_HOSTS_ONLY_',
2144 `R$+ < @ $=R > $@ RELAY
2145 ifdef(`_ACCESS_TABLE_', `dnl
2146 ifdef(`_RELAY_FULL_ADDR_', `dnl
2147 R$+ < @ $+ > $: <$(access To:$1@$2 $: ? $)> <$1 < @ $2 >>
2148 R<?> <$+ < @ $+ >> $: <$(access To:$2 $: ? $)> <$1 < @ $2 >>',`
2149 R$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >>')
2150 dnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
2151 R<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')',
2152 `R$+ < @ $* $=R > $@ RELAY
2153 ifdef(`_ACCESS_TABLE_', `dnl
2154 ifdef(`_RELAY_FULL_ADDR_', `dnl
2155 R$+ < @ $+ > $: $1 < @ $2 > $| $>SearchList <+ To> $| <F:$1@$2> <D:$2> <F:$1@> <>
2156 R$+ < @ $+ > $| <$*> $: <$3> <$1 <@ $2>>
2157 R$+ < @ $+ > $| $* $: <$3> <$1 <@ $2>>',
2158 `R$+ < @ $+ > $: $>D <$2> <?> <+ To> <$1 < @ $2 >>')')')
2159 ifdef(`_ACCESS_TABLE_', `dnl
2160 dnl workspace: <Result-of-lookup | ?> <localpart<@domain>>
2161 R<RELAY> $* $@ RELAY
2162 ifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2163 R<$*> <$*> $: $2',`dnl')
2166 ifdef(`_RELAY_MX_SERVED_', `dnl
2167 # allow relaying for hosts which we MX serve
2168 R$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 >
2169 dnl this must not necessarily happen if the client is checked first...
2170 R< : $* <TEMP> : > $* $#TEMP $@ 4.4.0 $: "450 Can not check MX records for recipient host " $1
2171 R<$* : $=w . : $*> $* $@ RELAY
2172 R< : $* : > $* $: $2',
2175 # check for local user (i.e. unqualified address)
2177 R<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 >
2179 dnl is it really? the standard requires user@domain, not just user
2180 dnl but we should accept it anyway (maybe making it an option:
2182 dnl postmaster must be accepted without domain (DRUMS)
2183 ifdef(`_REQUIRE_QUAL_RCPT_', `dnl
2184 R<?> postmaster $@ OK
2185 # require qualified recipient?
2186 dnl prepend daemon_flags
2187 R<?> $+ $: $&{daemon_flags} $| <?> $1
2188 dnl workspace: ${daemon_flags} $| <?> localpart
2189 dnl do not allow these at all or only from local systems?
2190 dnl r flag? add client_name
2191 R$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3
2192 dnl no r flag: relay to local user (only local part)
2193 # no qualified recipient required
2194 R$* $| <?> $+ $@ RELAY
2195 dnl client_name is empty
2196 R<?> <?> $+ $@ RELAY
2197 dnl client_name is local
2198 R<? $=w> <?> $+ $@ RELAY
2199 dnl client_name is not local
2200 R<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl
2201 dnl no qualified recipient required
2203 dnl it is a remote user: remove mark and then check client
2205 dnl currently the recipient address is not used below
2207 ######################################################################
2208 ### Relay_ok: is the relay/sender ok?
2210 dnl output: see explanation at call
2211 ######################################################################
2213 # anything originating locally is ok
2215 R$* $: $&{client_addr}
2216 R$@ $@ RELAY originated locally
2217 R0 $@ RELAY originated locally
2218 R127.0.0.1 $@ RELAY originated locally
2219 RIPv6:::1 $@ RELAY originated locally
2220 R$=R $* $@ RELAY relayable IP address
2221 ifdef(`_ACCESS_TABLE_', `dnl
2222 R$* $: $>A <$1> <?> <+ Connect> <$1>
2223 R<RELAY> $* $@ RELAY relayable IP address
2224 ifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl
2225 dnl this will cause rejections in cases like:
2226 dnl Connect:My.Host.Domain RELAY
2227 dnl Connect:My.Net REJECT
2228 dnl since in check_relay client_name is checked before client_addr
2229 R<REJECT> $* $@ REJECT rejected IP address')
2230 ifdef(`_ATMPF_', `R<_ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2231 R<$*> <$*> $: $2', `dnl')
2232 R$* $: [ $1 ] put brackets around it...
2233 R$=w $@ RELAY ... and see if it is local
2235 ifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
2236 ifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl
2237 ifdef(`_RELAY_MAIL_FROM_', `dnl
2238 dnl input: {client_addr} or something "broken"
2239 dnl just throw the input away; we do not need it.
2240 # check whether FROM is allowed to use system as relay
2241 R$* $: <?> $>CanonAddr $&f
2242 R<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot
2243 ifdef(`_RELAY_LOCAL_FROM_', `dnl
2244 # check whether local FROM is ok
2245 R<?> $+ < @ $=w > $@ RELAY FROM local', `dnl')
2246 ifdef(`_RELAY_DB_FROM_', `dnl
2247 R<?> $+ < @ $+ > $: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <>
2248 R<@> <RELAY> $@ RELAY RELAY FROM sender ok
2249 ifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2251 ifdef(`_RELAY_DB_FROM_DOMAIN_',
2252 `errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_
2256 dnl notice: the rulesets above do not leave a unique workspace behind.
2257 dnl it does not matter in this case because the following rule ignores
2258 dnl the input. otherwise these rules must "clean up" the workspace.
2260 # check client name: first: did it resolve?
2262 R$* $: < $&{client_resolve} >
2263 R<TEMP> $#TEMP $@ 4.4.0 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
2264 R<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
2265 R<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
2266 dnl ${client_resolve} should be OK, so go ahead
2267 R$* $: <@> $&{client_name}
2268 dnl should not be necessary since it has been done for client_addr already
2269 dnl this rule actually may cause a problem if {client_name} resolves to ""
2270 dnl however, this should not happen since the forward lookup should fail
2271 dnl and {client_resolve} should be TEMP or FAIL.
2272 dnl nevertheless, removing the rule doesn't hurt.
2274 dnl workspace: <@> ${client_name} (not empty)
2275 # pass to name server to make hostname canonical
2276 R<@> $* $=P $:<?> $1 $2
2277 R<@> $+ $:<?> $[ $1 $]
2278 dnl workspace: <?> ${client_name} (canonified)
2279 R$* . $1 strip trailing dots
2280 ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl
2281 R<?> $* $=m $@ RELAY', `dnl')
2283 ifdef(`_RELAY_HOSTS_ONLY_',
2285 ifdef(`_ACCESS_TABLE_', `dnl
2286 R<?> $* $: <$(access Connect:$1 $: ? $)> <$1>
2287 R<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')',
2288 `R<?> $* $=R $@ RELAY
2289 ifdef(`_ACCESS_TABLE_', `dnl
2290 R<?> $* $: $>D <$1> <?> <+ Connect> <$1>',`dnl')')
2291 ifdef(`_ACCESS_TABLE_', `dnl
2292 R<RELAY> $* $@ RELAY
2293 ifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2294 R<$*> <$*> $: $2',`dnl')
2295 dnl end of _PROMISCUOUS_RELAY_
2297 ifdef(`_DELAY_CHECKS_',`dnl
2298 # turn a canonical address in the form user<@domain>
2299 # qualify unqual. addresses with $j
2300 dnl it might have been only user (without <@domain>)
2302 R$* <@ $+ . > $1 <@ $2 >
2303 R$* <@ $* > $@ $1 <@ $2 >
2308 dnl code repeated here from Basic_check_mail
2309 dnl only called from check_rcpt in delay mode if checkrcpt returns $#
2310 R$* $: $1 $| $>"tls_client" $&{verify} $| MAIL
2312 dnl return result from checkrcpt
2318 dnl code repeated here from Basic_check_mail
2319 dnl only called from check_rcpt in delay mode if stopping due to Friend/Hater
2320 R$* $: $1 $| $>"tls_client" $&{verify} $| MAIL
2322 dnl return result from friend/hater check
2326 # call all necessary rulesets
2328 dnl this test should be in the Basic_check_rcpt ruleset
2329 dnl which is the correct DSN code?
2330 # R$@ $#error $@ 5.1.3 $: "553 Recipient address required"
2332 R$+ $: $1 $| $>checkrcpt $1
2333 dnl now we can simply stop checks by returning "$# xyz" instead of just "ok"
2334 dnl on error (or discard) stop now
2335 R$+ $| $#error $* $#error $2
2336 R$+ $| $#discard $* $#discard $2
2337 dnl otherwise call tls_client; see above
2338 R$+ $| $#$* $@ $>"Delay_TLS_Clt" $2
2339 R$+ $| $* $: <?> $>FullAddr $>CanonAddr $1
2341 `dnl lookup user@ and user@address
2342 ifdef(`_ACCESS_TABLE_', `',
2343 `errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db')
2345 dnl one of the next two rules is supposed to match
2346 dnl this code has been copied from BLACKLIST... etc
2347 dnl and simplified by omitting some < >.
2348 R<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@>
2349 R<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 >
2350 dnl R<?> $@ something_is_very_wrong_here
2351 # lookup the addresses only with Spam tag
2352 R<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <>
2353 R<@> $* $| $* $: $2 $1 reverse result
2355 ifdef(`_SPAM_FRIEND_',
2356 `# is the recipient a spam friend?
2357 ifdef(`_SPAM_HATER_',
2358 `errprint(`*** ERROR: define either Hater or Friend -- not both.
2360 R<FRIEND> $+ $@ $>"Delay_TLS_Clt2" SPAMFRIEND
2363 ifdef(`_SPAM_HATER_',
2364 `# is the recipient no spam hater?
2365 R<HATER> $+ $: $1 spam hater: continue checks
2366 R<$*> $+ $@ $>"Delay_TLS_Clt2" NOSPAMHATER everyone else: stop
2369 dnl run further checks: check_mail
2370 dnl should we "clean up" $&f?
2371 ifdef(`_FFR_MAIL_MACRO',
2372 `R$* $: $1 $| $>checkmail $&{mail_from}',
2373 `R$* $: $1 $| $>checkmail <$&f>')
2374 dnl recipient (canonical format) $| result of checkmail
2376 dnl run further checks: check_relay
2377 R$* $| $* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr}
2382 ifdef(`_BLOCK_BAD_HELO_', `dnl
2383 R$* $: $1 $| <$&{auth_authen}> Get auth info
2384 dnl Bypass the test for users who have authenticated.
2385 R$* $| <$+> $: $1 skip if auth
2386 R$* $| <$*> $: $1 $| <$&{client_addr}> [$&s] Get connection info
2387 dnl Bypass for local clients -- IP address starts with $=R
2388 R$* $| <$=R $*> [$*] $: $1 skip if local client
2389 dnl Bypass a "sendmail -bs" session, which use 0 for client ip address
2390 R$* $| <0> [$*] $: $1 skip if sendmail -bs
2391 dnl Reject our IP - assumes "[ip]" is in class $=w
2392 R$* $| <$*> $=w $#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2393 dnl Reject our hostname
2394 R$* $| <$*> [$=w] $#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2395 dnl Pass anything else with a "." in the domain parameter
2396 R$* $| <$*> [$+.$+] $: $1 qualified domain ok
2397 dnl Reject if there was no "." or only an initial or final "."
2398 R$* $| <$*> [$*] $#error $@ 5.7.1 $:"550 bogus HELO name used: " $&s
2399 dnl Clean up the workspace
2403 ifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)')
2404 ######################################################################
2405 ### F: LookUpFull -- search for an entry in access database
2407 ### lookup of full key (which should be an address) and
2408 ### variations if +detail exists: +* and without +detail
2412 ### <$2> -- default (what to return if not found in db)
2413 dnl must not be empty
2414 ### <$3> -- mark (must be <(!|+) single-token>)
2415 ### ! does lookup only with tag
2416 ### + does lookup with and without tag
2417 ### <$4> -- passthru (additional data passed unchanged through)
2418 dnl returns: <default> <passthru>
2419 dnl <result> <passthru>
2420 ######################################################################
2423 dnl workspace: <key> <def> <o tag> <thru>
2426 R<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
2427 dnl no match, try without tag
2429 R<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
2430 dnl no match, +detail: try +*
2432 R<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
2433 $: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
2434 dnl no match, +detail: try +* without tag
2436 R<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
2437 $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
2438 dnl no match, +detail: try without +detail
2440 R<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
2441 $: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
2442 dnl no match, +detail: try without +detail and without tag
2444 R<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
2445 $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
2446 dnl no match, return <default> <passthru>
2448 R<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5>
2449 ifdef(`_ATMPF_', `dnl tempfail?
2451 R<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl')
2452 dnl match, return <match> <passthru>
2454 R<$+> <$*> <$- $-> <$*> $@ <$1> <$5>
2456 ######################################################################
2457 ### E: LookUpExact -- search for an entry in access database
2461 ### <$2> -- default (what to return if not found in db)
2462 dnl must not be empty
2463 ### <$3> -- mark (must be <(!|+) single-token>)
2464 ### ! does lookup only with tag
2465 ### + does lookup with and without tag
2466 ### <$4> -- passthru (additional data passed unchanged through)
2467 dnl returns: <default> <passthru>
2468 dnl <result> <passthru>
2469 ######################################################################
2473 R<$*> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
2474 dnl no match, try without tag
2476 R<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
2477 dnl no match, return default passthru
2479 R<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5>
2480 ifdef(`_ATMPF_', `dnl tempfail?
2482 R<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl')
2483 dnl match, return <match> <passthru>
2485 R<$+> <$*> <$- $-> <$*> $@ <$1> <$5>
2487 ######################################################################
2488 ### U: LookUpUser -- search for an entry in access database
2490 ### lookup of key (which should be a local part) and
2491 ### variations if +detail exists: +* and without +detail
2494 ### <$1> -- key (user@)
2495 ### <$2> -- default (what to return if not found in db)
2496 dnl must not be empty
2497 ### <$3> -- mark (must be <(!|+) single-token>)
2498 ### ! does lookup only with tag
2499 ### + does lookup with and without tag
2500 ### <$4> -- passthru (additional data passed unchanged through)
2501 dnl returns: <default> <passthru>
2502 dnl <result> <passthru>
2503 ######################################################################
2506 dnl user lookups are always with trailing @
2508 R<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
2509 dnl no match, try without tag
2511 R<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
2512 dnl do not remove the @ from the lookup:
2513 dnl it is part of the +detail@ which is omitted for the lookup
2514 dnl no match, +detail: try +*
2516 R<?> <$+ + $* @> <$*> <$- $-> <$*>
2517 $: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
2518 dnl no match, +detail: try +* without tag
2520 R<?> <$+ + $* @> <$*> <+ $-> <$*>
2521 $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
2522 dnl no match, +detail: try without +detail
2524 R<?> <$+ + $* @> <$*> <$- $-> <$*>
2525 $: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
2526 dnl no match, +detail: try without +detail and without tag
2528 R<?> <$+ + $* @> <$*> <+ $-> <$*>
2529 $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
2530 dnl no match, return <default> <passthru>
2532 R<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5>
2533 ifdef(`_ATMPF_', `dnl tempfail?
2535 R<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl')
2536 dnl match, return <match> <passthru>
2538 R<$+> <$*> <$- $-> <$*> $@ <$1> <$5>
2540 ######################################################################
2541 ### SearchList: search a list of items in the access map
2543 ### <exact tag> $| <mark:address> <mark:address> ... <>
2544 dnl maybe we should have a @ (again) in front of the mark to
2545 dnl avoid errorneous matches (with error messages?)
2546 dnl if we can make sure that tag is always a single token
2547 dnl then we can omit the delimiter $|, otherwise we need it
2548 dnl to avoid errorneous matchs (first rule: D: if there
2549 dnl is that mark somewhere in the list, it will be taken).
2550 dnl moreover, we can do some tricks to enforce lookup with
2551 dnl the tag only, e.g.:
2552 ### where "exact" is either "+" or "!":
2553 ### <+ TAG> lookup with and w/o tag
2554 ### <! TAG> lookup with tag
2555 dnl Warning: + and ! should be in OperatorChars (otherwise there must be
2556 dnl a blank between them and the tag.
2557 ### possible values for "mark" are:
2558 ### D: recursive host lookup (LookUpDomain)
2559 dnl A: recursive address lookup (LookUpAddress) [not yet required]
2560 ### E: exact lookup, no modifications
2561 ### F: full lookup, try user+ext@domain and user@domain
2562 ### U: user lookup, try user+ext and user (input must have trailing @)
2563 ### return: <RHS of lookup> or <?> (not found)
2564 ######################################################################
2566 # class with valid marks for SearchList
2567 dnl if A is activated: add it
2568 C{Src}E F D U ifdef(`_FFR_SRCHLIST_A', `A')
2570 # just call the ruleset with the name of the tag... nice trick...
2572 R<$+> $| <$={Src}:$*> <$*> $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
2573 dnl workspace: <o tag> $| <rest> $| <result of lookup> <>
2574 dnl no match and nothing left: return
2575 R<$+> $| <> $| <?> <> $@ <?>
2576 dnl no match but something left: continue
2577 R<$+> $| <$+> $| <?> <> $@ $>SearchList <$1> $| <$2>
2579 R<$+> $| <$*> $| <$+> <> $@ <$3>
2580 dnl return result from recursive invocation
2581 R<$+> $| <$+> $@ <$2>
2582 dnl endif _ACCESS_TABLE_
2585 ######################################################################
2586 ### trust_auth: is user trusted to authenticate as someone else?
2589 ### $1: AUTH= parameter from MAIL command
2590 ######################################################################
2592 dnl empty ruleset definition so it can be called
2595 R$* $: $&{auth_type} $| $1
2596 # required by RFC 2554 section 4.
2597 R$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated"
2598 dnl seems to be useful...
2599 R$* $| $&{auth_authen} $@ identical
2600 R$* $| <$&{auth_authen}> $@ identical
2601 dnl call user supplied code
2602 R$* $| $* $: $1 $| $>"Local_trust_auth" $2
2605 R$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
2607 ######################################################################
2608 ### Relay_Auth: allow relaying based on authentication?
2611 ### $1: ${auth_type}
2612 ######################################################################
2615 ######################################################################
2616 ### srv_features: which features to offer to a client?
2617 ### (done in server)
2618 ######################################################################
2620 ifdef(`_LOCAL_SRV_FEATURES_', `dnl
2621 R$* $: $1 $| $>"Local_srv_features" $1
2623 R$* $| $* $: $1', `dnl')
2624 ifdef(`_ACCESS_TABLE_', `dnl
2625 R$* $: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <>
2626 R<?>$* $: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <>
2627 R<?>$* $: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)>
2629 ifdef(`_ATMPF_', `dnl tempfail?
2630 R<$* _ATMPF_>$* $#temp', `dnl')
2633 ######################################################################
2634 ### try_tls: try to use STARTTLS?
2635 ### (done in client)
2636 ######################################################################
2638 ifdef(`_LOCAL_TRY_TLS_', `dnl
2639 R$* $: $1 $| $>"Local_try_tls" $1
2641 R$* $| $* $: $1', `dnl')
2642 ifdef(`_ACCESS_TABLE_', `dnl
2643 R$* $: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <>
2644 R<?>$* $: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <>
2645 R<?>$* $: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)>
2647 ifdef(`_ATMPF_', `dnl tempfail?
2648 R<$* _ATMPF_>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2649 R<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"')
2651 ######################################################################
2652 ### tls_rcpt: is connection with server "good" enough?
2653 ### (done in client, per recipient)
2654 dnl called from deliver() before RCPT command
2658 ######################################################################
2660 ifdef(`_LOCAL_TLS_RCPT_', `dnl
2661 R$* $: $1 $| $>"Local_tls_rcpt" $1
2663 R$* $| $* $: $1', `dnl')
2664 ifdef(`_ACCESS_TABLE_', `dnl
2665 dnl store name of other side
2666 R$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1
2667 dnl canonify recipient address
2668 R$+ $: <?> $>CanonAddr $1
2669 dnl strip trailing dots
2670 R<?> $+ < @ $+ . > <?> $1 <@ $2 >
2672 R<?> $+ < @ $+ > $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
2674 R<?> $+ $: $1 $| <U:$1@> <E:>
2676 dnl also look up a default value via E:
2677 R$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <>
2678 dnl found nothing: stop here
2680 ifdef(`_ATMPF_', `dnl tempfail?
2681 R$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2682 dnl use the generic routine (for now)
2683 R$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>')
2685 ######################################################################
2686 ### tls_client: is connection with client "good" enough?
2687 ### (done in server)
2690 ### ${verify} $| (MAIL|STARTTLS)
2691 ######################################################################
2692 dnl MAIL: called from check_mail
2693 dnl STARTTLS: called from smtp() after STARTTLS has been accepted
2695 ifdef(`_LOCAL_TLS_CLIENT_', `dnl
2696 R$* $: $1 <?> $>"Local_tls_client" $1
2698 R$* <?> $* $: $1', `dnl')
2699 ifdef(`_ACCESS_TABLE_', `dnl
2700 dnl store name of other side
2701 R$* $: $(macro {TLS_Name} $@ $&{client_name} $) $1
2702 dnl ignore second arg for now
2703 dnl maybe use it to distinguish permanent/temporary error?
2704 dnl if MAIL: permanent (STARTTLS has not been offered)
2705 dnl if STARTTLS: temporary (offered but maybe failed)
2706 R$* $| $* $: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <>
2707 R$* $| <?>$* $: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <>
2708 dnl do a default lookup: just TLS_CLT_TAG
2709 R$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)>
2710 ifdef(`_ATMPF_', `dnl tempfail?
2711 R$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2712 R$* $@ $>"TLS_connection" $1', `dnl
2713 R$* $| $* $@ $>"TLS_connection" $1')
2715 ######################################################################
2716 ### tls_server: is connection with server "good" enough?
2717 ### (done in client)
2721 ######################################################################
2722 dnl i.e. has the server been authenticated and is encryption active?
2723 dnl called from deliver() after STARTTLS command
2725 ifdef(`_LOCAL_TLS_SERVER_', `dnl
2726 R$* $: $1 $| $>"Local_tls_server" $1
2728 R$* $| $* $: $1', `dnl')
2729 ifdef(`_ACCESS_TABLE_', `dnl
2730 dnl store name of other side
2731 R$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1
2732 R$* $: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <>
2733 R$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <>
2734 dnl do a default lookup: just TLS_SRV_TAG
2735 R$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)>
2736 ifdef(`_ATMPF_', `dnl tempfail?
2737 R$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2738 R$* $@ $>"TLS_connection" $1', `dnl
2739 R$* $@ $>"TLS_connection" $1')
2741 ######################################################################
2742 ### TLS_connection: is TLS connection "good" enough?
2745 ifdef(`_ACCESS_TABLE_', `dnl
2746 ### ${verify} $| <Requirement> [<>]', `dnl
2748 ### Requirement: RHS from access map, may be ? for none.
2749 dnl syntax for Requirement:
2750 dnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions]
2751 dnl extensions: could be a list of further requirements
2752 dnl for now: CN:string {cn_subject} == string
2753 ######################################################################
2755 ifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error
2756 dnl deal with TLS handshake failures: abort
2757 RSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."
2759 dnl common ruleset for tls_{client|server}
2760 dnl input: ${verify} $| <ResultOfLookup> [<>]
2761 dnl remove optional <>
2762 R$* $| <$*>$* $: $1 $| <$2>
2763 dnl workspace: ${verify} $| <ResultOfLookup>
2764 # create the appropriate error codes
2765 dnl permanent or temporary error?
2766 R$* $| <PERM + $={Tls} $*> $: $1 $| <503:5.7.0> <$2 $3>
2767 R$* $| <TEMP + $={Tls} $*> $: $1 $| <403:4.7.0> <$2 $3>
2768 dnl default case depends on TLS_PERM_ERR
2769 R$* $| <$={Tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3>
2770 dnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup>
2771 # deal with TLS handshake failures: abort
2772 RSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed."
2773 dnl no <reply:dns> i.e. not requirements in the access map
2774 dnl use default error
2775 RSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed."
2776 # deal with TLS protocol errors: abort
2777 RPROTOCOL $| <$-:$+> $* $#error $@ $2 $: $1 " STARTTLS failed."
2778 dnl no <reply:dns> i.e. not requirements in the access map
2779 dnl use default error
2780 RPROTOCOL $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') STARTTLS failed."
2781 R$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1
2782 dnl separate optional requirements
2783 R$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1
2784 R$* $| <$*> <$={Tls}:$->$* $: <$2> <$3:$4> <> $1
2785 dnl separate optional requirements
2786 R$* $| <$*> <$={Tls}:$- + $+>$* $: <$2> <$3:$4> <$5> $1
2787 dnl some other value in access map: accept
2788 dnl this also allows to override the default case (if used)
2790 # authentication required: give appropriate error
2791 # other side did authenticate (via STARTTLS)
2792 dnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify}
2793 dnl only verification required and it succeeded
2794 R<$*><VERIFY> <> OK $@ OK
2795 dnl verification required and it succeeded but extensions are given
2796 dnl change it to <SMTP:ESC> <REQ:0> <extensions>
2797 R<$*><VERIFY> <$+> OK $: <$1> <REQ:0> <$2>
2798 dnl verification required + some level of encryption
2799 R<$*><VERIFY:$-> <$*> OK $: <$1> <REQ:$2> <$3>
2800 dnl just some level of encryption required
2801 R<$*><ENCR:$-> <$*> $* $: <$1> <REQ:$2> <$3>
2803 dnl 1. <SMTP:ESC> <VERIFY [:bits]> <[extensions]> {verify} (!= OK)
2804 dnl 2. <SMTP:ESC> <REQ:bits> <[extensions]>
2805 dnl verification required but ${verify} is not set (case 1.)
2806 R<$-:$+><VERIFY $*> <$*> $#error $@ $2 $: $1 " authentication required"
2807 R<$-:$+><VERIFY $*> <$*> FAIL $#error $@ $2 $: $1 " authentication failed"
2808 R<$-:$+><VERIFY $*> <$*> NO $#error $@ $2 $: $1 " not authenticated"
2809 R<$-:$+><VERIFY $*> <$*> NOT $#error $@ $2 $: $1 " no authentication requested"
2810 R<$-:$+><VERIFY $*> <$*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS"
2811 dnl some other value for ${verify}
2812 R<$-:$+><VERIFY $*> <$*> $+ $#error $@ $2 $: $1 " authentication failure " $4
2813 dnl some level of encryption required: get the maximum level (case 2.)
2814 R<$*><REQ:$-> <$*> $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
2815 dnl compare required bits with actual bits
2816 R<$*><REQ:$-> <$*> $- $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
2817 R<$-:$+><$-:$-> <$*> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
2818 dnl strength requirements fulfilled
2819 dnl TLS Additional Requirements Separator
2820 dnl this should be something which does not appear in the extensions itself
2821 dnl @ could be part of a CN, DN, etc...
2822 dnl use < > ? those are encoded in CN, DN, ...
2823 define(`_TLS_ARS_', `++')dnl
2825 dnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare
2826 R<$-:$+><$-:$-> <$*> $* $: <$1:$2 _TLS_ARS_ $5>
2827 dnl workspace: <SMTP:ESC _TLS_ARS_ extensions>
2828 dnl continue: check extensions
2829 R<$-:$+ _TLS_ARS_ > $@ OK
2830 dnl split extensions into own list
2831 R<$-:$+ _TLS_ARS_ $+ > $: <$1:$2> <$3>
2832 R<$-:$+> < $+ _TLS_ARS_ $+ > <$1:$2> <$3> <$4>
2833 R<$-:$+> $+ $@ $>"TLS_req" $3 $| <$1:$2>
2835 ######################################################################
2836 ### TLS_req: check additional TLS requirements
2838 ### Parameters: [<list> <of> <req>] $| <$-:$+>
2839 ### $-: SMTP reply code
2840 ### $+: Enhanced Status Code
2841 dnl further requirements for this ruleset:
2842 dnl name of "other side" is stored is {TLS_name} (client/server_name)
2844 dnl currently only CN[:common_name] is implemented
2845 dnl right now this is only a logical AND
2846 dnl i.e. all requirements must be true
2847 dnl how about an OR? CN must be X or CN must be Y or ..
2848 dnl use a macro to compute this as a trivial sequential
2849 dnl operations (no precedences etc)?
2850 ######################################################################
2852 dnl no additional requirements: ok
2854 dnl require CN: but no CN specified: use name of other side
2855 R<CN> $* $| <$+> $: <CN:$&{TLS_Name}> $1 $| <$2>
2856 dnl match, check rest
2857 R<CN:$&{cn_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2>
2858 dnl CN does not match
2860 R<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
2862 R<CS:$&{cert_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2>
2863 dnl CS does not match
2865 R<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1
2866 dnl match, check rest
2867 R<CI:$&{cert_issuer}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2>
2868 dnl CI does not match
2870 R<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1
2871 dnl return from recursive call
2874 ######################################################################
2875 ### max: return the maximum of two values separated by :
2877 ### Parameters: [$-]:[$-]
2878 ######################################################################
2883 R$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2
2886 dnl endif _ACCESS_TABLE_
2889 ######################################################################
2890 ### RelayTLS: allow relaying based on TLS authentication
2894 ######################################################################
2897 dnl we do not allow relaying for anyone who can present a cert
2898 dnl signed by a "trusted" CA. For example, even if we put verisigns
2899 dnl CA in CertPath so we can authenticate users, we do not allow
2900 dnl them to abuse our server (they might be easier to get hold of,
2902 dnl so here is the trick: if the verification succeeded
2903 dnl we look up the cert issuer in the access map
2904 dnl (maybe after extracting a part with a regular expression)
2905 dnl if this returns RELAY we relay without further questions
2906 dnl if it returns SUBJECT we perform a similar check on the
2908 ifdef(`_ACCESS_TABLE_', `dnl
2909 R$* $: <?> $&{verify}
2910 R<?> OK $: OK authenticated: continue
2911 R<?> $* $@ NO not authenticated
2912 ifdef(`_CERT_REGEX_ISSUER_', `dnl
2913 R$* $: $(CERTIssuer $&{cert_issuer} $)',
2914 `R$* $: $&{cert_issuer}')
2915 R$+ $: $(access CERTISSUER`'_TAG_DELIM_`'$1 $)
2916 dnl use $# to stop further checks (delay_check)
2918 ifdef(`_CERT_REGEX_SUBJECT_', `dnl
2919 RSUBJECT $: <@> $(CERTSubject $&{cert_subject} $)',
2920 `RSUBJECT $: <@> $&{cert_subject}')
2921 R<@> $+ $: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $)
2925 ######################################################################
2926 ### authinfo: lookup authinfo in the access map
2929 ### $1: {server_name}
2930 ### $2: {server_addr}
2931 dnl both are currently ignored
2932 dnl if it should be done via another map, we either need to restrict
2933 dnl functionality (it calls D and A) or copy those rulesets (or add another
2934 dnl parameter which I want to avoid, it's quite complex already)
2935 ######################################################################
2936 dnl omit this ruleset if neither is defined?
2937 dnl it causes DefaultAuthInfo to be ignored
2938 dnl (which may be considered a good thing).
2940 ifdef(`_AUTHINFO_TABLE_', `dnl
2941 R$* $: <$(authinfo AuthInfo:$&{server_name} $: ? $)>
2942 R<?> $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)>
2943 R<?> $: <$(authinfo AuthInfo: $: ? $)>
2944 R<?> $@ no no authinfo available
2947 ifdef(`_ACCESS_TABLE_', `dnl
2948 R$* $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
2949 R$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
2950 R$* $| <?>$* $: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <>
2951 R$* $| <?>$* $@ no no authinfo available
2952 R$* $| <$*> <> $# $2
2955 ifdef(`_RATE_CONTROL_',`dnl
2956 ######################################################################
2958 ### Parameters: ignored
2959 ### return: $#error or OK
2960 ######################################################################
2962 ifdef(`_ACCESS_TABLE_', `dnl
2963 R$* $: <A:$&{client_addr}> <E:>
2964 dnl also look up a default value via E:
2965 R$+ $: $>SearchList <! ClientRate> $| $1 <>
2966 dnl found nothing: stop here
2968 ifdef(`_ATMPF_', `dnl tempfail?
2969 R<$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2970 dnl use the generic routine (for now)
2972 R<$+> $: <$1> $| $(arith l $@ $1 $@ $&{client_rate} $)
2973 dnl log this? Connection rate $&{client_rate} exceeds limit $1.
2974 R<$+> $| TRUE $#error $@ 4.3.2 $: _RATE_CONTROL_REPLY Connection rate limit exceeded.
2977 ifdef(`_CONN_CONTROL_',`dnl
2978 ######################################################################
2980 ### Parameters: ignored
2981 ### return: $#error or OK
2982 ######################################################################
2984 ifdef(`_ACCESS_TABLE_', `dnl
2985 R$* $: <A:$&{client_addr}> <E:>
2986 dnl also look up a default value via E:
2987 R$+ $: $>SearchList <! ClientConn> $| $1 <>
2988 dnl found nothing: stop here
2990 ifdef(`_ATMPF_', `dnl tempfail?
2991 R<$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl')
2992 dnl use the generic routine (for now)
2994 R<$+> $: <$1> $| $(arith l $@ $1 $@ $&{client_connections} $)
2995 dnl log this: Open connections $&{client_connections} exceeds limit $1.
2996 R<$+> $| TRUE $#error $@ 4.3.2 $: _CONN_CONTROL_REPLY Too many open connections.
2999 undivert(9)dnl LOCAL_RULESETS
3001 ######################################################################
3002 ######################################################################
3004 `##### MAIL FILTER DEFINITIONS'
3006 ######################################################################
3007 ######################################################################
3010 ######################################################################
3011 ######################################################################
3013 `##### MAILER DEFINITIONS'
3015 ######################################################################
3016 ######################################################################
3017 undivert(7)dnl MAILER_DEFINITIONS