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