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