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