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