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