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