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