proto.m4 revision 71345
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.38 2000/12/28 03:37:28 ca 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', `0') 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$* < $+ :; > $* $@ $2 :; <@> catch <list:;> 639R$* < $* ; > $1 < $2 > bogus bracketed semi 640 641# null input now results from list:; syntax 642R$@ $@ :; <@> 643 644# strip angle brackets -- note RFC733 heuristic to get innermost item 645R$* $: < $1 > housekeeping <> 646R$+ < $* > < $2 > strip excess on left 647R< $* > $+ < $1 > strip excess on right 648R<> $@ < @ > MAIL FROM:<> case 649R< $+ > $: $1 remove housekeeping <> 650 651ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 652# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 653R@ $+ , $+ @ $1 : $2 change all "," to ":" 654 655# localize and dispose of route-based addresses 656R@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 657dnl',`dnl 658# strip route address <@a,@b,@c:user@d> -> <user@d> 659R@ $+ , $+ $2 660R@ $+ : $+ $2 661dnl') 662 663# find focus for list syntax 664R $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 665R $+ : $* ; $@ $1 : $2; list syntax 666 667# find focus for @ syntax addresses 668R$+ @ $+ $: $1 < @ $2 > focus on domain 669R$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 670R$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 671 672# do some sanity checking 673R$* < @ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 674 675ifdef(`_NO_UUCP_', `dnl', 676`# convert old-style addresses to a domain-based address 677R$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 678R$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 679R$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 680') 681ifdef(`_USE_DECNET_SYNTAX_', 682`# convert node::user addresses into a domain-based address 683R$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 684R$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 685', 686 `dnl') 687# if we have % signs, take the rightmost one 688R$* % $* $1 @ $2 First make them all @s. 689R$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 690R$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 691 692# else we must be a local name 693R$* $@ $>Canonify2 $1 694 695 696################################################ 697### Ruleset 96 -- bottom half of ruleset 3 ### 698################################################ 699 700SCanonify2=96 701 702# handle special cases for local names 703R$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 704R$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 705ifdef(`_NO_UUCP_', `dnl', 706`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 707 708# check for IPv6 domain literal (save quoted form) 709R$* < @ [ IPv6 $- ] > $* $: $2 $| $1 < @@ [ $(dequote $2 $) ] > $3 mark IPv6 addr 710R$- $| $* < @@ $=w > $* $: $2 < @ $j . > $4 self-literal 711R$- $| $* < @@ [ $+ ] > $* $@ $2 < @ [ IPv6 $1 ] > $4 canon IP addr 712 713# check for IPv4 domain literal 714R$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [a.b.c.d] 715R$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 716R$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 717 718ifdef(`_DOMAIN_TABLE_', `dnl 719# look up domains in the domain table 720R$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 721 722undivert(2)dnl LOCAL_RULE_3 723 724ifdef(`_BITDOMAIN_TABLE_', `dnl 725# handle BITNET mapping 726R$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 727 728ifdef(`_UUDOMAIN_TABLE_', `dnl 729# handle UUCP mapping 730R$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 731 732ifdef(`_NO_UUCP_', `dnl', 733`ifdef(`UUCP_RELAY', 734`# pass UUCP addresses straight through 735R$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 736`# if really UUCP, handle it immediately 737ifdef(`_CLASS_U_', 738`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 739ifdef(`_CLASS_V_', 740`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 741ifdef(`_CLASS_W_', 742`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 743ifdef(`_CLASS_X_', 744`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 745ifdef(`_CLASS_Y_', 746`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 747 748ifdef(`_NO_CANONIFY_', `dnl', `dnl 749# try UUCP traffic as a local address 750R$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 751R$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 752')') 753# hostnames ending in class P are always canonical 754R$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 755dnl apply the next rule only for hostnames not in class P 756dnl this even works for phrases in class P since . is in class P 757dnl which daemon flags are set? 758R$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 759dnl the other rules in this section only apply if the hostname 760dnl does not end in class P hence no further checks are done here 761dnl if this ever changes make sure the lookups are "protected" again! 762ifdef(`_NO_CANONIFY_', `dnl 763dnl do not canonify unless: 764dnl domain ends in class {Canonify} (this does not work if the intersection 765dnl with class P is non-empty) 766dnl or {daemon_flags} has c set 767# pass to name server to make hostname canonical if in class {Canonify} 768R$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 769# pass to name server to make hostname canonical if requested 770R$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 771dnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 772R$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 773# add a trailing dot to qualified hostnames so other rules will work 774R$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 775ifdef(`_CANONIFY_HOSTS_', `dnl 776dnl this should only apply to unqualified hostnames 777dnl but if a valid character inside an unqualified hostname is an OperatorChar 778dnl then $- does not work. 779# lookup unqualified hostnames 780R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 781dnl _NO_CANONIFY_ is not set: canonify unless: 782dnl {daemon_flags} contains CC (do not canonify) 783dnl but add a trailing dot to qualified hostnames so other rules will work 784dnl should we do this for every hostname: even unqualified? 785R$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 786R$* CC $* $| $* $: $3 787# pass to name server to make hostname canonical 788R$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 789dnl remove {daemon_flags} for other cases 790R$* $| $* $: $2 791 792# local host aliases and pseudo-domains are always canonical 793R$* < @ $=w > $* $: $1 < @ $2 . > $3 794ifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 795`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 796`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 797ifdef(`_VIRTUSER_TABLE_', `dnl 798dnl virtual hosts are also canonical 799ifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 800`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 801`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 802`dnl') 803dnl remove superfluous dots (maybe repeatedly) which may have been added 804dnl by one of the rules before 805R$* < @ $* . . > $* $1 < @ $2 . > $3 806 807 808################################################## 809### Ruleset 4 -- Final Output Post-rewriting ### 810################################################## 811Sfinal=4 812 813R$+ :; <@> $@ $1 : handle <list:;> 814R$* <@> $@ handle <> and list:; 815 816# strip trailing dot off possibly canonical name 817R$* < @ $+ . > $* $1 < @ $2 > $3 818 819# eliminate internal code 820R$* < @ *LOCAL* > $* $1 < @ $j > $2 821 822# externalize local domain info 823R$* < $+ > $* $1 $2 $3 defocus 824R@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 825R@ $* $@ @ $1 ... and exit 826 827ifdef(`_NO_UUCP_', `dnl', 828`# UUCP must always be presented in old form 829R$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 830 831ifdef(`_USE_DECNET_SYNTAX_', 832`# put DECnet back in :: form 833R$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 834 `dnl') 835# delete duplicate local names 836R$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 837 838 839 840############################################################## 841### Ruleset 97 -- recanonicalize and call ruleset zero ### 842### (used for recursive calls) ### 843############################################################## 844 845SRecurse=97 846R$* $: $>canonify $1 847R$* $@ $>parse $1 848 849 850###################################### 851### Ruleset 0 -- Parse Address ### 852###################################### 853 854Sparse=0 855 856R$* $: $>Parse0 $1 initial parsing 857R<@> $#_LOCAL_ $: <@> special case error msgs 858R$* $: $>ParseLocal $1 handle local hacks 859R$* $: $>Parse1 $1 final parsing 860 861# 862# Parse0 -- do initial syntax checking and eliminate local addresses. 863# This should either return with the (possibly modified) input 864# or return with a #error mailer. It should not return with a 865# #mailer other than the #error mailer. 866# 867 868SParse0 869R<@> $@ <@> special case error msgs 870R$* : $* ; <@> $#error $@ 5.1.3 $: "501 List:; syntax illegal for recipient addresses" 871R@ <@ $* > < @ $1 > catch "@@host" bogosity 872R<@ $+> $#error $@ 5.1.3 $: "501 User address required" 873R$* $: <> $1 874R<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 875R<> $* <$* : $* > $* $#error $@ 5.1.3 $: "501 Colon illegal in host name part" 876R<> $* $1 877R$* < @ . $* > $* $#error $@ 5.1.2 $: "501 Invalid host name" 878R$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "501 Invalid host name" 879dnl comma only allowed before @; this check is not complete 880R$* , $~O $* $#error $@ 5.1.2 $: "501 Invalid route address" 881 882# now delete the local info -- note $=O to find characters that cause forwarding 883R$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 884R< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 885R$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 886R< @ $+ > $#error $@ 5.1.3 $: "501 User address required" 887R$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 888R$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 889R< @ *LOCAL* > $#error $@ 5.1.3 $: "501 User address required" 890R$* $=O $* < @ *LOCAL* > 891 $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 892R$* < @ *LOCAL* > $: $1 893 894# 895# Parse1 -- the bottom half of ruleset 0. 896# 897 898SParse1 899ifdef(`_LDAP_ROUTING_', `dnl 900# handle LDAP routing for hosts in $={LDAPRoute} 901R$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2>', 902`dnl') 903 904ifdef(`_MAILER_smtp_', 905`# handle numeric address spec 906dnl there is no check whether this is really an IP number 907R$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 908R$* < @ [ $+ ] > $* $1 < @ [ $2 ] : $S > $3 Add smart host to path 909R$* < @ [ IPv6 $- ] : > $* 910 $#_SMTP_ $@ [ $(dequote $2 $) ] $: $1 < @ [IPv6 $2 ] > $3 no smarthost: send 911R$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 912R$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 913R$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 914 `dnl') 915 916ifdef(`_VIRTUSER_TABLE_', `dnl 917# handle virtual users 918R$+ $: <!> $1 Mark for lookup 919ifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 920`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 921`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 922R<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 923R<@> $+ + $* < @ $* . > 924 $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 925R<@> $+ + $* < @ $* . > 926 $: < $(virtuser $1 @ $3 $@ $1 $: @ $) > $1 + $2 < @ $3 . > 927dnl try default entry: @domain 928dnl +*@domain 929R<@> $+ + $+ < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 930dnl @domain if +detail exists 931R<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 932dnl without +detail (or no match) 933R<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 934R<@> $+ $: $1 935R<!> $+ $: $1 936R< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 937R< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 938R< $+ > $+ < @ $+ > $: $>Recurse $1', 939`dnl') 940 941# short circuit local delivery so forwarded email works 942ifdef(`_MAILER_usenet_', `dnl 943R$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 944 945 946ifdef(`_STICKY_LOCAL_DOMAIN_', 947`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 948R< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 949dnl $H empty (but @$=w.) 950R< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 951R< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 952`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 953R$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 954 955ifdef(`_MAILER_TABLE_', `dnl 956# not local -- try mailer table lookup 957R$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 958R< $+ . > $* $: < $1 > $2 strip trailing dot 959R< $+ > $* $: < $(mailertable $1 $) > $2 lookup 960dnl it is $~[ instead of $- to avoid matches on IPv6 addresses 961R< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 962R< $+ > $* $: $>Mailertable <$1> $2 try domain', 963`dnl') 964undivert(4)dnl UUCP rules from `MAILER(uucp)' 965 966ifdef(`_NO_UUCP_', `dnl', 967`# resolve remotely connected UUCP links (if any) 968ifdef(`_CLASS_V_', 969`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 970 `dnl') 971ifdef(`_CLASS_W_', 972`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 973 `dnl') 974ifdef(`_CLASS_X_', 975`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 976 `dnl')') 977 978# resolve fake top level domains by forwarding to other hosts 979ifdef(`BITNET_RELAY', 980`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 981 `dnl') 982ifdef(`DECNET_RELAY', 983`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 984 `dnl') 985ifdef(`_MAILER_pop_', 986`R$+ < @ POP. > $#pop $: $1 user@POP', 987 `dnl') 988ifdef(`_MAILER_fax_', 989`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 990`ifdef(`FAX_RELAY', 991`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 992 `dnl')') 993 994ifdef(`UUCP_RELAY', 995`# forward non-local UUCP traffic to our UUCP relay 996R$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 997`ifdef(`_MAILER_uucp_', 998`# forward other UUCP traffic straight to UUCP 999R$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 1000 `dnl')') 1001ifdef(`_MAILER_usenet_', ` 1002# addresses sent to net.group.USENET will get forwarded to a newsgroup 1003R$+ . USENET $#usenet $@ usenet $: $1', 1004 `dnl') 1005 1006ifdef(`_LOCAL_RULES_', 1007`# figure out what should stay in our local mail system 1008undivert(1)', `dnl') 1009 1010# pass names that still have a host to a smarthost (if defined) 1011R$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 1012 1013# deal with other remote names 1014ifdef(`_MAILER_smtp_', 1015`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 1016`R$* < @$* > $* $#error $@ 5.1.2 $: "501 Unrecognized host name " $2') 1017 1018# handle locally delivered names 1019R$=L $#_LOCAL_ $: @ $1 special local names 1020R$+ $#_LOCAL_ $: $1 regular local names 1021 1022########################################################################### 1023### Ruleset 5 -- special rewriting after aliases have been expanded ### 1024########################################################################### 1025 1026SLocal_localaddr 1027Slocaladdr=5 1028R$+ $: $1 $| $>"Local_localaddr" $1 1029R$+ $| $#$* $#$2 1030R$+ $| $* $: $1 1031 1032ifdef(`_FFR_5_', ` 1033# Preserve host in a macro 1034R$+ $: $(macro {LocalAddrHost} $) $1 1035R$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 1036 1037ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', ` 1038# deal with plussed users so aliases work nicely 1039R$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 1040R$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 1041') 1042# prepend an empty "forward host" on the front 1043R$+ $: <> $1 1044 1045ifdef(`LUSER_RELAY', `dnl 1046# send unrecognized local users to a relay host 1047ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', ` 1048R< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 1049R< > $+ $: < ? $L > < > $(user $1 $) look up user 1050R< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 1051R< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 1052R< > $+ $: < $L > $(user $1 $) look up user 1053R< $* > $+ <> $: < > $2 found; strip $L')', 1054`dnl') 1055 1056# see if we have a relay or a hub 1057R< > $+ $: < $H > $1 try hub 1058R< > $+ $: < $R > $1 try relay 1059ifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', ` 1060R< > $+ $@ $1', ` 1061R< > $+ $: < > < $1 <> $&h > nope, restore +detail 1062R< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 1063R< > < $+ <> $* > $: < > < $1 > else discard 1064R< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 1065R< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 1066R< > < $+ > $@ $1 no +detail 1067R$+ $: $1 <> $&h add +detail back in 1068R$+ <> + $* $: $1 + $2 check whether +detail 1069R$+ <> $* $: $1 else discard') 1070R< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 1071R< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 1072R< $- : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 1073R< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 1074 1075ifdef(`_MAILER_TABLE_', `dnl 1076################################################################### 1077### Ruleset 90 -- try domain part of mailertable entry ### 1078dnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 1079################################################################### 1080 1081SMailertable=90 1082dnl shift and check 1083dnl %2 is not documented in cf/README 1084R$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 1085dnl it is $~[ instead of $- to avoid matches on IPv6 addresses 1086R$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 1087R$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 1088dnl is $2 always empty? 1089R$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 1090R< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 1091dnl return full address 1092R< $* > $* $@ $2 no mailertable match', 1093`dnl') 1094 1095################################################################### 1096### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 1097dnl input: in general: <[mailer:]host> lp<@domain>rest 1098dnl <> address -> address 1099dnl <error:d.s.n:text> -> error 1100dnl <error:text> -> error 1101dnl <mailer:user@host> lp<@domain>rest -> mailer host user 1102dnl <mailer:host> address -> mailer host address 1103dnl <localdomain> address -> address 1104dnl <[IPv6 number]> address -> relay number address 1105dnl <host> address -> relay host address 1106################################################################### 1107 1108SMailerToTriple=95 1109R< > $* $@ $1 strip off null relay 1110R< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 1111R< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 1112R< local : $* > $* $>CanonLocal < $1 > $2 1113R< $- : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 1114R< $- : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 1115R< $=w > $* $@ $2 delete local host 1116R< [ IPv6 $+ ] > $* $#_RELAY_ $@ $(dequote $1 $) $: $2 use unqualified mailer 1117R< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 1118 1119################################################################### 1120### Ruleset CanonLocal -- canonify local: syntax ### 1121dnl input: <user> address 1122dnl <x> <@host> : rest -> Recurse rest 1123dnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 1124dnl <> user <@host> rest -> local user@host user 1125dnl <> user -> local user user 1126dnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 1127dnl <user> lp <@host> rest -> local lp@host user 1128dnl <user> lp -> local lp user 1129################################################################### 1130 1131SCanonLocal 1132# strip local host from routed addresses 1133R< $* > < @ $+ > : $+ $@ $>Recurse $3 1134R< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 1135 1136# strip trailing dot from any host name that may appear 1137R< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 1138 1139# handle local: syntax -- use old user, either with or without host 1140R< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 1141R< > $+ $#_LOCAL_ $@ $1 $: $1 1142 1143# handle local:user@host syntax -- ignore host part 1144R< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 1145 1146# handle local:user syntax 1147R< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 1148R< $+ > $* $#_LOCAL_ $@ $2 $: $1 1149 1150################################################################### 1151### Ruleset 93 -- convert header names to masqueraded form ### 1152################################################################### 1153 1154SMasqHdr=93 1155 1156ifdef(`_GENERICS_TABLE_', `dnl 1157# handle generics database 1158ifdef(`_GENERICS_ENTIRE_DOMAIN_', 1159dnl if generics should be applied add a @ as mark 1160`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 1161`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 1162R$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 1163dnl workspace: either user<@domain> or <user@domain> user <@domain> @ 1164dnl ignore the first case for now 1165dnl if it has the mark lookup full address 1166R< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 1167dnl workspace: ... or <match|@user@domain> user <@domain> 1168dnl no match, try user+detail@domain 1169R<@$+ + $* @ $+> $+ < @ $+ > 1170 $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 1171R<@$+ + $* @ $+> $+ < @ $+ > 1172 $: < $(generics $1@$3 $: $) > $4 < @ $5 > 1173dnl no match, remove mark 1174R<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 1175dnl no match, try @domain for exceptions 1176R< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 1177dnl workspace: ... or <match> user <@domain> 1178dnl no match, try local part 1179R< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 1180R< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 1181R< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 1182R< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 1183R< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 1184R< > $* $: $1 not found', 1185`dnl') 1186 1187# do not masquerade anything in class N 1188R$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 1189 1190# special case the users that should be exposed 1191R$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 1192ifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 1193`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 1194`R$=E < @ $=M . > $@ $1 < @ $2 . >') 1195ifdef(`_LIMITED_MASQUERADE_', `dnl', 1196`R$=E < @ $=w . > $@ $1 < @ $2 . >') 1197 1198# handle domain-specific masquerading 1199ifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 1200`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 1201`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 1202ifdef(`_LIMITED_MASQUERADE_', `dnl', 1203`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 1204R$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 1205R$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 1206R$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 1207 1208################################################################### 1209### Ruleset 94 -- convert envelope names to masqueraded form ### 1210################################################################### 1211 1212SMasqEnv=94 1213ifdef(`_MASQUERADE_ENVELOPE_', 1214`R$+ $@ $>MasqHdr $1', 1215`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 1216 1217################################################################### 1218### Ruleset 98 -- local part of ruleset zero (can be null) ### 1219################################################################### 1220 1221SParseLocal=98 1222undivert(3)dnl LOCAL_RULE_0 1223 1224ifdef(`_LDAP_ROUTING_', `dnl 1225SLDAPExpand 1226# do the LDAP lookups 1227R<$+><$+> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> 1228 1229# if mailRoutingAddress and local or non-existant mailHost, 1230# return the new mailRoutingAddress 1231R< $+ > < $=w > < $+ > < $+ > $@ $>Parse0 $>canonify $1 1232R< $+ > < > < $+ > < $+ > $@ $>Parse0 $>canonify $1 1233 1234# if mailRoutingAddress and non-local mailHost, 1235# relay to mailHost with new mailRoutingAddress 1236R< $+ > < $+ > < $+ > < $+ > $#_RELAY_ $@ $2 $: $>canonify $1 1237 1238# if no mailRoutingAddress and local mailHost, 1239# return original address 1240R< > < $=w > <$+> <$+> $@ $2 1241 1242# if no mailRoutingAddress and non-local mailHost, 1243# relay to mailHost with original address 1244R< > < $+ > <$+> <$+> $#_RELAY_ $@ $1 $: $2 1245 1246# if no mailRoutingAddress and no mailHost, 1247# try @domain 1248R< > < > <$+> <$+ @ $+> $@ $>LDAPExpand <$1> <@ $3> 1249 1250# if no mailRoutingAddress and no mailHost and this was a domain attempt, 1251ifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 1252# user does not exist 1253R< > < > <$+> <@ $+> $#error $@ nouser $: "550 User unknown"', 1254`dnl 1255# return the original address 1256R< > < > <$+> <@ $+> $@ $1')', 1257`dnl') 1258 1259ifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 1260')') 1261ifdef(`_ACCESS_TABLE_', `dnl 1262###################################################################### 1263### LookUpDomain -- search for domain in access database 1264### 1265### Parameters: 1266### <$1> -- key (domain name) 1267### <$2> -- default (what to return if not found in db) 1268dnl must not be empty 1269### <$3> -- passthru (additional data passed unchanged through) 1270### <$4> -- mark (must be <(!|+) single-token>) 1271### ! does lookup only with tag 1272### + does lookup with and without tag 1273dnl returns: <default> <passthru> 1274dnl <result> <passthru> 1275###################################################################### 1276 1277SLookUpDomain 1278dnl remove IPv6 mark and dequote address 1279dnl it is a bit ugly because it is checked on each "iteration" 1280R<[IPv6 $-]> <$+> <$*> <$*> $: <[$(dequote $1 $)]> <$2> <$3> <$4> 1281dnl workspace <key> <default> <passthru> <mark> 1282dnl lookup with tag (in front, no delimiter here) 1283R<$*> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5> 1284dnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 1285ifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest 1286R<?> <$+.$+> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4> <$5 $6>', `dnl') 1287dnl lookup without tag? 1288R<?> <$+> <$+> <$*> <+ $*> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4> 1289ifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest 1290R<?> <$+.$+> <$+> <$*> <+ $*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <$4> <+ $5>', `dnl') 1291dnl lookup IP address (no check is done whether it is an IP number!) 1292R<?> <[$+.$-]> <$+> <$*> <$*> $@ $>LookUpDomain <[$1]> <$3> <$4> <$5> 1293dnl lookup IPv6 address 1294R<?> <[$+::$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5> 1295R<?> <[$+:$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5> 1296dnl not found, but subdomain: try again 1297R<?> <$+.$+> <$+> <$*> <$*> $@ $>LookUpDomain <$2> <$3> <$4> <$5> 1298dnl not found, no subdomain: return default 1299R<?> <$+> <$+> <$*> <$*> $@ <$2> <$3> 1300dnl return result of lookup 1301R<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4> 1302 1303###################################################################### 1304### LookUpAddress -- search for host address in access database 1305### 1306### Parameters: 1307### <$1> -- key (dot quadded host address) 1308### <$2> -- default (what to return if not found in db) 1309dnl must not be empty 1310### <$3> -- passthru (additional data passed through) 1311### <$4> -- mark (must be <(!|+) single-token>) 1312### ! does lookup only with tag 1313### + does lookup with and without tag 1314dnl returns: <default> <passthru> 1315dnl <result> <passthru> 1316###################################################################### 1317 1318SLookUpAddress 1319dnl lookup with tag 1320R<$+> <$+> <$*> <$- $+> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5> 1321dnl lookup without tag 1322R<?> <$+> <$+> <$*> <+ $+> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4> 1323dnl no match; IPv6: remove last part 1324R<?> <$+::$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 1325R<?> <$+:$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 1326dnl no match; IPv4: remove last part 1327R<?> <$+.$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 1328dnl no match: return default 1329R<?> <$+> <$+> <$*> <$*> $@ <$2> <$3> 1330dnl match: return result 1331R<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4>', 1332`dnl') 1333 1334###################################################################### 1335### CanonAddr -- Convert an address into a standard form for 1336### relay checking. Route address syntax is 1337### crudely converted into a %-hack address. 1338### 1339### Parameters: 1340### $1 -- full recipient address 1341### 1342### Returns: 1343### parsed address, not in source route form 1344dnl user%host%host<@domain> 1345dnl host!user<@domain> 1346###################################################################### 1347 1348SCanonAddr 1349R$* $: $>Parse0 $>canonify $1 make domain canonical 1350ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 1351R< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 1352R$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 1353R$* < @ $+ > : $* $3 $1 < @ $2 > 1354dnl') 1355 1356###################################################################### 1357### ParseRecipient -- Strip off hosts in $=R as well as possibly 1358### $* $=m or the access database. 1359### Check user portion for host separators. 1360### 1361### Parameters: 1362### $1 -- full recipient address 1363### 1364### Returns: 1365### parsed, non-local-relaying address 1366###################################################################### 1367 1368SParseRecipient 1369dnl mark and canonify address 1370R$* $: <?> $>CanonAddr $1 1371dnl workspace: <?> localpart<@domain[.]> 1372R<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 1373dnl workspace: <?> localpart<@domain> 1374R<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 1375 1376# if no $=O character, no host in the user portion, we are done 1377R<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 1378dnl no $=O in localpart: return 1379R<?> $* $@ $1 1380 1381dnl workspace: <?> localpart<@domain>, where localpart contains $=O 1382dnl mark everything which has an "authorized" domain with <RELAY> 1383ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 1384# if we relay, check username portion for user%host so host can be checked also 1385R<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 1386 1387ifdef(`_RELAY_MX_SERVED_', `dnl 1388dnl do "we" ($=w) act as backup MX server for the destination domain? 1389R<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 1390R<MX> < : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 1391dnl yes: mark it as <RELAY> 1392R<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 1393dnl no: put old <NO> mark back 1394R<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 1395 1396dnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 1397dnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 1398ifdef(`_RELAY_HOSTS_ONLY_', 1399`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 1400ifdef(`_ACCESS_TABLE_', `dnl 1401R<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 1402R<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 1403`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 1404ifdef(`_ACCESS_TABLE_', `dnl 1405R<NO> $* < @ $+ > $: $>LookUpDomain <$2> <NO> <$1 < @ $2 >> <+To> 1406R<$+> <$+> $: <$1> $2',`dnl')') 1407 1408 1409R<RELAY> $* < @ $* > $@ $>ParseRecipient $1 1410R<$-> $* $@ $2 1411 1412 1413###################################################################### 1414### check_relay -- check hostname/address on SMTP startup 1415###################################################################### 1416 1417SLocal_check_relay 1418Scheck`'_U_`'relay 1419R$* $: $1 $| $>"Local_check_relay" $1 1420R$* $| $* $| $#$* $#$3 1421R$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 1422 1423SBasic_check_relay 1424# check for deferred delivery mode 1425R$* $: < ${deliveryMode} > $1 1426R< d > $* $@ deferred 1427R< $* > $* $: $2 1428 1429ifdef(`_ACCESS_TABLE_', `dnl 1430dnl workspace: {client_name} $| {client_addr} 1431R$+ $| $+ $: $>LookUpDomain < $1 > <?> < $2 > <+Connect> 1432dnl workspace: <result-of-lookup> <{client_addr}> 1433R<?> <$+> $: $>LookUpAddress < $1 > <?> < $1 > <+Connect> no: another lookup 1434dnl workspace: <result-of-lookup> <{client_addr}> 1435R<?> < $+ > $: $1 found nothing 1436dnl workspace: <result-of-lookup> <{client_addr}> 1437dnl or {client_addr} 1438R<$={Accept}> < $* > $@ $1 return value of lookup 1439R<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 1440R<DISCARD> $* $#discard $: discard 1441dnl error tag 1442R<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 1443R<ERROR:$+> <$*> $#error $: $1 1444dnl generic error from access map 1445R<$+> <$*> $#error $: $1', `dnl') 1446 1447ifdef(`_RBL_',`dnl 1448# DNS based IP address spam list 1449R$* $: $&{client_addr} 1450R::ffff:$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 1451R$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 1452R<?>OK $: OKSOFAR 1453R<?>$+ $#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"', 1454`dnl') 1455undivert(8) 1456 1457###################################################################### 1458### check_mail -- check SMTP ``MAIL FROM:'' command argument 1459###################################################################### 1460 1461SLocal_check_mail 1462Scheck`'_U_`'mail 1463R$* $: $1 $| $>"Local_check_mail" $1 1464R$* $| $#$* $#$2 1465R$* $| $* $@ $>"Basic_check_mail" $1 1466 1467SBasic_check_mail 1468# check for deferred delivery mode 1469R$* $: < ${deliveryMode} > $1 1470R< d > $* $@ deferred 1471R< $* > $* $: $2 1472 1473# authenticated? 1474dnl done first: we can require authentication for every mail transaction 1475dnl workspace: address as given by MAIL FROM: (sender) 1476R$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 1477R$* $| $#$+ $#$2 1478dnl undo damage: remove result of tls_client call 1479R$* $| $* $: $1 1480 1481dnl workspace: address as given by MAIL FROM: 1482R<> $@ <OK> we MUST accept <> (RFC 1123) 1483ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 1484dnl do some additional checks 1485dnl no user@host 1486dnl no user@localhost (if nonlocal sender) 1487dnl this is a pretty simple canonification, it will not catch every case 1488dnl just make sure the address has <> around it (which is required by 1489dnl the RFC anyway, maybe we should complain if they are missing...) 1490dnl dirty trick: if it is user@host, just add a dot: user@host. this will 1491dnl not be modified by host lookups. 1492R$+ $: <?> $1 1493R<?><$+> $: <@> <$1> 1494R<?>$+ $: <@> <$1> 1495dnl workspace: <@> <address> 1496dnl prepend daemon_flags 1497R$* $: $&{daemon_flags} $| $1 1498dnl workspace: ${daemon_flags} $| <@> <address> 1499dnl do not allow these at all or only from local systems? 1500R$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 1501dnl accept unqualified sender: change mark to avoid test 1502R$* u $* $| <@> < $* > $: <?> < $3 > 1503dnl workspace: ${daemon_flags} $| <@> <address> 1504dnl or: <? ${client_name} > <address> 1505dnl or: <?> <address> 1506dnl remove daemon_flags 1507R$* $| $* $: $2 1508# handle case of @localhost on address 1509R<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 1510R<@> < $* @ [127.0.0.1] > 1511 $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 1512R<@> < $* @ localhost.$m > 1513 $: < ? $&{client_name} > < $1 @ localhost.$m > 1514ifdef(`_NO_UUCP_', `dnl', 1515`R<@> < $* @ localhost.UUCP > 1516 $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 1517dnl workspace: < ? $&{client_name} > <user@localhost|host> 1518dnl or: <@> <address> 1519dnl or: <?> <address> (thanks to u in ${daemon_flags}) 1520R<@> $* $: $1 no localhost as domain 1521dnl workspace: < ? $&{client_name} > <user@localhost|host> 1522dnl or: <address> 1523dnl or: <?> <address> (thanks to u in ${daemon_flags}) 1524R<? $=w> $* $: $2 local client: ok 1525R<? $+> <$+> $#error $@ 5.5.4 $: "501 Real domain name required for sender address" 1526dnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 1527R<?> $* $: $1') 1528dnl workspace: address (or <address>) 1529R$* $: <?> $>CanonAddr $1 canonify sender address and mark it 1530dnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 1531dnl there is nothing behind the <@host> so no trailing $* needed 1532R<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 1533# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 1534R<?> $* < @ $* $=P > $: <OK> $1 < @ $2 $3 > 1535dnl workspace <mark> CanonicalAddress where mark is ? or OK 1536ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 1537`R<?> $* < @ $+ > $: <OK> $1 < @ $2 > ... unresolvable OK', 1538`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 1539R<? $* <$->> $* < @ $+ > 1540 $: <$2> $3 < @ $4 >') 1541dnl workspace <mark> CanonicalAddress where mark is ?, OK, PERM, TEMP 1542dnl mark is ? iff the address is user (wo @domain) 1543 1544ifdef(`_ACCESS_TABLE_', `dnl 1545# check sender address: user@address, user@, address 1546dnl should we remove +ext from user? 1547dnl workspace: <mark> CanonicalAddress where mark is: ?, OK, PERM, TEMP 1548R<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <H:$3> 1549R<$+> $+ $: @<$1> <$2> $| <U:$2@> 1550dnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 1551dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 1552dnl will only return user<@domain when "reversing" the args 1553R@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+From> $| <$3> <> 1554dnl workspace: <@><mark> <CanonicalAddress> $| <result> 1555R<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 1556dnl workspace: <result> <mark> <CanonicalAddress> 1557# retransform for further use 1558dnl required form: 1559dnl <ResultOfLookup|mark> CanonicalAddress 1560R<?> <$+> <$*> $: <$1> $2 no match 1561R<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 1562dnl workspace <ResultOfLookup|mark> CanonicalAddress 1563dnl mark is ? iff the address is user (wo @domain) 1564 1565ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 1566# handle case of no @domain on address 1567dnl prepend daemon_flags 1568R<?> $* $: $&{daemon_flags} $| <?> $1 1569dnl accept unqualified sender: change mark to avoid test 1570R$* u $* $| <?> $* $: <OK> $3 1571dnl remove daemon_flags 1572R$* $| $* $: $2 1573R<?> $* $: < ? $&{client_name} > $1 1574R<?> $* $@ <OK> ...local unqualed ok 1575R<? $+> $* $#error $@ 5.5.4 $: "501 Domain name required for sender address " $&f 1576 ...remote is not') 1577# check results 1578R<?> $* $: @ $1 mark address: nothing known about it 1579R<OK> $* $@ <OK> 1580R<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 1581R<PERM> $* $#error $@ 5.1.8 $: "501 Domain of sender address " $&f " does not exist" 1582ifdef(`_ACCESS_TABLE_', `dnl 1583R<$={Accept}> $* $# $1 1584R<DISCARD> $* $#discard $: discard 1585R<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 1586dnl error tag 1587R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 1588R<ERROR:$+> $* $#error $: $1 1589dnl generic error from access map 1590R<$+> $* $#error $: $1 error from access db', 1591`dnl') 1592 1593###################################################################### 1594### check_rcpt -- check SMTP ``RCPT TO:'' command argument 1595###################################################################### 1596 1597SLocal_check_rcpt 1598Scheck`'_U_`'rcpt 1599R$* $: $1 $| $>"Local_check_rcpt" $1 1600R$* $| $#$* $#$2 1601R$* $| $* $@ $>"Basic_check_rcpt" $1 1602 1603SBasic_check_rcpt 1604# check for deferred delivery mode 1605R$* $: < ${deliveryMode} > $1 1606R< d > $* $@ deferred 1607R< $* > $* $: $2 1608 1609ifdef(`_REQUIRE_QUAL_RCPT_', `dnl 1610# require qualified recipient? 1611R$+ $: <?> $1 1612R<?><$+> $: <@> <$1> 1613R<?>$+ $: <@> <$1> 1614dnl prepend daemon_flags 1615R$* $: $&{daemon_flags} $| $1 1616dnl workspace: ${daemon_flags} $| <@> <address> 1617dnl do not allow these at all or only from local systems? 1618R$* r $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 1619R<?> < $* > $: <$1> 1620R<? $=w> < $* > $: <$1> 1621R<? $+> <$+> $#error $@ 5.5.4 $: "553 Domain name required" 1622dnl remove daemon_flags for other cases 1623R$* $| <@> $* $: $2', `dnl') 1624 1625ifdef(`_LOOSE_RELAY_CHECK_',`dnl 1626R$* $: $>CanonAddr $1 1627R$* < @ $* . > $1 < @ $2 > strip trailing dots', 1628`R$* $: $>ParseRecipient $1 strip relayable hosts') 1629 1630ifdef(`_BESTMX_IS_LOCAL_',`dnl 1631ifelse(_BESTMX_IS_LOCAL_, `', `dnl 1632# unlimited bestmx 1633R$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 1634`dnl 1635# limit bestmx to $=B 1636R$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 1637R$* $=O $* < @ $* @@ $=w . > $* $@ $>"Basic_check_rcpt" $1 $2 $3 1638R$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 1639R$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 1640 1641ifdef(`_BLACKLIST_RCPT_',`dnl 1642ifdef(`_ACCESS_TABLE_', `dnl 1643# blacklist local users or any host from receiving mail 1644R$* $: <?> $1 1645dnl user is now tagged with @ to be consistent with check_mail 1646dnl and to distinguish users from hosts (com would be host, com@ would be user) 1647R<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <H:$2> 1648R<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <H:$2> 1649R<?> $+ $: <> <$1> $| <U:$1@> 1650dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 1651dnl will only return user<@domain when "reversing" the args 1652R<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+To> $| <$2> <> 1653R<@> <$*> $| <$*> $: <$2> <$1> reverse result 1654R<?> <$*> $: @ $1 mark address as no match 1655R<$={Accept}> <$*> $: @ $2 mark address as no match 1656ifdef(`_DELAY_CHECKS_',`dnl 1657dnl we have to filter these because otherwise they would be interpreted 1658dnl as generic error message... 1659dnl error messages should be "tagged" by prefixing them with error: ! 1660dnl that would make a lot of things easier. 1661dnl maybe we should stop checks already here (if SPAM_xyx)? 1662R<$={SpamTag}> <$*> $: @ $2 mark address as no match') 1663R<REJECT> $* $#error $@ 5.2.1 $: "550 Mailbox disabled for this recipient" 1664R<DISCARD> $* $#discard $: discard 1665dnl error tag 1666R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 1667R<ERROR:$+> $* $#error $: $1 1668dnl generic error from access map 1669R<$+> $* $#error $: $1 error from access db 1670R@ $* $1 remove mark', `dnl')', `dnl') 1671 1672ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)') 1673# authenticated? 1674dnl do this unconditionally? this requires to manage CAs carefully 1675dnl just because someone has a CERT signed by a "trusted" CA 1676dnl does not mean we want to allow relaying for her, 1677dnl either use a subroutine or provide something more sophisticated 1678dnl this could for example check the DN (maybe an access map lookup) 1679R$* $: $1 $| $>RelayAuth $1 $| $&{verify} client authenticated? 1680R$* $| $# $+ $# $2 error/ok? 1681R$* $| $* $: $1 no 1682 1683# authenticated by a trusted mechanism? 1684R$* $: $1 $| $&{auth_type} 1685dnl empty ${auth_type}? 1686R$* $| $: $1 1687dnl mechanism ${auth_type} accepted? 1688dnl use $# to override further tests (delay_checks): see check_rcpt below 1689R$* $| $={TrustAuthMech} $# RELAYAUTH 1690dnl undo addition of ${auth_type} 1691R$* $| $* $: $1 1692dnl workspace: localpart<@domain> | localpart 1693ifelse(defn(`_NO_UUCP_'), `r', 1694`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 1695R$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 1696# anything terminating locally is ok 1697ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 1698R$+ < @ $* $=m > $@ RELAYTO', `dnl') 1699R$+ < @ $=w > $@ RELAYTO 1700ifdef(`_RELAY_HOSTS_ONLY_', 1701`R$+ < @ $=R > $@ RELAYTO 1702ifdef(`_ACCESS_TABLE_', `dnl 1703R$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 1704dnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 1705R<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 1706`R$+ < @ $* $=R > $@ RELAYTO 1707ifdef(`_ACCESS_TABLE_', `dnl 1708R$+ < @ $+ > $: $>LookUpDomain <$2> <?> <$1 < @ $2 >> <+To>',`dnl')') 1709ifdef(`_ACCESS_TABLE_', `dnl 1710dnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 1711R<RELAY> $* $@ RELAYTO 1712R<$*> <$*> $: $2',`dnl') 1713 1714 1715ifdef(`_RELAY_MX_SERVED_', `dnl 1716# allow relaying for hosts which we MX serve 1717R$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 1718dnl this must not necessarily happen if the client is checked first... 1719R< : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 1720R<$* : $=w . : $*> $* $@ RELAYTO 1721R< : $* : > $* $: $2', 1722`dnl') 1723 1724# check for local user (i.e. unqualified address) 1725R$* $: <?> $1 1726R<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 1727# local user is ok 1728dnl is it really? the standard requires user@domain, not just user 1729dnl but we should accept it anyway (maybe making it an option: 1730dnl RequireFQDN ?) 1731dnl postmaster must be accepted without domain (DRUMS) 1732ifdef(`_REQUIRE_QUAL_RCPT_', `dnl 1733R<?> postmaster $@ TOPOSTMASTER 1734# require qualified recipient? 1735dnl prepend daemon_flags 1736R<?> $+ $: $&{daemon_flags} $| <?> $1 1737dnl workspace: ${daemon_flags} $| <?> localpart 1738dnl do not allow these at all or only from local systems? 1739dnl r flag? add client_name 1740R$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 1741dnl no r flag: relay to local user (only local part) 1742# no qualified recipient required 1743R$* $| <?> $+ $@ RELAYTOLOCAL 1744dnl client_name is empty 1745R<?> <?> $+ $@ RELAYTOLOCAL 1746dnl client_name is local 1747R<? $=w> <?> $+ $@ RELAYTOLOCAL 1748dnl client_name is not local 1749R<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 1750dnl no qualified recipient required 1751R<?> $+ $@ RELAYTOLOCAL') 1752dnl it is a remote user: remove mark and then check client 1753R<$+> $* $: $2 1754dnl currently the recipient address is not used below 1755 1756# anything originating locally is ok 1757# check IP address 1758R$* $: $&{client_addr} 1759R$@ $@ RELAYFROM originated locally 1760R0 $@ RELAYFROM originated locally 1761R$=R $* $@ RELAYFROM relayable IP address 1762ifdef(`_ACCESS_TABLE_', `dnl 1763R$* $: $>LookUpAddress <$1> <?> <$1> <+Connect> 1764R<RELAY> $* $@ RELAYFROM relayable IP address 1765R<$*> <$*> $: $2', `dnl') 1766R$* $: [ $1 ] put brackets around it... 1767R$=w $@ RELAYFROM ... and see if it is local 1768 1769ifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 1770ifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 1771ifdef(`_RELAY_MAIL_FROM_', `dnl 1772dnl input: {client_addr} or something "broken" 1773dnl just throw the input away; we do not need it. 1774# check whether FROM is allowed to use system as relay 1775R$* $: <?> $>CanonAddr $&f 1776ifdef(`_RELAY_LOCAL_FROM_', `dnl 1777# check whether local FROM is ok 1778R<?> $+ < @ $=w . > $@ RELAYFROMMAIL FROM local', `dnl') 1779ifdef(`_RELAY_DB_FROM_', `dnl 1780R<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 1781R<?> $+ < @ $+ > $: $1 < @ $2 > $| $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<H:$2>') <> 1782R$* <RELAY> $@ RELAYFROMMAIL RELAY FROM sender ok', `dnl 1783ifdef(`_RELAY_DB_FROM_DOMAIN_', `errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 1784')', 1785`dnl') 1786dnl')', `dnl') 1787 1788# check client name: first: did it resolve? 1789dnl input: ignored 1790R$* $: < $&{client_resolve} > 1791R<TEMP> $#error $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 1792R<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 1793R<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 1794dnl ${client_resolve} should be OK, so go ahead 1795R$* $: <?> $&{client_name} 1796# pass to name server to make hostname canonical 1797R<?> $* $~P $:<?> $[ $1 $2 $] 1798R$* . $1 strip trailing dots 1799dnl should not be necessary since it has been done for client_addr already 1800R<?> $@ RELAYFROM 1801ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 1802R<?> $* $=m $@ RELAYFROM', `dnl') 1803R<?> $=w $@ RELAYFROM 1804ifdef(`_RELAY_HOSTS_ONLY_', 1805`R<?> $=R $@ RELAYFROM 1806ifdef(`_ACCESS_TABLE_', `dnl 1807R<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 1808R<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 1809`R<?> $* $=R $@ RELAYFROM 1810ifdef(`_ACCESS_TABLE_', `dnl 1811R<?> $* $: $>LookUpDomain <$1> <?> <$1> <+Connect>',`dnl')') 1812ifdef(`_ACCESS_TABLE_', `dnl 1813R<RELAY> $* $@ RELAYFROM 1814R<$*> <$*> $: $2',`dnl') 1815 1816# anything else is bogus 1817R$* $#error $@ 5.7.1 $: confRELAY_MSG 1818divert(0) 1819ifdef(`_DELAY_CHECKS_',`dnl 1820# turn a canonical address in the form user<@domain> 1821# qualify unqual. addresses with $j 1822dnl it might have been only user (without <@domain>) 1823SFullAddr 1824R$* <@ $+ . > $1 <@ $2 > 1825R$* <@ $* > $@ $1 <@ $2 > 1826R$+ $@ $1 <@ $j > 1827 1828# call all necessary rulesets 1829Scheck_rcpt 1830dnl this test should be in the Basic_check_rcpt ruleset 1831dnl which is the correct DSN code? 1832# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 1833R$+ $: $1 $| $>checkrcpt $1 1834dnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 1835R$+ $| $#$* $#$2 1836R$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 1837ifdef(`_SPAM_FH_', 1838`dnl lookup user@ and user@address 1839ifdef(`_ACCESS_TABLE_', `', 1840`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 1841')')dnl 1842dnl one of the next two rules is supposed to match 1843dnl this code has been copied from BLACKLIST... etc 1844dnl and simplified by omitting some < >. 1845R<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <U: $1@> 1846R<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > 1847dnl R<?> $@ something_is_very_wrong_here 1848# lookup the addresses only with To tag 1849R<> $* $| <$+> $: <@> $1 $| $>SearchList <!To> $| <$2> <> 1850R<@> $* $| $* $: $2 $1 reverse result 1851dnl', `dnl') 1852ifdef(`_SPAM_FRIEND_', 1853`# is the recipient a spam friend? 1854ifdef(`_SPAM_HATER_', 1855 `errprint(`*** ERROR: define either SpamHater or SpamFriend 1856')', `dnl') 1857R<SPAMFRIEND> $+ $@ SPAMFRIEND 1858R<$*> $+ $: $2', 1859`dnl') 1860ifdef(`_SPAM_HATER_', 1861`# is the recipient no spam hater? 1862R<SPAMHATER> $+ $: $1 spam hater: continue checks 1863R<$*> $+ $@ NOSPAMHATER everyone else: stop 1864dnl',`dnl') 1865dnl run further checks: check_mail 1866dnl should we "clean up" $&f? 1867R$* $: $1 $| $>checkmail <$&f> 1868R$* $| $#$* $#$2 1869dnl run further checks: check_relay 1870R$* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 1871R$* $| $#$* $#$2 1872R$* $| $* $: $1 1873', `dnl') 1874ifdef(`_ACCESS_TABLE_', `dnl 1875###################################################################### 1876### SearchList: search a list of items in the access map 1877### Parameters: 1878### <exact tag> $| <mark:address> <mark:address> ... <> 1879dnl maybe we should have a @ (again) in front of the mark to 1880dnl avoid errorneous matches (with error messages?) 1881dnl if we can make sure that tag is always a single token 1882dnl then we can omit the delimiter $|, otherwise we need it 1883dnl to avoid errorneous matchs (first rule: H: if there 1884dnl is that mark somewhere in the list, it will be taken). 1885dnl moreover, we can do some tricks to enforce lookup with 1886dnl the tag only, e.g.: 1887### where "exact" is either "+" or "!": 1888### <+ TAG> lookup with and w/o tag 1889### <! TAG> lookup with tag 1890dnl Warning: + and ! should be in OperatorChars (otherwise there must be 1891dnl a blank between them and the tag. 1892### possible values for "mark" are: 1893### H: recursive host lookup (LookUpDomain) 1894dnl A: recursive address lookup (LookUpAddress) [not yet required] 1895### E: exact lookup, no modifications 1896### F: full lookup, try user+ext@domain and user@domain 1897### U: user lookup, try user+ext and user (input must have trailing @) 1898### return: <RHS of lookup> or <?> (not found) 1899###################################################################### 1900 1901# class with valid marks for SearchList 1902dnl if A is activated: add it 1903C{src}E F H U 1904SSearchList 1905# mark H: lookup domain 1906R<$+> $| <H:$+> <$*> $: <$1> $| <@> $>LookUpDomain <$2> <?> <$3> <$1> 1907R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> 1908dnl A: NOT YET REQUIRED 1909dnl R<$+> $| <A:$+> <$*> $: <$1> $| <@> $>LookUpAddress <$2> <?> <$3> <$1> 1910dnl R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> 1911dnl lookup of the item with tag 1912dnl this applies to F: U: E: 1913R<$- $-> $| <$={src}:$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5> 1914dnl no match, try without tag 1915R<+ $-> $| <$={src}:$+> <$*> $: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4> 1916dnl do we really have to distinguish these cases? 1917dnl probably yes, there might be a + in the domain part (is that allowed?) 1918dnl user+detail lookups: should it be: 1919dnl user+detail, user+*, user; just like aliases? 1920R<$- $-> $| <F:$* + $*@$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@$5 $: F:$3 + $4@$5$)> <$6> 1921R<+ $-> $| <F:$* + $*@$+> <$*> $: <+ $1> $| <$(access $2@$4 $: F:$2 + $3@$4$)> <$5> 1922dnl user lookups are always with trailing @ 1923dnl do not remove the @ from the lookup: 1924dnl it is part of the +detail@ which is omitted for the lookup 1925R<$- $-> $| <U:$* + $*> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5> 1926dnl no match, try without tag 1927R<+ $-> $| <U:$* + $*> <$*> $: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4> 1928dnl no match, try rest of list 1929R<$+> $| <$={src}:$+> <$+> $@ $>SearchList <$1> $| <$4> 1930dnl no match, list empty: return failure 1931R<$+> $| <$={src}:$+> <> $@ <?> 1932dnl got result, return it 1933R<$+> $| <$+> <$*> $@ <$2> 1934dnl return result from recursive invocation 1935R<$+> $| <$+> $@ <$2>', `dnl') 1936 1937# is user trusted to authenticate as someone else? 1938dnl AUTH= parameter from MAIL command 1939Strust_auth 1940R$* $: $&{auth_type} $| $1 1941# required by RFC 2554 section 4. 1942R$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 1943dnl seems to be useful... 1944R$* $| $&{auth_authen} $@ identical 1945R$* $| <$&{auth_authen}> $@ identical 1946dnl call user supplied code 1947R$* $| $* $: $1 $| $>"Local_trust_auth" $1 1948R$* $| $#$* $#$2 1949dnl default: error 1950R$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 1951 1952dnl empty ruleset definition so it can be called 1953SLocal_trust_auth 1954 1955ifdef(`_FFR_TLS_O_T', `dnl 1956Soffer_tls 1957R$* $: $>LookUpDomain <$&{client_name}> <?> <> <! TLS_OFF_TAG> 1958R<?>$* $: $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_OFF_TAG> 1959R<?>$* $: <$(access TLS_OFF_TAG: $: ? $)> 1960R<?>$* $@ OK 1961R<NO> <> $#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]" 1962 1963Stry_tls 1964R$* $: $>LookUpDomain <$&{server_name}> <?> <> <! TLS_TRY_TAG> 1965R<?>$* $: $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_TRY_TAG> 1966R<?>$* $: <$(access TLS_TRY_TAG: $: ? $)> 1967R<?>$* $@ OK 1968R<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 1969')dnl 1970 1971# is connection with client "good" enough? (done in server) 1972# input: ${verify} $| (MAIL|STARTTLS) 1973dnl MAIL: called from check_mail 1974dnl STARTTLS: called from smtp() after STARTTLS has been accepted 1975Stls_client 1976ifdef(`_ACCESS_TABLE_', `dnl 1977dnl ignore second arg for now 1978dnl maybe use it to distinguish permanent/temporary error? 1979dnl if MAIL: permanent (STARTTLS has not been offered) 1980dnl if STARTTLS: temporary (offered but maybe failed) 1981R$* $| $* $: $1 $| $>LookUpDomain <$&{client_name}> <?> <> <! TLS_CLT_TAG> 1982R$* $| <?>$* $: $1 $| $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_CLT_TAG> 1983dnl do a default lookup: just TLS_CLT_TAG 1984R$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 1985R$* $@ $>"tls_connection" $1', `dnl 1986R$* $| $* $@ $>"tls_connection" $1') 1987 1988# is connection with server "good" enough? (done in client) 1989dnl i.e. has the server been authenticated and is encryption active? 1990dnl called from deliver() after STARTTLS command 1991# input: ${verify} 1992Stls_server 1993ifdef(`_ACCESS_TABLE_', `dnl 1994R$* $: $1 $| $>LookUpDomain <$&{server_name}> <?> <> <! TLS_SRV_TAG> 1995R$* $| <?>$* $: $1 $| $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_SRV_TAG> 1996dnl do a default lookup: just TLS_SRV_TAG 1997R$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 1998R$* $@ $>"tls_connection" $1', `dnl 1999R$* $@ $>"tls_connection" $1') 2000 2001Stls_connection 2002ifdef(`_ACCESS_TABLE_', `dnl 2003dnl common ruleset for tls_{client|server} 2004dnl input: $&{verify} $| <ResultOfLookup> [<>] 2005dnl remove optional <> 2006R$* $| <$*>$* $: $1 $| <$2> 2007dnl permanent or temporary error? 2008R$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 2009R$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 2010dnl default case depends on TLS_PERM_ERR 2011R$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 2012dnl deal with TLS handshake failures: abort 2013RSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 2014dnl no <reply:dns> i.e. not requirements in the access map 2015dnl use default error 2016RSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 2017R$* $| <$*> <VERIFY> $: <$2> <VERIFY> $1 2018R$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> $1 2019dnl some other value in access map: accept 2020dnl this also allows to override the default case (if used) 2021R$* $| $* $@ OK 2022# authentication required: give appropriate error 2023# other side did authenticate (via STARTTLS) 2024dnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> ${verify} 2025dnl only verification required and it succeeded 2026R<$*><VERIFY> OK $@ OK 2027dnl verification required + some level of encryption 2028R<$*><VERIFY:$-> OK $: <$1> <REQ:$2> 2029dnl just some level of encryption required 2030R<$*><ENCR:$-> $* $: <$1> <REQ:$2> 2031dnl verification required but ${verify} is not set 2032R<$-:$+><VERIFY $*> $#error $@ $2 $: $1 " authentication required" 2033R<$-:$+><VERIFY $*> FAIL $#error $@ $2 $: $1 " authentication failed" 2034R<$-:$+><VERIFY $*> NO $#error $@ $2 $: $1 " not authenticated" 2035R<$-:$+><VERIFY $*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 2036dnl some other value for ${verify} 2037R<$-:$+><VERIFY $*> $+ $#error $@ $2 $: $1 " authentication failure " $4 2038dnl some level of encryption required: get the maximum level 2039R<$*><REQ:$-> $: <$1> <REQ:$2> $>max $&{cipher_bits} : $&{auth_ssf} 2040dnl compare required bits with actual bits 2041R<$*><REQ:$-> $- $: <$1> <$2:$3> $(arith l $@ $3 $@ $2 $) 2042R<$-:$+><$-:$-> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 2043 2044Smax 2045dnl compute the max of two values separated by : 2046R: $: 0 2047R:$- $: $1 2048R$-: $: $1 2049R$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 2050RTRUE:$-:$- $: $2 2051R$-:$-:$- $: $2', 2052`dnl use default error 2053dnl deal with TLS handshake failures: abort 2054RSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."') 2055 2056SRelayAuth 2057# authenticated? 2058dnl we do not allow relaying for anyone who can present a cert 2059dnl signed by a "trusted" CA. For example, even if we put verisigns 2060dnl CA in CERTPath so we can authenticate users, we do not allow 2061dnl them to abuse our server (they might be easier to get hold of, 2062dnl but anyway). 2063dnl so here is the trick: if the verification succeeded 2064dnl we look up the cert issuer in the access map 2065dnl (maybe after extracting a part with a regular expression) 2066dnl if this returns RELAY we relay without further questions 2067dnl if it returns SUBJECT we perform a similar check on the 2068dnl cert subject. 2069R$* $| OK $: $1 2070R$* $| $* $@ NO not authenticated 2071ifdef(`_ACCESS_TABLE_', `dnl 2072ifdef(`_CERT_REGEX_ISSUER_', `dnl 2073R$* $: $1 $| $(CERTIssuer $&{cert_issuer} $)', 2074`R$* $: $1 $| $&{cert_issuer}') 2075R$* $| $+ $: $1 $| $(access CERTISSUER:$2 $) 2076dnl use $# to stop further checks (delay_check) 2077R$* $| RELAY $# RELAYCERTISSUER 2078ifdef(`_CERT_REGEX_SUBJECT_', `dnl 2079R$* $| SUBJECT $: $1 $| <@> $(CERTSubject $&{cert_subject} $)', 2080`R$* $| SUBJECT $: $1 $| <@> $&{cert_subject}') 2081R$* $| <@> $+ $: $1 $| <@> $(access CERTSUBJECT:$2 $) 2082R$* $| <@> RELAY $# RELAYCERTSUBJECT 2083R$* $| $* $: $1', `dnl') 2084 2085undivert(9)dnl LOCAL_RULESETS 2086ifdef(`_FFR_MILTER', ` 2087# 2088###################################################################### 2089###################################################################### 2090##### 2091`##### MAIL FILTER DEFINITIONS' 2092##### 2093###################################################################### 2094###################################################################### 2095_MAIL_FILTERS_') 2096# 2097###################################################################### 2098###################################################################### 2099##### 2100`##### MAILER DEFINITIONS' 2101##### 2102###################################################################### 2103###################################################################### 2104undivert(7)dnl MAILER_DEFINITIONS 2105 2106