proto.m4 revision 80785
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 1680785SgshapiroVERSIONID(`$Id: proto.m4,v 8.446.2.5.2.44 2001/07/31 22:25:49 gshapiro 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"')') 8077349Sgshapirodefine(`CODE553', `553') 8138032Speterdivert(0)dnl 8238032Speter 8364562Sgshapiro# override file safeties - setting this option compromises system security, 8464562Sgshapiro# addressing the actual file configuration problem is preferred 8564562Sgshapiro# need to set this before any file actions are encountered in the cf file 8664562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe') 8738032Speter 8864562Sgshapiro# default LDAP map specification 8964562Sgshapiro# need to set this now before any LDAP maps are defined 9064562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost') 9164562Sgshapiro 9238032Speter################## 9338032Speter# local info # 9438032Speter################## 9538032Speter 9638032SpeterCwlocalhost 9738032Speterifdef(`USE_CW_FILE', 9838032Speter`# file containing names of hosts for which we receive email 9938032SpeterFw`'confCW_FILE', 10038032Speter `dnl') 10138032Speter 10238032Speter# my official domain name 10338032Speter# ... `define' this only if sendmail cannot automatically determine your domain 10438032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM') 10538032Speter 10638032SpeterCP. 10738032Speter 10838032Speterifdef(`UUCP_RELAY', 10938032Speter`# UUCP relay host 11038032SpeterDY`'UUCP_RELAY 11138032SpeterCPUUCP 11238032Speter 11338032Speter')dnl 11438032Speterifdef(`BITNET_RELAY', 11538032Speter`# BITNET relay host 11638032SpeterDB`'BITNET_RELAY 11738032SpeterCPBITNET 11838032Speter 11938032Speter')dnl 12038032Speterifdef(`DECNET_RELAY', 12138032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl 12238032Speter# DECnet relay host 12338032SpeterDC`'DECNET_RELAY 12438032SpeterCPDECNET 12538032Speter 12638032Speter')dnl 12738032Speterifdef(`FAX_RELAY', 12838032Speter`# FAX relay host 12938032SpeterDF`'FAX_RELAY 13038032SpeterCPFAX 13138032Speter 13238032Speter')dnl 13338032Speter# "Smart" relay host (may be null) 13438032SpeterDS`'ifdef(`SMART_HOST', SMART_HOST) 13538032Speter 13638032Speterifdef(`LUSER_RELAY', `dnl 13738032Speter# place to which unknown users should be forwarded 13838032SpeterKuser user -m -a<> 13938032SpeterDL`'LUSER_RELAY', 14038032Speter`dnl') 14138032Speter 14238032Speter# operators that cannot be in local usernames (i.e., network indicators) 14338032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!') 14438032Speter 14538032Speter# a class with just dot (for identifying canonical names) 14638032SpeterC.. 14738032Speter 14838032Speter# a class with just a left bracket (for identifying domain literals) 14938032SpeterC[[ 15038032Speter 15164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 15264562Sgshapiro# access_db acceptance class 15364562SgshapiroC{Accept}OK RELAY 15464562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 15564562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl 15664562Sgshapiro# possible access_db RHS for spam friends/haters 15764562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')', 15838032Speter`dnl') 15938032Speter 16038032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl 16138032Speter# Resolve map (to check if a host exists in check_mail) 16238032SpeterKresolve host -a<OK> -T<TEMP>') 16338032Speter 16480785Sgshapiroifdef(`_NEED_MACRO_MAP_', `dnl 16580785Sgshapiroifdef(`_MACRO_MAP_', `', `# macro storage map 16680785Sgshapirodefine(`_MACRO_MAP_', `1')dnl 16780785SgshapiroKmacro macro')', `dnl') 16866494Sgshapiro 16938032Speterifdef(`confCR_FILE', `dnl 17066494Sgshapiro# Hosts for which relaying is permitted ($=R) 17138032SpeterFR`'confCR_FILE', 17238032Speter`dnl') 17338032Speter 17464562Sgshapirodefine(`TLS_SRV_TAG', `TLS_Srv')dnl 17564562Sgshapirodefine(`TLS_CLT_TAG', `TLS_Clt')dnl 17664562Sgshapirodefine(`TLS_TRY_TAG', `Try_TLS')dnl 17764562Sgshapirodefine(`TLS_OFF_TAG', `Offer_TLS')dnl 17864562Sgshapirodnl this may be useful in other contexts too 17964562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map 18064562Sgshapirodefine(`_ARITH_MAP_', `1')dnl 18164562SgshapiroKarith arith') 18264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 18364562Sgshapiro# possible values for tls_connect in access map 18464562SgshapiroC{tls}VERIFY ENCR', `dnl') 18564562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 18664562Sgshapiro# extract relevant part from cert issuer 18764562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl') 18864562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 18964562Sgshapiro# extract relevant part from cert subject 19064562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl') 19164562Sgshapiro 19238032Speter# who I send unqualified names to (null means deliver locally) 19338032SpeterDR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY) 19438032Speter 19538032Speter# who gets all local email traffic ($R has precedence for unqualified names) 19638032SpeterDH`'ifdef(`MAIL_HUB', MAIL_HUB) 19738032Speter 19838032Speter# dequoting map 19938032SpeterKdequote dequote 20038032Speter 20138032Speterdivert(0)dnl # end of nullclient diversion 20238032Speter# class E: names that should be exposed as from this host, even if we masquerade 20364562Sgshapiro# class L: names that should be delivered locally, even if we have a relay 20438032Speter# class M: domains that should be converted to $M 20564562Sgshapiro# class N: domains that should not be converted to $M 20638032Speter#CL root 20738032Speterundivert(5)dnl 20864562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl') 20938032Speter 21038032Speter# who I masquerade as (null for no masquerading) (see also $=M) 21138032SpeterDM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME) 21238032Speter 21338032Speter# my name for error messages 21438032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON') 21538032Speter 21664562Sgshapiroundivert(6)dnl LOCAL_CONFIG 21738032Speterinclude(_CF_DIR_`m4/version.m4') 21838032Speter 21938032Speter############### 22038032Speter# Options # 22138032Speter############### 22238032Speter 22338032Speter# strip message body to 7 bits on input? 22464562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False') 22538032Speter 22638032Speter# 8-bit data handling 22777349Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `pass8') 22838032Speter 22938032Speter# wait for alias file rebuild (default units: minutes) 23064562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m') 23138032Speter 23238032Speter# location of alias file 23364562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases') 23464562Sgshapiro 23538032Speter# minimum number of free blocks on filesystem 23664562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100') 23738032Speter 23838032Speter# maximum message size 23964562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000') 24038032Speter 24138032Speter# substitution for space (blank) characters 24264562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_') 24338032Speter 24438032Speter# avoid connecting to "expensive" mailers on initial submission? 24564562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False') 24638032Speter 24738032Speter# checkpoint queue runs after every N successful deliveries 24864562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10') 24938032Speter 25038032Speter# default delivery mode 25164562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background') 25238032Speter 25338032Speter# automatically rebuild the alias database? 25464562Sgshapiro# NOTE: There is a potential for a denial of service attack if this is set. 25564562Sgshapiro# This option is deprecated and will be removed from a future version. 25664562Sgshapiro_OPTION(AutoRebuildAliases, `confAUTO_REBUILD', `False') 25738032Speter 25838032Speter# error message header/file 25964562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header') 26038032Speter 26138032Speter# error mode 26264562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print') 26338032Speter 26438032Speter# save Unix-style "From_" lines at top of header? 26564562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False') 26638032Speter 26738032Speter# temporary file mode 26864562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600') 26938032Speter 27038032Speter# match recipients against GECOS field? 27164562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False') 27238032Speter 27338032Speter# maximum hop count 27464562Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `17') 27538032Speter 27638032Speter# location of help file 27764562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile') 27838032Speter 27938032Speter# ignore dots as terminators in incoming messages? 28064562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False') 28138032Speter 28238032Speter# name resolver options 28364562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY') 28438032Speter 28538032Speter# deliver MIME-encapsulated error messages? 28664562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True') 28738032Speter 28838032Speter# Forward file search path 28964562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward') 29038032Speter 29138032Speter# open connection cache size 29264562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2') 29338032Speter 29438032Speter# open connection cache timeout 29564562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m') 29638032Speter 29738032Speter# persistent host status directory 29864562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat') 29938032Speter 30038032Speter# single thread deliveries (requires HostStatusDirectory)? 30164562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False') 30238032Speter 30338032Speter# use Errors-To: header? 30464562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False') 30538032Speter 30638032Speter# log level 30764562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10') 30838032Speter 30938032Speter# send to me too, even in an alias expansion? 31064562Sgshapiro_OPTION(MeToo, `confME_TOO', `True') 31138032Speter 31238032Speter# verify RHS in newaliases? 31364562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False') 31438032Speter 31538032Speter# default messages to old style headers if no special punctuation? 31664562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False') 31738032Speter 31838032Speter# SMTP daemon options 31964562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl', 32064562Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. See cf/README for more information. 32164562Sgshapiro)'dnl 32264562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')') 32366494Sgshapiroifelse(defn(`_DPO_'), `', 32466494Sgshapiro`ifdef(`_NETINET6_', `O DaemonPortOptions=Name=MTA-IPv4, Family=inet 32566494SgshapiroO DaemonPortOptions=Name=MTA-IPv6, Family=inet6',`O DaemonPortOptions=Name=MTA')', `_DPO_') 32664562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E') 32738032Speter 32864562Sgshapiro# SMTP client options 32964562Sgshapiro_OPTION(ClientPortOptions, `confCLIENT_OPTIONS', `Address=0.0.0.0') 33064562Sgshapiro 33138032Speter# privacy flags 33264562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings') 33338032Speter 33438032Speter# who (if anyone) should get extra copies of error messages 33564562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster') 33638032Speter 33738032Speter# slope of queue-only function 33864562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000') 33938032Speter 34038032Speter# queue directory 34164562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue') 34238032Speter 34338032Speter# timeouts (many of these) 34464562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m') 34564562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m') 34664562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m') 34764562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m') 34864562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m') 34964562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h') 35064562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m') 35164562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h') 35264562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h') 35364562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m') 35464562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m') 35564562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m') 35664562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h') 35764562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s') 35864562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s') 35964562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m') 36064562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d') 36164562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d') 36264562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d') 36364562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d') 36464562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h') 36564562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h') 36664562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h') 36764562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h') 36864562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m') 36964562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s') 37064562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s') 37164562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s') 37264562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4') 37364562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4') 37464562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4') 37538032Speter 37638032Speter# should we not prune routes in route-addr syntax addresses? 37764562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False') 37838032Speter 37938032Speter# queue up everything before forking? 38064562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True') 38138032Speter 38238032Speter# status file 38364562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics') 38438032Speter 38538032Speter# time zone handling: 38638032Speter# if undefined, use system default 38738032Speter# if defined but null, use TZ envariable passed in 38838032Speter# if defined and non-null, use that info 38938032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=', 39038032Speter confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=', 39138032Speter `O TimeZoneSpec=confTIME_ZONE') 39238032Speter 39338032Speter# default UID (can be username or userid:groupid) 39464562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull') 39538032Speter 39638032Speter# list of locations of user database file (null means no lookup) 39764562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb') 39838032Speter 39938032Speter# fallback MX host 40064562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net') 40138032Speter 40238032Speter# if we are the best MX host for a site, try it directly instead of config err 40364562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False') 40438032Speter 40538032Speter# load average at which we just queue messages 40664562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8') 40738032Speter 40838032Speter# load average at which we refuse connections 40964562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12') 41038032Speter 41138032Speter# maximum number of children we allow at one time 41264562Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12') 41338032Speter 41438032Speter# maximum number of new connections per second 41571345Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `0') 41638032Speter 41738032Speter# work recipient factor 41864562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') 41938032Speter 42038032Speter# deliver each queued job in a separate process? 42164562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False') 42238032Speter 42338032Speter# work class factor 42464562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800') 42538032Speter 42638032Speter# work time factor 42764562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000') 42838032Speter 42938032Speter# shall we sort the queue by hostname first? 43064562Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority') 43138032Speter 43238032Speter# minimum time in queue before retry 43364562Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m') 43438032Speter 43538032Speter# default character set 43664562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1') 43738032Speter 43838032Speter# service switch file (ignored on Solaris, Ultrix, OSF/1, others) 43964562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch') 44038032Speter 44138032Speter# hosts file (normally /etc/hosts) 44264562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts') 44338032Speter 44438032Speter# dialup line delay on connection failure 44564562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s') 44638032Speter 44738032Speter# action to take if there are no recipients in the message 44864562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed') 44938032Speter 45038032Speter# chrooted environment for writing to files 45164562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch') 45238032Speter 45338032Speter# are colons OK in addresses? 45464562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True') 45538032Speter 45638032Speter# how many jobs can you process in the queue? 45764562Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000') 45838032Speter 45938032Speter# shall I avoid expanding CNAMEs (violates protocols)? 46064562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False') 46138032Speter 46238032Speter# SMTP initial login message (old $e macro) 46364562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b') 46438032Speter 46538032Speter# UNIX initial From header format (old $l macro) 46664562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d') 46738032Speter 46838032Speter# From: lines that have embedded newlines are unwrapped onto one line 46964562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False') 47038032Speter 47138032Speter# Allow HELO SMTP command that does not `include' a host name 47264562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False') 47338032Speter 47438032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic) 47564562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.') 47638032Speter 47738032Speter# delimiter (operator) characters (old $o macro) 47864562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]') 47938032Speter 48038032Speter# shall I avoid calling initgroups(3) because of high NIS costs? 48164562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False') 48238032Speter 48338032Speter# are group-writable `:include:' and .forward files (un)trustworthy? 48464562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True') 48538032Speter 48638032Speter# where do errors that occur when sending errors get sent? 48764562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster') 48838032Speter 48964562Sgshapiro# where to save bounces if all else fails 49064562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter') 49164562Sgshapiro 49238032Speter# what user id do we assume for the majority of the processing? 49364562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail') 49438032Speter 49538032Speter# maximum number of recipients per SMTP envelope 49664562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100') 49738032Speter 49838032Speter# shall we get local names from our installed interfaces? 49964562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 50038032Speter 50164562Sgshapiro# Return-Receipt-To: header implies DSN request 50264562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 50364562Sgshapiro 50464562Sgshapiro# override connection address (for testing) 50564562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 50664562Sgshapiro 50764562Sgshapiro# Trusted user for file ownership and starting the daemon 50864562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root') 50964562Sgshapiro 51064562Sgshapiro# Control socket for daemon management 51164562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 51264562Sgshapiro 51364562Sgshapiro# Maximum MIME header length to protect MUAs 51464562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0') 51564562Sgshapiro 51664562Sgshapiro# Maximum length of the sum of all headers 51764562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768') 51864562Sgshapiro 51964562Sgshapiro# Maximum depth of alias recursion 52064562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10') 52164562Sgshapiro 52264562Sgshapiro# location of pid file 52364562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid') 52464562Sgshapiro 52564562Sgshapiro# Prefix string for the process title shown on 'ps' listings 52664562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix') 52764562Sgshapiro 52864562Sgshapiro# Data file (df) memory-buffer file maximum size 52964562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096') 53064562Sgshapiro 53164562Sgshapiro# Transcript file (xf) memory-buffer file maximum size 53264562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096') 53364562Sgshapiro 53464562Sgshapiro# list of authentication mechanisms 53564562Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5') 53664562Sgshapiro 53764562Sgshapiro# default authentication information for outgoing connections 53864562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info') 53964562Sgshapiro 54064562Sgshapiro# SMTP AUTH flags 54164562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `') 54264562Sgshapiro 54364562Sgshapiroifdef(`_FFR_MILTER', ` 54464562Sgshapiro# Input mail filters 54564562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 54664562Sgshapiro 54764562Sgshapiro# Milter options 54864562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 54964562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') 55064562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') 55164562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')') 55264562Sgshapiro 55364562Sgshapiro# CA directory 55464562Sgshapiro_OPTION(CACERTPath, `confCACERT_PATH', `') 55564562Sgshapiro# CA file 55664562Sgshapiro_OPTION(CACERTFile, `confCACERT', `') 55764562Sgshapiro# Server Cert 55864562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `') 55964562Sgshapiro# Server private key 56064562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `') 56164562Sgshapiro# Client Cert 56264562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `') 56364562Sgshapiro# Client private key 56464562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 56564562Sgshapiro# DHParameters (only required if DSA/DH is used) 56664562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `') 56764562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL) 56864562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `') 56964562Sgshapiro 57064562Sgshapiroifdef(`confQUEUE_FILE_MODE', 57164562Sgshapiro`# queue file mode (qf files) 57264562SgshapiroO QueueFileMode=confQUEUE_FILE_MODE 57342575Speter') 57442575Speter 57538032Speter########################### 57638032Speter# Message precedences # 57738032Speter########################### 57838032Speter 57938032SpeterPfirst-class=0 58038032SpeterPspecial-delivery=100 58138032SpeterPlist=-30 58238032SpeterPbulk=-60 58338032SpeterPjunk=-100 58438032Speter 58538032Speter##################### 58638032Speter# Trusted users # 58738032Speter##################### 58838032Speter 58938032Speter# this is equivalent to setting class "t" 59064562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 59138032SpeterTroot 59238032SpeterTdaemon 59338032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp') 59438032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 59538032Speter 59638032Speter######################### 59738032Speter# Format of headers # 59838032Speter######################### 59938032Speter 60038032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl 60138032SpeterH?P?Return-Path: <$g> 60238032SpeterHReceived: confRECEIVED_HEADER 60338032SpeterH?D?Resent-Date: $a 60438032SpeterH?D?Date: $a 60538032SpeterH?F?Resent-From: confFROM_HEADER 60638032SpeterH?F?From: confFROM_HEADER 60738032SpeterH?x?Full-Name: $x 60838032Speter# HPosted-Date: $a 60938032Speter# H?l?Received-Date: $b 61038032SpeterH?M?Resent-Message-Id: <$t.$i@$j> 61138032SpeterH?M?Message-Id: <$t.$i@$j> 61264562Sgshapiro 61338032Speter# 61438032Speter###################################################################### 61538032Speter###################################################################### 61638032Speter##### 61738032Speter##### REWRITING RULES 61838032Speter##### 61938032Speter###################################################################### 62038032Speter###################################################################### 62138032Speter 62238032Speter############################################ 62338032Speter### Ruleset 3 -- Name Canonicalization ### 62438032Speter############################################ 62564562SgshapiroScanonify=3 62638032Speter 62738032Speter# handle null input (translate to <@> special case) 62838032SpeterR$@ $@ <@> 62938032Speter 63038032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon 63138032SpeterR$* $: $1 <@> mark addresses 63238032SpeterR$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> 63338032SpeterR@ $* <@> $: @ $1 unmark @host:... 63438032SpeterR$* :: $* <@> $: $1 :: $2 unmark node::addr 63538032SpeterR:`include': $* <@> $: :`include': $1 unmark :`include':... 63680785SgshapiroR$* [ IPv6 : $+ ] <@> $: $1 [ IPv6 : $2 ] unmark IPv6 addr 63738032SpeterR$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon 63838032SpeterR$* : $* <@> $: $2 strip colon if marked 63938032SpeterR$* <@> $: $1 unmark 64038032SpeterR$* ; $1 strip trailing semi 64171345SgshapiroR$* < $+ :; > $* $@ $2 :; <@> catch <list:;> 64238032SpeterR$* < $* ; > $1 < $2 > bogus bracketed semi 64338032Speter 64438032Speter# null input now results from list:; syntax 64538032SpeterR$@ $@ :; <@> 64638032Speter 64738032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item 64838032SpeterR$* $: < $1 > housekeeping <> 64938032SpeterR$+ < $* > < $2 > strip excess on left 65038032SpeterR< $* > $+ < $1 > strip excess on right 65138032SpeterR<> $@ < @ > MAIL FROM:<> case 65238032SpeterR< $+ > $: $1 remove housekeeping <> 65338032Speter 65464562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 65538032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 65638032SpeterR@ $+ , $+ @ $1 : $2 change all "," to ":" 65738032Speter 65838032Speter# localize and dispose of route-based addresses 65964562SgshapiroR@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 66064562Sgshapirodnl',`dnl 66164562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d> 66264562SgshapiroR@ $+ , $+ $2 66364562SgshapiroR@ $+ : $+ $2 66464562Sgshapirodnl') 66538032Speter 66638032Speter# find focus for list syntax 66764562SgshapiroR $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 66838032SpeterR $+ : $* ; $@ $1 : $2; list syntax 66938032Speter 67038032Speter# find focus for @ syntax addresses 67138032SpeterR$+ @ $+ $: $1 < @ $2 > focus on domain 67238032SpeterR$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 67364562SgshapiroR$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 67438032Speter 67538032Speter# do some sanity checking 67638032SpeterR$* < @ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 67738032Speter 67838032Speterifdef(`_NO_UUCP_', `dnl', 67938032Speter`# convert old-style addresses to a domain-based address 68064562SgshapiroR$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 68164562SgshapiroR$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 68264562SgshapiroR$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 68338032Speter') 68438032Speterifdef(`_USE_DECNET_SYNTAX_', 68538032Speter`# convert node::user addresses into a domain-based address 68664562SgshapiroR$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 68764562SgshapiroR$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 68838032Speter', 68938032Speter `dnl') 69038032Speter# if we have % signs, take the rightmost one 69138032SpeterR$* % $* $1 @ $2 First make them all @s. 69238032SpeterR$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 69364562SgshapiroR$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 69438032Speter 69538032Speter# else we must be a local name 69664562SgshapiroR$* $@ $>Canonify2 $1 69738032Speter 69838032Speter 69938032Speter################################################ 70038032Speter### Ruleset 96 -- bottom half of ruleset 3 ### 70138032Speter################################################ 70238032Speter 70364562SgshapiroSCanonify2=96 70438032Speter 70538032Speter# handle special cases for local names 70638032SpeterR$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 70738032SpeterR$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 70838032Speterifdef(`_NO_UUCP_', `dnl', 70938032Speter`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 71064562Sgshapiro 71164562Sgshapiro# check for IPv6 domain literal (save quoted form) 71280785SgshapiroR$* < @ [ IPv6 : $+ ] > $* $: $2 $| $1 < @@ [ $(dequote $2 $) ] > $3 mark IPv6 addr 71380785SgshapiroR$+ $| $* < @@ $=w > $* $: $2 < @ $j . > $4 self-literal 71480785SgshapiroR$+ $| $* < @@ [ $+ ] > $* $@ $2 < @ [ IPv6 : $1 ] > $4 canon IP addr 71564562Sgshapiro 71664562Sgshapiro# check for IPv4 domain literal 71738032SpeterR$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [a.b.c.d] 71838032SpeterR$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 71938032SpeterR$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 72038032Speter 72164562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl 72238032Speter# look up domains in the domain table 72338032SpeterR$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 72438032Speter 72564562Sgshapiroundivert(2)dnl LOCAL_RULE_3 72638032Speter 72764562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl 72838032Speter# handle BITNET mapping 72938032SpeterR$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 73038032Speter 73164562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl 73238032Speter# handle UUCP mapping 73338032SpeterR$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 73438032Speter 73538032Speterifdef(`_NO_UUCP_', `dnl', 73638032Speter`ifdef(`UUCP_RELAY', 73738032Speter`# pass UUCP addresses straight through 73838032SpeterR$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 73938032Speter`# if really UUCP, handle it immediately 74038032Speterifdef(`_CLASS_U_', 74138032Speter`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 74238032Speterifdef(`_CLASS_V_', 74338032Speter`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 74438032Speterifdef(`_CLASS_W_', 74538032Speter`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 74638032Speterifdef(`_CLASS_X_', 74738032Speter`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 74838032Speterifdef(`_CLASS_Y_', 74938032Speter`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 75038032Speter 75138032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl 75238032Speter# try UUCP traffic as a local address 75338032SpeterR$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 75438032SpeterR$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 75538032Speter')') 75664562Sgshapiro# hostnames ending in class P are always canonical 75764562SgshapiroR$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 75864562Sgshapirodnl apply the next rule only for hostnames not in class P 75964562Sgshapirodnl this even works for phrases in class P since . is in class P 76064562Sgshapirodnl which daemon flags are set? 76164562SgshapiroR$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 76264562Sgshapirodnl the other rules in this section only apply if the hostname 76364562Sgshapirodnl does not end in class P hence no further checks are done here 76464562Sgshapirodnl if this ever changes make sure the lookups are "protected" again! 76564562Sgshapiroifdef(`_NO_CANONIFY_', `dnl 76664562Sgshapirodnl do not canonify unless: 76764562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection 76864562Sgshapirodnl with class P is non-empty) 76964562Sgshapirodnl or {daemon_flags} has c set 77064562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify} 77164562SgshapiroR$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 77264562Sgshapiro# pass to name server to make hostname canonical if requested 77364562SgshapiroR$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 77464562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 77564562SgshapiroR$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 77664562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work 77764562SgshapiroR$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 77864562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl 77964562Sgshapirodnl this should only apply to unqualified hostnames 78064562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar 78164562Sgshapirodnl then $- does not work. 78264562Sgshapiro# lookup unqualified hostnames 78364562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 78464562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless: 78564562Sgshapirodnl {daemon_flags} contains CC (do not canonify) 78671345Sgshapirodnl but add a trailing dot to qualified hostnames so other rules will work 78771345Sgshapirodnl should we do this for every hostname: even unqualified? 78871345SgshapiroR$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6 78964562SgshapiroR$* CC $* $| $* $: $3 79038032Speter# pass to name server to make hostname canonical 79164562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 79264562Sgshapirodnl remove {daemon_flags} for other cases 79364562SgshapiroR$* $| $* $: $2 79438032Speter 79538032Speter# local host aliases and pseudo-domains are always canonical 79638032SpeterR$* < @ $=w > $* $: $1 < @ $2 . > $3 79738032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 79838032Speter`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 79938032Speter`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 80064562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 80164562Sgshapirodnl virtual hosts are also canonical 80264562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 80364562Sgshapiro`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 80464562Sgshapiro`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 80564562Sgshapiro`dnl') 80664562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added 80764562Sgshapirodnl by one of the rules before 80838032SpeterR$* < @ $* . . > $* $1 < @ $2 . > $3 80938032Speter 81038032Speter 81138032Speter################################################## 81238032Speter### Ruleset 4 -- Final Output Post-rewriting ### 81338032Speter################################################## 81464562SgshapiroSfinal=4 81538032Speter 81671345SgshapiroR$+ :; <@> $@ $1 : handle <list:;> 81738032SpeterR$* <@> $@ handle <> and list:; 81838032Speter 81938032Speter# strip trailing dot off possibly canonical name 82038032SpeterR$* < @ $+ . > $* $1 < @ $2 > $3 82138032Speter 82264562Sgshapiro# eliminate internal code 82338032SpeterR$* < @ *LOCAL* > $* $1 < @ $j > $2 82438032Speter 82538032Speter# externalize local domain info 82638032SpeterR$* < $+ > $* $1 $2 $3 defocus 82738032SpeterR@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 82838032SpeterR@ $* $@ @ $1 ... and exit 82938032Speter 83038032Speterifdef(`_NO_UUCP_', `dnl', 83138032Speter`# UUCP must always be presented in old form 83238032SpeterR$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 83338032Speter 83438032Speterifdef(`_USE_DECNET_SYNTAX_', 83538032Speter`# put DECnet back in :: form 83638032SpeterR$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 83738032Speter `dnl') 83838032Speter# delete duplicate local names 83938032SpeterR$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 84038032Speter 84138032Speter 84238032Speter 84338032Speter############################################################## 84438032Speter### Ruleset 97 -- recanonicalize and call ruleset zero ### 84538032Speter### (used for recursive calls) ### 84638032Speter############################################################## 84738032Speter 84864562SgshapiroSRecurse=97 84964562SgshapiroR$* $: $>canonify $1 85064562SgshapiroR$* $@ $>parse $1 85138032Speter 85238032Speter 85338032Speter###################################### 85438032Speter### Ruleset 0 -- Parse Address ### 85538032Speter###################################### 85638032Speter 85764562SgshapiroSparse=0 85838032Speter 85938032SpeterR$* $: $>Parse0 $1 initial parsing 86038032SpeterR<@> $#_LOCAL_ $: <@> special case error msgs 86164562SgshapiroR$* $: $>ParseLocal $1 handle local hacks 86238032SpeterR$* $: $>Parse1 $1 final parsing 86338032Speter 86438032Speter# 86538032Speter# Parse0 -- do initial syntax checking and eliminate local addresses. 86638032Speter# This should either return with the (possibly modified) input 86738032Speter# or return with a #error mailer. It should not return with a 86838032Speter# #mailer other than the #error mailer. 86938032Speter# 87038032Speter 87138032SpeterSParse0 87238032SpeterR<@> $@ <@> special case error msgs 87377349SgshapiroR$* : $* ; <@> $#error $@ 5.1.3 $: "CODE553 List:; syntax illegal for recipient addresses" 87464562SgshapiroR@ <@ $* > < @ $1 > catch "@@host" bogosity 87577349SgshapiroR<@ $+> $#error $@ 5.1.3 $: "CODE553 User address required" 87638032SpeterR$* $: <> $1 87738032SpeterR<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 87877349SgshapiroR<> $* <$* : $* > $* $#error $@ 5.1.3 $: "CODE553 Colon illegal in host name part" 87938032SpeterR<> $* $1 88077349SgshapiroR$* < @ . $* > $* $#error $@ 5.1.2 $: "CODE553 Invalid host name" 88177349SgshapiroR$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "CODE553 Invalid host name" 88264562Sgshapirodnl comma only allowed before @; this check is not complete 88377349SgshapiroR$* , $~O $* $#error $@ 5.1.2 $: "CODE553 Invalid route address" 88438032Speter 88538032Speter# now delete the local info -- note $=O to find characters that cause forwarding 88664562SgshapiroR$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 88764562SgshapiroR< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 88838032SpeterR$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 88977349SgshapiroR< @ $+ > $#error $@ 5.1.3 $: "CODE553 User address required" 89064562SgshapiroR$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 89138032SpeterR$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 89277349SgshapiroR< @ *LOCAL* > $#error $@ 5.1.3 $: "CODE553 User address required" 89338032SpeterR$* $=O $* < @ *LOCAL* > 89464562Sgshapiro $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 89538032SpeterR$* < @ *LOCAL* > $: $1 89638032Speter 89738032Speter# 89838032Speter# Parse1 -- the bottom half of ruleset 0. 89938032Speter# 90038032Speter 90138032SpeterSParse1 90264562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 90364562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute} 90464562SgshapiroR$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2>', 90564562Sgshapiro`dnl') 90664562Sgshapiro 90738032Speterifdef(`_MAILER_smtp_', 90838032Speter`# handle numeric address spec 90964562Sgshapirodnl there is no check whether this is really an IP number 91064562SgshapiroR$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 91164562SgshapiroR$* < @ [ $+ ] > $* $1 < @ [ $2 ] : $S > $3 Add smart host to path 91280785SgshapiroR$* < @ [ IPv6 : $+ ] : > $* 91380785Sgshapiro $#_SMTP_ $@ [ $(dequote $2 $) ] $: $1 < @ [IPv6 : $2 ] > $3 no smarthost: send 91464562SgshapiroR$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 91564562SgshapiroR$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 91664562SgshapiroR$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 91738032Speter `dnl') 91838032Speter 91964562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 92038032Speter# handle virtual users 92164562SgshapiroR$+ $: <!> $1 Mark for lookup 92264562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 92364562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 92464562Sgshapiro`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 92564562SgshapiroR<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 92638032SpeterR<@> $+ + $* < @ $* . > 92764562Sgshapiro $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 92838032SpeterR<@> $+ + $* < @ $* . > 92938032Speter $: < $(virtuser $1 @ $3 $@ $1 $: @ $) > $1 + $2 < @ $3 . > 93064562Sgshapirodnl try default entry: @domain 93164562Sgshapirodnl +*@domain 93264562SgshapiroR<@> $+ + $+ < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 93364562Sgshapirodnl @domain if +detail exists 93464562SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 93564562Sgshapirodnl without +detail (or no match) 93638032SpeterR<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 93738032SpeterR<@> $+ $: $1 93864562SgshapiroR<!> $+ $: $1 93964562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 94038032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 94180785Sgshapirodnl this is not a documented option 94280785Sgshapirodnl it performs no looping at all for virtusertable 94377349Sgshapiroifdef(`_NO_VIRTUSER_RECURSION_', 94477349Sgshapiro`R< $+ > $+ < @ $+ > $: $>ParseLocal $>Parse0 $>canonify $1', 94577349Sgshapiro`R< $+ > $+ < @ $+ > $: $>Recurse $1') 94677349Sgshapirodnl', `dnl') 94738032Speter 94838032Speter# short circuit local delivery so forwarded email works 94938032Speterifdef(`_MAILER_usenet_', `dnl 95064562SgshapiroR$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 95166494Sgshapiro 95266494Sgshapiro 95338032Speterifdef(`_STICKY_LOCAL_DOMAIN_', 95438032Speter`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 95564562SgshapiroR< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 95664562Sgshapirodnl $H empty (but @$=w.) 95738032SpeterR< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 95838032SpeterR< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 95964562Sgshapiro`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 96038032SpeterR$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 96138032Speter 96264562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 96338032Speter# not local -- try mailer table lookup 96438032SpeterR$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 96538032SpeterR< $+ . > $* $: < $1 > $2 strip trailing dot 96638032SpeterR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 96764562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 96864562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 96964562SgshapiroR< $+ > $* $: $>Mailertable <$1> $2 try domain', 97038032Speter`dnl') 97164562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)' 97238032Speter 97338032Speterifdef(`_NO_UUCP_', `dnl', 97438032Speter`# resolve remotely connected UUCP links (if any) 97538032Speterifdef(`_CLASS_V_', 97664562Sgshapiro`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 97738032Speter `dnl') 97838032Speterifdef(`_CLASS_W_', 97964562Sgshapiro`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 98038032Speter `dnl') 98138032Speterifdef(`_CLASS_X_', 98264562Sgshapiro`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 98338032Speter `dnl')') 98438032Speter 98538032Speter# resolve fake top level domains by forwarding to other hosts 98638032Speterifdef(`BITNET_RELAY', 98764562Sgshapiro`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 98838032Speter `dnl') 98938032Speterifdef(`DECNET_RELAY', 99064562Sgshapiro`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 99138032Speter `dnl') 99238032Speterifdef(`_MAILER_pop_', 99338032Speter`R$+ < @ POP. > $#pop $: $1 user@POP', 99438032Speter `dnl') 99538032Speterifdef(`_MAILER_fax_', 99638032Speter`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 99738032Speter`ifdef(`FAX_RELAY', 99864562Sgshapiro`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 99938032Speter `dnl')') 100038032Speter 100138032Speterifdef(`UUCP_RELAY', 100238032Speter`# forward non-local UUCP traffic to our UUCP relay 100364562SgshapiroR$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 100438032Speter`ifdef(`_MAILER_uucp_', 100538032Speter`# forward other UUCP traffic straight to UUCP 100638032SpeterR$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 100738032Speter `dnl')') 100838032Speterifdef(`_MAILER_usenet_', ` 100938032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup 101064562SgshapiroR$+ . USENET $#usenet $@ usenet $: $1', 101138032Speter `dnl') 101238032Speter 101338032Speterifdef(`_LOCAL_RULES_', 101438032Speter`# figure out what should stay in our local mail system 101538032Speterundivert(1)', `dnl') 101638032Speter 101738032Speter# pass names that still have a host to a smarthost (if defined) 101864562SgshapiroR$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 101938032Speter 102038032Speter# deal with other remote names 102138032Speterifdef(`_MAILER_smtp_', 102264562Sgshapiro`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 102377349Sgshapiro`R$* < @$* > $* $#error $@ 5.1.2 $: "CODE553 Unrecognized host name " $2') 102438032Speter 102538032Speter# handle locally delivered names 102664562SgshapiroR$=L $#_LOCAL_ $: @ $1 special local names 102738032SpeterR$+ $#_LOCAL_ $: $1 regular local names 102838032Speter 102938032Speter########################################################################### 103038032Speter### Ruleset 5 -- special rewriting after aliases have been expanded ### 103138032Speter########################################################################### 103238032Speter 103364562SgshapiroSLocal_localaddr 103464562SgshapiroSlocaladdr=5 103564562SgshapiroR$+ $: $1 $| $>"Local_localaddr" $1 103664562SgshapiroR$+ $| $#$* $#$2 103764562SgshapiroR$+ $| $* $: $1 103838032Speter 103966494Sgshapiroifdef(`_FFR_5_', ` 104066494Sgshapiro# Preserve host in a macro 104166494SgshapiroR$+ $: $(macro {LocalAddrHost} $) $1 104266494SgshapiroR$+ @ $+ $: $(macro {LocalAddrHost} $@ @ $2 $) $1') 104366494Sgshapiro 104466494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', `', ` 104538032Speter# deal with plussed users so aliases work nicely 104666494SgshapiroR$+ + * $#_LOCAL_ $@ $&h $: $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 104766494SgshapiroR$+ + $* $#_LOCAL_ $@ + $2 $: $1 + *`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') 104866494Sgshapiro') 104938032Speter# prepend an empty "forward host" on the front 105038032SpeterR$+ $: <> $1 105138032Speter 105238032Speterifdef(`LUSER_RELAY', `dnl 105338032Speter# send unrecognized local users to a relay host 105466494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', ` 105566494SgshapiroR< > $+ + $* $: < ? $L > <+ $2> $(user $1 $) look up user+ 105666494SgshapiroR< > $+ $: < ? $L > < > $(user $1 $) look up user 105766494SgshapiroR< ? $* > < $* > $+ <> $: < > $3 $2 found; strip $L 105866494SgshapiroR< ? $* > < $* > $+ $: < $1 > $3 $2 not found', ` 105964562SgshapiroR< > $+ $: < $L > $(user $1 $) look up user 106066494SgshapiroR< $* > $+ <> $: < > $2 found; strip $L')', 106138032Speter`dnl') 106238032Speter 106338032Speter# see if we have a relay or a hub 106438032SpeterR< > $+ $: < $H > $1 try hub 106538032SpeterR< > $+ $: < $R > $1 try relay 106666494Sgshapiroifdef(`_PRESERVE_LOCAL_PLUS_DETAIL_', ` 106766494SgshapiroR< > $+ $@ $1', ` 106864562SgshapiroR< > $+ $: < > < $1 <> $&h > nope, restore +detail 106964562SgshapiroR< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 107064562SgshapiroR< > < $+ <> $* > $: < > < $1 > else discard 107138032SpeterR< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 107266494SgshapiroR< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1`'ifdef(`_FFR_5_', ` $&{LocalAddrHost}') strip the extra + 107338032SpeterR< > < $+ > $@ $1 no +detail 107443730SpeterR$+ $: $1 <> $&h add +detail back in 107543730SpeterR$+ <> + $* $: $1 + $2 check whether +detail 107666494SgshapiroR$+ <> $* $: $1 else discard') 107764562SgshapiroR< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 107864562SgshapiroR< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 107964562SgshapiroR< $- : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 108064562SgshapiroR< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 108138032Speter 108264562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 108338032Speter################################################################### 108438032Speter### Ruleset 90 -- try domain part of mailertable entry ### 108564562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 108638032Speter################################################################### 108738032Speter 108864562SgshapiroSMailertable=90 108964562Sgshapirodnl shift and check 109064562Sgshapirodnl %2 is not documented in cf/README 109138032SpeterR$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 109264562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 109364562SgshapiroR$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 109464562SgshapiroR$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 109564562Sgshapirodnl is $2 always empty? 109638032SpeterR$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 109764562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 109864562Sgshapirodnl return full address 109938032SpeterR< $* > $* $@ $2 no mailertable match', 110038032Speter`dnl') 110138032Speter 110238032Speter################################################################### 110338032Speter### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 110464562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest 110564562Sgshapirodnl <> address -> address 110664562Sgshapirodnl <error:d.s.n:text> -> error 110764562Sgshapirodnl <error:text> -> error 110864562Sgshapirodnl <mailer:user@host> lp<@domain>rest -> mailer host user 110964562Sgshapirodnl <mailer:host> address -> mailer host address 111064562Sgshapirodnl <localdomain> address -> address 111180785Sgshapirodnl <[IPv6:number]> address -> relay number address 111264562Sgshapirodnl <host> address -> relay host address 111338032Speter################################################################### 111438032Speter 111564562SgshapiroSMailerToTriple=95 111638032SpeterR< > $* $@ $1 strip off null relay 111764562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 111838032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 111938032SpeterR< local : $* > $* $>CanonLocal < $1 > $2 112038032SpeterR< $- : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 112138032SpeterR< $- : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 112238032SpeterR< $=w > $* $@ $2 delete local host 112380785SgshapiroR< [ IPv6 : $+ ] > $* $#_RELAY_ $@ $(dequote $1 $) $: $2 use unqualified mailer 112438032SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 112538032Speter 112638032Speter################################################################### 112738032Speter### Ruleset CanonLocal -- canonify local: syntax ### 112864562Sgshapirodnl input: <user> address 112964562Sgshapirodnl <x> <@host> : rest -> Recurse rest 113064562Sgshapirodnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 113164562Sgshapirodnl <> user <@host> rest -> local user@host user 113264562Sgshapirodnl <> user -> local user user 113364562Sgshapirodnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 113464562Sgshapirodnl <user> lp <@host> rest -> local lp@host user 113564562Sgshapirodnl <user> lp -> local lp user 113638032Speter################################################################### 113738032Speter 113838032SpeterSCanonLocal 113943730Speter# strip local host from routed addresses 114064562SgshapiroR< $* > < @ $+ > : $+ $@ $>Recurse $3 114164562SgshapiroR< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 114243730Speter 114338032Speter# strip trailing dot from any host name that may appear 114438032SpeterR< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 114538032Speter 114638032Speter# handle local: syntax -- use old user, either with or without host 114738032SpeterR< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 114838032SpeterR< > $+ $#_LOCAL_ $@ $1 $: $1 114938032Speter 115038032Speter# handle local:user@host syntax -- ignore host part 115138032SpeterR< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 115238032Speter 115338032Speter# handle local:user syntax 115438032SpeterR< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 115538032SpeterR< $+ > $* $#_LOCAL_ $@ $2 $: $1 115638032Speter 115738032Speter################################################################### 115838032Speter### Ruleset 93 -- convert header names to masqueraded form ### 115938032Speter################################################################### 116038032Speter 116164562SgshapiroSMasqHdr=93 116238032Speter 116364562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 116438032Speter# handle generics database 116538032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_', 116664562Sgshapirodnl if generics should be applied add a @ as mark 116738032Speter`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 116838032Speter`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 116938032SpeterR$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 117064562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @ 117164562Sgshapirodnl ignore the first case for now 117264562Sgshapirodnl if it has the mark lookup full address 117364562SgshapiroR< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 117464562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain> 117564562Sgshapirodnl no match, try user+detail@domain 117664562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 117764562Sgshapiro $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 117864562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 117964562Sgshapiro $: < $(generics $1@$3 $: $) > $4 < @ $5 > 118064562Sgshapirodnl no match, remove mark 118164562SgshapiroR<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 118264562Sgshapirodnl no match, try @domain for exceptions 118364562SgshapiroR< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 118464562Sgshapirodnl workspace: ... or <match> user <@domain> 118564562Sgshapirodnl no match, try local part 118638032SpeterR< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 118764562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 118864562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 118964562SgshapiroR< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 119064562SgshapiroR< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 119138032SpeterR< > $* $: $1 not found', 119238032Speter`dnl') 119338032Speter 119464562Sgshapiro# do not masquerade anything in class N 119564562SgshapiroR$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 119664562Sgshapiro 119738032Speter# special case the users that should be exposed 119838032SpeterR$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 119938032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 120038032Speter`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 120138032Speter`R$=E < @ $=M . > $@ $1 < @ $2 . >') 120238032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 120338032Speter`R$=E < @ $=w . > $@ $1 < @ $2 . >') 120438032Speter 120538032Speter# handle domain-specific masquerading 120638032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 120738032Speter`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 120838032Speter`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 120938032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 121038032Speter`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 121138032SpeterR$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 121238032SpeterR$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 121338032SpeterR$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 121438032Speter 121538032Speter################################################################### 121638032Speter### Ruleset 94 -- convert envelope names to masqueraded form ### 121738032Speter################################################################### 121838032Speter 121964562SgshapiroSMasqEnv=94 122038032Speterifdef(`_MASQUERADE_ENVELOPE_', 122164562Sgshapiro`R$+ $@ $>MasqHdr $1', 122238032Speter`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 122338032Speter 122438032Speter################################################################### 122538032Speter### Ruleset 98 -- local part of ruleset zero (can be null) ### 122638032Speter################################################################### 122738032Speter 122864562SgshapiroSParseLocal=98 122964562Sgshapiroundivert(3)dnl LOCAL_RULE_0 123038032Speter 123164562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 123264562SgshapiroSLDAPExpand 123364562Sgshapiro# do the LDAP lookups 123464562SgshapiroR<$+><$+> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> 123564562Sgshapiro 123664562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost, 123764562Sgshapiro# return the new mailRoutingAddress 123864562SgshapiroR< $+ > < $=w > < $+ > < $+ > $@ $>Parse0 $>canonify $1 123964562SgshapiroR< $+ > < > < $+ > < $+ > $@ $>Parse0 $>canonify $1 124064562Sgshapiro 124164562Sgshapiro# if mailRoutingAddress and non-local mailHost, 124264562Sgshapiro# relay to mailHost with new mailRoutingAddress 124364562SgshapiroR< $+ > < $+ > < $+ > < $+ > $#_RELAY_ $@ $2 $: $>canonify $1 124464562Sgshapiro 124564562Sgshapiro# if no mailRoutingAddress and local mailHost, 124664562Sgshapiro# return original address 124764562SgshapiroR< > < $=w > <$+> <$+> $@ $2 124864562Sgshapiro 124964562Sgshapiro# if no mailRoutingAddress and non-local mailHost, 125064562Sgshapiro# relay to mailHost with original address 125164562SgshapiroR< > < $+ > <$+> <$+> $#_RELAY_ $@ $1 $: $2 125264562Sgshapiro 125364562Sgshapiro# if no mailRoutingAddress and no mailHost, 125464562Sgshapiro# try @domain 125564562SgshapiroR< > < > <$+> <$+ @ $+> $@ $>LDAPExpand <$1> <@ $3> 125664562Sgshapiro 125764562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt, 125864562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 125964562Sgshapiro# user does not exist 126064562SgshapiroR< > < > <$+> <@ $+> $#error $@ nouser $: "550 User unknown"', 126164562Sgshapiro`dnl 126264562Sgshapiro# return the original address 126364562SgshapiroR< > < > <$+> <@ $+> $@ $1')', 126464562Sgshapiro`dnl') 126564562Sgshapiro 126664562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 126764562Sgshapiro')') 126864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 126938032Speter###################################################################### 127038032Speter### LookUpDomain -- search for domain in access database 127138032Speter### 127238032Speter### Parameters: 127338032Speter### <$1> -- key (domain name) 127438032Speter### <$2> -- default (what to return if not found in db) 127564562Sgshapirodnl must not be empty 127638032Speter### <$3> -- passthru (additional data passed unchanged through) 127764562Sgshapiro### <$4> -- mark (must be <(!|+) single-token>) 127864562Sgshapiro### ! does lookup only with tag 127964562Sgshapiro### + does lookup with and without tag 128064562Sgshapirodnl returns: <default> <passthru> 128164562Sgshapirodnl <result> <passthru> 128238032Speter###################################################################### 128338032Speter 128438032SpeterSLookUpDomain 128564562Sgshapirodnl remove IPv6 mark and dequote address 128664562Sgshapirodnl it is a bit ugly because it is checked on each "iteration" 128780785SgshapiroR<[IPv6 : $+]> <$+> <$*> <$*> $: <[$(dequote $1 $)]> <$2> <$3> <$4> 128864562Sgshapirodnl workspace <key> <default> <passthru> <mark> 128964562Sgshapirodnl lookup with tag (in front, no delimiter here) 129064562SgshapiroR<$*> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5> 129164562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 129264562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest 129364562SgshapiroR<?> <$+.$+> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4> <$5 $6>', `dnl') 129464562Sgshapirodnl lookup without tag? 129564562SgshapiroR<?> <$+> <$+> <$*> <+ $*> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4> 129664562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest 129764562SgshapiroR<?> <$+.$+> <$+> <$*> <+ $*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <$4> <+ $5>', `dnl') 129864562Sgshapirodnl lookup IP address (no check is done whether it is an IP number!) 129964562SgshapiroR<?> <[$+.$-]> <$+> <$*> <$*> $@ $>LookUpDomain <[$1]> <$3> <$4> <$5> 130064562Sgshapirodnl lookup IPv6 address 130171345SgshapiroR<?> <[$+::$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5> 130264562SgshapiroR<?> <[$+:$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5> 130364562Sgshapirodnl not found, but subdomain: try again 130464562SgshapiroR<?> <$+.$+> <$+> <$*> <$*> $@ $>LookUpDomain <$2> <$3> <$4> <$5> 130564562Sgshapirodnl not found, no subdomain: return default 130664562SgshapiroR<?> <$+> <$+> <$*> <$*> $@ <$2> <$3> 130764562Sgshapirodnl return result of lookup 130864562SgshapiroR<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4> 130938032Speter 131038032Speter###################################################################### 131138032Speter### LookUpAddress -- search for host address in access database 131238032Speter### 131338032Speter### Parameters: 131438032Speter### <$1> -- key (dot quadded host address) 131538032Speter### <$2> -- default (what to return if not found in db) 131664562Sgshapirodnl must not be empty 131738032Speter### <$3> -- passthru (additional data passed through) 131864562Sgshapiro### <$4> -- mark (must be <(!|+) single-token>) 131964562Sgshapiro### ! does lookup only with tag 132064562Sgshapiro### + does lookup with and without tag 132164562Sgshapirodnl returns: <default> <passthru> 132264562Sgshapirodnl <result> <passthru> 132338032Speter###################################################################### 132438032Speter 132538032SpeterSLookUpAddress 132664562Sgshapirodnl lookup with tag 132764562SgshapiroR<$+> <$+> <$*> <$- $+> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5> 132864562Sgshapirodnl lookup without tag 132964562SgshapiroR<?> <$+> <$+> <$*> <+ $+> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4> 133064562Sgshapirodnl no match; IPv6: remove last part 133171345SgshapiroR<?> <$+::$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 133264562SgshapiroR<?> <$+:$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 133364562Sgshapirodnl no match; IPv4: remove last part 133464562SgshapiroR<?> <$+.$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 133564562Sgshapirodnl no match: return default 133664562SgshapiroR<?> <$+> <$+> <$*> <$*> $@ <$2> <$3> 133764562Sgshapirodnl match: return result 133864562SgshapiroR<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4>', 133938032Speter`dnl') 134038032Speter 134138032Speter###################################################################### 134242575Speter### CanonAddr -- Convert an address into a standard form for 134342575Speter### relay checking. Route address syntax is 134442575Speter### crudely converted into a %-hack address. 134542575Speter### 134642575Speter### Parameters: 134742575Speter### $1 -- full recipient address 134842575Speter### 134942575Speter### Returns: 135042575Speter### parsed address, not in source route form 135164562Sgshapirodnl user%host%host<@domain> 135264562Sgshapirodnl host!user<@domain> 135342575Speter###################################################################### 135442575Speter 135542575SpeterSCanonAddr 135664562SgshapiroR$* $: $>Parse0 $>canonify $1 make domain canonical 135764562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 135842575SpeterR< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 135942575SpeterR$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 136042575SpeterR$* < @ $+ > : $* $3 $1 < @ $2 > 136164562Sgshapirodnl') 136242575Speter 136342575Speter###################################################################### 136438032Speter### ParseRecipient -- Strip off hosts in $=R as well as possibly 136538032Speter### $* $=m or the access database. 136638032Speter### Check user portion for host separators. 136738032Speter### 136838032Speter### Parameters: 136938032Speter### $1 -- full recipient address 137038032Speter### 137138032Speter### Returns: 137238032Speter### parsed, non-local-relaying address 137338032Speter###################################################################### 137438032Speter 137538032SpeterSParseRecipient 137664562Sgshapirodnl mark and canonify address 137742575SpeterR$* $: <?> $>CanonAddr $1 137864562Sgshapirodnl workspace: <?> localpart<@domain[.]> 137942575SpeterR<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 138064562Sgshapirodnl workspace: <?> localpart<@domain> 138142575SpeterR<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 138238032Speter 138338032Speter# if no $=O character, no host in the user portion, we are done 138442575SpeterR<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 138564562Sgshapirodnl no $=O in localpart: return 138642575SpeterR<?> $* $@ $1 138738032Speter 138864562Sgshapirodnl workspace: <?> localpart<@domain>, where localpart contains $=O 138964562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY> 139038032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 139138032Speter# if we relay, check username portion for user%host so host can be checked also 139242575SpeterR<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 139342575Speter 139442575Speterifdef(`_RELAY_MX_SERVED_', `dnl 139564562Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain? 139642575SpeterR<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 139742575SpeterR<MX> < : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 139864562Sgshapirodnl yes: mark it as <RELAY> 139942575SpeterR<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 140064562Sgshapirodnl no: put old <NO> mark back 140142575SpeterR<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 140242575Speter 140364562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 140464562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 140538032Speterifdef(`_RELAY_HOSTS_ONLY_', 140642575Speter`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 140764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 140864562SgshapiroR<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 140942575SpeterR<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 141042575Speter`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 141164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 141264562SgshapiroR<NO> $* < @ $+ > $: $>LookUpDomain <$2> <NO> <$1 < @ $2 >> <+To> 141342575SpeterR<$+> <$+> $: <$1> $2',`dnl')') 141438032Speter 141564562Sgshapiro 141642575SpeterR<RELAY> $* < @ $* > $@ $>ParseRecipient $1 141742575SpeterR<$-> $* $@ $2 141842575Speter 141964562Sgshapiro 142038032Speter###################################################################### 142138032Speter### check_relay -- check hostname/address on SMTP startup 142238032Speter###################################################################### 142338032Speter 142438032SpeterSLocal_check_relay 142564562SgshapiroScheck`'_U_`'relay 142638032SpeterR$* $: $1 $| $>"Local_check_relay" $1 142738032SpeterR$* $| $* $| $#$* $#$3 142838032SpeterR$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 142938032Speter 143038032SpeterSBasic_check_relay 143138032Speter# check for deferred delivery mode 143238032SpeterR$* $: < ${deliveryMode} > $1 143338032SpeterR< d > $* $@ deferred 143438032SpeterR< $* > $* $: $2 143538032Speter 143664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 143766494Sgshapirodnl workspace: {client_name} $| {client_addr} 143864562SgshapiroR$+ $| $+ $: $>LookUpDomain < $1 > <?> < $2 > <+Connect> 143966494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 144064562SgshapiroR<?> <$+> $: $>LookUpAddress < $1 > <?> < $1 > <+Connect> no: another lookup 144166494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 144264562SgshapiroR<?> < $+ > $: $1 found nothing 144366494Sgshapirodnl workspace: <result-of-lookup> <{client_addr}> 144466494Sgshapirodnl or {client_addr} 144566494SgshapiroR<$={Accept}> < $* > $@ $1 return value of lookup 144664562SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 144738032SpeterR<DISCARD> $* $#discard $: discard 144864562Sgshapirodnl error tag 144966494SgshapiroR<ERROR:$-.$-.$-:$+> <$*> $#error $@ $1.$2.$3 $: $4 145066494SgshapiroR<ERROR:$+> <$*> $#error $: $1 145164562Sgshapirodnl generic error from access map 145266494SgshapiroR<$+> <$*> $#error $: $1', `dnl') 145338032Speter 145464562Sgshapiroifdef(`_RBL_',`dnl 145564562Sgshapiro# DNS based IP address spam list 145638032SpeterR$* $: $&{client_addr} 145764562SgshapiroR::ffff:$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 145864562SgshapiroR$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 145964562SgshapiroR<?>OK $: OKSOFAR 146064562SgshapiroR<?>$+ $#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"', 146138032Speter`dnl') 146264562Sgshapiroundivert(8) 146338032Speter 146438032Speter###################################################################### 146538032Speter### check_mail -- check SMTP ``MAIL FROM:'' command argument 146638032Speter###################################################################### 146738032Speter 146838032SpeterSLocal_check_mail 146964562SgshapiroScheck`'_U_`'mail 147038032SpeterR$* $: $1 $| $>"Local_check_mail" $1 147138032SpeterR$* $| $#$* $#$2 147238032SpeterR$* $| $* $@ $>"Basic_check_mail" $1 147338032Speter 147438032SpeterSBasic_check_mail 147538032Speter# check for deferred delivery mode 147638032SpeterR$* $: < ${deliveryMode} > $1 147738032SpeterR< d > $* $@ deferred 147838032SpeterR< $* > $* $: $2 147938032Speter 148064562Sgshapiro# authenticated? 148164562Sgshapirodnl done first: we can require authentication for every mail transaction 148264562Sgshapirodnl workspace: address as given by MAIL FROM: (sender) 148364562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 148464562SgshapiroR$* $| $#$+ $#$2 148564562Sgshapirodnl undo damage: remove result of tls_client call 148664562SgshapiroR$* $| $* $: $1 148738032Speter 148864562Sgshapirodnl workspace: address as given by MAIL FROM: 148964562SgshapiroR<> $@ <OK> we MUST accept <> (RFC 1123) 149038032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 149164562Sgshapirodnl do some additional checks 149264562Sgshapirodnl no user@host 149364562Sgshapirodnl no user@localhost (if nonlocal sender) 149464562Sgshapirodnl this is a pretty simple canonification, it will not catch every case 149564562Sgshapirodnl just make sure the address has <> around it (which is required by 149664562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...) 149764562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will 149864562Sgshapirodnl not be modified by host lookups. 149964562SgshapiroR$+ $: <?> $1 150064562SgshapiroR<?><$+> $: <@> <$1> 150164562SgshapiroR<?>$+ $: <@> <$1> 150264562Sgshapirodnl workspace: <@> <address> 150364562Sgshapirodnl prepend daemon_flags 150464562SgshapiroR$* $: $&{daemon_flags} $| $1 150564562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 150664562Sgshapirodnl do not allow these at all or only from local systems? 150764562SgshapiroR$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 150864562Sgshapirodnl accept unqualified sender: change mark to avoid test 150964562SgshapiroR$* u $* $| <@> < $* > $: <?> < $3 > 151064562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 151164562Sgshapirodnl or: <? ${client_name} > <address> 151264562Sgshapirodnl or: <?> <address> 151364562Sgshapirodnl remove daemon_flags 151464562SgshapiroR$* $| $* $: $2 151538032Speter# handle case of @localhost on address 151664562SgshapiroR<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 151764562SgshapiroR<@> < $* @ [127.0.0.1] > 151864562Sgshapiro $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 151964562SgshapiroR<@> < $* @ localhost.$m > 152064562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.$m > 152138032Speterifdef(`_NO_UUCP_', `dnl', 152264562Sgshapiro`R<@> < $* @ localhost.UUCP > 152364562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 152464562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 152564562Sgshapirodnl or: <@> <address> 152664562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 152764562SgshapiroR<@> $* $: $1 no localhost as domain 152864562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 152964562Sgshapirodnl or: <address> 153064562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 153164562SgshapiroR<? $=w> $* $: $2 local client: ok 153277349SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "CODE553 Real domain name required for sender address" 153364562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 153464562SgshapiroR<?> $* $: $1') 153564562Sgshapirodnl workspace: address (or <address>) 153664562SgshapiroR$* $: <?> $>CanonAddr $1 canonify sender address and mark it 153764562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 153864562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed 153964562SgshapiroR<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 154064562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 154164562SgshapiroR<?> $* < @ $* $=P > $: <OK> $1 < @ $2 $3 > 154264562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ? or OK 154364562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 154464562Sgshapiro`R<?> $* < @ $+ > $: <OK> $1 < @ $2 > ... unresolvable OK', 154564562Sgshapiro`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 154664562SgshapiroR<? $* <$->> $* < @ $+ > 154764562Sgshapiro $: <$2> $3 < @ $4 >') 154864562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ?, OK, PERM, TEMP 154964562Sgshapirodnl mark is ? iff the address is user (wo @domain) 155038032Speter 155164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 155264562Sgshapiro# check sender address: user@address, user@, address 155364562Sgshapirodnl should we remove +ext from user? 155464562Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, OK, PERM, TEMP 155564562SgshapiroR<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <H:$3> 155664562SgshapiroR<$+> $+ $: @<$1> <$2> $| <U:$2@> 155764562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 155864562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 155964562Sgshapirodnl will only return user<@domain when "reversing" the args 156064562SgshapiroR@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+From> $| <$3> <> 156164562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result> 156264562SgshapiroR<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 156364562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress> 156438032Speter# retransform for further use 156564562Sgshapirodnl required form: 156664562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress 156764562SgshapiroR<?> <$+> <$*> $: <$1> $2 no match 156864562SgshapiroR<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 156964562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress 157064562Sgshapirodnl mark is ? iff the address is user (wo @domain) 157138032Speter 157238032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 157338032Speter# handle case of no @domain on address 157464562Sgshapirodnl prepend daemon_flags 157564562SgshapiroR<?> $* $: $&{daemon_flags} $| <?> $1 157664562Sgshapirodnl accept unqualified sender: change mark to avoid test 157764562SgshapiroR$* u $* $| <?> $* $: <OK> $3 157864562Sgshapirodnl remove daemon_flags 157964562SgshapiroR$* $| $* $: $2 158038032SpeterR<?> $* $: < ? $&{client_name} > $1 158138032SpeterR<?> $* $@ <OK> ...local unqualed ok 158277349SgshapiroR<? $+> $* $#error $@ 5.5.4 $: "CODE553 Domain name required for sender address " $&f 158338032Speter ...remote is not') 158438032Speter# check results 158564562SgshapiroR<?> $* $: @ $1 mark address: nothing known about it 158638032SpeterR<OK> $* $@ <OK> 158764562SgshapiroR<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 158877349SgshapiroR<PERM> $* $#error $@ 5.1.8 $: "CODE553 Domain of sender address " $&f " does not exist" 158964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 159064562SgshapiroR<$={Accept}> $* $# $1 159138032SpeterR<DISCARD> $* $#discard $: discard 159264562SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 159364562Sgshapirodnl error tag 159464562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 159564562SgshapiroR<ERROR:$+> $* $#error $: $1 159664562Sgshapirodnl generic error from access map 159764562SgshapiroR<$+> $* $#error $: $1 error from access db', 159838032Speter`dnl') 159938032Speter 160038032Speter###################################################################### 160138032Speter### check_rcpt -- check SMTP ``RCPT TO:'' command argument 160238032Speter###################################################################### 160338032Speter 160438032SpeterSLocal_check_rcpt 160564562SgshapiroScheck`'_U_`'rcpt 160638032SpeterR$* $: $1 $| $>"Local_check_rcpt" $1 160738032SpeterR$* $| $#$* $#$2 160838032SpeterR$* $| $* $@ $>"Basic_check_rcpt" $1 160938032Speter 161038032SpeterSBasic_check_rcpt 161138032Speter# check for deferred delivery mode 161238032SpeterR$* $: < ${deliveryMode} > $1 161338032SpeterR< d > $* $@ deferred 161438032SpeterR< $* > $* $: $2 161538032Speter 161664562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 161764562Sgshapiro# require qualified recipient? 161864562SgshapiroR$+ $: <?> $1 161964562SgshapiroR<?><$+> $: <@> <$1> 162064562SgshapiroR<?>$+ $: <@> <$1> 162164562Sgshapirodnl prepend daemon_flags 162264562SgshapiroR$* $: $&{daemon_flags} $| $1 162364562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 162464562Sgshapirodnl do not allow these at all or only from local systems? 162564562SgshapiroR$* r $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 162664562SgshapiroR<?> < $* > $: <$1> 162764562SgshapiroR<? $=w> < $* > $: <$1> 162864562SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "553 Domain name required" 162964562Sgshapirodnl remove daemon_flags for other cases 163064562SgshapiroR$* $| <@> $* $: $2', `dnl') 163164562Sgshapiro 163238032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl 163342575SpeterR$* $: $>CanonAddr $1 163438032SpeterR$* < @ $* . > $1 < @ $2 > strip trailing dots', 163538032Speter`R$* $: $>ParseRecipient $1 strip relayable hosts') 163638032Speter 163742575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl 163842575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl 163942575Speter# unlimited bestmx 164042575SpeterR$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 164142575Speter`dnl 164242575Speter# limit bestmx to $=B 164343730SpeterR$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 164464562SgshapiroR$* $=O $* < @ $* @@ $=w . > $* $@ $>"Basic_check_rcpt" $1 $2 $3 164542575SpeterR$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 164642575SpeterR$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 164742575Speter 164838032Speterifdef(`_BLACKLIST_RCPT_',`dnl 164964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 165038032Speter# blacklist local users or any host from receiving mail 165138032SpeterR$* $: <?> $1 165264562Sgshapirodnl user is now tagged with @ to be consistent with check_mail 165364562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user) 165464562SgshapiroR<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <H:$2> 165564562SgshapiroR<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <H:$2> 165664562SgshapiroR<?> $+ $: <> <$1> $| <U:$1@> 165764562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 165864562Sgshapirodnl will only return user<@domain when "reversing" the args 165964562SgshapiroR<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+To> $| <$2> <> 166064562SgshapiroR<@> <$*> $| <$*> $: <$2> <$1> reverse result 166164562SgshapiroR<?> <$*> $: @ $1 mark address as no match 166264562SgshapiroR<$={Accept}> <$*> $: @ $2 mark address as no match 166364562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 166464562Sgshapirodnl we have to filter these because otherwise they would be interpreted 166564562Sgshapirodnl as generic error message... 166664562Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 166764562Sgshapirodnl that would make a lot of things easier. 166864562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)? 166964562SgshapiroR<$={SpamTag}> <$*> $: @ $2 mark address as no match') 167038032SpeterR<REJECT> $* $#error $@ 5.2.1 $: "550 Mailbox disabled for this recipient" 167164562SgshapiroR<DISCARD> $* $#discard $: discard 167264562Sgshapirodnl error tag 167364562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 167464562SgshapiroR<ERROR:$+> $* $#error $: $1 167564562Sgshapirodnl generic error from access map 167664562SgshapiroR<$+> $* $#error $: $1 error from access db 167764562SgshapiroR@ $* $1 remove mark', `dnl')', `dnl') 167838032Speter 167964562Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)') 168064562Sgshapiro# authenticated? 168164562Sgshapirodnl do this unconditionally? this requires to manage CAs carefully 168264562Sgshapirodnl just because someone has a CERT signed by a "trusted" CA 168364562Sgshapirodnl does not mean we want to allow relaying for her, 168464562Sgshapirodnl either use a subroutine or provide something more sophisticated 168564562Sgshapirodnl this could for example check the DN (maybe an access map lookup) 168664562SgshapiroR$* $: $1 $| $>RelayAuth $1 $| $&{verify} client authenticated? 168764562SgshapiroR$* $| $# $+ $# $2 error/ok? 168864562SgshapiroR$* $| $* $: $1 no 168964562Sgshapiro 169064562Sgshapiro# authenticated by a trusted mechanism? 169164562SgshapiroR$* $: $1 $| $&{auth_type} 169264562Sgshapirodnl empty ${auth_type}? 169364562SgshapiroR$* $| $: $1 169464562Sgshapirodnl mechanism ${auth_type} accepted? 169564562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below 169664562SgshapiroR$* $| $={TrustAuthMech} $# RELAYAUTH 169764562Sgshapirodnl undo addition of ${auth_type} 169864562SgshapiroR$* $| $* $: $1 169971345Sgshapirodnl workspace: localpart<@domain> | localpart 170064562Sgshapiroifelse(defn(`_NO_UUCP_'), `r', 170171345Sgshapiro`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH > 170271345SgshapiroR$* ! $* $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 170338032Speter# anything terminating locally is ok 170438032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 170564562SgshapiroR$+ < @ $* $=m > $@ RELAYTO', `dnl') 170664562SgshapiroR$+ < @ $=w > $@ RELAYTO 170738032Speterifdef(`_RELAY_HOSTS_ONLY_', 170864562Sgshapiro`R$+ < @ $=R > $@ RELAYTO 170964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 171064562SgshapiroR$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 171164562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 171264562SgshapiroR<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 171364562Sgshapiro`R$+ < @ $* $=R > $@ RELAYTO 171464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 171564562SgshapiroR$+ < @ $+ > $: $>LookUpDomain <$2> <?> <$1 < @ $2 >> <+To>',`dnl')') 171664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 171764562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 171864562SgshapiroR<RELAY> $* $@ RELAYTO 171938032SpeterR<$*> <$*> $: $2',`dnl') 172038032Speter 172164562Sgshapiro 172238032Speterifdef(`_RELAY_MX_SERVED_', `dnl 172338032Speter# allow relaying for hosts which we MX serve 172464562SgshapiroR$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 172564562Sgshapirodnl this must not necessarily happen if the client is checked first... 172638032SpeterR< : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 172764562SgshapiroR<$* : $=w . : $*> $* $@ RELAYTO 172842575SpeterR< : $* : > $* $: $2', 172938032Speter`dnl') 173038032Speter 173138032Speter# check for local user (i.e. unqualified address) 173238032SpeterR$* $: <?> $1 173342575SpeterR<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 173438032Speter# local user is ok 173564562Sgshapirodnl is it really? the standard requires user@domain, not just user 173664562Sgshapirodnl but we should accept it anyway (maybe making it an option: 173764562Sgshapirodnl RequireFQDN ?) 173864562Sgshapirodnl postmaster must be accepted without domain (DRUMS) 173964562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 174064562SgshapiroR<?> postmaster $@ TOPOSTMASTER 174164562Sgshapiro# require qualified recipient? 174264562Sgshapirodnl prepend daemon_flags 174364562SgshapiroR<?> $+ $: $&{daemon_flags} $| <?> $1 174464562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart 174564562Sgshapirodnl do not allow these at all or only from local systems? 174664562Sgshapirodnl r flag? add client_name 174764562SgshapiroR$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 174864562Sgshapirodnl no r flag: relay to local user (only local part) 174964562Sgshapiro# no qualified recipient required 175064562SgshapiroR$* $| <?> $+ $@ RELAYTOLOCAL 175164562Sgshapirodnl client_name is empty 175264562SgshapiroR<?> <?> $+ $@ RELAYTOLOCAL 175364562Sgshapirodnl client_name is local 175464562SgshapiroR<? $=w> <?> $+ $@ RELAYTOLOCAL 175564562Sgshapirodnl client_name is not local 175664562SgshapiroR<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 175764562Sgshapirodnl no qualified recipient required 175864562SgshapiroR<?> $+ $@ RELAYTOLOCAL') 175964562Sgshapirodnl it is a remote user: remove mark and then check client 176038032SpeterR<$+> $* $: $2 176164562Sgshapirodnl currently the recipient address is not used below 176238032Speter 176338032Speter# anything originating locally is ok 176464562Sgshapiro# check IP address 176564562SgshapiroR$* $: $&{client_addr} 176664562SgshapiroR$@ $@ RELAYFROM originated locally 176764562SgshapiroR0 $@ RELAYFROM originated locally 176864562SgshapiroR$=R $* $@ RELAYFROM relayable IP address 176964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 177064562SgshapiroR$* $: $>LookUpAddress <$1> <?> <$1> <+Connect> 177164562SgshapiroR<RELAY> $* $@ RELAYFROM relayable IP address 177264562SgshapiroR<$*> <$*> $: $2', `dnl') 177364562SgshapiroR$* $: [ $1 ] put brackets around it... 177464562SgshapiroR$=w $@ RELAYFROM ... and see if it is local 177564562Sgshapiro 177664562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 177764562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 177864562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl 177964562Sgshapirodnl input: {client_addr} or something "broken" 178064562Sgshapirodnl just throw the input away; we do not need it. 178164562Sgshapiro# check whether FROM is allowed to use system as relay 178264562SgshapiroR$* $: <?> $>CanonAddr $&f 178364562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl 178464562Sgshapiro# check whether local FROM is ok 178564562SgshapiroR<?> $+ < @ $=w . > $@ RELAYFROMMAIL FROM local', `dnl') 178664562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl 178764562SgshapiroR<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 178864562SgshapiroR<?> $+ < @ $+ > $: $1 < @ $2 > $| $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<H:$2>') <> 178964562SgshapiroR$* <RELAY> $@ RELAYFROMMAIL RELAY FROM sender ok', `dnl 179064562Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', `errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 179164562Sgshapiro')', 179264562Sgshapiro`dnl') 179364562Sgshapirodnl')', `dnl') 179464562Sgshapiro 179564562Sgshapiro# check client name: first: did it resolve? 179664562Sgshapirodnl input: ignored 179764562SgshapiroR$* $: < $&{client_resolve} > 179864562SgshapiroR<TEMP> $#error $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 179964562SgshapiroR<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 180064562SgshapiroR<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 180164562Sgshapirodnl ${client_resolve} should be OK, so go ahead 180238032SpeterR$* $: <?> $&{client_name} 180338032Speter# pass to name server to make hostname canonical 180464562SgshapiroR<?> $* $~P $:<?> $[ $1 $2 $] 180564562SgshapiroR$* . $1 strip trailing dots 180664562Sgshapirodnl should not be necessary since it has been done for client_addr already 180764562SgshapiroR<?> $@ RELAYFROM 180838032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 180964562SgshapiroR<?> $* $=m $@ RELAYFROM', `dnl') 181064562SgshapiroR<?> $=w $@ RELAYFROM 181138032Speterifdef(`_RELAY_HOSTS_ONLY_', 181264562Sgshapiro`R<?> $=R $@ RELAYFROM 181364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 181464562SgshapiroR<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 181564562SgshapiroR<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 181664562Sgshapiro`R<?> $* $=R $@ RELAYFROM 181764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 181864562SgshapiroR<?> $* $: $>LookUpDomain <$1> <?> <$1> <+Connect>',`dnl')') 181964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 182064562SgshapiroR<RELAY> $* $@ RELAYFROM 182138032SpeterR<$*> <$*> $: $2',`dnl') 182238032Speter 182364562Sgshapiro# anything else is bogus 182464562SgshapiroR$* $#error $@ 5.7.1 $: confRELAY_MSG 182564562Sgshapirodivert(0) 182664562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 182764562Sgshapiro# turn a canonical address in the form user<@domain> 182864562Sgshapiro# qualify unqual. addresses with $j 182964562Sgshapirodnl it might have been only user (without <@domain>) 183064562SgshapiroSFullAddr 183164562SgshapiroR$* <@ $+ . > $1 <@ $2 > 183264562SgshapiroR$* <@ $* > $@ $1 <@ $2 > 183364562SgshapiroR$+ $@ $1 <@ $j > 183438032Speter 183564562Sgshapiro# call all necessary rulesets 183664562SgshapiroScheck_rcpt 183764562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset 183864562Sgshapirodnl which is the correct DSN code? 183964562Sgshapiro# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 184064562SgshapiroR$+ $: $1 $| $>checkrcpt $1 184164562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 184264562SgshapiroR$+ $| $#$* $#$2 184364562SgshapiroR$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 184464562Sgshapiroifdef(`_SPAM_FH_', 184564562Sgshapiro`dnl lookup user@ and user@address 184664562Sgshapiroifdef(`_ACCESS_TABLE_', `', 184764562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 184864562Sgshapiro')')dnl 184964562Sgshapirodnl one of the next two rules is supposed to match 185064562Sgshapirodnl this code has been copied from BLACKLIST... etc 185164562Sgshapirodnl and simplified by omitting some < >. 185264562SgshapiroR<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <U: $1@> 185364562SgshapiroR<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > 185464562Sgshapirodnl R<?> $@ something_is_very_wrong_here 185564562Sgshapiro# lookup the addresses only with To tag 185664562SgshapiroR<> $* $| <$+> $: <@> $1 $| $>SearchList <!To> $| <$2> <> 185764562SgshapiroR<@> $* $| $* $: $2 $1 reverse result 185864562Sgshapirodnl', `dnl') 185964562Sgshapiroifdef(`_SPAM_FRIEND_', 186064562Sgshapiro`# is the recipient a spam friend? 186164562Sgshapiroifdef(`_SPAM_HATER_', 186264562Sgshapiro `errprint(`*** ERROR: define either SpamHater or SpamFriend 186364562Sgshapiro')', `dnl') 186464562SgshapiroR<SPAMFRIEND> $+ $@ SPAMFRIEND 186564562SgshapiroR<$*> $+ $: $2', 186664562Sgshapiro`dnl') 186764562Sgshapiroifdef(`_SPAM_HATER_', 186864562Sgshapiro`# is the recipient no spam hater? 186964562SgshapiroR<SPAMHATER> $+ $: $1 spam hater: continue checks 187064562SgshapiroR<$*> $+ $@ NOSPAMHATER everyone else: stop 187164562Sgshapirodnl',`dnl') 187264562Sgshapirodnl run further checks: check_mail 187364562Sgshapirodnl should we "clean up" $&f? 187464562SgshapiroR$* $: $1 $| $>checkmail <$&f> 187564562SgshapiroR$* $| $#$* $#$2 187664562Sgshapirodnl run further checks: check_relay 187764562SgshapiroR$* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 187864562SgshapiroR$* $| $#$* $#$2 187938032SpeterR$* $| $* $: $1 188038032Speter', `dnl') 188164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 188264562Sgshapiro###################################################################### 188364562Sgshapiro### SearchList: search a list of items in the access map 188464562Sgshapiro### Parameters: 188564562Sgshapiro### <exact tag> $| <mark:address> <mark:address> ... <> 188664562Sgshapirodnl maybe we should have a @ (again) in front of the mark to 188764562Sgshapirodnl avoid errorneous matches (with error messages?) 188864562Sgshapirodnl if we can make sure that tag is always a single token 188964562Sgshapirodnl then we can omit the delimiter $|, otherwise we need it 189064562Sgshapirodnl to avoid errorneous matchs (first rule: H: if there 189164562Sgshapirodnl is that mark somewhere in the list, it will be taken). 189264562Sgshapirodnl moreover, we can do some tricks to enforce lookup with 189364562Sgshapirodnl the tag only, e.g.: 189464562Sgshapiro### where "exact" is either "+" or "!": 189564562Sgshapiro### <+ TAG> lookup with and w/o tag 189664562Sgshapiro### <! TAG> lookup with tag 189764562Sgshapirodnl Warning: + and ! should be in OperatorChars (otherwise there must be 189864562Sgshapirodnl a blank between them and the tag. 189964562Sgshapiro### possible values for "mark" are: 190064562Sgshapiro### H: recursive host lookup (LookUpDomain) 190164562Sgshapirodnl A: recursive address lookup (LookUpAddress) [not yet required] 190264562Sgshapiro### E: exact lookup, no modifications 190364562Sgshapiro### F: full lookup, try user+ext@domain and user@domain 190464562Sgshapiro### U: user lookup, try user+ext and user (input must have trailing @) 190564562Sgshapiro### return: <RHS of lookup> or <?> (not found) 190664562Sgshapiro###################################################################### 190738032Speter 190864562Sgshapiro# class with valid marks for SearchList 190964562Sgshapirodnl if A is activated: add it 191064562SgshapiroC{src}E F H U 191164562SgshapiroSSearchList 191264562Sgshapiro# mark H: lookup domain 191364562SgshapiroR<$+> $| <H:$+> <$*> $: <$1> $| <@> $>LookUpDomain <$2> <?> <$3> <$1> 191464562SgshapiroR<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> 191564562Sgshapirodnl A: NOT YET REQUIRED 191664562Sgshapirodnl R<$+> $| <A:$+> <$*> $: <$1> $| <@> $>LookUpAddress <$2> <?> <$3> <$1> 191764562Sgshapirodnl R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> 191864562Sgshapirodnl lookup of the item with tag 191964562Sgshapirodnl this applies to F: U: E: 192064562SgshapiroR<$- $-> $| <$={src}:$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5> 192164562Sgshapirodnl no match, try without tag 192264562SgshapiroR<+ $-> $| <$={src}:$+> <$*> $: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4> 192364562Sgshapirodnl do we really have to distinguish these cases? 192464562Sgshapirodnl probably yes, there might be a + in the domain part (is that allowed?) 192564562Sgshapirodnl user+detail lookups: should it be: 192664562Sgshapirodnl user+detail, user+*, user; just like aliases? 192764562SgshapiroR<$- $-> $| <F:$* + $*@$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@$5 $: F:$3 + $4@$5$)> <$6> 192864562SgshapiroR<+ $-> $| <F:$* + $*@$+> <$*> $: <+ $1> $| <$(access $2@$4 $: F:$2 + $3@$4$)> <$5> 192964562Sgshapirodnl user lookups are always with trailing @ 193064562Sgshapirodnl do not remove the @ from the lookup: 193164562Sgshapirodnl it is part of the +detail@ which is omitted for the lookup 193264562SgshapiroR<$- $-> $| <U:$* + $*> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5> 193364562Sgshapirodnl no match, try without tag 193464562SgshapiroR<+ $-> $| <U:$* + $*> <$*> $: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4> 193564562Sgshapirodnl no match, try rest of list 193664562SgshapiroR<$+> $| <$={src}:$+> <$+> $@ $>SearchList <$1> $| <$4> 193764562Sgshapirodnl no match, list empty: return failure 193864562SgshapiroR<$+> $| <$={src}:$+> <> $@ <?> 193964562Sgshapirodnl got result, return it 194064562SgshapiroR<$+> $| <$+> <$*> $@ <$2> 194164562Sgshapirodnl return result from recursive invocation 194264562SgshapiroR<$+> $| <$+> $@ <$2>', `dnl') 194338032Speter 194464562Sgshapiro# is user trusted to authenticate as someone else? 194564562Sgshapirodnl AUTH= parameter from MAIL command 194664562SgshapiroStrust_auth 194764562SgshapiroR$* $: $&{auth_type} $| $1 194864562Sgshapiro# required by RFC 2554 section 4. 194964562SgshapiroR$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 195064562Sgshapirodnl seems to be useful... 195164562SgshapiroR$* $| $&{auth_authen} $@ identical 195264562SgshapiroR$* $| <$&{auth_authen}> $@ identical 195364562Sgshapirodnl call user supplied code 195464562SgshapiroR$* $| $* $: $1 $| $>"Local_trust_auth" $1 195564562SgshapiroR$* $| $#$* $#$2 195664562Sgshapirodnl default: error 195764562SgshapiroR$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 195864562Sgshapiro 195964562Sgshapirodnl empty ruleset definition so it can be called 196064562SgshapiroSLocal_trust_auth 196164562Sgshapiro 196264562Sgshapiroifdef(`_FFR_TLS_O_T', `dnl 196364562SgshapiroSoffer_tls 196464562SgshapiroR$* $: $>LookUpDomain <$&{client_name}> <?> <> <! TLS_OFF_TAG> 196564562SgshapiroR<?>$* $: $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_OFF_TAG> 196664562SgshapiroR<?>$* $: <$(access TLS_OFF_TAG: $: ? $)> 196764562SgshapiroR<?>$* $@ OK 196864562SgshapiroR<NO> <> $#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]" 196964562Sgshapiro 197064562SgshapiroStry_tls 197164562SgshapiroR$* $: $>LookUpDomain <$&{server_name}> <?> <> <! TLS_TRY_TAG> 197264562SgshapiroR<?>$* $: $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_TRY_TAG> 197364562SgshapiroR<?>$* $: <$(access TLS_TRY_TAG: $: ? $)> 197464562SgshapiroR<?>$* $@ OK 197571345SgshapiroR<NO>$* $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 197664562Sgshapiro')dnl 197764562Sgshapiro 197864562Sgshapiro# is connection with client "good" enough? (done in server) 197964562Sgshapiro# input: ${verify} $| (MAIL|STARTTLS) 198064562Sgshapirodnl MAIL: called from check_mail 198164562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted 198264562SgshapiroStls_client 198364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 198464562Sgshapirodnl ignore second arg for now 198564562Sgshapirodnl maybe use it to distinguish permanent/temporary error? 198664562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered) 198764562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed) 198864562SgshapiroR$* $| $* $: $1 $| $>LookUpDomain <$&{client_name}> <?> <> <! TLS_CLT_TAG> 198964562SgshapiroR$* $| <?>$* $: $1 $| $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_CLT_TAG> 199064562Sgshapirodnl do a default lookup: just TLS_CLT_TAG 199164562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 199264562SgshapiroR$* $@ $>"tls_connection" $1', `dnl 199364562SgshapiroR$* $| $* $@ $>"tls_connection" $1') 199464562Sgshapiro 199564562Sgshapiro# is connection with server "good" enough? (done in client) 199664562Sgshapirodnl i.e. has the server been authenticated and is encryption active? 199764562Sgshapirodnl called from deliver() after STARTTLS command 199864562Sgshapiro# input: ${verify} 199964562SgshapiroStls_server 200064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 200164562SgshapiroR$* $: $1 $| $>LookUpDomain <$&{server_name}> <?> <> <! TLS_SRV_TAG> 200264562SgshapiroR$* $| <?>$* $: $1 $| $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_SRV_TAG> 200364562Sgshapirodnl do a default lookup: just TLS_SRV_TAG 200464562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 200564562SgshapiroR$* $@ $>"tls_connection" $1', `dnl 200664562SgshapiroR$* $@ $>"tls_connection" $1') 200764562Sgshapiro 200864562SgshapiroStls_connection 200964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 201064562Sgshapirodnl common ruleset for tls_{client|server} 201164562Sgshapirodnl input: $&{verify} $| <ResultOfLookup> [<>] 201264562Sgshapirodnl remove optional <> 201364562SgshapiroR$* $| <$*>$* $: $1 $| <$2> 201464562Sgshapirodnl permanent or temporary error? 201564562SgshapiroR$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 201664562SgshapiroR$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 201764562Sgshapirodnl default case depends on TLS_PERM_ERR 201864562SgshapiroR$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 201964562Sgshapirodnl deal with TLS handshake failures: abort 202064562SgshapiroRSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 202164562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 202264562Sgshapirodnl use default error 202364562SgshapiroRSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 202464562SgshapiroR$* $| <$*> <VERIFY> $: <$2> <VERIFY> $1 202564562SgshapiroR$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> $1 202664562Sgshapirodnl some other value in access map: accept 202764562Sgshapirodnl this also allows to override the default case (if used) 202864562SgshapiroR$* $| $* $@ OK 202964562Sgshapiro# authentication required: give appropriate error 203064562Sgshapiro# other side did authenticate (via STARTTLS) 203164562Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> ${verify} 203264562Sgshapirodnl only verification required and it succeeded 203364562SgshapiroR<$*><VERIFY> OK $@ OK 203464562Sgshapirodnl verification required + some level of encryption 203564562SgshapiroR<$*><VERIFY:$-> OK $: <$1> <REQ:$2> 203664562Sgshapirodnl just some level of encryption required 203764562SgshapiroR<$*><ENCR:$-> $* $: <$1> <REQ:$2> 203864562Sgshapirodnl verification required but ${verify} is not set 203964562SgshapiroR<$-:$+><VERIFY $*> $#error $@ $2 $: $1 " authentication required" 204064562SgshapiroR<$-:$+><VERIFY $*> FAIL $#error $@ $2 $: $1 " authentication failed" 204164562SgshapiroR<$-:$+><VERIFY $*> NO $#error $@ $2 $: $1 " not authenticated" 204264562SgshapiroR<$-:$+><VERIFY $*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 204364562Sgshapirodnl some other value for ${verify} 204464562SgshapiroR<$-:$+><VERIFY $*> $+ $#error $@ $2 $: $1 " authentication failure " $4 204564562Sgshapirodnl some level of encryption required: get the maximum level 204664562SgshapiroR<$*><REQ:$-> $: <$1> <REQ:$2> $>max $&{cipher_bits} : $&{auth_ssf} 204764562Sgshapirodnl compare required bits with actual bits 204864562SgshapiroR<$*><REQ:$-> $- $: <$1> <$2:$3> $(arith l $@ $3 $@ $2 $) 204964562SgshapiroR<$-:$+><$-:$-> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 205064562Sgshapiro 205164562SgshapiroSmax 205264562Sgshapirodnl compute the max of two values separated by : 205364562SgshapiroR: $: 0 205464562SgshapiroR:$- $: $1 205564562SgshapiroR$-: $: $1 205664562SgshapiroR$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 205764562SgshapiroRTRUE:$-:$- $: $2 205864562SgshapiroR$-:$-:$- $: $2', 205964562Sgshapiro`dnl use default error 206064562Sgshapirodnl deal with TLS handshake failures: abort 206164562SgshapiroRSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."') 206264562Sgshapiro 206364562SgshapiroSRelayAuth 206464562Sgshapiro# authenticated? 206564562Sgshapirodnl we do not allow relaying for anyone who can present a cert 206664562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns 206764562Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow 206864562Sgshapirodnl them to abuse our server (they might be easier to get hold of, 206964562Sgshapirodnl but anyway). 207064562Sgshapirodnl so here is the trick: if the verification succeeded 207164562Sgshapirodnl we look up the cert issuer in the access map 207264562Sgshapirodnl (maybe after extracting a part with a regular expression) 207364562Sgshapirodnl if this returns RELAY we relay without further questions 207464562Sgshapirodnl if it returns SUBJECT we perform a similar check on the 207564562Sgshapirodnl cert subject. 207664562SgshapiroR$* $| OK $: $1 207764562SgshapiroR$* $| $* $@ NO not authenticated 207864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 207964562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 208064562SgshapiroR$* $: $1 $| $(CERTIssuer $&{cert_issuer} $)', 208164562Sgshapiro`R$* $: $1 $| $&{cert_issuer}') 208264562SgshapiroR$* $| $+ $: $1 $| $(access CERTISSUER:$2 $) 208364562Sgshapirodnl use $# to stop further checks (delay_check) 208464562SgshapiroR$* $| RELAY $# RELAYCERTISSUER 208564562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 208664562SgshapiroR$* $| SUBJECT $: $1 $| <@> $(CERTSubject $&{cert_subject} $)', 208764562Sgshapiro`R$* $| SUBJECT $: $1 $| <@> $&{cert_subject}') 208866494SgshapiroR$* $| <@> $+ $: $1 $| <@> $(access CERTSUBJECT:$2 $) 208964562SgshapiroR$* $| <@> RELAY $# RELAYCERTSUBJECT 209064562SgshapiroR$* $| $* $: $1', `dnl') 209164562Sgshapiro 209264562Sgshapiroundivert(9)dnl LOCAL_RULESETS 209364562Sgshapiroifdef(`_FFR_MILTER', ` 209438032Speter# 209538032Speter###################################################################### 209638032Speter###################################################################### 209738032Speter##### 209864562Sgshapiro`##### MAIL FILTER DEFINITIONS' 209964562Sgshapiro##### 210064562Sgshapiro###################################################################### 210164562Sgshapiro###################################################################### 210264562Sgshapiro_MAIL_FILTERS_') 210364562Sgshapiro# 210464562Sgshapiro###################################################################### 210564562Sgshapiro###################################################################### 210664562Sgshapiro##### 210738032Speter`##### MAILER DEFINITIONS' 210838032Speter##### 210938032Speter###################################################################### 211038032Speter###################################################################### 211164562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS 211266494Sgshapiro 2113