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