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