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