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