1divert(-1) 2# 3# Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. 4# All rights reserved. 5# Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. 6# Copyright (c) 1988, 1993 7# The Regents of the University of California. All rights reserved. 8# 9# By using this file, you agree to the terms and conditions set 10# forth in the LICENSE file which can be found at the top level of 11# the sendmail distribution. 12# 13# 14divert(0) 15 16VERSIONID(`$Id: proto.m4,v 8.649.2.17 2003/03/28 17:20:53 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:text> -> error 1287dnl <mailer:user@host> lp<@domain>rest -> mailer host user 1288dnl <mailer:host> address -> mailer host address 1289dnl <localdomain> address -> address 1290dnl <host> address -> relay host address 1291################################################################### 1292 1293SMailerToTriple=95 1294R< > $* $@ $1 strip off null relay 1295R< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 1296R< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 1297R< local : $* > $* $>CanonLocal < $1 > $2 1298dnl it is $~[ instead of $- to avoid matches on IPv6 addresses 1299R< $~[ : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 1300R< $~[ : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 1301R< $=w > $* $@ $2 delete local host 1302R< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 1303 1304################################################################### 1305### Ruleset CanonLocal -- canonify local: syntax ### 1306dnl input: <user> address 1307dnl <x> <@host> : rest -> Recurse rest 1308dnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 1309dnl <> user <@host> rest -> local user@host user 1310dnl <> user -> local user user 1311dnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 1312dnl <user> lp <@host> rest -> local lp@host user 1313dnl <user> lp -> local lp user 1314################################################################### 1315 1316SCanonLocal 1317# strip local host from routed addresses 1318R< $* > < @ $+ > : $+ $@ $>Recurse $3 1319R< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 1320 1321# strip trailing dot from any host name that may appear 1322R< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 1323 1324# handle local: syntax -- use old user, either with or without host 1325R< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 1326R< > $+ $#_LOCAL_ $@ $1 $: $1 1327 1328# handle local:user@host syntax -- ignore host part 1329R< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 1330 1331# handle local:user syntax 1332R< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 1333R< $+ > $* $#_LOCAL_ $@ $2 $: $1 1334 1335################################################################### 1336### Ruleset 93 -- convert header names to masqueraded form ### 1337################################################################### 1338 1339SMasqHdr=93 1340 1341ifdef(`_GENERICS_TABLE_', `dnl 1342# handle generics database 1343ifdef(`_GENERICS_ENTIRE_DOMAIN_', 1344dnl if generics should be applied add a @ as mark 1345`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 1346`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 1347R$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 1348dnl workspace: either user<@domain> or <user@domain> user <@domain> @ 1349dnl ignore the first case for now 1350dnl if it has the mark lookup full address 1351dnl broken: %1 is full address not just detail 1352R< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 1353dnl workspace: ... or <match|@user@domain> user <@domain> 1354dnl no match, try user+detail@domain 1355R<@$+ + $* @ $+> $+ < @ $+ > 1356 $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 1357R<@$+ + $* @ $+> $+ < @ $+ > 1358 $: < $(generics $1@$3 $: $) > $4 < @ $5 > 1359dnl no match, remove mark 1360R<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 1361dnl no match, try @domain for exceptions 1362R< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 1363dnl workspace: ... or <match> user <@domain> 1364dnl no match, try local part 1365R< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 1366R< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 1367R< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 1368R< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 1369R< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 1370R< > $* $: $1 not found', 1371`dnl') 1372 1373# do not masquerade anything in class N 1374R$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 1375 1376ifdef(`MASQUERADE_NAME', `dnl 1377# special case the users that should be exposed 1378R$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 1379ifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 1380`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 1381`R$=E < @ $=M . > $@ $1 < @ $2 . >') 1382ifdef(`_LIMITED_MASQUERADE_', `dnl', 1383`R$=E < @ $=w . > $@ $1 < @ $2 . >') 1384 1385# handle domain-specific masquerading 1386ifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 1387`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 1388`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 1389ifdef(`_LIMITED_MASQUERADE_', `dnl', 1390`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 1391R$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 1392R$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 1393R$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 1394dnl', `dnl no masquerading 1395dnl just fix *LOCAL* leftovers 1396R$* < @ *LOCAL* > $@ $1 < @ $j . >') 1397 1398################################################################### 1399### Ruleset 94 -- convert envelope names to masqueraded form ### 1400################################################################### 1401 1402SMasqEnv=94 1403ifdef(`_MASQUERADE_ENVELOPE_', 1404`R$+ $@ $>MasqHdr $1', 1405`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 1406 1407################################################################### 1408### Ruleset 98 -- local part of ruleset zero (can be null) ### 1409################################################################### 1410 1411SParseLocal=98 1412undivert(3)dnl LOCAL_RULE_0 1413 1414ifdef(`_LDAP_ROUTING_', `dnl 1415###################################################################### 1416### LDAPExpand: Expand address using LDAP routing 1417### 1418### Parameters: 1419### <$1> -- parsed address (user < @ domain . >) (pass through) 1420### <$2> -- RFC822 address (user @ domain) (used for lookup) 1421### <$3> -- +detail information 1422### 1423### Returns: 1424### Mailer triplet ($#mailer $@ host $: address) 1425### Parsed address (user < @ domain . >) 1426###################################################################### 1427 1428SLDAPExpand 1429# do the LDAP lookups 1430R<$+><$+><$*> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> <$3> 1431 1432# look for temporary failures (return original address, MTA will queue up) 1433R<$* <TMPF>> <$*> <$+> <$+> <$*> $@ $3 1434R<$*> <$* <TMPF>> <$+> <$+> <$*> $@ $3 1435 1436# if mailRoutingAddress and local or non-existant mailHost, 1437# return the new mailRoutingAddress 1438ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 1439R<$+@$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $6 @ $2 1440R<$+@$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 $5 @ $2') 1441R<$+> <$=w> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 1442R<$+> <> <$+> <$+> <$*> $@ $>Parse0 $>canonify $1 1443 1444 1445# if mailRoutingAddress and non-local mailHost, 1446# relay to mailHost with new mailRoutingAddress 1447ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 1448ifdef(`_MAILER_TABLE_', `dnl 1449# check mailertable for host, relay from there 1450R<$+@$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$3> $>canonify $1 $6 @ $2', 1451`R<$+@$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $3 $: $>canonify $1 $6 @ $2')') 1452ifdef(`_MAILER_TABLE_', `dnl 1453# check mailertable for host, relay from there 1454R<$+> <$+> <$+> <$+> <$*> $>LDAPMailertable <$2> $>canonify $1', 1455`R<$+> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $2 $: $>canonify $1') 1456 1457# if no mailRoutingAddress and local mailHost, 1458# return original address 1459R<> <$=w> <$+> <$+> <$*> $@ $2 1460 1461 1462# if no mailRoutingAddress and non-local mailHost, 1463# relay to mailHost with original address 1464ifdef(`_MAILER_TABLE_', `dnl 1465# check mailertable for host, relay from there 1466R<> <$+> <$+> <$+> <$*> $>LDAPMailertable <$1> $2', 1467`R<> <$+> <$+> <$+> <$*> $#_RELAY_ $@ $1 $: $2') 1468 1469ifdef(`_LDAP_ROUTE_DETAIL_', 1470`# if no mailRoutingAddress and no mailHost, 1471# try without +detail 1472R<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <$2 @ $4> <+$3>')dnl 1473 1474# if still no mailRoutingAddress and no mailHost, 1475# try @domain 1476ifelse(_LDAP_ROUTE_DETAIL_, `_PRESERVE_', `dnl 1477R<> <> <$+> <$+ + $* @ $+> <> $@ $>LDAPExpand <$1> <@ $4> <+$3>') 1478R<> <> <$+> <$+ @ $+> <$*> $@ $>LDAPExpand <$1> <@ $3> <$4> 1479 1480# if no mailRoutingAddress and no mailHost and this was a domain attempt, 1481ifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 1482# user does not exist 1483R<> <> <$+> <@ $+> <$*> $: <?> < $&{addr_type} > < $1 > 1484# only give error for envelope recipient 1485R<?> <e r> <$+> $#error $@ nouser $: "550 User unknown" 1486R<?> <$*> <$+> $@ $2', 1487`dnl 1488# return the original address 1489R<> <> <$+> <@ $+> <$*> $@ $1')', 1490`dnl') 1491 1492ifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 1493')') 1494ifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 1495###################################################################### 1496### D: LookUpDomain -- search for domain in access database 1497### 1498### Parameters: 1499### <$1> -- key (domain name) 1500### <$2> -- default (what to return if not found in db) 1501dnl must not be empty 1502### <$3> -- mark (must be <(!|+) single-token>) 1503### ! does lookup only with tag 1504### + does lookup with and without tag 1505### <$4> -- passthru (additional data passed unchanged through) 1506dnl returns: <default> <passthru> 1507dnl <result> <passthru> 1508###################################################################### 1509 1510SD 1511dnl workspace <key> <default> <passthru> <mark> 1512dnl lookup with tag (in front, no delimiter here) 1513dnl 2 3 4 5 1514R<$*> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 1515dnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 1516dnl lookup without tag? 1517dnl 1 2 3 4 1518R<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 1519ifdef(`_LOOKUPDOTDOMAIN_', `dnl omit first component: lookup .rest 1520dnl XXX apply this also to IP addresses? 1521dnl currently it works the wrong way round for [1.2.3.4] 1522dnl 1 2 3 4 5 6 1523R<?> <$+.$+> <$+> <$- $-> <$*> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4 $5> <$6> 1524dnl 1 2 3 4 5 1525R<?> <$+.$+> <$+> <+ $-> <$*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <+ $4> <$5>', `dnl') 1526ifdef(`_ACCESS_SKIP_', `dnl 1527dnl found SKIP: return <default> and <passthru> 1528dnl 1 2 3 4 5 1529R<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 1530dnl not found: IPv4 net (no check is done whether it is an IP number!) 1531dnl 1 2 3 4 5 6 1532R<?> <[$+.$-]> <$+> <$- $-> <$*> $@ $>D <[$1]> <$3> <$4 $5> <$6> 1533ifdef(`NO_NETINET6', `dnl', 1534`dnl not found: IPv6 net 1535dnl (could be merged with previous rule if we have a class containing .:) 1536dnl 1 2 3 4 5 6 1537R<?> <[$+::$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6> 1538R<?> <[$+:$-]> <$+> <$- $-> <$*> $: $>D <[$1]> <$3> <$4 $5> <$6>') 1539dnl not found, but subdomain: try again 1540dnl 1 2 3 4 5 6 1541R<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6> 1542ifdef(`_FFR_LOOKUPTAG_', `dnl lookup Tag: 1543dnl 1 2 3 4 1544R<?> <$+> <$+> <! $-> <$*> $: < $(access $3`'_TAG_DELIM_ $: ? $) > <$1> <$2> <! $3> <$4>', `dnl') 1545dnl not found, no subdomain: return <default> and <passthru> 1546dnl 1 2 3 4 5 1547R<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 1548ifdef(`_ATMPF_', `dnl tempfail? 1549dnl 2 3 4 5 6 1550R<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 1551dnl return <result of lookup> and <passthru> 1552dnl 2 3 4 5 6 1553R<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 1554 1555###################################################################### 1556### A: LookUpAddress -- search for host address in access database 1557### 1558### Parameters: 1559### <$1> -- key (dot quadded host address) 1560### <$2> -- default (what to return if not found in db) 1561dnl must not be empty 1562### <$3> -- mark (must be <(!|+) single-token>) 1563### ! does lookup only with tag 1564### + does lookup with and without tag 1565### <$4> -- passthru (additional data passed through) 1566dnl returns: <default> <passthru> 1567dnl <result> <passthru> 1568###################################################################### 1569 1570SA 1571dnl lookup with tag 1572dnl 2 3 4 5 1573R<$+> <$+> <$- $-> <$*> $: < $(access $4`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3 $4> <$5> 1574dnl lookup without tag 1575dnl 1 2 3 4 1576R<?> <$+> <$+> <+ $-> <$*> $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4> 1577dnl workspace <result-of-lookup|?> <key> <default> <mark> <passthru> 1578ifdef(`_ACCESS_SKIP_', `dnl 1579dnl found SKIP: return <default> and <passthru> 1580dnl 1 2 3 4 5 1581R<SKIP> <$+> <$+> <$- $-> <$*> $@ <$2> <$5>', `dnl') 1582ifdef(`NO_NETINET6', `dnl', 1583`dnl no match; IPv6: remove last part 1584dnl 1 2 3 4 5 6 1585R<?> <$+::$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 1586R<?> <$+:$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6>') 1587dnl no match; IPv4: remove last part 1588dnl 1 2 3 4 5 6 1589R<?> <$+.$-> <$+> <$- $-> <$*> $@ $>A <$1> <$3> <$4 $5> <$6> 1590dnl no match: return default 1591dnl 1 2 3 4 5 1592R<?> <$+> <$+> <$- $-> <$*> $@ <$2> <$5> 1593ifdef(`_ATMPF_', `dnl tempfail? 1594dnl 2 3 4 5 6 1595R<$* _ATMPF_> <$+> <$+> <$- $-> <$*> $@ <_ATMPF_> <$6>', `dnl') 1596dnl match: return result 1597dnl 2 3 4 5 6 1598R<$*> <$+> <$+> <$- $-> <$*> $@ <$1> <$6> 1599dnl endif _ACCESS_TABLE_ 1600divert(0) 1601###################################################################### 1602### CanonAddr -- Convert an address into a standard form for 1603### relay checking. Route address syntax is 1604### crudely converted into a %-hack address. 1605### 1606### Parameters: 1607### $1 -- full recipient address 1608### 1609### Returns: 1610### parsed address, not in source route form 1611dnl user%host%host<@domain> 1612dnl host!user<@domain> 1613###################################################################### 1614 1615SCanonAddr 1616R$* $: $>Parse0 $>canonify $1 make domain canonical 1617ifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 1618R< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 1619R$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 1620R$* < @ $+ > : $* $3 $1 < @ $2 > 1621dnl') 1622 1623###################################################################### 1624### ParseRecipient -- Strip off hosts in $=R as well as possibly 1625### $* $=m or the access database. 1626### Check user portion for host separators. 1627### 1628### Parameters: 1629### $1 -- full recipient address 1630### 1631### Returns: 1632### parsed, non-local-relaying address 1633###################################################################### 1634 1635SParseRecipient 1636dnl mark and canonify address 1637R$* $: <?> $>CanonAddr $1 1638dnl workspace: <?> localpart<@domain[.]> 1639R<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 1640dnl workspace: <?> localpart<@domain> 1641R<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 1642 1643# if no $=O character, no host in the user portion, we are done 1644R<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 1645dnl no $=O in localpart: return 1646R<?> $* $@ $1 1647 1648dnl workspace: <NO> localpart<@domain>, where localpart contains $=O 1649dnl mark everything which has an "authorized" domain with <RELAY> 1650ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 1651# if we relay, check username portion for user%host so host can be checked also 1652R<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 1653dnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 1654dnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 1655 1656dnl what if access map returns something else than RELAY? 1657dnl we are only interested in RELAY entries... 1658dnl other To: entries: blacklist recipient; generic entries? 1659dnl if it is an error we probably do not want to relay anyway 1660ifdef(`_RELAY_HOSTS_ONLY_', 1661`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 1662ifdef(`_ACCESS_TABLE_', `dnl 1663R<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 1664R<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 1665`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 1666ifdef(`_ACCESS_TABLE_', `dnl 1667R<NO> $* < @ $+ > $: $>D <$2> <NO> <+ To> <$1 < @ $2 >> 1668R<$+> <$+> $: <$1> $2',`dnl')') 1669 1670 1671ifdef(`_RELAY_MX_SERVED_', `dnl 1672dnl do "we" ($=w) act as backup MX server for the destination domain? 1673R<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 1674R<MX> < : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 1675dnl yes: mark it as <RELAY> 1676R<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 1677dnl no: put old <NO> mark back 1678R<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 1679 1680dnl do we relay to this recipient domain? 1681R<RELAY> $* < @ $* > $@ $>ParseRecipient $1 1682dnl something else 1683R<$+> $* $@ $2 1684 1685 1686###################################################################### 1687### check_relay -- check hostname/address on SMTP startup 1688###################################################################### 1689 1690SLocal_check_relay 1691Scheck`'_U_`'relay 1692R$* $: $1 $| $>"Local_check_relay" $1 1693R$* $| $* $| $#$* $#$3 1694R$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 1695 1696SBasic_check_relay 1697# check for deferred delivery mode 1698R$* $: < $&{deliveryMode} > $1 1699R< d > $* $@ deferred 1700R< $* > $* $: $2 1701 1702ifdef(`_ACCESS_TABLE_', `dnl 1703dnl workspace: {client_name} $| {client_addr} 1704R$+ $| $+ $: $>D < $1 > <?> <+ Connect> < $2 > 1705dnl workspace: <result-of-lookup> <{client_addr}> 1706dnl OR $| $+ if client_name is empty 1707R $| $+ $: $>A < $1 > <?> <+ Connect> <> empty client_name 1708dnl workspace: <result-of-lookup> <{client_addr}> 1709R<?> <$+> $: $>A < $1 > <?> <+ Connect> <> no: another lookup 1710dnl workspace: <result-of-lookup> (<>|<{client_addr}>) 1711R<?> <$*> $: OK found nothing 1712dnl workspace: <result-of-lookup> (<>|<{client_addr}>) | OK 1713R<$={Accept}> <$*> $@ $1 return value of lookup 1714R<REJECT> <$*> $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 1715R<DISCARD> <$*> $#discard $: discard 1716ifdef(`_FFR_QUARANTINE', 1717`R<QUARANTINE:$+> <$*> $#error $@ quarantine $: $1', `dnl') 1718dnl error tag 1719R<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 1720R<ERROR:$+> <$*> $#error $: $1 1721ifdef(`_ATMPF_', `R<$* _ATMPF_> <$*> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 1722dnl generic error from access map 1723R<$+> <$*> $#error $: $1', `dnl') 1724 1725ifdef(`_RBL_',`dnl 1726# DNS based IP address spam list 1727dnl workspace: ignored... 1728R$* $: $&{client_addr} 1729R$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 1730R<?>OK $: OKSOFAR 1731R<?>$+ $#error $@ 5.7.1 $: "550 Rejected: " $&{client_addr} " listed at _RBL_"', 1732`dnl') 1733undivert(8) 1734 1735###################################################################### 1736### check_mail -- check SMTP ``MAIL FROM:'' command argument 1737###################################################################### 1738 1739SLocal_check_mail 1740Scheck`'_U_`'mail 1741R$* $: $1 $| $>"Local_check_mail" $1 1742R$* $| $#$* $#$2 1743R$* $| $* $@ $>"Basic_check_mail" $1 1744 1745SBasic_check_mail 1746# check for deferred delivery mode 1747R$* $: < $&{deliveryMode} > $1 1748R< d > $* $@ deferred 1749R< $* > $* $: $2 1750 1751# authenticated? 1752dnl done first: we can require authentication for every mail transaction 1753dnl workspace: address as given by MAIL FROM: (sender) 1754R$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 1755R$* $| $#$+ $#$2 1756dnl undo damage: remove result of tls_client call 1757R$* $| $* $: $1 1758 1759dnl workspace: address as given by MAIL FROM: 1760R<> $@ <OK> we MUST accept <> (RFC 1123) 1761ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 1762dnl do some additional checks 1763dnl no user@host 1764dnl no user@localhost (if nonlocal sender) 1765dnl this is a pretty simple canonification, it will not catch every case 1766dnl just make sure the address has <> around it (which is required by 1767dnl the RFC anyway, maybe we should complain if they are missing...) 1768dnl dirty trick: if it is user@host, just add a dot: user@host. this will 1769dnl not be modified by host lookups. 1770R$+ $: <?> $1 1771R<?><$+> $: <@> <$1> 1772R<?>$+ $: <@> <$1> 1773dnl workspace: <@> <address> 1774dnl prepend daemon_flags 1775R$* $: $&{daemon_flags} $| $1 1776dnl workspace: ${daemon_flags} $| <@> <address> 1777dnl do not allow these at all or only from local systems? 1778R$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 1779dnl accept unqualified sender: change mark to avoid test 1780R$* u $* $| <@> < $* > $: <?> < $3 > 1781dnl workspace: ${daemon_flags} $| <@> <address> 1782dnl or: <? ${client_name} > <address> 1783dnl or: <?> <address> 1784dnl remove daemon_flags 1785R$* $| $* $: $2 1786# handle case of @localhost on address 1787R<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 1788R<@> < $* @ [127.0.0.1] > 1789 $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 1790R<@> < $* @ localhost.$m > 1791 $: < ? $&{client_name} > < $1 @ localhost.$m > 1792ifdef(`_NO_UUCP_', `dnl', 1793`R<@> < $* @ localhost.UUCP > 1794 $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 1795dnl workspace: < ? $&{client_name} > <user@localhost|host> 1796dnl or: <@> <address> 1797dnl or: <?> <address> (thanks to u in ${daemon_flags}) 1798R<@> $* $: $1 no localhost as domain 1799dnl workspace: < ? $&{client_name} > <user@localhost|host> 1800dnl or: <address> 1801dnl or: <?> <address> (thanks to u in ${daemon_flags}) 1802R<? $=w> $* $: $2 local client: ok 1803R<? $+> <$+> $#error $@ 5.5.4 $: "_CODE553 Real domain name required for sender address" 1804dnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 1805R<?> $* $: $1') 1806dnl workspace: address (or <address>) 1807R$* $: <?> $>CanonAddr $1 canonify sender address and mark it 1808dnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 1809dnl there is nothing behind the <@host> so no trailing $* needed 1810R<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 1811# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 1812R<?> $* < @ $* $=P > $: <_RES_OK_> $1 < @ $2 $3 > 1813dnl workspace <mark> CanonicalAddress where mark is ? or OK 1814dnl A sender address with my local host name ($j) is safe 1815R<?> $* < @ $j > $: <_RES_OK_> $1 < @ $j > 1816ifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 1817`R<?> $* < @ $+ > $: <_RES_OK_> $1 < @ $2 > ... unresolvable OK', 1818`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 1819R<? $* <$->> $* < @ $+ > 1820 $: <$2> $3 < @ $4 >') 1821dnl workspace <mark> CanonicalAddress where mark is ?, _RES_OK_, PERM, TEMP 1822dnl mark is ? iff the address is user (wo @domain) 1823 1824ifdef(`_ACCESS_TABLE_', `dnl 1825# check sender address: user@address, user@, address 1826dnl should we remove +ext from user? 1827dnl workspace: <mark> CanonicalAddress where mark is: ?, _RES_OK_, PERM, TEMP 1828R<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3> 1829R<$+> $+ $: @<$1> <$2> $| <U:$2@> 1830dnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 1831dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 1832dnl will only return user<@domain when "reversing" the args 1833R@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <> 1834dnl workspace: <@><mark> <CanonicalAddress> $| <result> 1835R<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 1836dnl workspace: <result> <mark> <CanonicalAddress> 1837# retransform for further use 1838dnl required form: 1839dnl <ResultOfLookup|mark> CanonicalAddress 1840R<?> <$+> <$*> $: <$1> $2 no match 1841R<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 1842dnl workspace <ResultOfLookup|mark> CanonicalAddress 1843dnl mark is ? iff the address is user (wo @domain) 1844 1845ifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 1846# handle case of no @domain on address 1847dnl prepend daemon_flags 1848R<?> $* $: $&{daemon_flags} $| <?> $1 1849dnl accept unqualified sender: change mark to avoid test 1850R$* u $* $| <?> $* $: <_RES_OK_> $3 1851dnl remove daemon_flags 1852R$* $| $* $: $2 1853R<?> $* $: < ? $&{client_addr} > $1 1854R<?> $* $@ <_RES_OK_> ...local unqualed ok 1855R<? $+> $* $#error $@ 5.5.4 $: "_CODE553 Domain name required for sender address " $&f 1856 ...remote is not') 1857# check results 1858R<?> $* $: @ $1 mark address: nothing known about it 1859R<$={ResOk}> $* $@ <_RES_OK_> domain ok: stop 1860R<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 1861R<PERM> $* $#error $@ 5.1.8 $: "_CODE553 Domain of sender address " $&f " does not exist" 1862ifdef(`_ACCESS_TABLE_', `dnl 1863R<$={Accept}> $* $# $1 accept from access map 1864R<DISCARD> $* $#discard $: discard 1865ifdef(`_FFR_QUARANTINE', 1866`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 1867R<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 1868dnl error tag 1869R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 1870R<ERROR:$+> $* $#error $: $1 1871ifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 1872dnl generic error from access map 1873R<$+> $* $#error $: $1 error from access db', 1874`dnl') 1875 1876###################################################################### 1877### check_rcpt -- check SMTP ``RCPT TO:'' command argument 1878###################################################################### 1879 1880SLocal_check_rcpt 1881Scheck`'_U_`'rcpt 1882R$* $: $1 $| $>"Local_check_rcpt" $1 1883R$* $| $#$* $#$2 1884R$* $| $* $@ $>"Basic_check_rcpt" $1 1885 1886SBasic_check_rcpt 1887# empty address? 1888R<> $#error $@ nouser $: "553 User address required" 1889R$@ $#error $@ nouser $: "553 User address required" 1890# check for deferred delivery mode 1891R$* $: < $&{deliveryMode} > $1 1892R< d > $* $@ deferred 1893R< $* > $* $: $2 1894 1895ifdef(`_REQUIRE_QUAL_RCPT_', `dnl 1896dnl this code checks for user@host where host is not a FQHN. 1897dnl it is not activated. 1898dnl notice: code to check for a recipient without a domain name is 1899dnl available down below; look for the same macro. 1900dnl this check is done here because the name might be qualified by the 1901dnl canonicalization. 1902# require fully qualified domain part? 1903dnl very simple canonification: make sure the address is in < > 1904R$+ $: <?> $1 1905R<?> <$+> $: <@> <$1> 1906R<?> $+ $: <@> <$1> 1907R<@> < postmaster > $: postmaster 1908R<@> < $* @ $+ . $+ > $: < $1 @ $2 . $3 > 1909dnl prepend daemon_flags 1910R<@> $* $: $&{daemon_flags} $| <@> $1 1911dnl workspace: ${daemon_flags} $| <@> <address> 1912dnl do not allow these at all or only from local systems? 1913R$* r $* $| <@> < $* @ $* > $: < ? $&{client_name} > < $3 @ $4 > 1914R<?> < $* > $: <$1> 1915R<? $=w> < $* > $: <$1> 1916R<? $+> <$+> $#error $@ 5.5.4 $: "553 Fully qualified domain name required" 1917dnl remove daemon_flags for other cases 1918R$* $| <@> $* $: $2', `dnl') 1919 1920dnl ################################################################## 1921dnl call subroutines for recipient and relay 1922dnl possible returns from subroutines: 1923dnl $#TEMP temporary failure 1924dnl $#error permanent failure (or temporary if from access map) 1925dnl $#other stop processing 1926dnl RELAY RELAYing allowed 1927dnl other otherwise 1928###################################################################### 1929R$* $: $1 $| @ $>"Rcpt_ok" $1 1930dnl temporary failure? remove mark @ and remember 1931R$* $| @ $#TEMP $+ $: $1 $| T $2 1932dnl error or ok (stop) 1933R$* $| @ $#$* $#$2 1934ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 1935R$* $| @ RELAY $@ RELAY 1936dnl something else: call check sender (relay) 1937R$* $| @ $* $: O $| $>"Relay_ok" $1 1938dnl temporary failure: call check sender (relay) 1939R$* $| T $+ $: T $2 $| $>"Relay_ok" $1 1940dnl temporary failure? return that 1941R$* $| $#TEMP $+ $#error $2 1942dnl error or ok (stop) 1943R$* $| $#$* $#$2 1944R$* $| RELAY $@ RELAY 1945dnl something else: return previous temp failure 1946R T $+ $| $* $#error $1 1947# anything else is bogus 1948R$* $#error $@ 5.7.1 $: confRELAY_MSG 1949divert(0) 1950 1951###################################################################### 1952### Rcpt_ok: is the recipient ok? 1953dnl input: recipient address (RCPT TO) 1954dnl output: see explanation at call 1955###################################################################### 1956SRcpt_ok 1957ifdef(`_LOOSE_RELAY_CHECK_',`dnl 1958R$* $: $>CanonAddr $1 1959R$* < @ $* . > $1 < @ $2 > strip trailing dots', 1960`R$* $: $>ParseRecipient $1 strip relayable hosts') 1961 1962ifdef(`_BESTMX_IS_LOCAL_',`dnl 1963ifelse(_BESTMX_IS_LOCAL_, `', `dnl 1964# unlimited bestmx 1965R$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 1966`dnl 1967# limit bestmx to $=B 1968R$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 1969R$* $=O $* < @ $* @@ $=w . > $* $@ $>"Rcpt_ok" $1 $2 $3 1970R$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 1971R$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 1972 1973ifdef(`_BLACKLIST_RCPT_',`dnl 1974ifdef(`_ACCESS_TABLE_', `dnl 1975# blacklist local users or any host from receiving mail 1976R$* $: <?> $1 1977dnl user is now tagged with @ to be consistent with check_mail 1978dnl and to distinguish users from hosts (com would be host, com@ would be user) 1979R<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2> 1980R<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2> 1981R<?> $+ $: <> <$1> $| <U:$1@> 1982dnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 1983dnl will only return user<@domain when "reversing" the args 1984R<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+ To> $| <$2> <> 1985R<@> <$*> $| <$*> $: <$2> <$1> reverse result 1986R<?> <$*> $: @ $1 mark address as no match 1987dnl we may have to filter here because otherwise some RHSs 1988dnl would be interpreted as generic error messages... 1989dnl error messages should be "tagged" by prefixing them with error: ! 1990dnl that would make a lot of things easier. 1991R<$={Accept}> <$*> $: @ $2 mark address as no match 1992ifdef(`_ACCESS_SKIP_', `dnl 1993R<SKIP> <$*> $: @ $1 mark address as no match', `dnl') 1994ifdef(`_DELAY_COMPAT_8_10_',`dnl 1995dnl compatility with 8.11/8.10: 1996dnl we have to filter these because otherwise they would be interpreted 1997dnl as generic error message... 1998dnl error messages should be "tagged" by prefixing them with error: ! 1999dnl that would make a lot of things easier. 2000dnl maybe we should stop checks already here (if SPAM_xyx)? 2001R<$={SpamTag}> <$*> $: @ $2 mark address as no match') 2002R<REJECT> $* $#error $@ 5.2.1 $: confRCPTREJ_MSG 2003R<DISCARD> $* $#discard $: discard 2004ifdef(`_FFR_QUARANTINE', 2005`R<QUARANTINE:$+> $* $#error $@ quarantine $: $1', `dnl') 2006dnl error tag 2007R<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 2008R<ERROR:$+> $* $#error $: $1 2009ifdef(`_ATMPF_', `R<_ATMPF_> $* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2010dnl generic error from access map 2011R<$+> $* $#error $: $1 error from access db 2012R@ $* $1 remove mark', `dnl')', `dnl') 2013 2014ifdef(`_PROMISCUOUS_RELAY_', `divert(-1)', `dnl') 2015# authenticated via TLS? 2016R$* $: $1 $| $>RelayTLS client authenticated? 2017R$* $| $# $+ $# $2 error/ok? 2018R$* $| $* $: $1 no 2019 2020R$* $: $1 $| $>"Local_Relay_Auth" $&{auth_type} 2021dnl workspace: localpart<@domain> $| result of Local_Relay_Auth 2022R$* $| $# $* $# $2 2023dnl if Local_Relay_Auth returns NO then do not check $={TrustAuthMech} 2024R$* $| NO $: $1 2025R$* $| $* $: $1 $| $&{auth_type} 2026dnl workspace: localpart<@domain> [ $| ${auth_type} ] 2027dnl empty ${auth_type}? 2028R$* $| $: $1 2029dnl mechanism ${auth_type} accepted? 2030dnl use $# to override further tests (delay_checks): see check_rcpt below 2031R$* $| $={TrustAuthMech} $# RELAY 2032dnl remove ${auth_type} 2033R$* $| $* $: $1 2034dnl workspace: localpart<@domain> | localpart 2035ifelse(defn(`_NO_UUCP_'), `r', 2036`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 2037R$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 2038# anything terminating locally is ok 2039ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 2040R$+ < @ $* $=m > $@ RELAY', `dnl') 2041R$+ < @ $=w > $@ RELAY 2042ifdef(`_RELAY_HOSTS_ONLY_', 2043`R$+ < @ $=R > $@ RELAY 2044ifdef(`_ACCESS_TABLE_', `dnl 2045R$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 2046dnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 2047R<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 2048`R$+ < @ $* $=R > $@ RELAY 2049ifdef(`_ACCESS_TABLE_', `dnl 2050R$+ < @ $+ > $: $>D <$2> <?> <+ To> <$1 < @ $2 >>',`dnl')') 2051ifdef(`_ACCESS_TABLE_', `dnl 2052dnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 2053R<RELAY> $* $@ RELAY 2054ifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2055R<$*> <$*> $: $2',`dnl') 2056 2057 2058ifdef(`_RELAY_MX_SERVED_', `dnl 2059# allow relaying for hosts which we MX serve 2060R$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 2061dnl this must not necessarily happen if the client is checked first... 2062R< : $* <TEMP> : > $* $#TEMP $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 2063R<$* : $=w . : $*> $* $@ RELAY 2064R< : $* : > $* $: $2', 2065`dnl') 2066 2067# check for local user (i.e. unqualified address) 2068R$* $: <?> $1 2069R<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 2070# local user is ok 2071dnl is it really? the standard requires user@domain, not just user 2072dnl but we should accept it anyway (maybe making it an option: 2073dnl RequireFQDN ?) 2074dnl postmaster must be accepted without domain (DRUMS) 2075ifdef(`_REQUIRE_QUAL_RCPT_', `dnl 2076R<?> postmaster $@ OK 2077# require qualified recipient? 2078dnl prepend daemon_flags 2079R<?> $+ $: $&{daemon_flags} $| <?> $1 2080dnl workspace: ${daemon_flags} $| <?> localpart 2081dnl do not allow these at all or only from local systems? 2082dnl r flag? add client_name 2083R$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 2084dnl no r flag: relay to local user (only local part) 2085# no qualified recipient required 2086R$* $| <?> $+ $@ RELAY 2087dnl client_name is empty 2088R<?> <?> $+ $@ RELAY 2089dnl client_name is local 2090R<? $=w> <?> $+ $@ RELAY 2091dnl client_name is not local 2092R<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 2093dnl no qualified recipient required 2094R<?> $+ $@ RELAY') 2095dnl it is a remote user: remove mark and then check client 2096R<$+> $* $: $2 2097dnl currently the recipient address is not used below 2098 2099###################################################################### 2100### Relay_ok: is the relay/sender ok? 2101dnl input: ignored 2102dnl output: see explanation at call 2103###################################################################### 2104SRelay_ok 2105# anything originating locally is ok 2106# check IP address 2107R$* $: $&{client_addr} 2108R$@ $@ RELAY originated locally 2109R0 $@ RELAY originated locally 2110R127.0.0.1 $@ RELAY originated locally 2111RIPv6:::1 $@ RELAY originated locally 2112R$=R $* $@ RELAY relayable IP address 2113ifdef(`_ACCESS_TABLE_', `dnl 2114R$* $: $>A <$1> <?> <+ Connect> <$1> 2115R<RELAY> $* $@ RELAY relayable IP address 2116ifdef(`_FFR_REJECT_IP_IN_CHECK_RCPT_',`dnl 2117dnl this will cause rejections in cases like: 2118dnl Connect:My.Host.Domain RELAY 2119dnl Connect:My.Net REJECT 2120dnl since in check_relay client_name is checked before client_addr 2121R<REJECT> $* $@ REJECT rejected IP address') 2122ifdef(`_ATMPF_', `R<_ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2123R<$*> <$*> $: $2', `dnl') 2124R$* $: [ $1 ] put brackets around it... 2125R$=w $@ RELAY ... and see if it is local 2126 2127ifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 2128ifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 2129ifdef(`_RELAY_MAIL_FROM_', `dnl 2130dnl input: {client_addr} or something "broken" 2131dnl just throw the input away; we do not need it. 2132# check whether FROM is allowed to use system as relay 2133R$* $: <?> $>CanonAddr $&f 2134R<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 2135ifdef(`_RELAY_LOCAL_FROM_', `dnl 2136# check whether local FROM is ok 2137R<?> $+ < @ $=w > $@ RELAY FROM local', `dnl') 2138ifdef(`_RELAY_DB_FROM_', `dnl 2139R<?> $+ < @ $+ > $: <@> $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', ifdef(`_RELAY_HOSTS_ONLY_', `<E:$2>', `<D:$2>')) <> 2140R<@> <RELAY> $@ RELAY RELAY FROM sender ok 2141ifdef(`_ATMPF_', `R<@> <_ATMPF_> $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2142', `dnl 2143ifdef(`_RELAY_DB_FROM_DOMAIN_', 2144`errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 2145')', 2146`dnl') 2147dnl')', `dnl') 2148dnl notice: the rulesets above do not leave a unique workspace behind. 2149dnl it does not matter in this case because the following rule ignores 2150dnl the input. otherwise these rules must "clean up" the workspace. 2151 2152# check client name: first: did it resolve? 2153dnl input: ignored 2154R$* $: < $&{client_resolve} > 2155R<TEMP> $#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 2156R<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 2157R<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 2158dnl ${client_resolve} should be OK, so go ahead 2159R$* $: <@> $&{client_name} 2160dnl should not be necessary since it has been done for client_addr already 2161dnl this rule actually may cause a problem if {client_name} resolves to "" 2162dnl however, this should not happen since the forward lookup should fail 2163dnl and {client_resolve} should be TEMP or FAIL. 2164dnl nevertheless, removing the rule doesn't hurt. 2165dnl R<@> $@ RELAY 2166dnl workspace: <@> ${client_name} (not empty) 2167# pass to name server to make hostname canonical 2168R<@> $* $=P $:<?> $1 $2 2169R<@> $+ $:<?> $[ $1 $] 2170dnl workspace: <?> ${client_name} (canonified) 2171R$* . $1 strip trailing dots 2172ifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 2173R<?> $* $=m $@ RELAY', `dnl') 2174R<?> $=w $@ RELAY 2175ifdef(`_RELAY_HOSTS_ONLY_', 2176`R<?> $=R $@ RELAY 2177ifdef(`_ACCESS_TABLE_', `dnl 2178R<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 2179R<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 2180`R<?> $* $=R $@ RELAY 2181ifdef(`_ACCESS_TABLE_', `dnl 2182R<?> $* $: $>D <$1> <?> <+ Connect> <$1>',`dnl')') 2183ifdef(`_ACCESS_TABLE_', `dnl 2184R<RELAY> $* $@ RELAY 2185ifdef(`_ATMPF_', `R<$* _ATMPF_> $* $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2186R<$*> <$*> $: $2',`dnl') 2187dnl end of _PROMISCUOUS_RELAY_ 2188divert(0) 2189ifdef(`_DELAY_CHECKS_',`dnl 2190# turn a canonical address in the form user<@domain> 2191# qualify unqual. addresses with $j 2192dnl it might have been only user (without <@domain>) 2193SFullAddr 2194R$* <@ $+ . > $1 <@ $2 > 2195R$* <@ $* > $@ $1 <@ $2 > 2196R$+ $@ $1 <@ $j > 2197 2198SDelay_TLS_Client 2199# authenticated? 2200dnl code repeated here from Basic_check_mail 2201dnl only called from check_rcpt in delay mode if checkrcpt returns $# 2202R$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 2203R$* $| $#$+ $#$2 2204dnl return result from checkrcpt 2205R$* $# $1 2206 2207SDelay_TLS_Client2 2208# authenticated? 2209dnl code repeated here from Basic_check_mail 2210dnl only called from check_rcpt in delay mode if stopping due to Friend/Hater 2211R$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 2212R$* $| $#$+ $#$2 2213dnl return result from friend/hater check 2214R$* $@ $1 2215 2216# call all necessary rulesets 2217Scheck_rcpt 2218dnl this test should be in the Basic_check_rcpt ruleset 2219dnl which is the correct DSN code? 2220# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 2221 2222R$+ $: $1 $| $>checkrcpt $1 2223dnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 2224dnl on error (or discard) stop now 2225R$+ $| $#error $* $#error $2 2226R$+ $| $#discard $* $#discard $2 2227dnl otherwise call tls_client; see above 2228R$+ $| $#$* $@ $>"Delay_TLS_Client" $2 2229R$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 2230ifdef(`_SPAM_FH_', 2231`dnl lookup user@ and user@address 2232ifdef(`_ACCESS_TABLE_', `', 2233`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 2234')')dnl 2235dnl one of the next two rules is supposed to match 2236dnl this code has been copied from BLACKLIST... etc 2237dnl and simplified by omitting some < >. 2238R<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > <U: $1@> 2239R<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > <D: $2 > 2240dnl R<?> $@ something_is_very_wrong_here 2241# lookup the addresses only with Spam tag 2242R<> $* $| <$+> $: <@> $1 $| $>SearchList <! Spam> $| <$2> <> 2243R<@> $* $| $* $: $2 $1 reverse result 2244dnl', `dnl') 2245ifdef(`_SPAM_FRIEND_', 2246`# is the recipient a spam friend? 2247ifdef(`_SPAM_HATER_', 2248 `errprint(`*** ERROR: define either Hater or Friend -- not both. 2249')', `dnl') 2250R<FRIEND> $+ $@ $>"Delay_TLS_Client2" SPAMFRIEND 2251R<$*> $+ $: $2', 2252`dnl') 2253ifdef(`_SPAM_HATER_', 2254`# is the recipient no spam hater? 2255R<HATER> $+ $: $1 spam hater: continue checks 2256R<$*> $+ $@ $>"Delay_TLS_Client2" NOSPAMHATER everyone else: stop 2257dnl',`dnl') 2258dnl run further checks: check_mail 2259dnl should we "clean up" $&f? 2260ifdef(`_FFR_MAIL_MACRO', 2261`R$* $: $1 $| $>checkmail $&{mail_from}', 2262`R$* $: $1 $| $>checkmail <$&f>') 2263dnl recipient (canonical format) $| result of checkmail 2264R$* $| $#$* $#$2 2265dnl run further checks: check_relay 2266R$* $| $* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 2267R$* $| $#$* $#$2 2268R$* $| $* $: $1 2269', `dnl') 2270 2271ifdef(`_ACCESS_TABLE_', `dnl', `divert(-1)') 2272###################################################################### 2273### F: LookUpFull -- search for an entry in access database 2274### 2275### lookup of full key (which should be an address) and 2276### variations if +detail exists: +* and without +detail 2277### 2278### Parameters: 2279### <$1> -- key 2280### <$2> -- default (what to return if not found in db) 2281dnl must not be empty 2282### <$3> -- mark (must be <(!|+) single-token>) 2283### ! does lookup only with tag 2284### + does lookup with and without tag 2285### <$4> -- passthru (additional data passed unchanged through) 2286dnl returns: <default> <passthru> 2287dnl <result> <passthru> 2288###################################################################### 2289 2290SF 2291dnl workspace: <key> <def> <o tag> <thru> 2292dnl full lookup 2293dnl 2 3 4 5 2294R<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 2295dnl no match, try without tag 2296dnl 1 2 3 4 2297R<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 2298dnl no match, +detail: try +* 2299dnl 1 2 3 4 5 6 7 2300R<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 2301 $: <$(access $6`'_TAG_DELIM_`'$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 2302dnl no match, +detail: try +* without tag 2303dnl 1 2 3 4 5 6 2304R<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 2305 $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 2306dnl no match, +detail: try without +detail 2307dnl 1 2 3 4 5 6 7 2308R<?> <$+ + $* @ $+> <$*> <$- $-> <$*> 2309 $: <$(access $6`'_TAG_DELIM_`'$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7> 2310dnl no match, +detail: try without +detail and without tag 2311dnl 1 2 3 4 5 6 2312R<?> <$+ + $* @ $+> <$*> <+ $-> <$*> 2313 $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6> 2314dnl no match, return <default> <passthru> 2315dnl 1 2 3 4 5 2316R<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 2317ifdef(`_ATMPF_', `dnl tempfail? 2318dnl 2 3 4 5 2319R<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 2320dnl match, return <match> <passthru> 2321dnl 2 3 4 5 2322R<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 2323 2324###################################################################### 2325### E: LookUpExact -- search for an entry in access database 2326### 2327### Parameters: 2328### <$1> -- key 2329### <$2> -- default (what to return if not found in db) 2330dnl must not be empty 2331### <$3> -- mark (must be <(!|+) single-token>) 2332### ! does lookup only with tag 2333### + does lookup with and without tag 2334### <$4> -- passthru (additional data passed unchanged through) 2335dnl returns: <default> <passthru> 2336dnl <result> <passthru> 2337###################################################################### 2338 2339SE 2340dnl 2 3 4 5 2341R<$*> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 2342dnl no match, try without tag 2343dnl 1 2 3 4 2344R<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 2345dnl no match, return default passthru 2346dnl 1 2 3 4 5 2347R<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 2348ifdef(`_ATMPF_', `dnl tempfail? 2349dnl 2 3 4 5 2350R<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 2351dnl match, return <match> <passthru> 2352dnl 2 3 4 5 2353R<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 2354 2355###################################################################### 2356### U: LookUpUser -- search for an entry in access database 2357### 2358### lookup of key (which should be a local part) and 2359### variations if +detail exists: +* and without +detail 2360### 2361### Parameters: 2362### <$1> -- key (user@) 2363### <$2> -- default (what to return if not found in db) 2364dnl must not be empty 2365### <$3> -- mark (must be <(!|+) single-token>) 2366### ! does lookup only with tag 2367### + does lookup with and without tag 2368### <$4> -- passthru (additional data passed unchanged through) 2369dnl returns: <default> <passthru> 2370dnl <result> <passthru> 2371###################################################################### 2372 2373SU 2374dnl user lookups are always with trailing @ 2375dnl 2 3 4 5 2376R<$+> <$*> <$- $-> <$*> $: <$(access $4`'_TAG_DELIM_`'$1 $: ? $)> <$1> <$2> <$3 $4> <$5> 2377dnl no match, try without tag 2378dnl 1 2 3 4 2379R<?> <$+> <$*> <+ $-> <$*> $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4> 2380dnl do not remove the @ from the lookup: 2381dnl it is part of the +detail@ which is omitted for the lookup 2382dnl no match, +detail: try +* 2383dnl 1 2 3 4 5 6 2384R<?> <$+ + $* @> <$*> <$- $-> <$*> 2385 $: <$(access $5`'_TAG_DELIM_`'$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 2386dnl no match, +detail: try +* without tag 2387dnl 1 2 3 4 5 2388R<?> <$+ + $* @> <$*> <+ $-> <$*> 2389 $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 2390dnl no match, +detail: try without +detail 2391dnl 1 2 3 4 5 6 2392R<?> <$+ + $* @> <$*> <$- $-> <$*> 2393 $: <$(access $5`'_TAG_DELIM_`'$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6> 2394dnl no match, +detail: try without +detail and without tag 2395dnl 1 2 3 4 5 2396R<?> <$+ + $* @> <$*> <+ $-> <$*> 2397 $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5> 2398dnl no match, return <default> <passthru> 2399dnl 1 2 3 4 5 2400R<?> <$+> <$*> <$- $-> <$*> $@ <$2> <$5> 2401ifdef(`_ATMPF_', `dnl tempfail? 2402dnl 2 3 4 5 2403R<$+ _ATMPF_> <$*> <$- $-> <$*> $@ <_ATMPF_> <$5>', `dnl') 2404dnl match, return <match> <passthru> 2405dnl 2 3 4 5 2406R<$+> <$*> <$- $-> <$*> $@ <$1> <$5> 2407 2408###################################################################### 2409### SearchList: search a list of items in the access map 2410### Parameters: 2411### <exact tag> $| <mark:address> <mark:address> ... <> 2412dnl maybe we should have a @ (again) in front of the mark to 2413dnl avoid errorneous matches (with error messages?) 2414dnl if we can make sure that tag is always a single token 2415dnl then we can omit the delimiter $|, otherwise we need it 2416dnl to avoid errorneous matchs (first rule: D: if there 2417dnl is that mark somewhere in the list, it will be taken). 2418dnl moreover, we can do some tricks to enforce lookup with 2419dnl the tag only, e.g.: 2420### where "exact" is either "+" or "!": 2421### <+ TAG> lookup with and w/o tag 2422### <! TAG> lookup with tag 2423dnl Warning: + and ! should be in OperatorChars (otherwise there must be 2424dnl a blank between them and the tag. 2425### possible values for "mark" are: 2426### D: recursive host lookup (LookUpDomain) 2427dnl A: recursive address lookup (LookUpAddress) [not yet required] 2428### E: exact lookup, no modifications 2429### F: full lookup, try user+ext@domain and user@domain 2430### U: user lookup, try user+ext and user (input must have trailing @) 2431### return: <RHS of lookup> or <?> (not found) 2432###################################################################### 2433 2434# class with valid marks for SearchList 2435dnl if A is activated: add it 2436C{src}E F D U ifdef(`_FFR_SRCHLIST_A', `A') 2437SSearchList 2438# just call the ruleset with the name of the tag... nice trick... 2439dnl 2 3 4 2440R<$+> $| <$={src}:$*> <$*> $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <> 2441dnl workspace: <o tag> $| <rest> $| <result of lookup> <> 2442dnl no match and nothing left: return 2443R<$+> $| <> $| <?> <> $@ <?> 2444dnl no match but something left: continue 2445R<$+> $| <$+> $| <?> <> $@ $>SearchList <$1> $| <$2> 2446dnl match: return 2447R<$+> $| <$*> $| <$+> <> $@ <$3> 2448dnl return result from recursive invocation 2449R<$+> $| <$+> $@ <$2> 2450dnl endif _ACCESS_TABLE_ 2451divert(0) 2452 2453###################################################################### 2454### trust_auth: is user trusted to authenticate as someone else? 2455### 2456### Parameters: 2457### $1: AUTH= parameter from MAIL command 2458###################################################################### 2459 2460dnl empty ruleset definition so it can be called 2461SLocal_trust_auth 2462Strust_auth 2463R$* $: $&{auth_type} $| $1 2464# required by RFC 2554 section 4. 2465R$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 2466dnl seems to be useful... 2467R$* $| $&{auth_authen} $@ identical 2468R$* $| <$&{auth_authen}> $@ identical 2469dnl call user supplied code 2470R$* $| $* $: $1 $| $>"Local_trust_auth" $1 2471R$* $| $#$* $#$2 2472dnl default: error 2473R$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 2474 2475###################################################################### 2476### Relay_Auth: allow relaying based on authentication? 2477### 2478### Parameters: 2479### $1: ${auth_type} 2480###################################################################### 2481SLocal_Relay_Auth 2482 2483ifdef(`_ACCESS_TABLE_', `dnl 2484###################################################################### 2485### srv_features: which features to offer to a client? 2486### (done in server) 2487###################################################################### 2488Ssrv_features 2489ifdef(`_LOCAL_SRV_FEATURES_', `dnl 2490R$* $: $1 $| $>"Local_srv_features" $1 2491R$* $| $#$* $#$2 2492R$* $| $* $: $1', `dnl') 2493R$* $: $>D <$&{client_name}> <?> <! SRV_FEAT_TAG> <> 2494R<?>$* $: $>A <$&{client_addr}> <?> <! SRV_FEAT_TAG> <> 2495R<?>$* $: <$(access SRV_FEAT_TAG`'_TAG_DELIM_ $: ? $)> 2496R<?>$* $@ OK 2497ifdef(`_ATMPF_', `dnl tempfail? 2498R<$* _ATMPF_>$* $#temp', `dnl') 2499R<$+>$* $# $1 2500 2501###################################################################### 2502### try_tls: try to use STARTTLS? 2503### (done in client) 2504###################################################################### 2505Stry_tls 2506ifdef(`_LOCAL_TRY_TLS_', `dnl 2507R$* $: $1 $| $>"Local_try_tls" $1 2508R$* $| $#$* $#$2 2509R$* $| $* $: $1', `dnl') 2510R$* $: $>D <$&{server_name}> <?> <! TLS_TRY_TAG> <> 2511R<?>$* $: $>A <$&{server_addr}> <?> <! TLS_TRY_TAG> <> 2512R<?>$* $: <$(access TLS_TRY_TAG`'_TAG_DELIM_ $: ? $)> 2513R<?>$* $@ OK 2514ifdef(`_ATMPF_', `dnl tempfail? 2515R<$* _ATMPF_>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2516R<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 2517 2518###################################################################### 2519### tls_rcpt: is connection with server "good" enough? 2520### (done in client, per recipient) 2521dnl called from deliver() before RCPT command 2522### 2523### Parameters: 2524### $1: recipient 2525###################################################################### 2526Stls_rcpt 2527ifdef(`_LOCAL_TLS_RCPT_', `dnl 2528R$* $: $1 $| $>"Local_tls_rcpt" $1 2529R$* $| $#$* $#$2 2530R$* $| $* $: $1', `dnl') 2531dnl store name of other side 2532R$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 2533dnl canonify recipient address 2534R$+ $: <?> $>CanonAddr $1 2535dnl strip trailing dots 2536R<?> $+ < @ $+ . > <?> $1 <@ $2 > 2537dnl full address? 2538R<?> $+ < @ $+ > $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:> 2539dnl only localpart? 2540R<?> $+ $: $1 $| <U:$1@> <E:> 2541dnl look it up 2542dnl also look up a default value via E: 2543R$* $| $+ $: $1 $| $>SearchList <! TLS_RCPT_TAG> $| $2 <> 2544dnl found nothing: stop here 2545R$* $| <?> $@ OK 2546ifdef(`_ATMPF_', `dnl tempfail? 2547R$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2548dnl use the generic routine (for now) 2549R$* $| <$+> $@ $>"TLS_connection" $&{verify} $| <$2>') 2550 2551###################################################################### 2552### tls_client: is connection with client "good" enough? 2553### (done in server) 2554### 2555### Parameters: 2556### ${verify} $| (MAIL|STARTTLS) 2557###################################################################### 2558dnl MAIL: called from check_mail 2559dnl STARTTLS: called from smtp() after STARTTLS has been accepted 2560Stls_client 2561ifdef(`_LOCAL_TLS_CLIENT_', `dnl 2562R$* $: $1 $| $>"Local_tls_client" $1 2563R$* $| $#$* $#$2 2564R$* $| $* $: $1', `dnl') 2565ifdef(`_ACCESS_TABLE_', `dnl 2566dnl store name of other side 2567R$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 2568dnl ignore second arg for now 2569dnl maybe use it to distinguish permanent/temporary error? 2570dnl if MAIL: permanent (STARTTLS has not been offered) 2571dnl if STARTTLS: temporary (offered but maybe failed) 2572R$* $| $* $: $1 $| $>D <$&{client_name}> <?> <! TLS_CLT_TAG> <> 2573R$* $| <?>$* $: $1 $| $>A <$&{client_addr}> <?> <! TLS_CLT_TAG> <> 2574dnl do a default lookup: just TLS_CLT_TAG 2575R$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 2576ifdef(`_ATMPF_', `dnl tempfail? 2577R$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2578R$* $@ $>"TLS_connection" $1', `dnl 2579R$* $| $* $@ $>"TLS_connection" $1') 2580 2581###################################################################### 2582### tls_server: is connection with server "good" enough? 2583### (done in client) 2584### 2585### Parameter: 2586### ${verify} 2587###################################################################### 2588dnl i.e. has the server been authenticated and is encryption active? 2589dnl called from deliver() after STARTTLS command 2590Stls_server 2591ifdef(`_LOCAL_TLS_SERVER_', `dnl 2592R$* $: $1 $| $>"Local_tls_server" $1 2593R$* $| $#$* $#$2 2594R$* $| $* $: $1', `dnl') 2595ifdef(`_ACCESS_TABLE_', `dnl 2596dnl store name of other side 2597R$* $: $(macro {TLS_Name} $@ $&{server_name} $) $1 2598R$* $: $1 $| $>D <$&{server_name}> <?> <! TLS_SRV_TAG> <> 2599R$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! TLS_SRV_TAG> <> 2600dnl do a default lookup: just TLS_SRV_TAG 2601R$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 2602ifdef(`_ATMPF_', `dnl tempfail? 2603R$* $| <$* _ATMPF_> $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."', `dnl') 2604R$* $@ $>"TLS_connection" $1', `dnl 2605R$* $@ $>"TLS_connection" $1') 2606 2607###################################################################### 2608### TLS_connection: is TLS connection "good" enough? 2609### 2610### Parameters: 2611ifdef(`_ACCESS_TABLE_', `dnl 2612### ${verify} $| <Requirement> [<>]', `dnl 2613### ${verify}') 2614### Requirement: RHS from access map, may be ? for none. 2615dnl syntax for Requirement: 2616dnl [(PERM|TEMP)+] (VERIFY[:bits]|ENCR:bits) [+extensions] 2617dnl extensions: could be a list of further requirements 2618dnl for now: CN:string {cn_subject} == string 2619###################################################################### 2620STLS_connection 2621ifdef(`_ACCESS_TABLE_', `dnl', `dnl use default error 2622dnl deal with TLS handshake failures: abort 2623RSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake." 2624divert(-1)') 2625dnl common ruleset for tls_{client|server} 2626dnl input: ${verify} $| <ResultOfLookup> [<>] 2627dnl remove optional <> 2628R$* $| <$*>$* $: $1 $| <$2> 2629dnl workspace: ${verify} $| <ResultOfLookup> 2630# create the appropriate error codes 2631dnl permanent or temporary error? 2632R$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 2633R$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 2634dnl default case depends on TLS_PERM_ERR 2635R$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 2636dnl workspace: ${verify} $| [<SMTP:ESC>] <ResultOfLookup> 2637# deal with TLS handshake failures: abort 2638RSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 2639dnl no <reply:dns> i.e. not requirements in the access map 2640dnl use default error 2641RSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 2642R$* $| <$*> <VERIFY> $: <$2> <VERIFY> <> $1 2643dnl separate optional requirements 2644R$* $| <$*> <VERIFY + $+> $: <$2> <VERIFY> <$3> $1 2645R$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> <> $1 2646dnl separate optional requirements 2647R$* $| <$*> <$={tls}:$- + $+>$* $: <$2> <$3:$4> <$5> $1 2648dnl some other value in access map: accept 2649dnl this also allows to override the default case (if used) 2650R$* $| $* $@ OK 2651# authentication required: give appropriate error 2652# other side did authenticate (via STARTTLS) 2653dnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> <[extensions]> ${verify} 2654dnl only verification required and it succeeded 2655R<$*><VERIFY> <> OK $@ OK 2656dnl verification required and it succeeded but extensions are given 2657dnl change it to <SMTP:ESC> <REQ:0> <extensions> 2658R<$*><VERIFY> <$+> OK $: <$1> <REQ:0> <$2> 2659dnl verification required + some level of encryption 2660R<$*><VERIFY:$-> <$*> OK $: <$1> <REQ:$2> <$3> 2661dnl just some level of encryption required 2662R<$*><ENCR:$-> <$*> $* $: <$1> <REQ:$2> <$3> 2663dnl workspace: 2664dnl 1. <SMTP:ESC> <VERIFY [:bits]> <[extensions]> {verify} (!= OK) 2665dnl 2. <SMTP:ESC> <REQ:bits> <[extensions]> 2666dnl verification required but ${verify} is not set (case 1.) 2667R<$-:$+><VERIFY $*> <$*> $#error $@ $2 $: $1 " authentication required" 2668R<$-:$+><VERIFY $*> <$*> FAIL $#error $@ $2 $: $1 " authentication failed" 2669R<$-:$+><VERIFY $*> <$*> NO $#error $@ $2 $: $1 " not authenticated" 2670R<$-:$+><VERIFY $*> <$*> NOT $#error $@ $2 $: $1 " no authentication requested" 2671R<$-:$+><VERIFY $*> <$*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 2672dnl some other value for ${verify} 2673R<$-:$+><VERIFY $*> <$*> $+ $#error $@ $2 $: $1 " authentication failure " $4 2674dnl some level of encryption required: get the maximum level (case 2.) 2675R<$*><REQ:$-> <$*> $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf} 2676dnl compare required bits with actual bits 2677R<$*><REQ:$-> <$*> $- $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $) 2678R<$-:$+><$-:$-> <$*> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 2679dnl strength requirements fulfilled 2680dnl TLS Additional Requirements Separator 2681dnl this should be something which does not appear in the extensions itself 2682dnl @ could be part of a CN, DN, etc... 2683dnl use < > ? those are encoded in CN, DN, ... 2684define(`_TLS_ARS_', `++')dnl 2685dnl workspace: 2686dnl <SMTP:ESC> <REQ:bits> <extensions> result-of-compare 2687R<$-:$+><$-:$-> <$*> $* $: <$1:$2 _TLS_ARS_ $5> 2688dnl workspace: <SMTP:ESC _TLS_ARS_ extensions> 2689dnl continue: check extensions 2690R<$-:$+ _TLS_ARS_ > $@ OK 2691dnl split extensions into own list 2692R<$-:$+ _TLS_ARS_ $+ > $: <$1:$2> <$3> 2693R<$-:$+> < $+ _TLS_ARS_ $+ > <$1:$2> <$3> <$4> 2694R<$-:$+> $+ $@ $>"TLS_req" $3 $| <$1:$2> 2695 2696###################################################################### 2697### TLS_req: check additional TLS requirements 2698### 2699### Parameters: [<list> <of> <req>] $| <$-:$+> 2700### $-: SMTP reply code 2701### $+: Enhanced Status Code 2702dnl further requirements for this ruleset: 2703dnl name of "other side" is stored is {TLS_name} (client/server_name) 2704dnl 2705dnl currently only CN[:common_name] is implemented 2706dnl right now this is only a logical AND 2707dnl i.e. all requirements must be true 2708dnl how about an OR? CN must be X or CN must be Y or .. 2709dnl use a macro to compute this as a trivial sequential 2710dnl operations (no precedences etc)? 2711###################################################################### 2712STLS_req 2713dnl no additional requirements: ok 2714R $| $+ $@ OK 2715dnl require CN: but no CN specified: use name of other side 2716R<CN> $* $| <$+> $: <CN:$&{TLS_Name}> $1 $| <$2> 2717dnl match, check rest 2718R<CN:$&{cn_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 2719dnl CN does not match 2720dnl 1 2 3 4 2721R<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1 2722dnl cert subject 2723R<CS:$&{cert_subject}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 2724dnl CS does not match 2725dnl 1 2 3 4 2726R<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1 2727dnl match, check rest 2728R<CI:$&{cert_issuer}> $* $| <$+> $@ $>"TLS_req" $1 $| <$2> 2729dnl CI does not match 2730dnl 1 2 3 4 2731R<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1 2732dnl return from recursive call 2733ROK $@ OK 2734 2735###################################################################### 2736### max: return the maximum of two values separated by : 2737### 2738### Parameters: [$-]:[$-] 2739###################################################################### 2740Smax 2741R: $: 0 2742R:$- $: $1 2743R$-: $: $1 2744R$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 2745RTRUE:$-:$- $: $2 2746R$-:$-:$- $: $2 2747dnl endif _ACCESS_TABLE_ 2748divert(0) 2749 2750###################################################################### 2751### RelayTLS: allow relaying based on TLS authentication 2752### 2753### Parameters: 2754### none 2755###################################################################### 2756SRelayTLS 2757# authenticated? 2758dnl we do not allow relaying for anyone who can present a cert 2759dnl signed by a "trusted" CA. For example, even if we put verisigns 2760dnl CA in CertPath so we can authenticate users, we do not allow 2761dnl them to abuse our server (they might be easier to get hold of, 2762dnl but anyway). 2763dnl so here is the trick: if the verification succeeded 2764dnl we look up the cert issuer in the access map 2765dnl (maybe after extracting a part with a regular expression) 2766dnl if this returns RELAY we relay without further questions 2767dnl if it returns SUBJECT we perform a similar check on the 2768dnl cert subject. 2769ifdef(`_ACCESS_TABLE_', `dnl 2770R$* $: <?> $&{verify} 2771R<?> OK $: OK authenticated: continue 2772R<?> $* $@ NO not authenticated 2773ifdef(`_CERT_REGEX_ISSUER_', `dnl 2774R$* $: $(CERTIssuer $&{cert_issuer} $)', 2775`R$* $: $&{cert_issuer}') 2776R$+ $: $(access CERTISSUER`'_TAG_DELIM_`'$1 $) 2777dnl use $# to stop further checks (delay_check) 2778RRELAY $# RELAY 2779ifdef(`_CERT_REGEX_SUBJECT_', `dnl 2780RSUBJECT $: <@> $(CERTSubject $&{cert_subject} $)', 2781`RSUBJECT $: <@> $&{cert_subject}') 2782R<@> $+ $: <@> $(access CERTSUBJECT`'_TAG_DELIM_`'$1 $) 2783R<@> RELAY $# RELAY 2784R$* $: NO', `dnl') 2785 2786###################################################################### 2787### authinfo: lookup authinfo in the access map 2788### 2789### Parameters: 2790### $1: {server_name} 2791### $2: {server_addr} 2792dnl both are currently ignored 2793dnl if it should be done via another map, we either need to restrict 2794dnl functionality (it calls D and A) or copy those rulesets (or add another 2795dnl parameter which I want to avoid, it's quite complex already) 2796###################################################################### 2797dnl omit this ruleset if neither is defined? 2798dnl it causes DefaultAuthInfo to be ignored 2799dnl (which may be considered a good thing). 2800Sauthinfo 2801ifdef(`_AUTHINFO_TABLE_', `dnl 2802R$* $: <$(authinfo AuthInfo:$&{server_name} $: ? $)> 2803R<?> $: <$(authinfo AuthInfo:$&{server_addr} $: ? $)> 2804R<?> $: <$(authinfo AuthInfo: $: ? $)> 2805R<?> $@ no no authinfo available 2806R<$*> $# $1 2807dnl', `dnl 2808ifdef(`_ACCESS_TABLE_', `dnl 2809R$* $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <> 2810R$* $| <?>$* $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <> 2811R$* $| <?>$* $: $1 $| <$(access AuthInfo`'_TAG_DELIM_ $: ? $)> <> 2812R$* $| <?>$* $@ no no authinfo available 2813R$* $| <$*> <> $# $2 2814dnl', `dnl')') 2815 2816undivert(9)dnl LOCAL_RULESETS 2817# 2818###################################################################### 2819###################################################################### 2820##### 2821`##### MAIL FILTER DEFINITIONS' 2822##### 2823###################################################################### 2824###################################################################### 2825_MAIL_FILTERS_ 2826# 2827###################################################################### 2828###################################################################### 2829##### 2830`##### MAILER DEFINITIONS' 2831##### 2832###################################################################### 2833###################################################################### 2834undivert(7)dnl MAILER_DEFINITIONS 2835 2836