proto.m4 revision 71345
138032Speterdivert(-1) 238032Speter# 364562Sgshapiro# Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 464562Sgshapiro# All rights reserved. 538032Speter# Copyright (c) 1983, 1995 Eric P. Allman. All rights reserved. 638032Speter# Copyright (c) 1988, 1993 738032Speter# The Regents of the University of California. All rights reserved. 838032Speter# 938032Speter# By using this file, you agree to the terms and conditions set 1038032Speter# forth in the LICENSE file which can be found at the top level of 1138032Speter# the sendmail distribution. 1238032Speter# 1338032Speter# 1438032Speterdivert(0) 1538032Speter 1671345SgshapiroVERSIONID(`$Id: proto.m4,v 8.446.2.5.2.38 2000/12/28 03:37:28 ca Exp $') 1738032Speter 1838032SpeterMAILER(local)dnl 1938032Speter 2064562Sgshapiro# level CF_LEVEL config file format 2164562SgshapiroV`'CF_LEVEL/ifdef(`VENDOR_NAME', `VENDOR_NAME', `Berkeley') 2238032Speterdivert(-1) 2338032Speter 2438032Speter# do some sanity checking 2538032Speterifdef(`__OSTYPE__',, 2664562Sgshapiro `errprint(`*** ERROR: No system type defined (use OSTYPE macro) 2764562Sgshapiro')') 2838032Speter 2938032Speter# pick our default mailers 3038032Speterifdef(`confSMTP_MAILER',, `define(`confSMTP_MAILER', `esmtp')') 3138032Speterifdef(`confLOCAL_MAILER',, `define(`confLOCAL_MAILER', `local')') 3238032Speterifdef(`confRELAY_MAILER',, 3338032Speter `define(`confRELAY_MAILER', 3438032Speter `ifdef(`_MAILER_smtp_', `relay', 3538032Speter `ifdef(`_MAILER_uucp', `uucp-new', `unknown')')')') 3638032Speterifdef(`confUUCP_MAILER',, `define(`confUUCP_MAILER', `uucp-old')') 3738032Speterdefine(`_SMTP_', `confSMTP_MAILER')dnl for readability only 3838032Speterdefine(`_LOCAL_', `confLOCAL_MAILER')dnl for readability only 3938032Speterdefine(`_RELAY_', `confRELAY_MAILER')dnl for readability only 4038032Speterdefine(`_UUCP_', `confUUCP_MAILER')dnl for readability only 4138032Speter 4238032Speter# back compatibility with old config files 4338032Speterifdef(`confDEF_GROUP_ID', 4464562Sgshapiro`errprint(`*** confDEF_GROUP_ID is obsolete. 4564562Sgshapiro Use confDEF_USER_ID with a colon in the value instead. 4664562Sgshapiro')') 4738032Speterifdef(`confREAD_TIMEOUT', 4864562Sgshapiro`errprint(`*** confREAD_TIMEOUT is obsolete. 4964562Sgshapiro Use individual confTO_<timeout> parameters instead. 5064562Sgshapiro')') 5138032Speterifdef(`confMESSAGE_TIMEOUT', 5238032Speter `define(`_ARG_', index(confMESSAGE_TIMEOUT, /)) 5338032Speter ifelse(_ARG_, -1, 5438032Speter `define(`confTO_QUEUERETURN', confMESSAGE_TIMEOUT)', 5538032Speter `define(`confTO_QUEUERETURN', 5638032Speter substr(confMESSAGE_TIMEOUT, 0, _ARG_)) 5738032Speter define(`confTO_QUEUEWARN', 5838032Speter substr(confMESSAGE_TIMEOUT, eval(_ARG_+1)))')') 5938032Speterifdef(`confMIN_FREE_BLOCKS', `ifelse(index(confMIN_FREE_BLOCKS, /), -1,, 6064562Sgshapiro`errprint(`*** compound confMIN_FREE_BLOCKS is obsolete. 6164562Sgshapiro Use confMAX_MESSAGE_SIZE for the second part of the value. 6264562Sgshapiro')')') 6338032Speter 6464562Sgshapiro 6564562Sgshapiro# Sanity check on ldap_routing feature 6664562Sgshapiro# If the user doesn't specify a new map, they better have given as a 6764562Sgshapiro# default LDAP specification which has the LDAP base (and most likely the host) 6864562Sgshapiroifdef(`confLDAP_DEFAULT_SPEC',, `ifdef(`_LDAP_ROUTING_WARN_', `errprint(` 6964562SgshapiroWARNING: Using default FEATURE(ldap_routing) map definition(s) 7064562Sgshapirowithout setting confLDAP_DEFAULT_SPEC option. 7164562Sgshapiro')')')dnl 7264562Sgshapiro 7338032Speter# clean option definitions below.... 7464562Sgshapirodefine(`_OPTION', `ifdef(`$2', `O $1`'ifelse(defn(`$2'), `',, `=$2')', `#O $1`'ifelse(`$3', `',,`=$3')')')dnl 7538032Speter 7664562Sgshapirodnl required to "rename" the check_* rulesets... 7764562Sgshapirodefine(`_U_',ifdef(`_DELAY_CHECKS_',`',`_')) 7864562Sgshapirodnl default relaying denied message 7964562Sgshapiroifdef(`confRELAY_MSG', `', `define(`confRELAY_MSG', `"550 Relaying denied"')') 8038032Speterdivert(0)dnl 8138032Speter 8264562Sgshapiro# override file safeties - setting this option compromises system security, 8364562Sgshapiro# addressing the actual file configuration problem is preferred 8464562Sgshapiro# need to set this before any file actions are encountered in the cf file 8564562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe') 8638032Speter 8764562Sgshapiro# default LDAP map specification 8864562Sgshapiro# need to set this now before any LDAP maps are defined 8964562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost') 9064562Sgshapiro 9138032Speter################## 9238032Speter# local info # 9338032Speter################## 9438032Speter 9538032SpeterCwlocalhost 9638032Speterifdef(`USE_CW_FILE', 9738032Speter`# file containing names of hosts for which we receive email 9838032SpeterFw`'confCW_FILE', 9938032Speter `dnl') 10038032Speter 10138032Speter# my official domain name 10238032Speter# ... `define' this only if sendmail cannot automatically determine your domain 10338032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM') 10438032Speter 10538032SpeterCP. 10638032Speter 10738032Speterifdef(`UUCP_RELAY', 10838032Speter`# UUCP relay host 10938032SpeterDY`'UUCP_RELAY 11038032SpeterCPUUCP 11138032Speter 11238032Speter')dnl 11338032Speterifdef(`BITNET_RELAY', 11438032Speter`# BITNET relay host 11538032SpeterDB`'BITNET_RELAY 11638032SpeterCPBITNET 11738032Speter 11838032Speter')dnl 11938032Speterifdef(`DECNET_RELAY', 12038032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl 12138032Speter# DECnet relay host 12238032SpeterDC`'DECNET_RELAY 12338032SpeterCPDECNET 12438032Speter 12538032Speter')dnl 12638032Speterifdef(`FAX_RELAY', 12738032Speter`# FAX relay host 12838032SpeterDF`'FAX_RELAY 12938032SpeterCPFAX 13038032Speter 13138032Speter')dnl 13238032Speter# "Smart" relay host (may be null) 13338032SpeterDS`'ifdef(`SMART_HOST', SMART_HOST) 13438032Speter 13538032Speterifdef(`LUSER_RELAY', `dnl 13638032Speter# place to which unknown users should be forwarded 13738032SpeterKuser user -m -a<> 13838032SpeterDL`'LUSER_RELAY', 13938032Speter`dnl') 14038032Speter 14138032Speter# operators that cannot be in local usernames (i.e., network indicators) 14238032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!') 14338032Speter 14438032Speter# a class with just dot (for identifying canonical names) 14538032SpeterC.. 14638032Speter 14738032Speter# a class with just a left bracket (for identifying domain literals) 14838032SpeterC[[ 14938032Speter 15064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 15164562Sgshapiro# access_db acceptance class 15264562SgshapiroC{Accept}OK RELAY 15364562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 15464562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl 15564562Sgshapiro# possible access_db RHS for spam friends/haters 15664562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')', 15738032Speter`dnl') 15838032Speter 15938032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl 16038032Speter# Resolve map (to check if a host exists in check_mail) 16138032SpeterKresolve host -a<OK> -T<TEMP>') 16238032Speter 16366494Sgshapiroifdef(`_FFR_5_', `# macro storage map 16466494SgshapiroKmacro macro') 16566494Sgshapiro 16638032Speterifdef(`confCR_FILE', `dnl 16766494Sgshapiro# Hosts for which relaying is permitted ($=R) 16838032SpeterFR`'confCR_FILE', 16938032Speter`dnl') 17038032Speter 17164562Sgshapirodefine(`TLS_SRV_TAG', `TLS_Srv')dnl 17264562Sgshapirodefine(`TLS_CLT_TAG', `TLS_Clt')dnl 17364562Sgshapirodefine(`TLS_TRY_TAG', `Try_TLS')dnl 17464562Sgshapirodefine(`TLS_OFF_TAG', `Offer_TLS')dnl 17564562Sgshapirodnl this may be useful in other contexts too 17664562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map 17764562Sgshapirodefine(`_ARITH_MAP_', `1')dnl 17864562SgshapiroKarith arith') 17964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 18064562Sgshapiro# possible values for tls_connect in access map 18164562SgshapiroC{tls}VERIFY ENCR', `dnl') 18264562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 18364562Sgshapiro# extract relevant part from cert issuer 18464562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl') 18564562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 18664562Sgshapiro# extract relevant part from cert subject 18764562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl') 18864562Sgshapiro 18938032Speter# who I send unqualified names to (null means deliver locally) 19038032SpeterDR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY) 19138032Speter 19238032Speter# who gets all local email traffic ($R has precedence for unqualified names) 19338032SpeterDH`'ifdef(`MAIL_HUB', MAIL_HUB) 19438032Speter 19538032Speter# dequoting map 19638032SpeterKdequote dequote 19738032Speter 19838032Speterdivert(0)dnl # end of nullclient diversion 19938032Speter# class E: names that should be exposed as from this host, even if we masquerade 20064562Sgshapiro# class L: names that should be delivered locally, even if we have a relay 20138032Speter# class M: domains that should be converted to $M 20264562Sgshapiro# class N: domains that should not be converted to $M 20338032Speter#CL root 20438032Speterundivert(5)dnl 20564562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl') 20638032Speter 20738032Speter# who I masquerade as (null for no masquerading) (see also $=M) 20838032SpeterDM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME) 20938032Speter 21038032Speter# my name for error messages 21138032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON') 21238032Speter 21364562Sgshapiroundivert(6)dnl LOCAL_CONFIG 21438032Speterinclude(_CF_DIR_`m4/version.m4') 21538032Speter 21638032Speter############### 21738032Speter# Options # 21838032Speter############### 21938032Speter 22038032Speter# strip message body to 7 bits on input? 22164562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False') 22238032Speter 22338032Speter# 8-bit data handling 22464562Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `adaptive') 22538032Speter 22638032Speter# wait for alias file rebuild (default units: minutes) 22764562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m') 22838032Speter 22938032Speter# location of alias file 23064562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases') 23164562Sgshapiro 23238032Speter# minimum number of free blocks on filesystem 23364562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100') 23438032Speter 23538032Speter# maximum message size 23664562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000') 23738032Speter 23838032Speter# substitution for space (blank) characters 23964562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_') 24038032Speter 24138032Speter# avoid connecting to "expensive" mailers on initial submission? 24264562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False') 24338032Speter 24438032Speter# checkpoint queue runs after every N successful deliveries 24564562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10') 24638032Speter 24738032Speter# default delivery mode 24864562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background') 24938032Speter 25038032Speter# automatically rebuild the alias database? 25164562Sgshapiro# NOTE: There is a potential for a denial of service attack if this is set. 25264562Sgshapiro# This option is deprecated and will be removed from a future version. 25364562Sgshapiro_OPTION(AutoRebuildAliases, `confAUTO_REBUILD', `False') 25438032Speter 25538032Speter# error message header/file 25664562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header') 25738032Speter 25838032Speter# error mode 25964562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print') 26038032Speter 26138032Speter# save Unix-style "From_" lines at top of header? 26264562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False') 26338032Speter 26438032Speter# temporary file mode 26564562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600') 26638032Speter 26738032Speter# match recipients against GECOS field? 26864562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False') 26938032Speter 27038032Speter# maximum hop count 27164562Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `17') 27238032Speter 27338032Speter# location of help file 27464562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile') 27538032Speter 27638032Speter# ignore dots as terminators in incoming messages? 27764562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False') 27838032Speter 27938032Speter# name resolver options 28064562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY') 28138032Speter 28238032Speter# deliver MIME-encapsulated error messages? 28364562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True') 28438032Speter 28538032Speter# Forward file search path 28664562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward') 28738032Speter 28838032Speter# open connection cache size 28964562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2') 29038032Speter 29138032Speter# open connection cache timeout 29264562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m') 29338032Speter 29438032Speter# persistent host status directory 29564562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat') 29638032Speter 29738032Speter# single thread deliveries (requires HostStatusDirectory)? 29864562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False') 29938032Speter 30038032Speter# use Errors-To: header? 30164562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False') 30238032Speter 30338032Speter# log level 30464562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10') 30538032Speter 30638032Speter# send to me too, even in an alias expansion? 30764562Sgshapiro_OPTION(MeToo, `confME_TOO', `True') 30838032Speter 30938032Speter# verify RHS in newaliases? 31064562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False') 31138032Speter 31238032Speter# default messages to old style headers if no special punctuation? 31364562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False') 31438032Speter 31538032Speter# SMTP daemon options 31664562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl', 31764562Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. See cf/README for more information. 31864562Sgshapiro)'dnl 31964562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')') 32066494Sgshapiroifelse(defn(`_DPO_'), `', 32166494Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-IPv4, Family=inet 32266494SgshapiroO DaemonPortOptions=Name=MTA-IPv6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_') 32364562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E') 32438032Speter 32564562Sgshapiro# SMTP client options 32664562Sgshapiro_OPTION(ClientPortOptions, `confCLIENT_OPTIONS', `Address=0.0.0.0') 32764562Sgshapiro 32838032Speter# privacy flags 32964562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings') 33038032Speter 33138032Speter# who (if anyone) should get extra copies of error messages 33264562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster') 33338032Speter 33438032Speter# slope of queue-only function 33564562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000') 33638032Speter 33738032Speter# queue directory 33864562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue') 33938032Speter 34038032Speter# timeouts (many of these) 34164562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m') 34264562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m') 34364562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m') 34464562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m') 34564562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m') 34664562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h') 34764562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m') 34864562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h') 34964562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h') 35064562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m') 35164562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m') 35264562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m') 35364562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h') 35464562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s') 35564562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s') 35664562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m') 35764562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d') 35864562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d') 35964562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d') 36064562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d') 36164562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h') 36264562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h') 36364562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h') 36464562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h') 36564562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m') 36664562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s') 36764562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s') 36864562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s') 36964562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4') 37064562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4') 37164562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4') 37238032Speter 37338032Speter# should we not prune routes in route-addr syntax addresses? 37464562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False') 37538032Speter 37638032Speter# queue up everything before forking? 37764562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True') 37838032Speter 37938032Speter# status file 38064562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics') 38138032Speter 38238032Speter# time zone handling: 38338032Speter# if undefined, use system default 38438032Speter# if defined but null, use TZ envariable passed in 38538032Speter# if defined and non-null, use that info 38638032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=', 38738032Speter confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=', 38838032Speter `O TimeZoneSpec=confTIME_ZONE') 38938032Speter 39038032Speter# default UID (can be username or userid:groupid) 39164562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull') 39238032Speter 39338032Speter# list of locations of user database file (null means no lookup) 39464562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb') 39538032Speter 39638032Speter# fallback MX host 39764562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net') 39838032Speter 39938032Speter# if we are the best MX host for a site, try it directly instead of config err 40064562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False') 40138032Speter 40238032Speter# load average at which we just queue messages 40364562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8') 40438032Speter 40538032Speter# load average at which we refuse connections 40664562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12') 40738032Speter 40838032Speter# maximum number of children we allow at one time 40964562Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12') 41038032Speter 41138032Speter# maximum number of new connections per second 41271345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0') 41338032Speter 41438032Speter# work recipient factor 41564562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') 41638032Speter 41738032Speter# deliver each queued job in a separate process? 41864562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False') 41938032Speter 42038032Speter# work class factor 42164562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800') 42238032Speter 42338032Speter# work time factor 42464562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000') 42538032Speter 42638032Speter# shall we sort the queue by hostname first? 42764562Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority') 42838032Speter 42938032Speter# minimum time in queue before retry 43064562Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m') 43138032Speter 43238032Speter# default character set 43364562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1') 43438032Speter 43538032Speter# service switch file (ignored on Solaris, Ultrix, OSF/1, others) 43664562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch') 43738032Speter 43838032Speter# hosts file (normally /etc/hosts) 43964562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts') 44038032Speter 44138032Speter# dialup line delay on connection failure 44264562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s') 44338032Speter 44438032Speter# action to take if there are no recipients in the message 44564562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed') 44638032Speter 44738032Speter# chrooted environment for writing to files 44864562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch') 44938032Speter 45038032Speter# are colons OK in addresses? 45164562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True') 45238032Speter 45338032Speter# how many jobs can you process in the queue? 45464562Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000') 45538032Speter 45638032Speter# shall I avoid expanding CNAMEs (violates protocols)? 45764562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False') 45838032Speter 45938032Speter# SMTP initial login message (old $e macro) 46064562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b') 46138032Speter 46238032Speter# UNIX initial From header format (old $l macro) 46364562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d') 46438032Speter 46538032Speter# From: lines that have embedded newlines are unwrapped onto one line 46664562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False') 46738032Speter 46838032Speter# Allow HELO SMTP command that does not `include' a host name 46964562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False') 47038032Speter 47138032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic) 47264562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.') 47338032Speter 47438032Speter# delimiter (operator) characters (old $o macro) 47564562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]') 47638032Speter 47738032Speter# shall I avoid calling initgroups(3) because of high NIS costs? 47864562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False') 47938032Speter 48038032Speter# are group-writable `:include:' and .forward files (un)trustworthy? 48164562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True') 48238032Speter 48338032Speter# where do errors that occur when sending errors get sent? 48464562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster') 48538032Speter 48664562Sgshapiro# where to save bounces if all else fails 48764562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter') 48864562Sgshapiro 48938032Speter# what user id do we assume for the majority of the processing? 49064562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail') 49138032Speter 49238032Speter# maximum number of recipients per SMTP envelope 49364562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100') 49438032Speter 49538032Speter# shall we get local names from our installed interfaces? 49664562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 49738032Speter 49864562Sgshapiro# Return-Receipt-To: header implies DSN request 49964562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 50064562Sgshapiro 50164562Sgshapiro# override connection address (for testing) 50264562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 50364562Sgshapiro 50464562Sgshapiro# Trusted user for file ownership and starting the daemon 50564562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root') 50664562Sgshapiro 50764562Sgshapiro# Control socket for daemon management 50864562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 50964562Sgshapiro 51064562Sgshapiro# Maximum MIME header length to protect MUAs 51164562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0') 51264562Sgshapiro 51364562Sgshapiro# Maximum length of the sum of all headers 51464562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768') 51564562Sgshapiro 51664562Sgshapiro# Maximum depth of alias recursion 51764562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10') 51864562Sgshapiro 51964562Sgshapiro# location of pid file 52064562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid') 52164562Sgshapiro 52264562Sgshapiro# Prefix string for the process title shown on 'ps' listings 52364562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix') 52464562Sgshapiro 52564562Sgshapiro# Data file (df) memory-buffer file maximum size 52664562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096') 52764562Sgshapiro 52864562Sgshapiro# Transcript file (xf) memory-buffer file maximum size 52964562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096') 53064562Sgshapiro 53164562Sgshapiro# list of authentication mechanisms 53264562Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5') 53364562Sgshapiro 53464562Sgshapiro# default authentication information for outgoing connections 53564562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info') 53664562Sgshapiro 53764562Sgshapiro# SMTP AUTH flags 53864562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `') 53964562Sgshapiro 54064562Sgshapiroifdef(`_FFR_MILTER', ` 54164562Sgshapiro# Input mail filters 54264562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 54364562Sgshapiro 54464562Sgshapiro# Milter options 54564562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 54664562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') 54764562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') 54864562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')') 54964562Sgshapiro 55064562Sgshapiro# CA directory 55164562Sgshapiro_OPTION(CACERTPath, `confCACERT_PATH', `') 55264562Sgshapiro# CA file 55364562Sgshapiro_OPTION(CACERTFile, `confCACERT', `') 55464562Sgshapiro# Server Cert 55564562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `') 55664562Sgshapiro# Server private key 55764562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `') 55864562Sgshapiro# Client Cert 55964562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `') 56064562Sgshapiro# Client private key 56164562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 56264562Sgshapiro# DHParameters (only required if DSA/DH is used) 56364562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `') 56464562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL) 56564562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `') 56664562Sgshapiro 56764562Sgshapiroifdef(`confQUEUE_FILE_MODE', 56864562Sgshapiro`# queue file mode (qf files) 56964562SgshapiroO QueueFileMode=confQUEUE_FILE_MODE 57042575Speter') 57142575Speter 57238032Speter########################### 57338032Speter# Message precedences # 57438032Speter########################### 57538032Speter 57638032SpeterPfirst-class=0 57738032SpeterPspecial-delivery=100 57838032SpeterPlist=-30 57938032SpeterPbulk=-60 58038032SpeterPjunk=-100 58138032Speter 58238032Speter##################### 58338032Speter# Trusted users # 58438032Speter##################### 58538032Speter 58638032Speter# this is equivalent to setting class "t" 58764562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 58838032SpeterTroot 58938032SpeterTdaemon 59038032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp') 59138032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 59238032Speter 59338032Speter######################### 59438032Speter# Format of headers # 59538032Speter######################### 59638032Speter 59738032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl 59838032SpeterH?P?Return-Path: <$g> 59938032SpeterHReceived: confRECEIVED_HEADER 60038032SpeterH?D?Resent-Date: $a 60138032SpeterH?D?Date: $a 60238032SpeterH?F?Resent-From: confFROM_HEADER 60338032SpeterH?F?From: confFROM_HEADER 60438032SpeterH?x?Full-Name: $x 60538032Speter# HPosted-Date: $a 60638032Speter# H?l?Received-Date: $b 60738032SpeterH?M?Resent-Message-Id: <$t.$i@$j> 60838032SpeterH?M?Message-Id: <$t.$i@$j> 60964562Sgshapiro 61038032Speter# 61138032Speter###################################################################### 61238032Speter###################################################################### 61338032Speter##### 61438032Speter##### REWRITING RULES 61538032Speter##### 61638032Speter###################################################################### 61738032Speter###################################################################### 61838032Speter 61938032Speter############################################ 62038032Speter### Ruleset 3 -- Name Canonicalization ### 62138032Speter############################################ 62264562SgshapiroScanonify=3 62338032Speter 62438032Speter# handle null input (translate to <@> special case) 62538032SpeterR$@ $@ <@> 62638032Speter 62738032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon 62838032SpeterR$* $: $1 <@> mark addresses 62938032SpeterR$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> 63038032SpeterR@ $* <@> $: @ $1 unmark @host:... 63138032SpeterR$* :: $* <@> $: $1 :: $2 unmark node::addr 63238032SpeterR:`include': $* <@> $: :`include': $1 unmark :`include':... 63364562SgshapiroR$* [ IPv6 $- ] <@> $: $1 [ IPv6 $2 ] unmark IPv6 addr 63438032SpeterR$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon 63538032SpeterR$* : $* <@> $: $2 strip colon if marked 63638032SpeterR$* <@> $: $1 unmark 63738032SpeterR$* ; $1 strip trailing semi 63871345SgshapiroR$* < $+ :; > $* $@ $2 :; <@> catch <list:;> 63938032SpeterR$* < $* ; > $1 < $2 > bogus bracketed semi 64038032Speter 64138032Speter# null input now results from list:; syntax 64238032SpeterR$@ $@ :; <@> 64338032Speter 64438032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item 64538032SpeterR$* $: < $1 > housekeeping <> 64638032SpeterR$+ < $* > < $2 > strip excess on left 64738032SpeterR< $* > $+ < $1 > strip excess on right 64838032SpeterR<> $@ < @ > MAIL FROM:<> case 64938032SpeterR< $+ > $: $1 remove housekeeping <> 65038032Speter 65164562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 65238032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 65338032SpeterR@ $+ , $+ @ $1 : $2 change all "," to ":" 65438032Speter 65538032Speter# localize and dispose of route-based addresses 65664562SgshapiroR@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 65764562Sgshapirodnl',`dnl 65864562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d> 65964562SgshapiroR@ $+ , $+ $2 66064562SgshapiroR@ $+ : $+ $2 66164562Sgshapirodnl') 66238032Speter 66338032Speter# find focus for list syntax 66464562SgshapiroR $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 66538032SpeterR $+ : $* ; $@ $1 : $2; list syntax 66638032Speter 66738032Speter# find focus for @ syntax addresses 66838032SpeterR$+ @ $+ $: $1 < @ $2 > focus on domain 66938032SpeterR$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 67064562SgshapiroR$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 67138032Speter 67238032Speter# do some sanity checking 67338032SpeterR$* < @ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 67438032Speter 67538032Speterifdef(`_NO_UUCP_', `dnl', 67638032Speter`# convert old-style addresses to a domain-based address 67764562SgshapiroR$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 67864562SgshapiroR$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 67964562SgshapiroR$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 68038032Speter') 68138032Speterifdef(`_USE_DECNET_SYNTAX_', 68238032Speter`# convert node::user addresses into a domain-based address 68364562SgshapiroR$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 68464562SgshapiroR$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 68538032Speter', 68638032Speter `dnl') 68738032Speter# if we have % signs, take the rightmost one 68838032SpeterR$* % $* $1 @ $2 First make them all @s. 68938032SpeterR$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 69064562SgshapiroR$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 69138032Speter 69238032Speter# else we must be a local name 69364562SgshapiroR$* $@ $>Canonify2 $1 69438032Speter 69538032Speter 69638032Speter################################################ 69738032Speter### Ruleset 96 -- bottom half of ruleset 3 ### 69838032Speter################################################ 69938032Speter 70064562SgshapiroSCanonify2=96 70138032Speter 70238032Speter# handle special cases for local names 70338032SpeterR$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 70438032SpeterR$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 70538032Speterifdef(`_NO_UUCP_', `dnl', 70638032Speter`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 70764562Sgshapiro 70864562Sgshapiro# check for IPv6 domain literal (save quoted form) 70964562SgshapiroR$* < @ [ IPv6 $- ] > $* $: $2 $| $1 < @@ [ $(dequote $2 $) ] > $3 mark IPv6 addr 71064562SgshapiroR$- $| $* < @@ $=w > $* $: $2 < @ $j . > $4 self-literal 71164562SgshapiroR$- $| $* < @@ [ $+ ] > $* $@ $2 < @ [ IPv6 $1 ] > $4 canon IP addr 71264562Sgshapiro 71364562Sgshapiro# check for IPv4 domain literal 71438032SpeterR$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [a.b.c.d] 71538032SpeterR$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 71638032SpeterR$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 71738032Speter 71864562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl 71938032Speter# look up domains in the domain table 72038032SpeterR$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 72138032Speter 72264562Sgshapiroundivert(2)dnl LOCAL_RULE_3 72338032Speter 72464562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl 72538032Speter# handle BITNET mapping 72638032SpeterR$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 72738032Speter 72864562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl 72938032Speter# handle UUCP mapping 73038032SpeterR$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 73138032Speter 73238032Speterifdef(`_NO_UUCP_', `dnl', 73338032Speter`ifdef(`UUCP_RELAY', 73438032Speter`# pass UUCP addresses straight through 73538032SpeterR$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 73638032Speter`# if really UUCP, handle it immediately 73738032Speterifdef(`_CLASS_U_', 73838032Speter`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 73938032Speterifdef(`_CLASS_V_', 74038032Speter`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 74138032Speterifdef(`_CLASS_W_', 74238032Speter`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 74338032Speterifdef(`_CLASS_X_', 74438032Speter`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 74538032Speterifdef(`_CLASS_Y_', 74638032Speter`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 74738032Speter 74838032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl 74938032Speter# try UUCP traffic as a local address 75038032SpeterR$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 75138032SpeterR$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 75238032Speter')') 75364562Sgshapiro# hostnames ending in class P are always canonical 75464562SgshapiroR$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 75564562Sgshapirodnl apply the next rule only for hostnames not in class P 75664562Sgshapirodnl this even works for phrases in class P since . is in class P 75764562Sgshapirodnl which daemon flags are set? 75864562SgshapiroR$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 75964562Sgshapirodnl the other rules in this section only apply if the hostname 76064562Sgshapirodnl does not end in class P hence no further checks are done here 76164562Sgshapirodnl if this ever changes make sure the lookups are "protected" again! 76264562Sgshapiroifdef(`_NO_CANONIFY_', `dnl 76364562Sgshapirodnl do not canonify unless: 76464562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection 76564562Sgshapirodnl with class P is non-empty) 76664562Sgshapirodnl or {daemon_flags} has c set 76764562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify} 76864562SgshapiroR$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 76964562Sgshapiro# pass to name server to make hostname canonical if requested 77064562SgshapiroR$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 77164562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 77264562SgshapiroR$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 77364562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work 77464562SgshapiroR$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 77564562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl 77664562Sgshapirodnl this should only apply to unqualified hostnames 77764562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar 77864562Sgshapirodnl then $- does not work. 77964562Sgshapiro# lookup unqualified hostnames 78064562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 78164562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless: 78264562Sgshapirodnl {daemon_flags} contains CC (do not canonify) 78371345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work 78471345Sgshapirodnl should we do this for every hostname: even unqualified? 78571345SgshapiroR$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 78664562SgshapiroR$* CC $* $| $* $: $3 78738032Speter# pass to name server to make hostname canonical 78864562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 78964562Sgshapirodnl remove {daemon_flags} for other cases 79064562SgshapiroR$* $| $* $: $2 79138032Speter 79238032Speter# local host aliases and pseudo-domains are always canonical 79338032SpeterR$* < @ $=w > $* $: $1 < @ $2 . > $3 79438032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 79538032Speter`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 79638032Speter`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 79764562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 79864562Sgshapirodnl virtual hosts are also canonical 79964562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 80064562Sgshapiro`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 80164562Sgshapiro`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 80264562Sgshapiro`dnl') 80364562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added 80464562Sgshapirodnl by one of the rules before 80538032SpeterR$* < @ $* . . > $* $1 < @ $2 . > $3 80638032Speter 80738032Speter 80838032Speter################################################## 80938032Speter### Ruleset 4 -- Final Output Post-rewriting ### 81038032Speter################################################## 81164562SgshapiroSfinal=4 81238032Speter 81371345SgshapiroR$+ :; <@> $@ $1 : handle <list:;> 81438032SpeterR$* <@> $@ handle <> and list:; 81538032Speter 81638032Speter# strip trailing dot off possibly canonical name 81738032SpeterR$* < @ $+ . > $* $1 < @ $2 > $3 81838032Speter 81964562Sgshapiro# eliminate internal code 82038032SpeterR$* < @ *LOCAL* > $* $1 < @ $j > $2 82138032Speter 82238032Speter# externalize local domain info 82338032SpeterR$* < $+ > $* $1 $2 $3 defocus 82438032SpeterR@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 82538032SpeterR@ $* $@ @ $1 ... and exit 82638032Speter 82738032Speterifdef(`_NO_UUCP_', `dnl', 82838032Speter`# UUCP must always be presented in old form 82938032SpeterR$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 83038032Speter 83138032Speterifdef(`_USE_DECNET_SYNTAX_', 83238032Speter`# put DECnet back in :: form 83338032SpeterR$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 83438032Speter `dnl') 83538032Speter# delete duplicate local names 83638032SpeterR$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 83738032Speter 83838032Speter 83938032Speter 84038032Speter############################################################## 84138032Speter### Ruleset 97 -- recanonicalize and call ruleset zero ### 84238032Speter### (used for recursive calls) ### 84338032Speter############################################################## 84438032Speter 84564562SgshapiroSRecurse=97 84664562SgshapiroR$* $: $>canonify $1 84764562SgshapiroR$* $@ $>parse $1 84838032Speter 84938032Speter 85038032Speter###################################### 85138032Speter### Ruleset 0 -- Parse Address ### 85238032Speter###################################### 85338032Speter 85464562SgshapiroSparse=0 85538032Speter 85638032SpeterR$* $: $>Parse0 $1 initial parsing 85738032SpeterR<@> $#_LOCAL_ $: <@> special case error msgs 85864562SgshapiroR$* $: $>ParseLocal $1 handle local hacks 85938032SpeterR$* $: $>Parse1 $1 final parsing 86038032Speter 86138032Speter# 86238032Speter# Parse0 -- do initial syntax checking and eliminate local addresses. 86338032Speter# This should either return with the (possibly modified) input 86438032Speter# or return with a #error mailer. It should not return with a 86538032Speter# #mailer other than the #error mailer. 86638032Speter# 86738032Speter 86838032SpeterSParse0 86938032SpeterR<@> $@ <@> special case error msgs 87066494SgshapiroR$* : $* ; <@> $#error $@ 5.1.3 $: "501 List:; syntax illegal for recipient addresses" 87164562SgshapiroR@ <@ $* > < @ $1 > catch "@@host" bogosity 87266494SgshapiroR<@ $+> $#error $@ 5.1.3 $: "501 User address required" 87338032SpeterR$* $: <> $1 87438032SpeterR<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 87566494SgshapiroR<> $* <$* : $* > $* $#error $@ 5.1.3 $: "501 Colon illegal in host name part" 87638032SpeterR<> $* $1 87766494SgshapiroR$* < @ . $* > $* $#error $@ 5.1.2 $: "501 Invalid host name" 87866494SgshapiroR$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "501 Invalid host name" 87964562Sgshapirodnl comma only allowed before @; this check is not complete 88066494SgshapiroR$* , $~O $* $#error $@ 5.1.2 $: "501 Invalid route address" 88138032Speter 88238032Speter# now delete the local info -- note $=O to find characters that cause forwarding 88364562SgshapiroR$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 88464562SgshapiroR< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 88538032SpeterR$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 88666494SgshapiroR< @ $+ > $#error $@ 5.1.3 $: "501 User address required" 88764562SgshapiroR$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 88838032SpeterR$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 88966494SgshapiroR< @ *LOCAL* > $#error $@ 5.1.3 $: "501 User address required" 89038032SpeterR$* $=O $* < @ *LOCAL* > 89164562Sgshapiro $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 89238032SpeterR$* < @ *LOCAL* > $: $1 89338032Speter 89438032Speter# 89538032Speter# Parse1 -- the bottom half of ruleset 0. 89638032Speter# 89738032Speter 89838032SpeterSParse1 89964562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 90064562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute} 90164562SgshapiroR$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2>', 90264562Sgshapiro`dnl') 90364562Sgshapiro 90438032Speterifdef(`_MAILER_smtp_', 90538032Speter`# handle numeric address spec 90664562Sgshapirodnl there is no check whether this is really an IP number 90764562SgshapiroR$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 90864562SgshapiroR$* < @ [ $+ ] > $* $1 < @ [ $2 ] : $S > $3 Add smart host to path 90964562SgshapiroR$* < @ [ IPv6 $- ] : > $* 91064562Sgshapiro $#_SMTP_ $@ [ $(dequote $2 $) ] $: $1 < @ [IPv6 $2 ] > $3 no smarthost: send 91164562SgshapiroR$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 91264562SgshapiroR$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 91364562SgshapiroR$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 91438032Speter `dnl') 91538032Speter 91664562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 91738032Speter# handle virtual users 91864562SgshapiroR$+ $: <!> $1 Mark for lookup 91964562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 92064562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 92164562Sgshapiro`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 92264562SgshapiroR<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 92338032SpeterR<@> $+ + $* < @ $* . > 92464562Sgshapiro $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 92538032SpeterR<@> $+ + $* < @ $* . > 92638032Speter $: < $(virtuser $1 @ $3 $@ $1 $: @ $) > $1 + $2 < @ $3 . > 92764562Sgshapirodnl try default entry: @domain 92864562Sgshapirodnl +*@domain 92964562SgshapiroR<@> $+ + $+ < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 93064562Sgshapirodnl @domain if +detail exists 93164562SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 93264562Sgshapirodnl without +detail (or no match) 93338032SpeterR<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 93438032SpeterR<@> $+ $: $1 93564562SgshapiroR<!> $+ $: $1 93664562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 93738032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 93864562SgshapiroR< $+ > $+ < @ $+ > $: $>Recurse $1', 93938032Speter`dnl') 94038032Speter 94138032Speter# short circuit local delivery so forwarded email works 94238032Speterifdef(`_MAILER_usenet_', `dnl 94364562SgshapiroR$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 94466494Sgshapiro 94566494Sgshapiro 94638032Speterifdef(`_STICKY_LOCAL_DOMAIN_', 94738032Speter`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 94864562SgshapiroR< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 94964562Sgshapirodnl $H empty (but @$=w.) 95038032SpeterR< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 95138032SpeterR< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 95264562Sgshapiro`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 95338032SpeterR$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 95438032Speter 95564562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 95638032Speter# not local -- try mailer table lookup 95738032SpeterR$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 95838032SpeterR< $+ . > $* $: < $1 > $2 strip trailing dot 95938032SpeterR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 96064562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 96164562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 96264562SgshapiroR< $+ > $* $: $>Mailertable <$1> $2 try domain', 96338032Speter`dnl') 96464562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)' 96538032Speter 96638032Speterifdef(`_NO_UUCP_', `dnl', 96738032Speter`# resolve remotely connected UUCP links (if any) 96838032Speterifdef(`_CLASS_V_', 96964562Sgshapiro`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 97038032Speter `dnl') 97138032Speterifdef(`_CLASS_W_', 97264562Sgshapiro`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 97338032Speter `dnl') 97438032Speterifdef(`_CLASS_X_', 97564562Sgshapiro`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 97638032Speter `dnl')') 97738032Speter 97838032Speter# resolve fake top level domains by forwarding to other hosts 97938032Speterifdef(`BITNET_RELAY', 98064562Sgshapiro`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 98138032Speter `dnl') 98238032Speterifdef(`DECNET_RELAY', 98364562Sgshapiro`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 98438032Speter `dnl') 98538032Speterifdef(`_MAILER_pop_', 98638032Speter`R$+ < @ POP. > $#pop $: $1 user@POP', 98738032Speter `dnl') 98838032Speterifdef(`_MAILER_fax_', 98938032Speter`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 99038032Speter`ifdef(`FAX_RELAY', 99164562Sgshapiro`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 99238032Speter `dnl')') 99338032Speter 99438032Speterifdef(`UUCP_RELAY', 99538032Speter`# forward non-local UUCP traffic to our UUCP relay 99664562SgshapiroR$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 99738032Speter`ifdef(`_MAILER_uucp_', 99838032Speter`# forward other UUCP traffic straight to UUCP 99938032SpeterR$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 100038032Speter `dnl')') 100138032Speterifdef(`_MAILER_usenet_', ` 100238032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup 100364562SgshapiroR$+ . USENET $#usenet $@ usenet $: $1', 100438032Speter `dnl') 100538032Speter 100638032Speterifdef(`_LOCAL_RULES_', 100738032Speter`# figure out what should stay in our local mail system 100838032Speterundivert(1)', `dnl') 100938032Speter 101038032Speter# pass names that still have a host to a smarthost (if defined) 101164562SgshapiroR$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 101238032Speter 101338032Speter# deal with other remote names 101438032Speterifdef(`_MAILER_smtp_', 101564562Sgshapiro`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 101666494Sgshapiro`R$* < @$* > $* $#error $@ 5.1.2 $: "501 Unrecognized host name " $2') 101738032Speter 101838032Speter# handle locally delivered names 101964562SgshapiroR$=L $#_LOCAL_ $: @ $1 special local names 102038032SpeterR$+ $#_LOCAL_ $: $1 regular local names 102138032Speter 102238032Speter########################################################################### 102338032Speter### Ruleset 5 -- special rewriting after aliases have been expanded ### 102438032Speter########################################################################### 102538032Speter 102664562SgshapiroSLocal_localaddr 102764562SgshapiroSlocaladdr=5 102864562SgshapiroR$+ $: $1 $| $>"Local_localaddr" $1 102964562SgshapiroR$+ $| $#$* $#$2 103064562SgshapiroR$+ $| $* $: $1 103138032Speter 103266494Sgshapiroifdef(`_FFR_5_', ` 103366494Sgshapiro# Preserve host in a macro 103466494SgshapiroR$+ $: $(macro {LocalAddrHost} $) $1 103566494SgshapiroR$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 103666494Sgshapiro 103766494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', ` 103838032Speter# deal with plussed users so aliases work nicely 103966494SgshapiroR$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 104066494SgshapiroR$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 104166494Sgshapiro') 104238032Speter# prepend an empty "forward host" on the front 104338032SpeterR$+ $: <> $1 104438032Speter 104538032Speterifdef(`LUSER_RELAY', `dnl 104638032Speter# send unrecognized local users to a relay host 104766494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', ` 104866494SgshapiroR< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 104966494SgshapiroR< > $+ $: < ? $L > < > $(user $1 $) look up user 105066494SgshapiroR< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 105166494SgshapiroR< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 105264562SgshapiroR< > $+ $: < $L > $(user $1 $) look up user 105366494SgshapiroR< $* > $+ <> $: < > $2 found; strip $L')', 105438032Speter`dnl') 105538032Speter 105638032Speter# see if we have a relay or a hub 105738032SpeterR< > $+ $: < $H > $1 try hub 105838032SpeterR< > $+ $: < $R > $1 try relay 105966494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', ` 106066494SgshapiroR< > $+ $@ $1', ` 106164562SgshapiroR< > $+ $: < > < $1 <> $&h > nope, restore +detail 106264562SgshapiroR< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 106364562SgshapiroR< > < $+ <> $* > $: < > < $1 > else discard 106438032SpeterR< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 106566494SgshapiroR< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 106638032SpeterR< > < $+ > $@ $1 no +detail 106743730SpeterR$+ $: $1 <> $&h add +detail back in 106843730SpeterR$+ <> + $* $: $1 + $2 check whether +detail 106966494SgshapiroR$+ <> $* $: $1 else discard') 107064562SgshapiroR< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 107164562SgshapiroR< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 107264562SgshapiroR< $- : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 107364562SgshapiroR< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 107438032Speter 107564562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 107638032Speter################################################################### 107738032Speter### Ruleset 90 -- try domain part of mailertable entry ### 107864562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 107938032Speter################################################################### 108038032Speter 108164562SgshapiroSMailertable=90 108264562Sgshapirodnl shift and check 108364562Sgshapirodnl %2 is not documented in cf/README 108438032SpeterR$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 108564562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 108664562SgshapiroR$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 108764562SgshapiroR$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 108864562Sgshapirodnl is $2 always empty? 108938032SpeterR$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 109064562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 109164562Sgshapirodnl return full address 109238032SpeterR< $* > $* $@ $2 no mailertable match', 109338032Speter`dnl') 109438032Speter 109538032Speter################################################################### 109638032Speter### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 109764562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest 109864562Sgshapirodnl <> address -> address 109964562Sgshapirodnl <error:d.s.n:text> -> error 110064562Sgshapirodnl <error:text> -> error 110164562Sgshapirodnl <mailer:user@host> lp<@domain>rest -> mailer host user 110264562Sgshapirodnl <mailer:host> address -> mailer host address 110364562Sgshapirodnl <localdomain> address -> address 110464562Sgshapirodnl <[IPv6 number]> address -> relay number address 110564562Sgshapirodnl <host> address -> relay host address 110638032Speter################################################################### 110738032Speter 110864562SgshapiroSMailerToTriple=95 110938032SpeterR< > $* $@ $1 strip off null relay 111064562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 111138032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 111238032SpeterR< local : $* > $* $>CanonLocal < $1 > $2 111338032SpeterR< $- : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 111438032SpeterR< $- : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 111538032SpeterR< $=w > $* $@ $2 delete local host 111664562SgshapiroR< [ IPv6 $+ ] > $* $#_RELAY_ $@ $(dequote $1 $) $: $2 use unqualified mailer 111738032SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 111838032Speter 111938032Speter################################################################### 112038032Speter### Ruleset CanonLocal -- canonify local: syntax ### 112164562Sgshapirodnl input: <user> address 112264562Sgshapirodnl <x> <@host> : rest -> Recurse rest 112364562Sgshapirodnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 112464562Sgshapirodnl <> user <@host> rest -> local user@host user 112564562Sgshapirodnl <> user -> local user user 112664562Sgshapirodnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 112764562Sgshapirodnl <user> lp <@host> rest -> local lp@host user 112864562Sgshapirodnl <user> lp -> local lp user 112938032Speter################################################################### 113038032Speter 113138032SpeterSCanonLocal 113243730Speter# strip local host from routed addresses 113364562SgshapiroR< $* > < @ $+ > : $+ $@ $>Recurse $3 113464562SgshapiroR< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 113543730Speter 113638032Speter# strip trailing dot from any host name that may appear 113738032SpeterR< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 113838032Speter 113938032Speter# handle local: syntax -- use old user, either with or without host 114038032SpeterR< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 114138032SpeterR< > $+ $#_LOCAL_ $@ $1 $: $1 114238032Speter 114338032Speter# handle local:user@host syntax -- ignore host part 114438032SpeterR< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 114538032Speter 114638032Speter# handle local:user syntax 114738032SpeterR< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 114838032SpeterR< $+ > $* $#_LOCAL_ $@ $2 $: $1 114938032Speter 115038032Speter################################################################### 115138032Speter### Ruleset 93 -- convert header names to masqueraded form ### 115238032Speter################################################################### 115338032Speter 115464562SgshapiroSMasqHdr=93 115538032Speter 115664562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 115738032Speter# handle generics database 115838032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_', 115964562Sgshapirodnl if generics should be applied add a @ as mark 116038032Speter`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 116138032Speter`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 116238032SpeterR$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 116364562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @ 116464562Sgshapirodnl ignore the first case for now 116564562Sgshapirodnl if it has the mark lookup full address 116664562SgshapiroR< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 116764562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain> 116864562Sgshapirodnl no match, try user+detail@domain 116964562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 117064562Sgshapiro $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 117164562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 117264562Sgshapiro $: < $(generics $1@$3 $: $) > $4 < @ $5 > 117364562Sgshapirodnl no match, remove mark 117464562SgshapiroR<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 117564562Sgshapirodnl no match, try @domain for exceptions 117664562SgshapiroR< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 117764562Sgshapirodnl workspace: ... or <match> user <@domain> 117864562Sgshapirodnl no match, try local part 117938032SpeterR< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 118064562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 118164562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 118264562SgshapiroR< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 118364562SgshapiroR< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 118438032SpeterR< > $* $: $1 not found', 118538032Speter`dnl') 118638032Speter 118764562Sgshapiro# do not masquerade anything in class N 118864562SgshapiroR$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 118964562Sgshapiro 119038032Speter# special case the users that should be exposed 119138032SpeterR$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 119238032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 119338032Speter`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 119438032Speter`R$=E < @ $=M . > $@ $1 < @ $2 . >') 119538032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 119638032Speter`R$=E < @ $=w . > $@ $1 < @ $2 . >') 119738032Speter 119838032Speter# handle domain-specific masquerading 119938032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 120038032Speter`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 120138032Speter`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 120238032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 120338032Speter`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 120438032SpeterR$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 120538032SpeterR$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 120638032SpeterR$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 120738032Speter 120838032Speter################################################################### 120938032Speter### Ruleset 94 -- convert envelope names to masqueraded form ### 121038032Speter################################################################### 121138032Speter 121264562SgshapiroSMasqEnv=94 121338032Speterifdef(`_MASQUERADE_ENVELOPE_', 121464562Sgshapiro`R$+ $@ $>MasqHdr $1', 121538032Speter`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 121638032Speter 121738032Speter################################################################### 121838032Speter### Ruleset 98 -- local part of ruleset zero (can be null) ### 121938032Speter################################################################### 122038032Speter 122164562SgshapiroSParseLocal=98 122264562Sgshapiroundivert(3)dnl LOCAL_RULE_0 122338032Speter 122464562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 122564562SgshapiroSLDAPExpand 122664562Sgshapiro# do the LDAP lookups 122764562SgshapiroR<$+><$+> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> 122864562Sgshapiro 122964562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost, 123064562Sgshapiro# return the new mailRoutingAddress 123164562SgshapiroR< $+ > < $=w > < $+ > < $+ > $@ $>Parse0 $>canonify $1 123264562SgshapiroR< $+ > < > < $+ > < $+ > $@ $>Parse0 $>canonify $1 123364562Sgshapiro 123464562Sgshapiro# if mailRoutingAddress and non-local mailHost, 123564562Sgshapiro# relay to mailHost with new mailRoutingAddress 123664562SgshapiroR< $+ > < $+ > < $+ > < $+ > $#_RELAY_ $@ $2 $: $>canonify $1 123764562Sgshapiro 123864562Sgshapiro# if no mailRoutingAddress and local mailHost, 123964562Sgshapiro# return original address 124064562SgshapiroR< > < $=w > <$+> <$+> $@ $2 124164562Sgshapiro 124264562Sgshapiro# if no mailRoutingAddress and non-local mailHost, 124364562Sgshapiro# relay to mailHost with original address 124464562SgshapiroR< > < $+ > <$+> <$+> $#_RELAY_ $@ $1 $: $2 124564562Sgshapiro 124664562Sgshapiro# if no mailRoutingAddress and no mailHost, 124764562Sgshapiro# try @domain 124864562SgshapiroR< > < > <$+> <$+ @ $+> $@ $>LDAPExpand <$1> <@ $3> 124964562Sgshapiro 125064562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt, 125164562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 125264562Sgshapiro# user does not exist 125364562SgshapiroR< > < > <$+> <@ $+> $#error $@ nouser $: "550 User unknown"', 125464562Sgshapiro`dnl 125564562Sgshapiro# return the original address 125664562SgshapiroR< > < > <$+> <@ $+> $@ $1')', 125764562Sgshapiro`dnl') 125864562Sgshapiro 125964562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 126064562Sgshapiro')') 126164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 126238032Speter###################################################################### 126338032Speter### LookUpDomain -- search for domain in access database 126438032Speter### 126538032Speter### Parameters: 126638032Speter### <$1> -- key (domain name) 126738032Speter### <$2> -- default (what to return if not found in db) 126864562Sgshapirodnl must not be empty 126938032Speter### <$3> -- passthru (additional data passed unchanged through) 127064562Sgshapiro### <$4> -- mark (must be <(!|+) single-token>) 127164562Sgshapiro### ! does lookup only with tag 127264562Sgshapiro### + does lookup with and without tag 127364562Sgshapirodnl returns: <default> <passthru> 127464562Sgshapirodnl <result> <passthru> 127538032Speter###################################################################### 127638032Speter 127738032SpeterSLookUpDomain 127864562Sgshapirodnl remove IPv6 mark and dequote address 127964562Sgshapirodnl it is a bit ugly because it is checked on each "iteration" 128064562SgshapiroR<[IPv6 $-]> <$+> <$*> <$*> $: <[$(dequote $1 $)]> <$2> <$3> <$4> 128164562Sgshapirodnl workspace <key> <default> <passthru> <mark> 128264562Sgshapirodnl lookup with tag (in front, no delimiter here) 128364562SgshapiroR<$*> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5> 128464562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 128564562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest 128664562SgshapiroR<?> <$+.$+> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4> <$5 $6>', `dnl') 128764562Sgshapirodnl lookup without tag? 128864562SgshapiroR<?> <$+> <$+> <$*> <+ $*> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4> 128964562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest 129064562SgshapiroR<?> <$+.$+> <$+> <$*> <+ $*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <$4> <+ $5>', `dnl') 129164562Sgshapirodnl lookup IP address (no check is done whether it is an IP number!) 129264562SgshapiroR<?> <[$+.$-]> <$+> <$*> <$*> $@ $>LookUpDomain <[$1]> <$3> <$4> <$5> 129364562Sgshapirodnl lookup IPv6 address 129471345SgshapiroR<?> <[$+::$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5> 129564562SgshapiroR<?> <[$+:$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5> 129664562Sgshapirodnl not found, but subdomain: try again 129764562SgshapiroR<?> <$+.$+> <$+> <$*> <$*> $@ $>LookUpDomain <$2> <$3> <$4> <$5> 129864562Sgshapirodnl not found, no subdomain: return default 129964562SgshapiroR<?> <$+> <$+> <$*> <$*> $@ <$2> <$3> 130064562Sgshapirodnl return result of lookup 130164562SgshapiroR<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4> 130238032Speter 130338032Speter###################################################################### 130438032Speter### LookUpAddress -- search for host address in access database 130538032Speter### 130638032Speter### Parameters: 130738032Speter### <$1> -- key (dot quadded host address) 130838032Speter### <$2> -- default (what to return if not found in db) 130964562Sgshapirodnl must not be empty 131038032Speter### <$3> -- passthru (additional data passed through) 131164562Sgshapiro### <$4> -- mark (must be <(!|+) single-token>) 131264562Sgshapiro### ! does lookup only with tag 131364562Sgshapiro### + does lookup with and without tag 131464562Sgshapirodnl returns: <default> <passthru> 131564562Sgshapirodnl <result> <passthru> 131638032Speter###################################################################### 131738032Speter 131838032SpeterSLookUpAddress 131964562Sgshapirodnl lookup with tag 132064562SgshapiroR<$+> <$+> <$*> <$- $+> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5> 132164562Sgshapirodnl lookup without tag 132264562SgshapiroR<?> <$+> <$+> <$*> <+ $+> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4> 132364562Sgshapirodnl no match; IPv6: remove last part 132471345SgshapiroR<?> <$+::$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 132564562SgshapiroR<?> <$+:$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 132664562Sgshapirodnl no match; IPv4: remove last part 132764562SgshapiroR<?> <$+.$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 132864562Sgshapirodnl no match: return default 132964562SgshapiroR<?> <$+> <$+> <$*> <$*> $@ <$2> <$3> 133064562Sgshapirodnl match: return result 133164562SgshapiroR<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4>', 133238032Speter`dnl') 133338032Speter 133438032Speter###################################################################### 133542575Speter### CanonAddr -- Convert an address into a standard form for 133642575Speter### relay checking. Route address syntax is 133742575Speter### crudely converted into a %-hack address. 133842575Speter### 133942575Speter### Parameters: 134042575Speter### $1 -- full recipient address 134142575Speter### 134242575Speter### Returns: 134342575Speter### parsed address, not in source route form 134464562Sgshapirodnl user%host%host<@domain> 134564562Sgshapirodnl host!user<@domain> 134642575Speter###################################################################### 134742575Speter 134842575SpeterSCanonAddr 134964562SgshapiroR$* $: $>Parse0 $>canonify $1 make domain canonical 135064562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 135142575SpeterR< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 135242575SpeterR$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 135342575SpeterR$* < @ $+ > : $* $3 $1 < @ $2 > 135464562Sgshapirodnl') 135542575Speter 135642575Speter###################################################################### 135738032Speter### ParseRecipient -- Strip off hosts in $=R as well as possibly 135838032Speter### $* $=m or the access database. 135938032Speter### Check user portion for host separators. 136038032Speter### 136138032Speter### Parameters: 136238032Speter### $1 -- full recipient address 136338032Speter### 136438032Speter### Returns: 136538032Speter### parsed, non-local-relaying address 136638032Speter###################################################################### 136738032Speter 136838032SpeterSParseRecipient 136964562Sgshapirodnl mark and canonify address 137042575SpeterR$* $: <?> $>CanonAddr $1 137164562Sgshapirodnl workspace: <?> localpart<@domain[.]> 137242575SpeterR<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 137364562Sgshapirodnl workspace: <?> localpart<@domain> 137442575SpeterR<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 137538032Speter 137638032Speter# if no $=O character, no host in the user portion, we are done 137742575SpeterR<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 137864562Sgshapirodnl no $=O in localpart: return 137942575SpeterR<?> $* $@ $1 138038032Speter 138164562Sgshapirodnl workspace: <?> localpart<@domain>, where localpart contains $=O 138264562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY> 138338032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 138438032Speter# if we relay, check username portion for user%host so host can be checked also 138542575SpeterR<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 138642575Speter 138742575Speterifdef(`_RELAY_MX_SERVED_', `dnl 138864562Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain? 138942575SpeterR<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 139042575SpeterR<MX> < : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 139164562Sgshapirodnl yes: mark it as <RELAY> 139242575SpeterR<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 139364562Sgshapirodnl no: put old <NO> mark back 139442575SpeterR<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 139542575Speter 139664562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 139764562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 139838032Speterifdef(`_RELAY_HOSTS_ONLY_', 139942575Speter`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 140064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 140164562SgshapiroR<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 140242575SpeterR<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 140342575Speter`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 140464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 140564562SgshapiroR<NO> $* < @ $+ > $: $>LookUpDomain <$2> <NO> <$1 < @ $2 >> <+To> 140642575SpeterR<$+> <$+> $: <$1> $2',`dnl')') 140738032Speter 140864562Sgshapiro 140942575SpeterR<RELAY> $* < @ $* > $@ $>ParseRecipient $1 141042575SpeterR<$-> $* $@ $2 141142575Speter 141264562Sgshapiro 141338032Speter###################################################################### 141438032Speter### check_relay -- check hostname/address on SMTP startup 141538032Speter###################################################################### 141638032Speter 141738032SpeterSLocal_check_relay 141864562SgshapiroScheck`'_U_`'relay 141938032SpeterR$* $: $1 $| $>"Local_check_relay" $1 142038032SpeterR$* $| $* $| $#$* $#$3 142138032SpeterR$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 142238032Speter 142338032SpeterSBasic_check_relay 142438032Speter# check for deferred delivery mode 142538032SpeterR$* $: < ${deliveryMode} > $1 142638032SpeterR< d > $* $@ deferred 142738032SpeterR< $* > $* $: $2 142838032Speter 142964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 143066494Sgshapirodnl workspace: {client_name} $| {client_addr} 143164562SgshapiroR$+ $| $+ $: $>LookUpDomain < $1 > <?> < $2 > <+Connect> 143266494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 143364562SgshapiroR<?> <$+> $: $>LookUpAddress < $1 > <?> < $1 > <+Connect> no: another lookup 143466494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 143564562SgshapiroR<?> < $+ > $: $1 found nothing 143666494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 143766494Sgshapirodnl or {client_addr} 143866494SgshapiroR<$={Accept}> < $* > $@ $1 return value of lookup 143964562SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 144038032SpeterR<DISCARD> $* $#discard $: discard 144164562Sgshapirodnl error tag 144266494SgshapiroR<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 144366494SgshapiroR<ERROR:$+> <$*> $#error $: $1 144464562Sgshapirodnl generic error from access map 144566494SgshapiroR<$+> <$*> $#error $: $1', `dnl') 144638032Speter 144764562Sgshapiroifdef(`_RBL_',`dnl 144864562Sgshapiro# DNS based IP address spam list 144938032SpeterR$* $: $&{client_addr} 145064562SgshapiroR::ffff:$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 145164562SgshapiroR$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 145264562SgshapiroR<?>OK $: OKSOFAR 145364562SgshapiroR<?>$+ $#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"', 145438032Speter`dnl') 145564562Sgshapiroundivert(8) 145638032Speter 145738032Speter###################################################################### 145838032Speter### check_mail -- check SMTP ``MAIL FROM:'' command argument 145938032Speter###################################################################### 146038032Speter 146138032SpeterSLocal_check_mail 146264562SgshapiroScheck`'_U_`'mail 146338032SpeterR$* $: $1 $| $>"Local_check_mail" $1 146438032SpeterR$* $| $#$* $#$2 146538032SpeterR$* $| $* $@ $>"Basic_check_mail" $1 146638032Speter 146738032SpeterSBasic_check_mail 146838032Speter# check for deferred delivery mode 146938032SpeterR$* $: < ${deliveryMode} > $1 147038032SpeterR< d > $* $@ deferred 147138032SpeterR< $* > $* $: $2 147238032Speter 147364562Sgshapiro# authenticated? 147464562Sgshapirodnl done first: we can require authentication for every mail transaction 147564562Sgshapirodnl workspace: address as given by MAIL FROM: (sender) 147664562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 147764562SgshapiroR$* $| $#$+ $#$2 147864562Sgshapirodnl undo damage: remove result of tls_client call 147964562SgshapiroR$* $| $* $: $1 148038032Speter 148164562Sgshapirodnl workspace: address as given by MAIL FROM: 148264562SgshapiroR<> $@ <OK> we MUST accept <> (RFC 1123) 148338032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 148464562Sgshapirodnl do some additional checks 148564562Sgshapirodnl no user@host 148664562Sgshapirodnl no user@localhost (if nonlocal sender) 148764562Sgshapirodnl this is a pretty simple canonification, it will not catch every case 148864562Sgshapirodnl just make sure the address has <> around it (which is required by 148964562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...) 149064562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will 149164562Sgshapirodnl not be modified by host lookups. 149264562SgshapiroR$+ $: <?> $1 149364562SgshapiroR<?><$+> $: <@> <$1> 149464562SgshapiroR<?>$+ $: <@> <$1> 149564562Sgshapirodnl workspace: <@> <address> 149664562Sgshapirodnl prepend daemon_flags 149764562SgshapiroR$* $: $&{daemon_flags} $| $1 149864562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 149964562Sgshapirodnl do not allow these at all or only from local systems? 150064562SgshapiroR$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 150164562Sgshapirodnl accept unqualified sender: change mark to avoid test 150264562SgshapiroR$* u $* $| <@> < $* > $: <?> < $3 > 150364562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 150464562Sgshapirodnl or: <? ${client_name} > <address> 150564562Sgshapirodnl or: <?> <address> 150664562Sgshapirodnl remove daemon_flags 150764562SgshapiroR$* $| $* $: $2 150838032Speter# handle case of @localhost on address 150964562SgshapiroR<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 151064562SgshapiroR<@> < $* @ [127.0.0.1] > 151164562Sgshapiro $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 151264562SgshapiroR<@> < $* @ localhost.$m > 151364562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.$m > 151438032Speterifdef(`_NO_UUCP_', `dnl', 151564562Sgshapiro`R<@> < $* @ localhost.UUCP > 151664562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 151764562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 151864562Sgshapirodnl or: <@> <address> 151964562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 152064562SgshapiroR<@> $* $: $1 no localhost as domain 152164562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 152264562Sgshapirodnl or: <address> 152364562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 152464562SgshapiroR<? $=w> $* $: $2 local client: ok 152566494SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "501 Real domain name required for sender address" 152664562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 152764562SgshapiroR<?> $* $: $1') 152864562Sgshapirodnl workspace: address (or <address>) 152964562SgshapiroR$* $: <?> $>CanonAddr $1 canonify sender address and mark it 153064562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 153164562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed 153264562SgshapiroR<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 153364562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 153464562SgshapiroR<?> $* < @ $* $=P > $: <OK> $1 < @ $2 $3 > 153564562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ? or OK 153664562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 153764562Sgshapiro`R<?> $* < @ $+ > $: <OK> $1 < @ $2 > ... unresolvable OK', 153864562Sgshapiro`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 153964562SgshapiroR<? $* <$->> $* < @ $+ > 154064562Sgshapiro $: <$2> $3 < @ $4 >') 154164562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ?, OK, PERM, TEMP 154264562Sgshapirodnl mark is ? iff the address is user (wo @domain) 154338032Speter 154464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 154564562Sgshapiro# check sender address: user@address, user@, address 154664562Sgshapirodnl should we remove +ext from user? 154764562Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, OK, PERM, TEMP 154864562SgshapiroR<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <H:$3> 154964562SgshapiroR<$+> $+ $: @<$1> <$2> $| <U:$2@> 155064562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 155164562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 155264562Sgshapirodnl will only return user<@domain when "reversing" the args 155364562SgshapiroR@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+From> $| <$3> <> 155464562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result> 155564562SgshapiroR<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 155664562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress> 155738032Speter# retransform for further use 155864562Sgshapirodnl required form: 155964562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress 156064562SgshapiroR<?> <$+> <$*> $: <$1> $2 no match 156164562SgshapiroR<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 156264562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress 156364562Sgshapirodnl mark is ? iff the address is user (wo @domain) 156438032Speter 156538032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 156638032Speter# handle case of no @domain on address 156764562Sgshapirodnl prepend daemon_flags 156864562SgshapiroR<?> $* $: $&{daemon_flags} $| <?> $1 156964562Sgshapirodnl accept unqualified sender: change mark to avoid test 157064562SgshapiroR$* u $* $| <?> $* $: <OK> $3 157164562Sgshapirodnl remove daemon_flags 157264562SgshapiroR$* $| $* $: $2 157338032SpeterR<?> $* $: < ? $&{client_name} > $1 157438032SpeterR<?> $* $@ <OK> ...local unqualed ok 157566494SgshapiroR<? $+> $* $#error $@ 5.5.4 $: "501 Domain name required for sender address " $&f 157638032Speter ...remote is not') 157738032Speter# check results 157864562SgshapiroR<?> $* $: @ $1 mark address: nothing known about it 157938032SpeterR<OK> $* $@ <OK> 158064562SgshapiroR<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 158164562SgshapiroR<PERM> $* $#error $@ 5.1.8 $: "501 Domain of sender address " $&f " does not exist" 158264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 158364562SgshapiroR<$={Accept}> $* $# $1 158438032SpeterR<DISCARD> $* $#discard $: discard 158564562SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 158664562Sgshapirodnl error tag 158764562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 158864562SgshapiroR<ERROR:$+> $* $#error $: $1 158964562Sgshapirodnl generic error from access map 159064562SgshapiroR<$+> $* $#error $: $1 error from access db', 159138032Speter`dnl') 159238032Speter 159338032Speter###################################################################### 159438032Speter### check_rcpt -- check SMTP ``RCPT TO:'' command argument 159538032Speter###################################################################### 159638032Speter 159738032SpeterSLocal_check_rcpt 159864562SgshapiroScheck`'_U_`'rcpt 159938032SpeterR$* $: $1 $| $>"Local_check_rcpt" $1 160038032SpeterR$* $| $#$* $#$2 160138032SpeterR$* $| $* $@ $>"Basic_check_rcpt" $1 160238032Speter 160338032SpeterSBasic_check_rcpt 160438032Speter# check for deferred delivery mode 160538032SpeterR$* $: < ${deliveryMode} > $1 160638032SpeterR< d > $* $@ deferred 160738032SpeterR< $* > $* $: $2 160838032Speter 160964562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 161064562Sgshapiro# require qualified recipient? 161164562SgshapiroR$+ $: <?> $1 161264562SgshapiroR<?><$+> $: <@> <$1> 161364562SgshapiroR<?>$+ $: <@> <$1> 161464562Sgshapirodnl prepend daemon_flags 161564562SgshapiroR$* $: $&{daemon_flags} $| $1 161664562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 161764562Sgshapirodnl do not allow these at all or only from local systems? 161864562SgshapiroR$* r $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 161964562SgshapiroR<?> < $* > $: <$1> 162064562SgshapiroR<? $=w> < $* > $: <$1> 162164562SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "553 Domain name required" 162264562Sgshapirodnl remove daemon_flags for other cases 162364562SgshapiroR$* $| <@> $* $: $2', `dnl') 162464562Sgshapiro 162538032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl 162642575SpeterR$* $: $>CanonAddr $1 162738032SpeterR$* < @ $* . > $1 < @ $2 > strip trailing dots', 162838032Speter`R$* $: $>ParseRecipient $1 strip relayable hosts') 162938032Speter 163042575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl 163142575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl 163242575Speter# unlimited bestmx 163342575SpeterR$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 163442575Speter`dnl 163542575Speter# limit bestmx to $=B 163643730SpeterR$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 163764562SgshapiroR$* $=O $* < @ $* @@ $=w . > $* $@ $>"Basic_check_rcpt" $1 $2 $3 163842575SpeterR$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 163942575SpeterR$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 164042575Speter 164138032Speterifdef(`_BLACKLIST_RCPT_',`dnl 164264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 164338032Speter# blacklist local users or any host from receiving mail 164438032SpeterR$* $: <?> $1 164564562Sgshapirodnl user is now tagged with @ to be consistent with check_mail 164664562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user) 164764562SgshapiroR<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <H:$2> 164864562SgshapiroR<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <H:$2> 164964562SgshapiroR<?> $+ $: <> <$1> $| <U:$1@> 165064562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 165164562Sgshapirodnl will only return user<@domain when "reversing" the args 165264562SgshapiroR<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+To> $| <$2> <> 165364562SgshapiroR<@> <$*> $| <$*> $: <$2> <$1> reverse result 165464562SgshapiroR<?> <$*> $: @ $1 mark address as no match 165564562SgshapiroR<$={Accept}> <$*> $: @ $2 mark address as no match 165664562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 165764562Sgshapirodnl we have to filter these because otherwise they would be interpreted 165864562Sgshapirodnl as generic error message... 165964562Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 166064562Sgshapirodnl that would make a lot of things easier. 166164562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)? 166264562SgshapiroR<$={SpamTag}> <$*> $: @ $2 mark address as no match') 166338032SpeterR<REJECT> $* $#error $@ 5.2.1 $: "550 Mailbox disabled for this recipient" 166464562SgshapiroR<DISCARD> $* $#discard $: discard 166564562Sgshapirodnl error tag 166664562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 166764562SgshapiroR<ERROR:$+> $* $#error $: $1 166864562Sgshapirodnl generic error from access map 166964562SgshapiroR<$+> $* $#error $: $1 error from access db 167064562SgshapiroR@ $* $1 remove mark', `dnl')', `dnl') 167138032Speter 167264562Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)') 167364562Sgshapiro# authenticated? 167464562Sgshapirodnl do this unconditionally? this requires to manage CAs carefully 167564562Sgshapirodnl just because someone has a CERT signed by a "trusted" CA 167664562Sgshapirodnl does not mean we want to allow relaying for her, 167764562Sgshapirodnl either use a subroutine or provide something more sophisticated 167864562Sgshapirodnl this could for example check the DN (maybe an access map lookup) 167964562SgshapiroR$* $: $1 $| $>RelayAuth $1 $| $&{verify} client authenticated? 168064562SgshapiroR$* $| $# $+ $# $2 error/ok? 168164562SgshapiroR$* $| $* $: $1 no 168264562Sgshapiro 168364562Sgshapiro# authenticated by a trusted mechanism? 168464562SgshapiroR$* $: $1 $| $&{auth_type} 168564562Sgshapirodnl empty ${auth_type}? 168664562SgshapiroR$* $| $: $1 168764562Sgshapirodnl mechanism ${auth_type} accepted? 168864562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below 168964562SgshapiroR$* $| $={TrustAuthMech} $# RELAYAUTH 169064562Sgshapirodnl undo addition of ${auth_type} 169164562SgshapiroR$* $| $* $: $1 169271345Sgshapirodnl workspace: localpart<@domain> | localpart 169364562Sgshapiroifelse(defn(`_NO_UUCP_'), `r', 169471345Sgshapiro`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 169571345SgshapiroR$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 169638032Speter# anything terminating locally is ok 169738032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 169864562SgshapiroR$+ < @ $* $=m > $@ RELAYTO', `dnl') 169964562SgshapiroR$+ < @ $=w > $@ RELAYTO 170038032Speterifdef(`_RELAY_HOSTS_ONLY_', 170164562Sgshapiro`R$+ < @ $=R > $@ RELAYTO 170264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 170364562SgshapiroR$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 170464562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 170564562SgshapiroR<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 170664562Sgshapiro`R$+ < @ $* $=R > $@ RELAYTO 170764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 170864562SgshapiroR$+ < @ $+ > $: $>LookUpDomain <$2> <?> <$1 < @ $2 >> <+To>',`dnl')') 170964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 171064562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 171164562SgshapiroR<RELAY> $* $@ RELAYTO 171238032SpeterR<$*> <$*> $: $2',`dnl') 171338032Speter 171464562Sgshapiro 171538032Speterifdef(`_RELAY_MX_SERVED_', `dnl 171638032Speter# allow relaying for hosts which we MX serve 171764562SgshapiroR$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 171864562Sgshapirodnl this must not necessarily happen if the client is checked first... 171938032SpeterR< : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 172064562SgshapiroR<$* : $=w . : $*> $* $@ RELAYTO 172142575SpeterR< : $* : > $* $: $2', 172238032Speter`dnl') 172338032Speter 172438032Speter# check for local user (i.e. unqualified address) 172538032SpeterR$* $: <?> $1 172642575SpeterR<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 172738032Speter# local user is ok 172864562Sgshapirodnl is it really? the standard requires user@domain, not just user 172964562Sgshapirodnl but we should accept it anyway (maybe making it an option: 173064562Sgshapirodnl RequireFQDN ?) 173164562Sgshapirodnl postmaster must be accepted without domain (DRUMS) 173264562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 173364562SgshapiroR<?> postmaster $@ TOPOSTMASTER 173464562Sgshapiro# require qualified recipient? 173564562Sgshapirodnl prepend daemon_flags 173664562SgshapiroR<?> $+ $: $&{daemon_flags} $| <?> $1 173764562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart 173864562Sgshapirodnl do not allow these at all or only from local systems? 173964562Sgshapirodnl r flag? add client_name 174064562SgshapiroR$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 174164562Sgshapirodnl no r flag: relay to local user (only local part) 174264562Sgshapiro# no qualified recipient required 174364562SgshapiroR$* $| <?> $+ $@ RELAYTOLOCAL 174464562Sgshapirodnl client_name is empty 174564562SgshapiroR<?> <?> $+ $@ RELAYTOLOCAL 174664562Sgshapirodnl client_name is local 174764562SgshapiroR<? $=w> <?> $+ $@ RELAYTOLOCAL 174864562Sgshapirodnl client_name is not local 174964562SgshapiroR<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 175064562Sgshapirodnl no qualified recipient required 175164562SgshapiroR<?> $+ $@ RELAYTOLOCAL') 175264562Sgshapirodnl it is a remote user: remove mark and then check client 175338032SpeterR<$+> $* $: $2 175464562Sgshapirodnl currently the recipient address is not used below 175538032Speter 175638032Speter# anything originating locally is ok 175764562Sgshapiro# check IP address 175864562SgshapiroR$* $: $&{client_addr} 175964562SgshapiroR$@ $@ RELAYFROM originated locally 176064562SgshapiroR0 $@ RELAYFROM originated locally 176164562SgshapiroR$=R $* $@ RELAYFROM relayable IP address 176264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 176364562SgshapiroR$* $: $>LookUpAddress <$1> <?> <$1> <+Connect> 176464562SgshapiroR<RELAY> $* $@ RELAYFROM relayable IP address 176564562SgshapiroR<$*> <$*> $: $2', `dnl') 176664562SgshapiroR$* $: [ $1 ] put brackets around it... 176764562SgshapiroR$=w $@ RELAYFROM ... and see if it is local 176864562Sgshapiro 176964562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 177064562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 177164562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl 177264562Sgshapirodnl input: {client_addr} or something "broken" 177364562Sgshapirodnl just throw the input away; we do not need it. 177464562Sgshapiro# check whether FROM is allowed to use system as relay 177564562SgshapiroR$* $: <?> $>CanonAddr $&f 177664562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl 177764562Sgshapiro# check whether local FROM is ok 177864562SgshapiroR<?> $+ < @ $=w . > $@ RELAYFROMMAIL FROM local', `dnl') 177964562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl 178064562SgshapiroR<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 178164562SgshapiroR<?> $+ < @ $+ > $: $1 < @ $2 > $| $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<H:$2>') <> 178264562SgshapiroR$* <RELAY> $@ RELAYFROMMAIL RELAY FROM sender ok', `dnl 178364562Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', `errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 178464562Sgshapiro')', 178564562Sgshapiro`dnl') 178664562Sgshapirodnl')', `dnl') 178764562Sgshapiro 178864562Sgshapiro# check client name: first: did it resolve? 178964562Sgshapirodnl input: ignored 179064562SgshapiroR$* $: < $&{client_resolve} > 179164562SgshapiroR<TEMP> $#error $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 179264562SgshapiroR<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 179364562SgshapiroR<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 179464562Sgshapirodnl ${client_resolve} should be OK, so go ahead 179538032SpeterR$* $: <?> $&{client_name} 179638032Speter# pass to name server to make hostname canonical 179764562SgshapiroR<?> $* $~P $:<?> $[ $1 $2 $] 179864562SgshapiroR$* . $1 strip trailing dots 179964562Sgshapirodnl should not be necessary since it has been done for client_addr already 180064562SgshapiroR<?> $@ RELAYFROM 180138032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 180264562SgshapiroR<?> $* $=m $@ RELAYFROM', `dnl') 180364562SgshapiroR<?> $=w $@ RELAYFROM 180438032Speterifdef(`_RELAY_HOSTS_ONLY_', 180564562Sgshapiro`R<?> $=R $@ RELAYFROM 180664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 180764562SgshapiroR<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 180864562SgshapiroR<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 180964562Sgshapiro`R<?> $* $=R $@ RELAYFROM 181064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 181164562SgshapiroR<?> $* $: $>LookUpDomain <$1> <?> <$1> <+Connect>',`dnl')') 181264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 181364562SgshapiroR<RELAY> $* $@ RELAYFROM 181438032SpeterR<$*> <$*> $: $2',`dnl') 181538032Speter 181664562Sgshapiro# anything else is bogus 181764562SgshapiroR$* $#error $@ 5.7.1 $: confRELAY_MSG 181864562Sgshapirodivert(0) 181964562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 182064562Sgshapiro# turn a canonical address in the form user<@domain> 182164562Sgshapiro# qualify unqual. addresses with $j 182264562Sgshapirodnl it might have been only user (without <@domain>) 182364562SgshapiroSFullAddr 182464562SgshapiroR$* <@ $+ . > $1 <@ $2 > 182564562SgshapiroR$* <@ $* > $@ $1 <@ $2 > 182664562SgshapiroR$+ $@ $1 <@ $j > 182738032Speter 182864562Sgshapiro# call all necessary rulesets 182964562SgshapiroScheck_rcpt 183064562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset 183164562Sgshapirodnl which is the correct DSN code? 183264562Sgshapiro# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 183364562SgshapiroR$+ $: $1 $| $>checkrcpt $1 183464562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 183564562SgshapiroR$+ $| $#$* $#$2 183664562SgshapiroR$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 183764562Sgshapiroifdef(`_SPAM_FH_', 183864562Sgshapiro`dnl lookup user@ and user@address 183964562Sgshapiroifdef(`_ACCESS_TABLE_', `', 184064562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 184164562Sgshapiro')')dnl 184264562Sgshapirodnl one of the next two rules is supposed to match 184364562Sgshapirodnl this code has been copied from BLACKLIST... etc 184464562Sgshapirodnl and simplified by omitting some < >. 184564562SgshapiroR<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <U: $1@> 184664562SgshapiroR<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > 184764562Sgshapirodnl R<?> $@ something_is_very_wrong_here 184864562Sgshapiro# lookup the addresses only with To tag 184964562SgshapiroR<> $* $| <$+> $: <@> $1 $| $>SearchList <!To> $| <$2> <> 185064562SgshapiroR<@> $* $| $* $: $2 $1 reverse result 185164562Sgshapirodnl', `dnl') 185264562Sgshapiroifdef(`_SPAM_FRIEND_', 185364562Sgshapiro`# is the recipient a spam friend? 185464562Sgshapiroifdef(`_SPAM_HATER_', 185564562Sgshapiro `errprint(`*** ERROR: define either SpamHater or SpamFriend 185664562Sgshapiro')', `dnl') 185764562SgshapiroR<SPAMFRIEND> $+ $@ SPAMFRIEND 185864562SgshapiroR<$*> $+ $: $2', 185964562Sgshapiro`dnl') 186064562Sgshapiroifdef(`_SPAM_HATER_', 186164562Sgshapiro`# is the recipient no spam hater? 186264562SgshapiroR<SPAMHATER> $+ $: $1 spam hater: continue checks 186364562SgshapiroR<$*> $+ $@ NOSPAMHATER everyone else: stop 186464562Sgshapirodnl',`dnl') 186564562Sgshapirodnl run further checks: check_mail 186664562Sgshapirodnl should we "clean up" $&f? 186764562SgshapiroR$* $: $1 $| $>checkmail <$&f> 186864562SgshapiroR$* $| $#$* $#$2 186964562Sgshapirodnl run further checks: check_relay 187064562SgshapiroR$* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 187164562SgshapiroR$* $| $#$* $#$2 187238032SpeterR$* $| $* $: $1 187338032Speter', `dnl') 187464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 187564562Sgshapiro###################################################################### 187664562Sgshapiro### SearchList: search a list of items in the access map 187764562Sgshapiro### Parameters: 187864562Sgshapiro### <exact tag> $| <mark:address> <mark:address> ... <> 187964562Sgshapirodnl maybe we should have a @ (again) in front of the mark to 188064562Sgshapirodnl avoid errorneous matches (with error messages?) 188164562Sgshapirodnl if we can make sure that tag is always a single token 188264562Sgshapirodnl then we can omit the delimiter $|, otherwise we need it 188364562Sgshapirodnl to avoid errorneous matchs (first rule: H: if there 188464562Sgshapirodnl is that mark somewhere in the list, it will be taken). 188564562Sgshapirodnl moreover, we can do some tricks to enforce lookup with 188664562Sgshapirodnl the tag only, e.g.: 188764562Sgshapiro### where "exact" is either "+" or "!": 188864562Sgshapiro### <+ TAG> lookup with and w/o tag 188964562Sgshapiro### <! TAG> lookup with tag 189064562Sgshapirodnl Warning: + and ! should be in OperatorChars (otherwise there must be 189164562Sgshapirodnl a blank between them and the tag. 189264562Sgshapiro### possible values for "mark" are: 189364562Sgshapiro### H: recursive host lookup (LookUpDomain) 189464562Sgshapirodnl A: recursive address lookup (LookUpAddress) [not yet required] 189564562Sgshapiro### E: exact lookup, no modifications 189664562Sgshapiro### F: full lookup, try user+ext@domain and user@domain 189764562Sgshapiro### U: user lookup, try user+ext and user (input must have trailing @) 189864562Sgshapiro### return: <RHS of lookup> or <?> (not found) 189964562Sgshapiro###################################################################### 190038032Speter 190164562Sgshapiro# class with valid marks for SearchList 190264562Sgshapirodnl if A is activated: add it 190364562SgshapiroC{src}E F H U 190464562SgshapiroSSearchList 190564562Sgshapiro# mark H: lookup domain 190664562SgshapiroR<$+> $| <H:$+> <$*> $: <$1> $| <@> $>LookUpDomain <$2> <?> <$3> <$1> 190764562SgshapiroR<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> 190864562Sgshapirodnl A: NOT YET REQUIRED 190964562Sgshapirodnl R<$+> $| <A:$+> <$*> $: <$1> $| <@> $>LookUpAddress <$2> <?> <$3> <$1> 191064562Sgshapirodnl R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> 191164562Sgshapirodnl lookup of the item with tag 191264562Sgshapirodnl this applies to F: U: E: 191364562SgshapiroR<$- $-> $| <$={src}:$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5> 191464562Sgshapirodnl no match, try without tag 191564562SgshapiroR<+ $-> $| <$={src}:$+> <$*> $: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4> 191664562Sgshapirodnl do we really have to distinguish these cases? 191764562Sgshapirodnl probably yes, there might be a + in the domain part (is that allowed?) 191864562Sgshapirodnl user+detail lookups: should it be: 191964562Sgshapirodnl user+detail, user+*, user; just like aliases? 192064562SgshapiroR<$- $-> $| <F:$* + $*@$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@$5 $: F:$3 + $4@$5$)> <$6> 192164562SgshapiroR<+ $-> $| <F:$* + $*@$+> <$*> $: <+ $1> $| <$(access $2@$4 $: F:$2 + $3@$4$)> <$5> 192264562Sgshapirodnl user lookups are always with trailing @ 192364562Sgshapirodnl do not remove the @ from the lookup: 192464562Sgshapirodnl it is part of the +detail@ which is omitted for the lookup 192564562SgshapiroR<$- $-> $| <U:$* + $*> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5> 192664562Sgshapirodnl no match, try without tag 192764562SgshapiroR<+ $-> $| <U:$* + $*> <$*> $: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4> 192864562Sgshapirodnl no match, try rest of list 192964562SgshapiroR<$+> $| <$={src}:$+> <$+> $@ $>SearchList <$1> $| <$4> 193064562Sgshapirodnl no match, list empty: return failure 193164562SgshapiroR<$+> $| <$={src}:$+> <> $@ <?> 193264562Sgshapirodnl got result, return it 193364562SgshapiroR<$+> $| <$+> <$*> $@ <$2> 193464562Sgshapirodnl return result from recursive invocation 193564562SgshapiroR<$+> $| <$+> $@ <$2>', `dnl') 193638032Speter 193764562Sgshapiro# is user trusted to authenticate as someone else? 193864562Sgshapirodnl AUTH= parameter from MAIL command 193964562SgshapiroStrust_auth 194064562SgshapiroR$* $: $&{auth_type} $| $1 194164562Sgshapiro# required by RFC 2554 section 4. 194264562SgshapiroR$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 194364562Sgshapirodnl seems to be useful... 194464562SgshapiroR$* $| $&{auth_authen} $@ identical 194564562SgshapiroR$* $| <$&{auth_authen}> $@ identical 194664562Sgshapirodnl call user supplied code 194764562SgshapiroR$* $| $* $: $1 $| $>"Local_trust_auth" $1 194864562SgshapiroR$* $| $#$* $#$2 194964562Sgshapirodnl default: error 195064562SgshapiroR$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 195164562Sgshapiro 195264562Sgshapirodnl empty ruleset definition so it can be called 195364562SgshapiroSLocal_trust_auth 195464562Sgshapiro 195564562Sgshapiroifdef(`_FFR_TLS_O_T', `dnl 195664562SgshapiroSoffer_tls 195764562SgshapiroR$* $: $>LookUpDomain <$&{client_name}> <?> <> <! TLS_OFF_TAG> 195864562SgshapiroR<?>$* $: $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_OFF_TAG> 195964562SgshapiroR<?>$* $: <$(access TLS_OFF_TAG: $: ? $)> 196064562SgshapiroR<?>$* $@ OK 196164562SgshapiroR<NO> <> $#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]" 196264562Sgshapiro 196364562SgshapiroStry_tls 196464562SgshapiroR$* $: $>LookUpDomain <$&{server_name}> <?> <> <! TLS_TRY_TAG> 196564562SgshapiroR<?>$* $: $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_TRY_TAG> 196664562SgshapiroR<?>$* $: <$(access TLS_TRY_TAG: $: ? $)> 196764562SgshapiroR<?>$* $@ OK 196871345SgshapiroR<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 196964562Sgshapiro')dnl 197064562Sgshapiro 197164562Sgshapiro# is connection with client "good" enough? (done in server) 197264562Sgshapiro# input: ${verify} $| (MAIL|STARTTLS) 197364562Sgshapirodnl MAIL: called from check_mail 197464562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted 197564562SgshapiroStls_client 197664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 197764562Sgshapirodnl ignore second arg for now 197864562Sgshapirodnl maybe use it to distinguish permanent/temporary error? 197964562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered) 198064562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed) 198164562SgshapiroR$* $| $* $: $1 $| $>LookUpDomain <$&{client_name}> <?> <> <! TLS_CLT_TAG> 198264562SgshapiroR$* $| <?>$* $: $1 $| $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_CLT_TAG> 198364562Sgshapirodnl do a default lookup: just TLS_CLT_TAG 198464562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 198564562SgshapiroR$* $@ $>"tls_connection" $1', `dnl 198664562SgshapiroR$* $| $* $@ $>"tls_connection" $1') 198764562Sgshapiro 198864562Sgshapiro# is connection with server "good" enough? (done in client) 198964562Sgshapirodnl i.e. has the server been authenticated and is encryption active? 199064562Sgshapirodnl called from deliver() after STARTTLS command 199164562Sgshapiro# input: ${verify} 199264562SgshapiroStls_server 199364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 199464562SgshapiroR$* $: $1 $| $>LookUpDomain <$&{server_name}> <?> <> <! TLS_SRV_TAG> 199564562SgshapiroR$* $| <?>$* $: $1 $| $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_SRV_TAG> 199664562Sgshapirodnl do a default lookup: just TLS_SRV_TAG 199764562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 199864562SgshapiroR$* $@ $>"tls_connection" $1', `dnl 199964562SgshapiroR$* $@ $>"tls_connection" $1') 200064562Sgshapiro 200164562SgshapiroStls_connection 200264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 200364562Sgshapirodnl common ruleset for tls_{client|server} 200464562Sgshapirodnl input: $&{verify} $| <ResultOfLookup> [<>] 200564562Sgshapirodnl remove optional <> 200664562SgshapiroR$* $| <$*>$* $: $1 $| <$2> 200764562Sgshapirodnl permanent or temporary error? 200864562SgshapiroR$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 200964562SgshapiroR$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 201064562Sgshapirodnl default case depends on TLS_PERM_ERR 201164562SgshapiroR$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 201264562Sgshapirodnl deal with TLS handshake failures: abort 201364562SgshapiroRSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 201464562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 201564562Sgshapirodnl use default error 201664562SgshapiroRSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 201764562SgshapiroR$* $| <$*> <VERIFY> $: <$2> <VERIFY> $1 201864562SgshapiroR$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> $1 201964562Sgshapirodnl some other value in access map: accept 202064562Sgshapirodnl this also allows to override the default case (if used) 202164562SgshapiroR$* $| $* $@ OK 202264562Sgshapiro# authentication required: give appropriate error 202364562Sgshapiro# other side did authenticate (via STARTTLS) 202464562Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> ${verify} 202564562Sgshapirodnl only verification required and it succeeded 202664562SgshapiroR<$*><VERIFY> OK $@ OK 202764562Sgshapirodnl verification required + some level of encryption 202864562SgshapiroR<$*><VERIFY:$-> OK $: <$1> <REQ:$2> 202964562Sgshapirodnl just some level of encryption required 203064562SgshapiroR<$*><ENCR:$-> $* $: <$1> <REQ:$2> 203164562Sgshapirodnl verification required but ${verify} is not set 203264562SgshapiroR<$-:$+><VERIFY $*> $#error $@ $2 $: $1 " authentication required" 203364562SgshapiroR<$-:$+><VERIFY $*> FAIL $#error $@ $2 $: $1 " authentication failed" 203464562SgshapiroR<$-:$+><VERIFY $*> NO $#error $@ $2 $: $1 " not authenticated" 203564562SgshapiroR<$-:$+><VERIFY $*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 203664562Sgshapirodnl some other value for ${verify} 203764562SgshapiroR<$-:$+><VERIFY $*> $+ $#error $@ $2 $: $1 " authentication failure " $4 203864562Sgshapirodnl some level of encryption required: get the maximum level 203964562SgshapiroR<$*><REQ:$-> $: <$1> <REQ:$2> $>max $&{cipher_bits} : $&{auth_ssf} 204064562Sgshapirodnl compare required bits with actual bits 204164562SgshapiroR<$*><REQ:$-> $- $: <$1> <$2:$3> $(arith l $@ $3 $@ $2 $) 204264562SgshapiroR<$-:$+><$-:$-> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 204364562Sgshapiro 204464562SgshapiroSmax 204564562Sgshapirodnl compute the max of two values separated by : 204664562SgshapiroR: $: 0 204764562SgshapiroR:$- $: $1 204864562SgshapiroR$-: $: $1 204964562SgshapiroR$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 205064562SgshapiroRTRUE:$-:$- $: $2 205164562SgshapiroR$-:$-:$- $: $2', 205264562Sgshapiro`dnl use default error 205364562Sgshapirodnl deal with TLS handshake failures: abort 205464562SgshapiroRSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."') 205564562Sgshapiro 205664562SgshapiroSRelayAuth 205764562Sgshapiro# authenticated? 205864562Sgshapirodnl we do not allow relaying for anyone who can present a cert 205964562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns 206064562Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow 206164562Sgshapirodnl them to abuse our server (they might be easier to get hold of, 206264562Sgshapirodnl but anyway). 206364562Sgshapirodnl so here is the trick: if the verification succeeded 206464562Sgshapirodnl we look up the cert issuer in the access map 206564562Sgshapirodnl (maybe after extracting a part with a regular expression) 206664562Sgshapirodnl if this returns RELAY we relay without further questions 206764562Sgshapirodnl if it returns SUBJECT we perform a similar check on the 206864562Sgshapirodnl cert subject. 206964562SgshapiroR$* $| OK $: $1 207064562SgshapiroR$* $| $* $@ NO not authenticated 207164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 207264562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 207364562SgshapiroR$* $: $1 $| $(CERTIssuer $&{cert_issuer} $)', 207464562Sgshapiro`R$* $: $1 $| $&{cert_issuer}') 207564562SgshapiroR$* $| $+ $: $1 $| $(access CERTISSUER:$2 $) 207664562Sgshapirodnl use $# to stop further checks (delay_check) 207764562SgshapiroR$* $| RELAY $# RELAYCERTISSUER 207864562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 207964562SgshapiroR$* $| SUBJECT $: $1 $| <@> $(CERTSubject $&{cert_subject} $)', 208064562Sgshapiro`R$* $| SUBJECT $: $1 $| <@> $&{cert_subject}') 208166494SgshapiroR$* $| <@> $+ $: $1 $| <@> $(access CERTSUBJECT:$2 $) 208264562SgshapiroR$* $| <@> RELAY $# RELAYCERTSUBJECT 208364562SgshapiroR$* $| $* $: $1', `dnl') 208464562Sgshapiro 208564562Sgshapiroundivert(9)dnl LOCAL_RULESETS 208664562Sgshapiroifdef(`_FFR_MILTER', ` 208738032Speter# 208838032Speter###################################################################### 208938032Speter###################################################################### 209038032Speter##### 209164562Sgshapiro`##### MAIL FILTER DEFINITIONS' 209264562Sgshapiro##### 209364562Sgshapiro###################################################################### 209464562Sgshapiro###################################################################### 209564562Sgshapiro_MAIL_FILTERS_') 209664562Sgshapiro# 209764562Sgshapiro###################################################################### 209864562Sgshapiro###################################################################### 209964562Sgshapiro##### 210038032Speter`##### MAILER DEFINITIONS' 210138032Speter##### 210238032Speter###################################################################### 210338032Speter###################################################################### 210464562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS 210566494Sgshapiro 2106