1divert(-1) 2# 3# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 4# All rights reserved. 5# Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. 6# Copyright (c) 1988, 1993 7# The Regents of the University of California. All rights reserved. 8# 9# By using this file, you agree to the terms and conditions set 10# forth in the LICENSE file which can be found at the top level of 11# the sendmail distribution. 12# 13# 14divert(0) 15 16VERSIONID(`$Id: proto.m4,v 8.446.2.5.2.29 2000/09/15 04:45:14 gshapiro Exp $') 17 18MAILER(local)dnl 19 20# level CF_LEVEL config file format 21V`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley') 22divert(-1) 23 24# do some sanity checking 25ifdef(`__OSTYPE__',, 26 `errprint(`*** ERROR: No system type defined (use OSTYPE macro) 27')') 28 29# pick our default mailers 30ifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')') 31ifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')') 32ifdef(`confRELAY_MAILER',, 33 `define(`confRELAY_MAILER', 34 `ifdef(`_MAILER_smtp_', `relay', 35 `ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')') 36ifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')') 37define(`_SMTP_', `confSMTP_MAILER')dnl for readability only 38define(`_LOCAL_', `confLOCAL_MAILER')dnl for readability only 39define(`_RELAY_', `confRELAY_MAILER')dnl for readability only 40define(`_UUCP_', `confUUCP_MAILER')dnl for readability only 41 42# back compatibility with old config files 43ifdef(`confDEF_GROUP_ID', 44`errprint(`*** confDEF_GROUP_ID is obsolete. 45 Use confDEF_USER_ID with a colon in the value instead. 46')') 47ifdef(`confREAD_TIMEOUT', 48`errprint(`*** confREAD_TIMEOUT is obsolete. 49 Use individual confTO_<timeout> parameters instead. 50')') 51ifdef(`confMESSAGE_TIMEOUT', 52 `define(`_ARG_', index(confMESSAGE_TIMEOUT, /)) 53 ifelse(_ARG_, -1, 54 `define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)', 55 `define(`confTO_QUEUERETURN', 56 substr(confMESSAGE_TIMEOUT, 0, _ARG_)) 57 define(`confTO_QUEUEWARN', 58 substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')') 59ifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,, 60`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete. 61 Use confMAX_MESSAGE_SIZE for the second part of the value. 62')')') 63 64 65# Sanity check on ldap_routing feature 66# If the user doesn't specify a new map, they better have given as a 67# default LDAP specification which has the LDAP base (and most likely the host) 68ifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(` 69WARNING: Using default FEATURE(ldap_routing) map definition(s) 70without setting confLDAP_DEFAULT_SPEC option. 71')')')dnl 72 73# clean option definitions below.... 74define(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl 75 76dnl required to "rename" the check_* rulesets... 77define(`_U_',ifdef(`_DELAY_CHECKS_',`',`_')) 78dnl default relaying denied message 79ifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG', `"550 Relaying denied"')') 80divert(0)dnl 81 82# override file safeties - setting this option compromises system security, 83# addressing the actual file configuration problem is preferred 84# need to set this before any file actions are encountered in the cf file 85_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe') 86 87# default LDAP map specification 88# need to set this now before any LDAP maps are defined 89_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost') 90 91################## 92# local info # 93################## 94 95Cwlocalhost 96ifdef(`USE_CW_FILE', 97`# file containing names of hosts for which we receive email 98Fw`'confCW_FILE', 99 `dnl') 100 101# my official domain name 102# ... `define' this only if sendmail cannot automatically determine your domain 103ifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM') 104 105CP. 106 107ifdef(`UUCP_RELAY', 108`# UUCP relay host 109DY`'UUCP_RELAY 110CPUUCP 111 112')dnl 113ifdef(`BITNET_RELAY', 114`# BITNET relay host 115DB`'BITNET_RELAY 116CPBITNET 117 118')dnl 119ifdef(`DECNET_RELAY', 120`define(`_USE_DECNET_SYNTAX_', 1)dnl 121# DECnet relay host 122DC`'DECNET_RELAY 123CPDECNET 124 125')dnl 126ifdef(`FAX_RELAY', 127`# FAX relay host 128DF`'FAX_RELAY 129CPFAX 130 131')dnl 132# "Smart" relay host (may be null) 133DS`'ifdef(`SMART_HOST', SMART_HOST) 134 135ifdef(`LUSER_RELAY', `dnl 136# place to which unknown users should be forwarded 137Kuser user -m -a<> 138DL`'LUSER_RELAY', 139`dnl') 140 141# operators that cannot be in local usernames (i.e., network indicators) 142CO @ % ifdef(`_NO_UUCP_', `', `!') 143 144# a class with just dot (for identifying canonical names) 145C.. 146 147# a class with just a left bracket (for identifying domain literals) 148C[[ 149 150ifdef(`_ACCESS_TABLE_', `dnl 151# access_db acceptance class 152C{Accept}OK RELAY 153ifdef(`_DELAY_CHECKS_',`dnl 154ifdef(`_BLACKLIST_RCPT_',`dnl 155# possible access_db RHS for spam friends/haters 156C{SpamTag}SPAMFRIEND SPAMHATER')')', 157`dnl') 158 159ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl 160# Resolve map (to check if a host exists in check_mail) 161Kresolve host -a<OK> -T<TEMP>') 162 163ifdef(`_FFR_5_', `# macro storage map 164Kmacro macro') 165 166ifdef(`confCR_FILE', `dnl 167# Hosts for which relaying is permitted ($=R) 168FR`'confCR_FILE', 169`dnl') 170 171define(`TLS_SRV_TAG', `TLS_Srv')dnl 172define(`TLS_CLT_TAG', `TLS_Clt')dnl 173define(`TLS_TRY_TAG', `Try_TLS')dnl 174define(`TLS_OFF_TAG', `Offer_TLS')dnl 175dnl this may be useful in other contexts too 176ifdef(`_ARITH_MAP_', `', `# arithmetic map 177define(`_ARITH_MAP_', `1')dnl 178Karith arith') 179ifdef(`_ACCESS_TABLE_', `dnl 180# possible values for tls_connect in access map 181C{tls}VERIFY ENCR', `dnl') 182ifdef(`_CERT_REGEX_ISSUER_', `dnl 183# extract relevant part from cert issuer 184KCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl') 185ifdef(`_CERT_REGEX_SUBJECT_', `dnl 186# extract relevant part from cert subject 187KCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl') 188 189# who I send unqualified names to (null means deliver locally) 190DR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY) 191 192# who gets all local email traffic ($R has precedence for unqualified names) 193DH`'ifdef(`MAIL_HUB', MAIL_HUB) 194 195# dequoting map 196Kdequote dequote 197 198divert(0)dnl # end of nullclient diversion 199# class E: names that should be exposed as from this host, even if we masquerade 200# class L: names that should be delivered locally, even if we have a relay 201# class M: domains that should be converted to $M 202# class N: domains that should not be converted to $M 203#CL root 204undivert(5)dnl 205ifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl') 206 207# who I masquerade as (null for no masquerading) (see also $=M) 208DM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME) 209 210# my name for error messages 211ifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON') 212 213undivert(6)dnl LOCAL_CONFIG 214include(_CF_DIR_`m4/version.m4') 215 216############### 217# Options # 218############### 219 220# strip message body to 7 bits on input? 221_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False') 222 223# 8-bit data handling 224_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `adaptive') 225 226# wait for alias file rebuild (default units: minutes) 227_OPTION(AliasWait, `confALIAS_WAIT', `5m') 228 229# location of alias file 230_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases') 231 232# minimum number of free blocks on filesystem 233_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100') 234 235# maximum message size 236_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000') 237 238# substitution for space (blank) characters 239_OPTION(BlankSub, `confBLANK_SUB', `_') 240 241# avoid connecting to "expensive" mailers on initial submission? 242_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False') 243 244# checkpoint queue runs after every N successful deliveries 245_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10') 246 247# default delivery mode 248_OPTION(DeliveryMode, `confDELIVERY_MODE', `background') 249 250# automatically rebuild the alias database? 251# NOTE: There is a potential for a denial of service attack if this is set. 252# This option is deprecated and will be removed from a future version. 253_OPTION(AutoRebuildAliases, `confAUTO_REBUILD', `False') 254 255# error message header/file 256_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header') 257 258# error mode 259_OPTION(ErrorMode, `confERROR_MODE', `print') 260 261# save Unix-style "From_" lines at top of header? 262_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False') 263 264# temporary file mode 265_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600') 266 267# match recipients against GECOS field? 268_OPTION(MatchGECOS, `confMATCH_GECOS', `False') 269 270# maximum hop count 271_OPTION(MaxHopCount, `confMAX_HOP', `17') 272 273# location of help file 274O HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile') 275 276# ignore dots as terminators in incoming messages? 277_OPTION(IgnoreDots, `confIGNORE_DOTS', `False') 278 279# name resolver options 280_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY') 281 282# deliver MIME-encapsulated error messages? 283_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True') 284 285# Forward file search path 286_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward') 287 288# open connection cache size 289_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2') 290 291# open connection cache timeout 292_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m') 293 294# persistent host status directory 295_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat') 296 297# single thread deliveries (requires HostStatusDirectory)? 298_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False') 299 300# use Errors-To: header? 301_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False') 302 303# log level 304_OPTION(LogLevel, `confLOG_LEVEL', `10') 305 306# send to me too, even in an alias expansion? 307_OPTION(MeToo, `confME_TOO', `True') 308 309# verify RHS in newaliases? 310_OPTION(CheckAliases, `confCHECK_ALIASES', `False') 311 312# default messages to old style headers if no special punctuation? 313_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False') 314 315# SMTP daemon options 316ifelse(defn(`confDAEMON_OPTIONS'), `', `dnl', 317`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. See cf/README for more information. 318)'dnl 319`DAEMON_OPTIONS(`confDAEMON_OPTIONS')') 320ifelse(defn(`_DPO_'), `', 321`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-IPv4, Family=inet 322O DaemonPortOptions=Name=MTA-IPv6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_') 323ifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E') 324 325# SMTP client options 326_OPTION(ClientPortOptions, `confCLIENT_OPTIONS', `Address=0.0.0.0') 327 328# privacy flags 329_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings') 330 331# who (if anyone) should get extra copies of error messages 332_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster') 333 334# slope of queue-only function 335_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000') 336 337# queue directory 338O QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue') 339 340# timeouts (many of these) 341_OPTION(Timeout.initial, `confTO_INITIAL', `5m') 342_OPTION(Timeout.connect, `confTO_CONNECT', `5m') 343_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m') 344_OPTION(Timeout.helo, `confTO_HELO', `5m') 345_OPTION(Timeout.mail, `confTO_MAIL', `10m') 346_OPTION(Timeout.rcpt, `confTO_RCPT', `1h') 347_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m') 348_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h') 349_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h') 350_OPTION(Timeout.rset, `confTO_RSET', `5m') 351_OPTION(Timeout.quit, `confTO_QUIT', `2m') 352_OPTION(Timeout.misc, `confTO_MISC', `2m') 353_OPTION(Timeout.command, `confTO_COMMAND', `1h') 354_OPTION(Timeout.ident, `confTO_IDENT', `5s') 355_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s') 356_OPTION(Timeout.control, `confTO_CONTROL', `2m') 357_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d') 358_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d') 359_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d') 360_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d') 361_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h') 362_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h') 363_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h') 364_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h') 365_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m') 366_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s') 367_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s') 368_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s') 369_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4') 370_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4') 371_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4') 372 373# should we not prune routes in route-addr syntax addresses? 374_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False') 375 376# queue up everything before forking? 377_OPTION(SuperSafe, `confSAFE_QUEUE', `True') 378 379# status file 380O StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics') 381 382# time zone handling: 383# if undefined, use system default 384# if defined but null, use TZ envariable passed in 385# if defined and non-null, use that info 386ifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=', 387 confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=', 388 `O TimeZoneSpec=confTIME_ZONE') 389 390# default UID (can be username or userid:groupid) 391_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull') 392 393# list of locations of user database file (null means no lookup) 394_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb') 395 396# fallback MX host 397_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net') 398 399# if we are the best MX host for a site, try it directly instead of config err 400_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False') 401 402# load average at which we just queue messages 403_OPTION(QueueLA, `confQUEUE_LA', `8') 404 405# load average at which we refuse connections 406_OPTION(RefuseLA, `confREFUSE_LA', `12') 407 408# maximum number of children we allow at one time 409_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12') 410 411# maximum number of new connections per second 412_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `3') 413 414# work recipient factor 415_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') 416 417# deliver each queued job in a separate process? 418_OPTION(ForkEachJob, `confSEPARATE_PROC', `False') 419 420# work class factor 421_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800') 422 423# work time factor 424_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000') 425 426# shall we sort the queue by hostname first? 427_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority') 428 429# minimum time in queue before retry 430_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m') 431 432# default character set 433_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1') 434 435# service switch file (ignored on Solaris, Ultrix, OSF/1, others) 436_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch') 437 438# hosts file (normally /etc/hosts) 439_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts') 440 441# dialup line delay on connection failure 442_OPTION(DialDelay, `confDIAL_DELAY', `10s') 443 444# action to take if there are no recipients in the message 445_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed') 446 447# chrooted environment for writing to files 448_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch') 449 450# are colons OK in addresses? 451_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True') 452 453# how many jobs can you process in the queue? 454_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000') 455 456# shall I avoid expanding CNAMEs (violates protocols)? 457_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False') 458 459# SMTP initial login message (old $e macro) 460_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b') 461 462# UNIX initial From header format (old $l macro) 463_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d') 464 465# From: lines that have embedded newlines are unwrapped onto one line 466_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False') 467 468# Allow HELO SMTP command that does not `include' a host name 469_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False') 470 471# Characters to be quoted in a full name phrase (@,;:\()[] are automatic) 472_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.') 473 474# delimiter (operator) characters (old $o macro) 475_OPTION(OperatorChars, `confOPERATORS', `.:@[]') 476 477# shall I avoid calling initgroups(3) because of high NIS costs? 478_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False') 479 480# are group-writable `:include:' and .forward files (un)trustworthy? 481_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True') 482 483# where do errors that occur when sending errors get sent? 484_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster') 485 486# where to save bounces if all else fails 487_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter') 488 489# what user id do we assume for the majority of the processing? 490_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail') 491 492# maximum number of recipients per SMTP envelope 493_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100') 494 495# shall we get local names from our installed interfaces? 496_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 497 498# Return-Receipt-To: header implies DSN request 499_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 500 501# override connection address (for testing) 502_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 503 504# Trusted user for file ownership and starting the daemon 505_OPTION(TrustedUser, `confTRUSTED_USER', `root') 506 507# Control socket for daemon management 508_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 509 510# Maximum MIME header length to protect MUAs 511_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0') 512 513# Maximum length of the sum of all headers 514_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768') 515 516# Maximum depth of alias recursion 517_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10') 518 519# location of pid file 520_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid') 521 522# Prefix string for the process title shown on 'ps' listings 523_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix') 524 525# Data file (df) memory-buffer file maximum size 526_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096') 527 528# Transcript file (xf) memory-buffer file maximum size 529_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096') 530 531# list of authentication mechanisms 532_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5') 533 534# default authentication information for outgoing connections 535_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info') 536 537# SMTP AUTH flags 538_OPTION(AuthOptions, `confAUTH_OPTIONS', `') 539 540ifdef(`_FFR_MILTER', ` 541# Input mail filters 542_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 543 544# Milter options 545_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 546_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') 547_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') 548_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')') 549 550# CA directory 551_OPTION(CACERTPath, `confCACERT_PATH', `') 552# CA file 553_OPTION(CACERTFile, `confCACERT', `') 554# Server Cert 555_OPTION(ServerCertFile, `confSERVER_CERT', `') 556# Server private key 557_OPTION(ServerKeyFile, `confSERVER_KEY', `') 558# Client Cert 559_OPTION(ClientCertFile, `confCLIENT_CERT', `') 560# Client private key 561_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 562# DHParameters (only required if DSA/DH is used) 563_OPTION(DHParameters, `confDH_PARAMETERS', `') 564# Random data source (required for systems without /dev/urandom under OpenSSL) 565_OPTION(RandFile, `confRAND_FILE', `') 566 567ifdef(`confQUEUE_FILE_MODE', 568`# queue file mode (qf files) 569O QueueFileMode=confQUEUE_FILE_MODE 570') 571 572########################### 573# Message precedences # 574########################### 575 576Pfirst-class=0 577Pspecial-delivery=100 578Plist=-30 579Pbulk=-60 580Pjunk=-100 581 582##################### 583# Trusted users # 584##################### 585 586# this is equivalent to setting class "t" 587ifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 588Troot 589Tdaemon 590ifdef(`_NO_UUCP_', `dnl', `Tuucp') 591ifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 592 593######################### 594# Format of headers # 595######################### 596 597ifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl 598H?P?Return-Path: <$g> 599HReceived: confRECEIVED_HEADER 600H?D?Resent-Date: $a 601H?D?Date: $a 602H?F?Resent-From: confFROM_HEADER 603H?F?From: confFROM_HEADER 604H?x?Full-Name: $x 605# HPosted-Date: $a 606# H?l?Received-Date: $b 607H?M?Resent-Message-Id: <$t.$i@$j> 608H?M?Message-Id: <$t.$i@$j> 609 610# 611###################################################################### 612###################################################################### 613##### 614##### REWRITING RULES 615##### 616###################################################################### 617###################################################################### 618 619############################################ 620### Ruleset 3 -- Name Canonicalization ### 621############################################ 622Scanonify=3 623 624# handle null input (translate to <@> special case) 625R$@ $@ <@> 626 627# strip group: syntax (not inside angle brackets!) and trailing semicolon 628R$* $: $1 <@> mark addresses 629R$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> 630R@ $* <@> $: @ $1 unmark @host:... 631R$* :: $* <@> $: $1 :: $2 unmark node::addr 632R:`include': $* <@> $: :`include': $1 unmark :`include':... 633R$* [ IPv6 $- ] <@> $: $1 [ IPv6 $2 ] unmark IPv6 addr 634R$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon 635R$* : $* <@> $: $2 strip colon if marked 636R$* <@> $: $1 unmark 637R$* ; $1 strip trailing semi 638R$* < $* ; > $1 < $2 > bogus bracketed semi 639 640# null input now results from list:; syntax 641R$@ $@ :; <@> 642 643# strip angle brackets -- note RFC733 heuristic to get innermost item 644R$* $: < $1 > housekeeping <> 645R$+ < $* > < $2 > strip excess on left 646R< $* > $+ < $1 > strip excess on right 647R<> $@ < @ > MAIL FROM:<> case 648R< $+ > $: $1 remove housekeeping <> 649 650ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 651# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 652R@ $+ , $+ @ $1 : $2 change all "," to ":" 653 654# localize and dispose of route-based addresses 655R@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 656dnl',`dnl 657# strip route address <@a,@b,@c:user@d> -> <user@d> 658R@ $+ , $+ $2 659R@ $+ : $+ $2 660dnl') 661 662# find focus for list syntax 663R $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 664R $+ : $* ; $@ $1 : $2; list syntax 665 666# find focus for @ syntax addresses 667R$+ @ $+ $: $1 < @ $2 > focus on domain 668R$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 669R$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 670 671# do some sanity checking 672R$* < @ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 673 674ifdef(`_NO_UUCP_', `dnl', 675`# convert old-style addresses to a domain-based address 676R$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 677R$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 678R$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 679') 680ifdef(`_USE_DECNET_SYNTAX_', 681`# convert node::user addresses into a domain-based address 682R$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 683R$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 684', 685 `dnl') 686# if we have % signs, take the rightmost one 687R$* % $* $1 @ $2 First make them all @s. 688R$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 689R$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 690 691# else we must be a local name 692R$* $@ $>Canonify2 $1 693 694 695################################################ 696### Ruleset 96 -- bottom half of ruleset 3 ### 697################################################ 698 699SCanonify2=96 700 701# handle special cases for local names 702R$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 703R$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 704ifdef(`_NO_UUCP_', `dnl', 705`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 706 707# check for IPv6 domain literal (save quoted form) 708R$* < @ [ IPv6 $- ] > $* $: $2 $| $1 < @@ [ $(dequote $2 $) ] > $3 mark IPv6 addr 709R$- $| $* < @@ $=w > $* $: $2 < @ $j . > $4 self-literal 710R$- $| $* < @@ [ $+ ] > $* $@ $2 < @ [ IPv6 $1 ] > $4 canon IP addr 711 712# check for IPv4 domain literal 713R$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [a.b.c.d] 714R$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 715R$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 716 717ifdef(`_DOMAIN_TABLE_', `dnl 718# look up domains in the domain table 719R$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 720 721undivert(2)dnl LOCAL_RULE_3 722 723ifdef(`_BITDOMAIN_TABLE_', `dnl 724# handle BITNET mapping 725R$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 726 727ifdef(`_UUDOMAIN_TABLE_', `dnl 728# handle UUCP mapping 729R$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 730 731ifdef(`_NO_UUCP_', `dnl', 732`ifdef(`UUCP_RELAY', 733`# pass UUCP addresses straight through 734R$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 735`# if really UUCP, handle it immediately 736ifdef(`_CLASS_U_', 737`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 738ifdef(`_CLASS_V_', 739`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 740ifdef(`_CLASS_W_', 741`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 742ifdef(`_CLASS_X_', 743`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 744ifdef(`_CLASS_Y_', 745`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 746 747ifdef(`_NO_CANONIFY_', `dnl', `dnl 748# try UUCP traffic as a local address 749R$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 750R$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 751')') 752# hostnames ending in class P are always canonical 753R$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 754dnl apply the next rule only for hostnames not in class P 755dnl this even works for phrases in class P since . is in class P 756dnl which daemon flags are set? 757R$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 758dnl the other rules in this section only apply if the hostname 759dnl does not end in class P hence no further checks are done here 760dnl if this ever changes make sure the lookups are "protected" again! 761ifdef(`_NO_CANONIFY_', `dnl 762dnl do not canonify unless: 763dnl domain ends in class {Canonify} (this does not work if the intersection 764dnl with class P is non-empty) 765dnl or {daemon_flags} has c set 766# pass to name server to make hostname canonical if in class {Canonify} 767R$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 768# pass to name server to make hostname canonical if requested 769R$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 770dnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 771R$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 772# add a trailing dot to qualified hostnames so other rules will work 773R$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 774ifdef(`_CANONIFY_HOSTS_', `dnl 775dnl this should only apply to unqualified hostnames 776dnl but if a valid character inside an unqualified hostname is an OperatorChar 777dnl then $- does not work. 778# lookup unqualified hostnames 779R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 780dnl _NO_CANONIFY_ is not set: canonify unless: 781dnl {daemon_flags} contains CC (do not canonify) 782R$* CC $* $| $* $: $3 783# pass to name server to make hostname canonical 784R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 785dnl remove {daemon_flags} for other cases 786R$* $| $* $: $2 787 788# local host aliases and pseudo-domains are always canonical 789R$* < @ $=w > $* $: $1 < @ $2 . > $3 790ifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 791`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 792`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 793ifdef(`_VIRTUSER_TABLE_', `dnl 794dnl virtual hosts are also canonical 795ifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 796`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 797`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 798`dnl') 799dnl remove superfluous dots (maybe repeatedly) which may have been added 800dnl by one of the rules before 801R$* < @ $* . . > $* $1 < @ $2 . > $3 802 803 804################################################## 805### Ruleset 4 -- Final Output Post-rewriting ### 806################################################## 807Sfinal=4 808 809R$* <@> $@ handle <> and list:; 810 811# strip trailing dot off possibly canonical name 812R$* < @ $+ . > $* $1 < @ $2 > $3 813 814# eliminate internal code 815R$* < @ *LOCAL* > $* $1 < @ $j > $2 816 817# externalize local domain info 818R$* < $+ > $* $1 $2 $3 defocus 819R@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 820R@ $* $@ @ $1 ... and exit 821 822ifdef(`_NO_UUCP_', `dnl', 823`# UUCP must always be presented in old form 824R$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 825 826ifdef(`_USE_DECNET_SYNTAX_', 827`# put DECnet back in :: form 828R$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 829 `dnl') 830# delete duplicate local names 831R$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 832 833 834 835############################################################## 836### Ruleset 97 -- recanonicalize and call ruleset zero ### 837### (used for recursive calls) ### 838############################################################## 839 840SRecurse=97 841R$* $: $>canonify $1 842R$* $@ $>parse $1 843 844 845###################################### 846### Ruleset 0 -- Parse Address ### 847###################################### 848 849Sparse=0 850 851R$* $: $>Parse0 $1 initial parsing 852R<@> $#_LOCAL_ $: <@> special case error msgs 853R$* $: $>ParseLocal $1 handle local hacks 854R$* $: $>Parse1 $1 final parsing 855 856# 857# Parse0 -- do initial syntax checking and eliminate local addresses. 858# This should either return with the (possibly modified) input 859# or return with a #error mailer. It should not return with a 860# #mailer other than the #error mailer. 861# 862 863SParse0 864R<@> $@ <@> special case error msgs 865R$* : $* ; <@> $#error $@ 5.1.3 $: "501 List:; syntax illegal for recipient addresses" 866R@ <@ $* > < @ $1 > catch "@@host" bogosity 867R<@ $+> $#error $@ 5.1.3 $: "501 User address required" 868R$* $: <> $1 869R<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 870R<> $* <$* : $* > $* $#error $@ 5.1.3 $: "501 Colon illegal in host name part" 871R<> $* $1 872R$* < @ . $* > $* $#error $@ 5.1.2 $: "501 Invalid host name" 873R$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "501 Invalid host name" 874dnl comma only allowed before @; this check is not complete 875R$* , $~O $* $#error $@ 5.1.2 $: "501 Invalid route address" 876 877# now delete the local info -- note $=O to find characters that cause forwarding 878R$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 879R< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 880R$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 881R< @ $+ > $#error $@ 5.1.3 $: "501 User address required" 882R$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 883R$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 884R< @ *LOCAL* > $#error $@ 5.1.3 $: "501 User address required" 885R$* $=O $* < @ *LOCAL* > 886 $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 887R$* < @ *LOCAL* > $: $1 888 889# 890# Parse1 -- the bottom half of ruleset 0. 891# 892 893SParse1 894ifdef(`_LDAP_ROUTING_', `dnl 895# handle LDAP routing for hosts in $={LDAPRoute} 896R$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2>', 897`dnl') 898 899ifdef(`_MAILER_smtp_', 900`# handle numeric address spec 901dnl there is no check whether this is really an IP number 902R$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 903R$* < @ [ $+ ] > $* $1 < @ [ $2 ] : $S > $3 Add smart host to path 904R$* < @ [ IPv6 $- ] : > $* 905 $#_SMTP_ $@ [ $(dequote $2 $) ] $: $1 < @ [IPv6 $2 ] > $3 no smarthost: send 906R$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 907R$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 908R$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 909 `dnl') 910 911ifdef(`_VIRTUSER_TABLE_', `dnl 912# handle virtual users 913R$+ $: <!> $1 Mark for lookup 914ifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 915`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 916`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 917R<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 918R<@> $+ + $* < @ $* . > 919 $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 920R<@> $+ + $* < @ $* . > 921 $: < $(virtuser $1 @ $3 $@ $1 $: @ $) > $1 + $2 < @ $3 . > 922dnl try default entry: @domain 923dnl +*@domain 924R<@> $+ + $+ < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 925dnl @domain if +detail exists 926R<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 927dnl without +detail (or no match) 928R<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 929R<@> $+ $: $1 930R<!> $+ $: $1 931R< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 932R< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 933R< $+ > $+ < @ $+ > $: $>Recurse $1', 934`dnl') 935 936# short circuit local delivery so forwarded email works 937ifdef(`_MAILER_usenet_', `dnl 938R$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 939 940 941ifdef(`_STICKY_LOCAL_DOMAIN_', 942`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 943R< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 944dnl $H empty (but @$=w.) 945R< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 946R< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 947`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 948R$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 949 950ifdef(`_MAILER_TABLE_', `dnl 951# not local -- try mailer table lookup 952R$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 953R< $+ . > $* $: < $1 > $2 strip trailing dot 954R< $+ > $* $: < $(mailertable $1 $) > $2 lookup 955dnl it is $~[ instead of $- to avoid matches on IPv6 addresses 956R< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 957R< $+ > $* $: $>Mailertable <$1> $2 try domain', 958`dnl') 959undivert(4)dnl UUCP rules from `MAILER(uucp)' 960 961ifdef(`_NO_UUCP_', `dnl', 962`# resolve remotely connected UUCP links (if any) 963ifdef(`_CLASS_V_', 964`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 965 `dnl') 966ifdef(`_CLASS_W_', 967`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 968 `dnl') 969ifdef(`_CLASS_X_', 970`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 971 `dnl')') 972 973# resolve fake top level domains by forwarding to other hosts 974ifdef(`BITNET_RELAY', 975`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 976 `dnl') 977ifdef(`DECNET_RELAY', 978`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 979 `dnl') 980ifdef(`_MAILER_pop_', 981`R$+ < @ POP. > $#pop $: $1 user@POP', 982 `dnl') 983ifdef(`_MAILER_fax_', 984`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 985`ifdef(`FAX_RELAY', 986`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 987 `dnl')') 988 989ifdef(`UUCP_RELAY', 990`# forward non-local UUCP traffic to our UUCP relay 991R$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 992`ifdef(`_MAILER_uucp_', 993`# forward other UUCP traffic straight to UUCP 994R$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 995 `dnl')') 996ifdef(`_MAILER_usenet_', ` 997# addresses sent to net.group.USENET will get forwarded to a newsgroup 998R$+ . USENET $#usenet $@ usenet $: $1', 999 `dnl') 1000 1001ifdef(`_LOCAL_RULES_', 1002`# figure out what should stay in our local mail system 1003undivert(1)', `dnl') 1004 1005# pass names that still have a host to a smarthost (if defined) 1006R$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 1007 1008# deal with other remote names 1009ifdef(`_MAILER_smtp_', 1010`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 1011`R$* < @$* > $* $#error $@ 5.1.2 $: "501 Unrecognized host name " $2') 1012 1013# handle locally delivered names 1014R$=L $#_LOCAL_ $: @ $1 special local names 1015R$+ $#_LOCAL_ $: $1 regular local names 1016 1017########################################################################### 1018### Ruleset 5 -- special rewriting after aliases have been expanded ### 1019########################################################################### 1020 1021SLocal_localaddr 1022Slocaladdr=5 1023R$+ $: $1 $| $>"Local_localaddr" $1 1024R$+ $| $#$* $#$2 1025R$+ $| $* $: $1 1026 1027ifdef(`_FFR_5_', ` 1028# Preserve host in a macro 1029R$+ $: $(macro {LocalAddrHost} $) $1 1030R$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 1031 1032ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', ` 1033# deal with plussed users so aliases work nicely 1034R$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 1035R$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 1036') 1037# prepend an empty "forward host" on the front 1038R$+ $: <> $1 1039 1040ifdef(`LUSER_RELAY', `dnl 1041# send unrecognized local users to a relay host 1042ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', ` 1043R< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 1044R< > $+ $: < ? $L > < > $(user $1 $) look up user 1045R< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 1046R< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 1047R< > $+ $: < $L > $(user $1 $) look up user 1048R< $* > $+ <> $: < > $2 found; strip $L')', 1049`dnl') 1050 1051# see if we have a relay or a hub 1052R< > $+ $: < $H > $1 try hub 1053R< > $+ $: < $R > $1 try relay 1054ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', ` 1055R< > $+ $@ $1', ` 1056R< > $+ $: < > < $1 <> $&h > nope, restore +detail 1057R< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 1058R< > < $+ <> $* > $: < > < $1 > else discard 1059R< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 1060R< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 1061R< > < $+ > $@ $1 no +detail 1062R$+ $: $1 <> $&h add +detail back in 1063R$+ <> + $* $: $1 + $2 check whether +detail 1064R$+ <> $* $: $1 else discard') 1065R< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 1066R< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 1067R< $- : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 1068R< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 1069 1070ifdef(`_MAILER_TABLE_', `dnl 1071################################################################### 1072### Ruleset 90 -- try domain part of mailertable entry ### 1073dnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 1074################################################################### 1075 1076SMailertable=90 1077dnl shift and check 1078dnl %2 is not documented in cf/README 1079R$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 1080dnl it is $~[ instead of $- to avoid matches on IPv6 addresses 1081R$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 1082R$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 1083dnl is $2 always empty? 1084R$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 1085R< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 1086dnl return full address 1087R< $* > $* $@ $2 no mailertable match', 1088`dnl') 1089 1090################################################################### 1091### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 1092dnl input: in general: <[mailer:]host> lp<@domain>rest 1093dnl <> address -> address 1094dnl <error:d.s.n:text> -> error 1095dnl <error:text> -> error 1096dnl <mailer:user@host> lp<@domain>rest -> mailer host user 1097dnl <mailer:host> address -> mailer host address 1098dnl <localdomain> address -> address 1099dnl <[IPv6 number]> address -> relay number address 1100dnl <host> address -> relay host address 1101################################################################### 1102 1103SMailerToTriple=95 1104R< > $* $@ $1 strip off null relay 1105R< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 1106R< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 1107R< local : $* > $* $>CanonLocal < $1 > $2 1108R< $- : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 1109R< $- : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 1110R< $=w > $* $@ $2 delete local host 1111R< [ IPv6 $+ ] > $* $#_RELAY_ $@ $(dequote $1 $) $: $2 use unqualified mailer 1112R< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 1113 1114################################################################### 1115### Ruleset CanonLocal -- canonify local: syntax ### 1116dnl input: <user> address 1117dnl <x> <@host> : rest -> Recurse rest 1118dnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 1119dnl <> user <@host> rest -> local user@host user 1120dnl <> user -> local user user 1121dnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 1122dnl <user> lp <@host> rest -> local lp@host user 1123dnl <user> lp -> local lp user 1124################################################################### 1125 1126SCanonLocal 1127# strip local host from routed addresses 1128R< $* > < @ $+ > : $+ $@ $>Recurse $3 1129R< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 1130 1131# strip trailing dot from any host name that may appear 1132R< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 1133 1134# handle local: syntax -- use old user, either with or without host 1135R< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 1136R< > $+ $#_LOCAL_ $@ $1 $: $1 1137 1138# handle local:user@host syntax -- ignore host part 1139R< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 1140 1141# handle local:user syntax 1142R< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 1143R< $+ > $* $#_LOCAL_ $@ $2 $: $1 1144 1145################################################################### 1146### Ruleset 93 -- convert header names to masqueraded form ### 1147################################################################### 1148 1149SMasqHdr=93 1150 1151ifdef(`_GENERICS_TABLE_', `dnl 1152# handle generics database 1153ifdef(`_GENERICS_ENTIRE_DOMAIN_', 1154dnl if generics should be applied add a @ as mark 1155`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 1156`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 1157R$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 1158dnl workspace: either user<@domain> or <user@domain> user <@domain> @ 1159dnl ignore the first case for now 1160dnl if it has the mark lookup full address 1161R< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 1162dnl workspace: ... or <match|@user@domain> user <@domain> 1163dnl no match, try user+detail@domain 1164R<@$+ + $* @ $+> $+ < @ $+ > 1165 $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 1166R<@$+ + $* @ $+> $+ < @ $+ > 1167 $: < $(generics $1@$3 $: $) > $4 < @ $5 > 1168dnl no match, remove mark 1169R<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 1170dnl no match, try @domain for exceptions 1171R< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 1172dnl workspace: ... or <match> user <@domain> 1173dnl no match, try local part 1174R< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 1175R< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 1176R< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 1177R< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 1178R< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 1179R< > $* $: $1 not found', 1180`dnl') 1181 1182# do not masquerade anything in class N 1183R$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 1184 1185# special case the users that should be exposed 1186R$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 1187ifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 1188`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 1189`R$=E < @ $=M . > $@ $1 < @ $2 . >') 1190ifdef(`_LIMITED_MASQUERADE_', `dnl', 1191`R$=E < @ $=w . > $@ $1 < @ $2 . >') 1192 1193# handle domain-specific masquerading 1194ifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 1195`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 1196`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 1197ifdef(`_LIMITED_MASQUERADE_', `dnl', 1198`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 1199R$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 1200R$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 1201R$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 1202 1203################################################################### 1204### Ruleset 94 -- convert envelope names to masqueraded form ### 1205################################################################### 1206 1207SMasqEnv=94 1208ifdef(`_MASQUERADE_ENVELOPE_', 1209`R$+ $@ $>MasqHdr $1', 1210`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 1211 1212################################################################### 1213### Ruleset 98 -- local part of ruleset zero (can be null) ### 1214################################################################### 1215 1216SParseLocal=98 1217undivert(3)dnl LOCAL_RULE_0 1218 1219ifdef(`_LDAP_ROUTING_', `dnl 1220SLDAPExpand 1221# do the LDAP lookups 1222R<$+><$+> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> 1223 1224# if mailRoutingAddress and local or non-existant mailHost, 1225# return the new mailRoutingAddress 1226R< $+ > < $=w > < $+ > < $+ > $@ $>Parse0 $>canonify $1 1227R< $+ > < > < $+ > < $+ > $@ $>Parse0 $>canonify $1 1228 1229# if mailRoutingAddress and non-local mailHost, 1230# relay to mailHost with new mailRoutingAddress 1231R< $+ > < $+ > < $+ > < $+ > $#_RELAY_ $@ $2 $: $>canonify $1 1232 1233# if no mailRoutingAddress and local mailHost, 1234# return original address 1235R< > < $=w > <$+> <$+> $@ $2 1236 1237# if no mailRoutingAddress and non-local mailHost, 1238# relay to mailHost with original address 1239R< > < $+ > <$+> <$+> $#_RELAY_ $@ $1 $: $2 1240 1241# if no mailRoutingAddress and no mailHost, 1242# try @domain 1243R< > < > <$+> <$+ @ $+> $@ $>LDAPExpand <$1> <@ $3> 1244 1245# if no mailRoutingAddress and no mailHost and this was a domain attempt, 1246ifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 1247# user does not exist 1248R< > < > <$+> <@ $+> $#error $@ nouser $: "550 User unknown"', 1249`dnl 1250# return the original address 1251R< > < > <$+> <@ $+> $@ $1')', 1252`dnl') 1253 1254ifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 1255')') 1256ifdef(`_ACCESS_TABLE_', `dnl 1257###################################################################### 1258### LookUpDomain -- search for domain in access database 1259### 1260### Parameters: 1261### <$1> -- key (domain name) 1262### <$2> -- default (what to return if not found in db) 1263dnl must not be empty 1264### <$3> -- passthru (additional data passed unchanged through) 1265### <$4> -- mark (must be <(!|+) single-token>) 1266### ! does lookup only with tag 1267### + does lookup with and without tag 1268dnl returns: <default> <passthru> 1269dnl <result> <passthru> 1270###################################################################### 1271 1272SLookUpDomain 1273dnl remove IPv6 mark and dequote address 1274dnl it is a bit ugly because it is checked on each "iteration" 1275R<[IPv6 $-]> <$+> <$*> <$*> $: <[$(dequote $1 $)]> <$2> <$3> <$4> 1276dnl workspace <key> <default> <passthru> <mark> 1277dnl lookup with tag (in front, no delimiter here) 1278R<$*> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5> 1279dnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 1280ifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest 1281R<?> <$+.$+> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4> <$5 $6>', `dnl') 1282dnl lookup without tag? 1283R<?> <$+> <$+> <$*> <+ $*> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4> 1284ifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest 1285R<?> <$+.$+> <$+> <$*> <+ $*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <$4> <+ $5>', `dnl') 1286dnl lookup IP address (no check is done whether it is an IP number!) 1287R<?> <[$+.$-]> <$+> <$*> <$*> $@ $>LookUpDomain <[$1]> <$3> <$4> <$5> 1288dnl lookup IPv6 address 1289R<?> <[$+:$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5> 1290dnl not found, but subdomain: try again 1291R<?> <$+.$+> <$+> <$*> <$*> $@ $>LookUpDomain <$2> <$3> <$4> <$5> 1292dnl not found, no subdomain: return default 1293R<?> <$+> <$+> <$*> <$*> $@ <$2> <$3> 1294dnl return result of lookup 1295R<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4> 1296 1297###################################################################### 1298### LookUpAddress -- search for host address in access database 1299### 1300### Parameters: 1301### <$1> -- key (dot quadded host address) 1302### <$2> -- default (what to return if not found in db) 1303dnl must not be empty 1304### <$3> -- passthru (additional data passed through) 1305### <$4> -- mark (must be <(!|+) single-token>) 1306### ! does lookup only with tag 1307### + does lookup with and without tag 1308dnl returns: <default> <passthru> 1309dnl <result> <passthru> 1310###################################################################### 1311 1312SLookUpAddress 1313dnl lookup with tag 1314R<$+> <$+> <$*> <$- $+> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5> 1315dnl lookup without tag 1316R<?> <$+> <$+> <$*> <+ $+> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4> 1317dnl no match; IPv6: remove last part 1318R<?> <$+:$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 1319dnl no match; IPv4: remove last part 1320R<?> <$+.$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 1321dnl no match: return default 1322R<?> <$+> <$+> <$*> <$*> $@ <$2> <$3> 1323dnl match: return result 1324R<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4>', 1325`dnl') 1326 1327###################################################################### 1328### CanonAddr -- Convert an address into a standard form for 1329### relay checking. Route address syntax is 1330### crudely converted into a %-hack address. 1331### 1332### Parameters: 1333### $1 -- full recipient address 1334### 1335### Returns: 1336### parsed address, not in source route form 1337dnl user%host%host<@domain> 1338dnl host!user<@domain> 1339###################################################################### 1340 1341SCanonAddr 1342R$* $: $>Parse0 $>canonify $1 make domain canonical 1343ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 1344R< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 1345R$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 1346R$* < @ $+ > : $* $3 $1 < @ $2 > 1347dnl') 1348 1349###################################################################### 1350### ParseRecipient -- Strip off hosts in $=R as well as possibly 1351### $* $=m or the access database. 1352### Check user portion for host separators. 1353### 1354### Parameters: 1355### $1 -- full recipient address 1356### 1357### Returns: 1358### parsed, non-local-relaying address 1359###################################################################### 1360 1361SParseRecipient 1362dnl mark and canonify address 1363R$* $: <?> $>CanonAddr $1 1364dnl workspace: <?> localpart<@domain[.]> 1365R<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 1366dnl workspace: <?> localpart<@domain> 1367R<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 1368 1369# if no $=O character, no host in the user portion, we are done 1370R<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 1371dnl no $=O in localpart: return 1372R<?> $* $@ $1 1373 1374dnl workspace: <?> localpart<@domain>, where localpart contains $=O 1375dnl mark everything which has an "authorized" domain with <RELAY> 1376ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 1377# if we relay, check username portion for user%host so host can be checked also 1378R<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 1379 1380ifdef(`_RELAY_MX_SERVED_', `dnl 1381dnl do "we" ($=w) act as backup MX server for the destination domain? 1382R<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 1383R<MX> < : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 1384dnl yes: mark it as <RELAY> 1385R<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 1386dnl no: put old <NO> mark back 1387R<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 1388 1389dnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 1390dnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 1391ifdef(`_RELAY_HOSTS_ONLY_', 1392`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 1393ifdef(`_ACCESS_TABLE_', `dnl 1394R<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 1395R<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 1396`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 1397ifdef(`_ACCESS_TABLE_', `dnl 1398R<NO> $* < @ $+ > $: $>LookUpDomain <$2> <NO> <$1 < @ $2 >> <+To> 1399R<$+> <$+> $: <$1> $2',`dnl')') 1400 1401 1402R<RELAY> $* < @ $* > $@ $>ParseRecipient $1 1403R<$-> $* $@ $2 1404 1405 1406###################################################################### 1407### check_relay -- check hostname/address on SMTP startup 1408###################################################################### 1409 1410SLocal_check_relay 1411Scheck`'_U_`'relay 1412R$* $: $1 $| $>"Local_check_relay" $1 1413R$* $| $* $| $#$* $#$3 1414R$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 1415 1416SBasic_check_relay 1417# check for deferred delivery mode 1418R$* $: < ${deliveryMode} > $1 1419R< d > $* $@ deferred 1420R< $* > $* $: $2 1421 1422ifdef(`_ACCESS_TABLE_', `dnl 1423dnl workspace: {client_name} $| {client_addr} 1424R$+ $| $+ $: $>LookUpDomain < $1 > <?> < $2 > <+Connect> 1425dnl workspace: <result-of-lookup> <{client_addr}> 1426R<?> <$+> $: $>LookUpAddress < $1 > <?> < $1 > <+Connect> no: another lookup 1427dnl workspace: <result-of-lookup> <{client_addr}> 1428R<?> < $+ > $: $1 found nothing 1429dnl workspace: <result-of-lookup> <{client_addr}> 1430dnl or {client_addr} 1431R<$={Accept}> < $* > $@ $1 return value of lookup 1432R<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 1433R<DISCARD> $* $#discard $: discard 1434dnl error tag 1435R<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 1436R<ERROR:$+> <$*> $#error $: $1 1437dnl generic error from access map 1438R<$+> <$*> $#error $: $1', `dnl') 1439 1440ifdef(`_RBL_',`dnl 1441# DNS based IP address spam list 1442R$* $: $&{client_addr} 1443R::ffff:$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 1444R$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 1445R<?>OK $: OKSOFAR 1446R<?>$+ $#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"', 1447`dnl') 1448undivert(8) 1449 1450###################################################################### 1451### check_mail -- check SMTP ``MAIL FROM:'' command argument 1452###################################################################### 1453 1454SLocal_check_mail 1455Scheck`'_U_`'mail 1456R$* $: $1 $| $>"Local_check_mail" $1 1457R$* $| $#$* $#$2 1458R$* $| $* $@ $>"Basic_check_mail" $1 1459 1460SBasic_check_mail 1461# check for deferred delivery mode 1462R$* $: < ${deliveryMode} > $1 1463R< d > $* $@ deferred 1464R< $* > $* $: $2 1465 1466# authenticated? 1467dnl done first: we can require authentication for every mail transaction 1468dnl workspace: address as given by MAIL FROM: (sender) 1469R$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 1470R$* $| $#$+ $#$2 1471dnl undo damage: remove result of tls_client call 1472R$* $| $* $: $1 1473 1474dnl workspace: address as given by MAIL FROM: 1475R<> $@ <OK> we MUST accept <> (RFC 1123) 1476ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 1477dnl do some additional checks 1478dnl no user@host 1479dnl no user@localhost (if nonlocal sender) 1480dnl this is a pretty simple canonification, it will not catch every case 1481dnl just make sure the address has <> around it (which is required by 1482dnl the RFC anyway, maybe we should complain if they are missing...) 1483dnl dirty trick: if it is user@host, just add a dot: user@host. this will 1484dnl not be modified by host lookups. 1485R$+ $: <?> $1 1486R<?><$+> $: <@> <$1> 1487R<?>$+ $: <@> <$1> 1488dnl workspace: <@> <address> 1489dnl prepend daemon_flags 1490R$* $: $&{daemon_flags} $| $1 1491dnl workspace: ${daemon_flags} $| <@> <address> 1492dnl do not allow these at all or only from local systems? 1493R$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 1494dnl accept unqualified sender: change mark to avoid test 1495R$* u $* $| <@> < $* > $: <?> < $3 > 1496dnl workspace: ${daemon_flags} $| <@> <address> 1497dnl or: <? ${client_name} > <address> 1498dnl or: <?> <address> 1499dnl remove daemon_flags 1500R$* $| $* $: $2 1501# handle case of @localhost on address 1502R<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 1503R<@> < $* @ [127.0.0.1] > 1504 $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 1505R<@> < $* @ localhost.$m > 1506 $: < ? $&{client_name} > < $1 @ localhost.$m > 1507ifdef(`_NO_UUCP_', `dnl', 1508`R<@> < $* @ localhost.UUCP > 1509 $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 1510dnl workspace: < ? $&{client_name} > <user@localhost|host> 1511dnl or: <@> <address> 1512dnl or: <?> <address> (thanks to u in ${daemon_flags}) 1513R<@> $* $: $1 no localhost as domain 1514dnl workspace: < ? $&{client_name} > <user@localhost|host> 1515dnl or: <address> 1516dnl or: <?> <address> (thanks to u in ${daemon_flags}) 1517R<? $=w> $* $: $2 local client: ok 1518R<? $+> <$+> $#error $@ 5.5.4 $: "501 Real domain name required for sender address" 1519dnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 1520R<?> $* $: $1') 1521dnl workspace: address (or <address>) 1522R$* $: <?> $>CanonAddr $1 canonify sender address and mark it 1523dnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 1524dnl there is nothing behind the <@host> so no trailing $* needed 1525R<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 1526# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 1527R<?> $* < @ $* $=P > $: <OK> $1 < @ $2 $3 > 1528dnl workspace <mark> CanonicalAddress where mark is ? or OK 1529ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 1530`R<?> $* < @ $+ > $: <OK> $1 < @ $2 > ... unresolvable OK', 1531`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 1532R<? $* <$->> $* < @ $+ > 1533 $: <$2> $3 < @ $4 >') 1534dnl workspace <mark> CanonicalAddress where mark is ?, OK, PERM, TEMP 1535dnl mark is ? iff the address is user (wo @domain) 1536 1537ifdef(`_ACCESS_TABLE_', `dnl 1538# check sender address: user@address, user@, address 1539dnl should we remove +ext from user? 1540dnl workspace: <mark> CanonicalAddress where mark is: ?, OK, PERM, TEMP 1541R<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <H:$3> 1542R<$+> $+ $: @<$1> <$2> $| <U:$2@> 1543dnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 1544dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 1545dnl will only return user<@domain when "reversing" the args 1546R@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+From> $| <$3> <> 1547dnl workspace: <@><mark> <CanonicalAddress> $| <result> 1548R<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 1549dnl workspace: <result> <mark> <CanonicalAddress> 1550# retransform for further use 1551dnl required form: 1552dnl <ResultOfLookup|mark> CanonicalAddress 1553R<?> <$+> <$*> $: <$1> $2 no match 1554R<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 1555dnl workspace <ResultOfLookup|mark> CanonicalAddress 1556dnl mark is ? iff the address is user (wo @domain) 1557 1558ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 1559# handle case of no @domain on address 1560dnl prepend daemon_flags 1561R<?> $* $: $&{daemon_flags} $| <?> $1 1562dnl accept unqualified sender: change mark to avoid test 1563R$* u $* $| <?> $* $: <OK> $3 1564dnl remove daemon_flags 1565R$* $| $* $: $2 1566R<?> $* $: < ? $&{client_name} > $1 1567R<?> $* $@ <OK> ...local unqualed ok 1568R<? $+> $* $#error $@ 5.5.4 $: "501 Domain name required for sender address " $&f 1569 ...remote is not') 1570# check results 1571R<?> $* $: @ $1 mark address: nothing known about it 1572R<OK> $* $@ <OK> 1573R<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 1574R<PERM> $* $#error $@ 5.1.8 $: "501 Domain of sender address " $&f " does not exist" 1575ifdef(`_ACCESS_TABLE_', `dnl 1576R<$={Accept}> $* $# $1 1577R<DISCARD> $* $#discard $: discard 1578R<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 1579dnl error tag 1580R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 1581R<ERROR:$+> $* $#error $: $1 1582dnl generic error from access map 1583R<$+> $* $#error $: $1 error from access db', 1584`dnl') 1585 1586###################################################################### 1587### check_rcpt -- check SMTP ``RCPT TO:'' command argument 1588###################################################################### 1589 1590SLocal_check_rcpt 1591Scheck`'_U_`'rcpt 1592R$* $: $1 $| $>"Local_check_rcpt" $1 1593R$* $| $#$* $#$2 1594R$* $| $* $@ $>"Basic_check_rcpt" $1 1595 1596SBasic_check_rcpt 1597# check for deferred delivery mode 1598R$* $: < ${deliveryMode} > $1 1599R< d > $* $@ deferred 1600R< $* > $* $: $2 1601 1602ifdef(`_REQUIRE_QUAL_RCPT_', `dnl 1603# require qualified recipient? 1604R$+ $: <?> $1 1605R<?><$+> $: <@> <$1> 1606R<?>$+ $: <@> <$1> 1607dnl prepend daemon_flags 1608R$* $: $&{daemon_flags} $| $1 1609dnl workspace: ${daemon_flags} $| <@> <address> 1610dnl do not allow these at all or only from local systems? 1611R$* r $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 1612R<?> < $* > $: <$1> 1613R<? $=w> < $* > $: <$1> 1614R<? $+> <$+> $#error $@ 5.5.4 $: "553 Domain name required" 1615dnl remove daemon_flags for other cases 1616R$* $| <@> $* $: $2', `dnl') 1617 1618ifdef(`_LOOSE_RELAY_CHECK_',`dnl 1619R$* $: $>CanonAddr $1 1620R$* < @ $* . > $1 < @ $2 > strip trailing dots', 1621`R$* $: $>ParseRecipient $1 strip relayable hosts') 1622 1623ifdef(`_BESTMX_IS_LOCAL_',`dnl 1624ifelse(_BESTMX_IS_LOCAL_, `', `dnl 1625# unlimited bestmx 1626R$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 1627`dnl 1628# limit bestmx to $=B 1629R$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 1630R$* $=O $* < @ $* @@ $=w . > $* $@ $>"Basic_check_rcpt" $1 $2 $3 1631R$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 1632R$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 1633 1634ifdef(`_BLACKLIST_RCPT_',`dnl 1635ifdef(`_ACCESS_TABLE_', `dnl 1636# blacklist local users or any host from receiving mail 1637R$* $: <?> $1 1638dnl user is now tagged with @ to be consistent with check_mail 1639dnl and to distinguish users from hosts (com would be host, com@ would be user) 1640R<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <H:$2> 1641R<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <H:$2> 1642R<?> $+ $: <> <$1> $| <U:$1@> 1643dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 1644dnl will only return user<@domain when "reversing" the args 1645R<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+To> $| <$2> <> 1646R<@> <$*> $| <$*> $: <$2> <$1> reverse result 1647R<?> <$*> $: @ $1 mark address as no match 1648R<$={Accept}> <$*> $: @ $2 mark address as no match 1649ifdef(`_DELAY_CHECKS_',`dnl 1650dnl we have to filter these because otherwise they would be interpreted 1651dnl as generic error message... 1652dnl error messages should be "tagged" by prefixing them with error: ! 1653dnl that would make a lot of things easier. 1654dnl maybe we should stop checks already here (if SPAM_xyx)? 1655R<$={SpamTag}> <$*> $: @ $2 mark address as no match') 1656R<REJECT> $* $#error $@ 5.2.1 $: "550 Mailbox disabled for this recipient" 1657R<DISCARD> $* $#discard $: discard 1658dnl error tag 1659R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 1660R<ERROR:$+> $* $#error $: $1 1661dnl generic error from access map 1662R<$+> $* $#error $: $1 error from access db 1663R@ $* $1 remove mark', `dnl')', `dnl') 1664 1665ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)') 1666# authenticated? 1667dnl do this unconditionally? this requires to manage CAs carefully 1668dnl just because someone has a CERT signed by a "trusted" CA 1669dnl does not mean we want to allow relaying for her, 1670dnl either use a subroutine or provide something more sophisticated 1671dnl this could for example check the DN (maybe an access map lookup) 1672R$* $: $1 $| $>RelayAuth $1 $| $&{verify} client authenticated? 1673R$* $| $# $+ $# $2 error/ok? 1674R$* $| $* $: $1 no 1675 1676# authenticated by a trusted mechanism? 1677R$* $: $1 $| $&{auth_type} 1678dnl empty ${auth_type}? 1679R$* $| $: $1 1680dnl mechanism ${auth_type} accepted? 1681dnl use $# to override further tests (delay_checks): see check_rcpt below 1682R$* $| $={TrustAuthMech} $# RELAYAUTH 1683dnl undo addition of ${auth_type} 1684R$* $| $* $: $1 1685dnl workspace: localpart<@domain> 1686ifelse(defn(`_NO_UUCP_'), `r', 1687`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 1688# anything terminating locally is ok 1689ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 1690R$+ < @ $* $=m > $@ RELAYTO', `dnl') 1691R$+ < @ $=w > $@ RELAYTO 1692ifdef(`_RELAY_HOSTS_ONLY_', 1693`R$+ < @ $=R > $@ RELAYTO 1694ifdef(`_ACCESS_TABLE_', `dnl 1695R$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 1696dnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 1697R<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 1698`R$+ < @ $* $=R > $@ RELAYTO 1699ifdef(`_ACCESS_TABLE_', `dnl 1700R$+ < @ $+ > $: $>LookUpDomain <$2> <?> <$1 < @ $2 >> <+To>',`dnl')') 1701ifdef(`_ACCESS_TABLE_', `dnl 1702dnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 1703R<RELAY> $* $@ RELAYTO 1704R<$*> <$*> $: $2',`dnl') 1705 1706 1707ifdef(`_RELAY_MX_SERVED_', `dnl 1708# allow relaying for hosts which we MX serve 1709R$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 1710dnl this must not necessarily happen if the client is checked first... 1711R< : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 1712R<$* : $=w . : $*> $* $@ RELAYTO 1713R< : $* : > $* $: $2', 1714`dnl') 1715 1716# check for local user (i.e. unqualified address) 1717R$* $: <?> $1 1718R<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 1719# local user is ok 1720dnl is it really? the standard requires user@domain, not just user 1721dnl but we should accept it anyway (maybe making it an option: 1722dnl RequireFQDN ?) 1723dnl postmaster must be accepted without domain (DRUMS) 1724ifdef(`_REQUIRE_QUAL_RCPT_', `dnl 1725R<?> postmaster $@ TOPOSTMASTER 1726# require qualified recipient? 1727dnl prepend daemon_flags 1728R<?> $+ $: $&{daemon_flags} $| <?> $1 1729dnl workspace: ${daemon_flags} $| <?> localpart 1730dnl do not allow these at all or only from local systems? 1731dnl r flag? add client_name 1732R$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 1733dnl no r flag: relay to local user (only local part) 1734# no qualified recipient required 1735R$* $| <?> $+ $@ RELAYTOLOCAL 1736dnl client_name is empty 1737R<?> <?> $+ $@ RELAYTOLOCAL 1738dnl client_name is local 1739R<? $=w> <?> $+ $@ RELAYTOLOCAL 1740dnl client_name is not local 1741R<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 1742dnl no qualified recipient required 1743R<?> $+ $@ RELAYTOLOCAL') 1744dnl it is a remote user: remove mark and then check client 1745R<$+> $* $: $2 1746dnl currently the recipient address is not used below 1747 1748# anything originating locally is ok 1749# check IP address 1750R$* $: $&{client_addr} 1751R$@ $@ RELAYFROM originated locally 1752R0 $@ RELAYFROM originated locally 1753R$=R $* $@ RELAYFROM relayable IP address 1754ifdef(`_ACCESS_TABLE_', `dnl 1755R$* $: $>LookUpAddress <$1> <?> <$1> <+Connect> 1756R<RELAY> $* $@ RELAYFROM relayable IP address 1757R<$*> <$*> $: $2', `dnl') 1758R$* $: [ $1 ] put brackets around it... 1759R$=w $@ RELAYFROM ... and see if it is local 1760 1761ifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 1762ifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 1763ifdef(`_RELAY_MAIL_FROM_', `dnl 1764dnl input: {client_addr} or something "broken" 1765dnl just throw the input away; we do not need it. 1766# check whether FROM is allowed to use system as relay 1767R$* $: <?> $>CanonAddr $&f 1768ifdef(`_RELAY_LOCAL_FROM_', `dnl 1769# check whether local FROM is ok 1770R<?> $+ < @ $=w . > $@ RELAYFROMMAIL FROM local', `dnl') 1771ifdef(`_RELAY_DB_FROM_', `dnl 1772R<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 1773R<?> $+ < @ $+ > $: $1 < @ $2 > $| $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<H:$2>') <> 1774R$* <RELAY> $@ RELAYFROMMAIL RELAY FROM sender ok', `dnl 1775ifdef(`_RELAY_DB_FROM_DOMAIN_', `errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 1776')', 1777`dnl') 1778dnl')', `dnl') 1779 1780# check client name: first: did it resolve? 1781dnl input: ignored 1782R$* $: < $&{client_resolve} > 1783R<TEMP> $#error $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 1784R<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 1785R<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 1786dnl ${client_resolve} should be OK, so go ahead 1787R$* $: <?> $&{client_name} 1788# pass to name server to make hostname canonical 1789R<?> $* $~P $:<?> $[ $1 $2 $] 1790R$* . $1 strip trailing dots 1791dnl should not be necessary since it has been done for client_addr already 1792R<?> $@ RELAYFROM 1793ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 1794R<?> $* $=m $@ RELAYFROM', `dnl') 1795R<?> $=w $@ RELAYFROM 1796ifdef(`_RELAY_HOSTS_ONLY_', 1797`R<?> $=R $@ RELAYFROM 1798ifdef(`_ACCESS_TABLE_', `dnl 1799R<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 1800R<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 1801`R<?> $* $=R $@ RELAYFROM 1802ifdef(`_ACCESS_TABLE_', `dnl 1803R<?> $* $: $>LookUpDomain <$1> <?> <$1> <+Connect>',`dnl')') 1804ifdef(`_ACCESS_TABLE_', `dnl 1805R<RELAY> $* $@ RELAYFROM 1806R<$*> <$*> $: $2',`dnl') 1807 1808# anything else is bogus 1809R$* $#error $@ 5.7.1 $: confRELAY_MSG 1810divert(0) 1811ifdef(`_DELAY_CHECKS_',`dnl 1812# turn a canonical address in the form user<@domain> 1813# qualify unqual. addresses with $j 1814dnl it might have been only user (without <@domain>) 1815SFullAddr 1816R$* <@ $+ . > $1 <@ $2 > 1817R$* <@ $* > $@ $1 <@ $2 > 1818R$+ $@ $1 <@ $j > 1819 1820# call all necessary rulesets 1821Scheck_rcpt 1822dnl this test should be in the Basic_check_rcpt ruleset 1823dnl which is the correct DSN code? 1824# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 1825R$+ $: $1 $| $>checkrcpt $1 1826dnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 1827R$+ $| $#$* $#$2 1828R$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 1829ifdef(`_SPAM_FH_', 1830`dnl lookup user@ and user@address 1831ifdef(`_ACCESS_TABLE_', `', 1832`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 1833')')dnl 1834dnl one of the next two rules is supposed to match 1835dnl this code has been copied from BLACKLIST... etc 1836dnl and simplified by omitting some < >. 1837R<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <U: $1@> 1838R<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > 1839dnl R<?> $@ something_is_very_wrong_here 1840# lookup the addresses only with To tag 1841R<> $* $| <$+> $: <@> $1 $| $>SearchList <!To> $| <$2> <> 1842R<@> $* $| $* $: $2 $1 reverse result 1843dnl', `dnl') 1844ifdef(`_SPAM_FRIEND_', 1845`# is the recipient a spam friend? 1846ifdef(`_SPAM_HATER_', 1847 `errprint(`*** ERROR: define either SpamHater or SpamFriend 1848')', `dnl') 1849R<SPAMFRIEND> $+ $@ SPAMFRIEND 1850R<$*> $+ $: $2', 1851`dnl') 1852ifdef(`_SPAM_HATER_', 1853`# is the recipient no spam hater? 1854R<SPAMHATER> $+ $: $1 spam hater: continue checks 1855R<$*> $+ $@ NOSPAMHATER everyone else: stop 1856dnl',`dnl') 1857dnl run further checks: check_mail 1858dnl should we "clean up" $&f? 1859R$* $: $1 $| $>checkmail <$&f> 1860R$* $| $#$* $#$2 1861dnl run further checks: check_relay 1862R$* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 1863R$* $| $#$* $#$2 1864R$* $| $* $: $1 1865', `dnl') 1866ifdef(`_ACCESS_TABLE_', `dnl 1867###################################################################### 1868### SearchList: search a list of items in the access map 1869### Parameters: 1870### <exact tag> $| <mark:address> <mark:address> ... <> 1871dnl maybe we should have a @ (again) in front of the mark to 1872dnl avoid errorneous matches (with error messages?) 1873dnl if we can make sure that tag is always a single token 1874dnl then we can omit the delimiter $|, otherwise we need it 1875dnl to avoid errorneous matchs (first rule: H: if there 1876dnl is that mark somewhere in the list, it will be taken). 1877dnl moreover, we can do some tricks to enforce lookup with 1878dnl the tag only, e.g.: 1879### where "exact" is either "+" or "!": 1880### <+ TAG> lookup with and w/o tag 1881### <! TAG> lookup with tag 1882dnl Warning: + and ! should be in OperatorChars (otherwise there must be 1883dnl a blank between them and the tag. 1884### possible values for "mark" are: 1885### H: recursive host lookup (LookUpDomain) 1886dnl A: recursive address lookup (LookUpAddress) [not yet required] 1887### E: exact lookup, no modifications 1888### F: full lookup, try user+ext@domain and user@domain 1889### U: user lookup, try user+ext and user (input must have trailing @) 1890### return: <RHS of lookup> or <?> (not found) 1891###################################################################### 1892 1893# class with valid marks for SearchList 1894dnl if A is activated: add it 1895C{src}E F H U 1896SSearchList 1897# mark H: lookup domain 1898R<$+> $| <H:$+> <$*> $: <$1> $| <@> $>LookUpDomain <$2> <?> <$3> <$1> 1899R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> 1900dnl A: NOT YET REQUIRED 1901dnl R<$+> $| <A:$+> <$*> $: <$1> $| <@> $>LookUpAddress <$2> <?> <$3> <$1> 1902dnl R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> 1903dnl lookup of the item with tag 1904dnl this applies to F: U: E: 1905R<$- $-> $| <$={src}:$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5> 1906dnl no match, try without tag 1907R<+ $-> $| <$={src}:$+> <$*> $: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4> 1908dnl do we really have to distinguish these cases? 1909dnl probably yes, there might be a + in the domain part (is that allowed?) 1910dnl user+detail lookups: should it be: 1911dnl user+detail, user+*, user; just like aliases? 1912R<$- $-> $| <F:$* + $*@$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@$5 $: F:$3 + $4@$5$)> <$6> 1913R<+ $-> $| <F:$* + $*@$+> <$*> $: <+ $1> $| <$(access $2@$4 $: F:$2 + $3@$4$)> <$5> 1914dnl user lookups are always with trailing @ 1915dnl do not remove the @ from the lookup: 1916dnl it is part of the +detail@ which is omitted for the lookup 1917R<$- $-> $| <U:$* + $*> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5> 1918dnl no match, try without tag 1919R<+ $-> $| <U:$* + $*> <$*> $: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4> 1920dnl no match, try rest of list 1921R<$+> $| <$={src}:$+> <$+> $@ $>SearchList <$1> $| <$4> 1922dnl no match, list empty: return failure 1923R<$+> $| <$={src}:$+> <> $@ <?> 1924dnl got result, return it 1925R<$+> $| <$+> <$*> $@ <$2> 1926dnl return result from recursive invocation 1927R<$+> $| <$+> $@ <$2>', `dnl') 1928 1929# is user trusted to authenticate as someone else? 1930dnl AUTH= parameter from MAIL command 1931Strust_auth 1932R$* $: $&{auth_type} $| $1 1933# required by RFC 2554 section 4. 1934R$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 1935dnl seems to be useful... 1936R$* $| $&{auth_authen} $@ identical 1937R$* $| <$&{auth_authen}> $@ identical 1938dnl call user supplied code 1939R$* $| $* $: $1 $| $>"Local_trust_auth" $1 1940R$* $| $#$* $#$2 1941dnl default: error 1942R$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 1943 1944dnl empty ruleset definition so it can be called 1945SLocal_trust_auth 1946 1947ifdef(`_FFR_TLS_O_T', `dnl 1948Soffer_tls 1949R$* $: $>LookUpDomain <$&{client_name}> <?> <> <! TLS_OFF_TAG> 1950R<?>$* $: $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_OFF_TAG> 1951R<?>$* $: <$(access TLS_OFF_TAG: $: ? $)> 1952R<?>$* $@ OK 1953R<NO> <> $#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]" 1954 1955Stry_tls 1956R$* $: $>LookUpDomain <$&{server_name}> <?> <> <! TLS_TRY_TAG> 1957R<?>$* $: $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_TRY_TAG> 1958R<?>$* $: <$(access TLS_TRY_TAG: $: ? $)> 1959R<?>$* $@ OK 1960R<NO> <> $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 1961')dnl 1962 1963# is connection with client "good" enough? (done in server) 1964# input: ${verify} $| (MAIL|STARTTLS) 1965dnl MAIL: called from check_mail 1966dnl STARTTLS: called from smtp() after STARTTLS has been accepted 1967Stls_client 1968ifdef(`_ACCESS_TABLE_', `dnl 1969dnl ignore second arg for now 1970dnl maybe use it to distinguish permanent/temporary error? 1971dnl if MAIL: permanent (STARTTLS has not been offered) 1972dnl if STARTTLS: temporary (offered but maybe failed) 1973R$* $| $* $: $1 $| $>LookUpDomain <$&{client_name}> <?> <> <! TLS_CLT_TAG> 1974R$* $| <?>$* $: $1 $| $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_CLT_TAG> 1975dnl do a default lookup: just TLS_CLT_TAG 1976R$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 1977R$* $@ $>"tls_connection" $1', `dnl 1978R$* $| $* $@ $>"tls_connection" $1') 1979 1980# is connection with server "good" enough? (done in client) 1981dnl i.e. has the server been authenticated and is encryption active? 1982dnl called from deliver() after STARTTLS command 1983# input: ${verify} 1984Stls_server 1985ifdef(`_ACCESS_TABLE_', `dnl 1986R$* $: $1 $| $>LookUpDomain <$&{server_name}> <?> <> <! TLS_SRV_TAG> 1987R$* $| <?>$* $: $1 $| $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_SRV_TAG> 1988dnl do a default lookup: just TLS_SRV_TAG 1989R$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 1990R$* $@ $>"tls_connection" $1', `dnl 1991R$* $@ $>"tls_connection" $1') 1992 1993Stls_connection 1994ifdef(`_ACCESS_TABLE_', `dnl 1995dnl common ruleset for tls_{client|server} 1996dnl input: $&{verify} $| <ResultOfLookup> [<>] 1997dnl remove optional <> 1998R$* $| <$*>$* $: $1 $| <$2> 1999dnl permanent or temporary error? 2000R$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 2001R$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 2002dnl default case depends on TLS_PERM_ERR 2003R$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 2004dnl deal with TLS handshake failures: abort 2005RSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 2006dnl no <reply:dns> i.e. not requirements in the access map 2007dnl use default error 2008RSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 2009R$* $| <$*> <VERIFY> $: <$2> <VERIFY> $1 2010R$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> $1 2011dnl some other value in access map: accept 2012dnl this also allows to override the default case (if used) 2013R$* $| $* $@ OK 2014# authentication required: give appropriate error 2015# other side did authenticate (via STARTTLS) 2016dnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> ${verify} 2017dnl only verification required and it succeeded 2018R<$*><VERIFY> OK $@ OK 2019dnl verification required + some level of encryption 2020R<$*><VERIFY:$-> OK $: <$1> <REQ:$2> 2021dnl just some level of encryption required 2022R<$*><ENCR:$-> $* $: <$1> <REQ:$2> 2023dnl verification required but ${verify} is not set 2024R<$-:$+><VERIFY $*> $#error $@ $2 $: $1 " authentication required" 2025R<$-:$+><VERIFY $*> FAIL $#error $@ $2 $: $1 " authentication failed" 2026R<$-:$+><VERIFY $*> NO $#error $@ $2 $: $1 " not authenticated" 2027R<$-:$+><VERIFY $*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 2028dnl some other value for ${verify} 2029R<$-:$+><VERIFY $*> $+ $#error $@ $2 $: $1 " authentication failure " $4 2030dnl some level of encryption required: get the maximum level 2031R<$*><REQ:$-> $: <$1> <REQ:$2> $>max $&{cipher_bits} : $&{auth_ssf} 2032dnl compare required bits with actual bits 2033R<$*><REQ:$-> $- $: <$1> <$2:$3> $(arith l $@ $3 $@ $2 $) 2034R<$-:$+><$-:$-> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 2035 2036Smax 2037dnl compute the max of two values separated by : 2038R: $: 0 2039R:$- $: $1 2040R$-: $: $1 2041R$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 2042RTRUE:$-:$- $: $2 2043R$-:$-:$- $: $2', 2044`dnl use default error 2045dnl deal with TLS handshake failures: abort 2046RSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."') 2047 2048SRelayAuth 2049# authenticated? 2050dnl we do not allow relaying for anyone who can present a cert 2051dnl signed by a "trusted" CA. For example, even if we put verisigns 2052dnl CA in CERTPath so we can authenticate users, we do not allow 2053dnl them to abuse our server (they might be easier to get hold of, 2054dnl but anyway). 2055dnl so here is the trick: if the verification succeeded 2056dnl we look up the cert issuer in the access map 2057dnl (maybe after extracting a part with a regular expression) 2058dnl if this returns RELAY we relay without further questions 2059dnl if it returns SUBJECT we perform a similar check on the 2060dnl cert subject. 2061R$* $| OK $: $1 2062R$* $| $* $@ NO not authenticated 2063ifdef(`_ACCESS_TABLE_', `dnl 2064ifdef(`_CERT_REGEX_ISSUER_', `dnl 2065R$* $: $1 $| $(CERTIssuer $&{cert_issuer} $)', 2066`R$* $: $1 $| $&{cert_issuer}') 2067R$* $| $+ $: $1 $| $(access CERTISSUER:$2 $) 2068dnl use $# to stop further checks (delay_check) 2069R$* $| RELAY $# RELAYCERTISSUER 2070ifdef(`_CERT_REGEX_SUBJECT_', `dnl 2071R$* $| SUBJECT $: $1 $| <@> $(CERTSubject $&{cert_subject} $)', 2072`R$* $| SUBJECT $: $1 $| <@> $&{cert_subject}') 2073R$* $| <@> $+ $: $1 $| <@> $(access CERTSUBJECT:$2 $) 2074R$* $| <@> RELAY $# RELAYCERTSUBJECT 2075R$* $| $* $: $1', `dnl') 2076 2077undivert(9)dnl LOCAL_RULESETS 2078ifdef(`_FFR_MILTER', ` 2079# 2080###################################################################### 2081###################################################################### 2082##### 2083`##### MAIL FILTER DEFINITIONS' 2084##### 2085###################################################################### 2086###################################################################### 2087_MAIL_FILTERS_') 2088# 2089###################################################################### 2090###################################################################### 2091##### 2092`##### MAILER DEFINITIONS' 2093##### 2094###################################################################### 2095###################################################################### 2096undivert(7)dnl MAILER_DEFINITIONS 2097 2098