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