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