proto.m4 revision 64562
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 1664562SgshapiroVERSIONID(`$Id: proto.m4,v 8.446.2.5.2.12 2000/07/19 21:41:19 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"')') 8038032Speterdivert(0)dnl 8138032Speter 8264562Sgshapiro# override file safeties - setting this option compromises system security, 8364562Sgshapiro# addressing the actual file configuration problem is preferred 8464562Sgshapiro# need to set this before any file actions are encountered in the cf file 8564562Sgshapiro_OPTION(DontBlameSendmail, `confDONT_BLAME_SENDMAIL', `safe') 8638032Speter 8764562Sgshapiro# default LDAP map specification 8864562Sgshapiro# need to set this now before any LDAP maps are defined 8964562Sgshapiro_OPTION(LDAPDefaultSpec, `confLDAP_DEFAULT_SPEC', `-h localhost') 9064562Sgshapiro 9138032Speter################## 9238032Speter# local info # 9338032Speter################## 9438032Speter 9538032SpeterCwlocalhost 9638032Speterifdef(`USE_CW_FILE', 9738032Speter`# file containing names of hosts for which we receive email 9838032SpeterFw`'confCW_FILE', 9938032Speter `dnl') 10038032Speter 10138032Speter# my official domain name 10238032Speter# ... `define' this only if sendmail cannot automatically determine your domain 10338032Speterifdef(`confDOMAIN_NAME', `Dj`'confDOMAIN_NAME', `#Dj$w.Foo.COM') 10438032Speter 10538032SpeterCP. 10638032Speter 10738032Speterifdef(`UUCP_RELAY', 10838032Speter`# UUCP relay host 10938032SpeterDY`'UUCP_RELAY 11038032SpeterCPUUCP 11138032Speter 11238032Speter')dnl 11338032Speterifdef(`BITNET_RELAY', 11438032Speter`# BITNET relay host 11538032SpeterDB`'BITNET_RELAY 11638032SpeterCPBITNET 11738032Speter 11838032Speter')dnl 11938032Speterifdef(`DECNET_RELAY', 12038032Speter`define(`_USE_DECNET_SYNTAX_', 1)dnl 12138032Speter# DECnet relay host 12238032SpeterDC`'DECNET_RELAY 12338032SpeterCPDECNET 12438032Speter 12538032Speter')dnl 12638032Speterifdef(`FAX_RELAY', 12738032Speter`# FAX relay host 12838032SpeterDF`'FAX_RELAY 12938032SpeterCPFAX 13038032Speter 13138032Speter')dnl 13238032Speter# "Smart" relay host (may be null) 13338032SpeterDS`'ifdef(`SMART_HOST', SMART_HOST) 13438032Speter 13538032Speterifdef(`LUSER_RELAY', `dnl 13638032Speter# place to which unknown users should be forwarded 13738032SpeterKuser user -m -a<> 13838032SpeterDL`'LUSER_RELAY', 13938032Speter`dnl') 14038032Speter 14138032Speter# operators that cannot be in local usernames (i.e., network indicators) 14238032SpeterCO @ % ifdef(`_NO_UUCP_', `', `!') 14338032Speter 14438032Speter# a class with just dot (for identifying canonical names) 14538032SpeterC.. 14638032Speter 14738032Speter# a class with just a left bracket (for identifying domain literals) 14838032SpeterC[[ 14938032Speter 15064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 15164562Sgshapiro# access_db acceptance class 15264562SgshapiroC{Accept}OK RELAY 15364562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 15464562Sgshapiroifdef(`_BLACKLIST_RCPT_',`dnl 15564562Sgshapiro# possible access_db RHS for spam friends/haters 15664562SgshapiroC{SpamTag}SPAMFRIEND SPAMHATER')')', 15738032Speter`dnl') 15838032Speter 15938032Speterifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_',`dnl',`dnl 16038032Speter# Resolve map (to check if a host exists in check_mail) 16138032SpeterKresolve host -a<OK> -T<TEMP>') 16238032Speter 16338032Speterifdef(`confCR_FILE', `dnl 16438032Speter# Hosts that will permit relaying ($=R) 16538032SpeterFR`'confCR_FILE', 16638032Speter`dnl') 16738032Speter 16864562Sgshapirodefine(`TLS_SRV_TAG', `TLS_Srv')dnl 16964562Sgshapirodefine(`TLS_CLT_TAG', `TLS_Clt')dnl 17064562Sgshapirodefine(`TLS_TRY_TAG', `Try_TLS')dnl 17164562Sgshapirodefine(`TLS_OFF_TAG', `Offer_TLS')dnl 17264562Sgshapirodnl this may be useful in other contexts too 17364562Sgshapiroifdef(`_ARITH_MAP_', `', `# arithmetic map 17464562Sgshapirodefine(`_ARITH_MAP_', `1')dnl 17564562SgshapiroKarith arith') 17664562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 17764562Sgshapiro# possible values for tls_connect in access map 17864562SgshapiroC{tls}VERIFY ENCR', `dnl') 17964562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 18064562Sgshapiro# extract relevant part from cert issuer 18164562SgshapiroKCERTIssuer regex _CERT_REGEX_ISSUER_', `dnl') 18264562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 18364562Sgshapiro# extract relevant part from cert subject 18464562SgshapiroKCERTSubject regex _CERT_REGEX_SUBJECT_', `dnl') 18564562Sgshapiro 18638032Speter# who I send unqualified names to (null means deliver locally) 18738032SpeterDR`'ifdef(`LOCAL_RELAY', LOCAL_RELAY) 18838032Speter 18938032Speter# who gets all local email traffic ($R has precedence for unqualified names) 19038032SpeterDH`'ifdef(`MAIL_HUB', MAIL_HUB) 19138032Speter 19238032Speter# dequoting map 19338032SpeterKdequote dequote 19438032Speter 19538032Speterdivert(0)dnl # end of nullclient diversion 19638032Speter# class E: names that should be exposed as from this host, even if we masquerade 19764562Sgshapiro# class L: names that should be delivered locally, even if we have a relay 19838032Speter# class M: domains that should be converted to $M 19964562Sgshapiro# class N: domains that should not be converted to $M 20038032Speter#CL root 20138032Speterundivert(5)dnl 20264562Sgshapiroifdef(`_VIRTHOSTS_', `CR$={VirtHost}', `dnl') 20338032Speter 20438032Speter# who I masquerade as (null for no masquerading) (see also $=M) 20538032SpeterDM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME) 20638032Speter 20738032Speter# my name for error messages 20838032Speterifdef(`confMAILER_NAME', `Dn`'confMAILER_NAME', `#DnMAILER-DAEMON') 20938032Speter 21064562Sgshapiroundivert(6)dnl LOCAL_CONFIG 21138032Speterinclude(_CF_DIR_`m4/version.m4') 21238032Speter 21338032Speter############### 21438032Speter# Options # 21538032Speter############### 21638032Speter 21738032Speter# strip message body to 7 bits on input? 21864562Sgshapiro_OPTION(SevenBitInput, `confSEVEN_BIT_INPUT', `False') 21938032Speter 22038032Speter# 8-bit data handling 22164562Sgshapiro_OPTION(EightBitMode, `confEIGHT_BIT_HANDLING', `adaptive') 22238032Speter 22338032Speter# wait for alias file rebuild (default units: minutes) 22464562Sgshapiro_OPTION(AliasWait, `confALIAS_WAIT', `5m') 22538032Speter 22638032Speter# location of alias file 22764562Sgshapiro_OPTION(AliasFile, `ALIAS_FILE', `MAIL_SETTINGS_DIR`'aliases') 22864562Sgshapiro 22938032Speter# minimum number of free blocks on filesystem 23064562Sgshapiro_OPTION(MinFreeBlocks, `confMIN_FREE_BLOCKS', `100') 23138032Speter 23238032Speter# maximum message size 23364562Sgshapiro_OPTION(MaxMessageSize, `confMAX_MESSAGE_SIZE', `1000000') 23438032Speter 23538032Speter# substitution for space (blank) characters 23664562Sgshapiro_OPTION(BlankSub, `confBLANK_SUB', `_') 23738032Speter 23838032Speter# avoid connecting to "expensive" mailers on initial submission? 23964562Sgshapiro_OPTION(HoldExpensive, `confCON_EXPENSIVE', `False') 24038032Speter 24138032Speter# checkpoint queue runs after every N successful deliveries 24264562Sgshapiro_OPTION(CheckpointInterval, `confCHECKPOINT_INTERVAL', `10') 24338032Speter 24438032Speter# default delivery mode 24564562Sgshapiro_OPTION(DeliveryMode, `confDELIVERY_MODE', `background') 24638032Speter 24738032Speter# automatically rebuild the alias database? 24864562Sgshapiro# NOTE: There is a potential for a denial of service attack if this is set. 24964562Sgshapiro# This option is deprecated and will be removed from a future version. 25064562Sgshapiro_OPTION(AutoRebuildAliases, `confAUTO_REBUILD', `False') 25138032Speter 25238032Speter# error message header/file 25364562Sgshapiro_OPTION(ErrorHeader, `confERROR_MESSAGE', `MAIL_SETTINGS_DIR`'error-header') 25438032Speter 25538032Speter# error mode 25664562Sgshapiro_OPTION(ErrorMode, `confERROR_MODE', `print') 25738032Speter 25838032Speter# save Unix-style "From_" lines at top of header? 25964562Sgshapiro_OPTION(SaveFromLine, `confSAVE_FROM_LINES', `False') 26038032Speter 26138032Speter# temporary file mode 26264562Sgshapiro_OPTION(TempFileMode, `confTEMP_FILE_MODE', `0600') 26338032Speter 26438032Speter# match recipients against GECOS field? 26564562Sgshapiro_OPTION(MatchGECOS, `confMATCH_GECOS', `False') 26638032Speter 26738032Speter# maximum hop count 26864562Sgshapiro_OPTION(MaxHopCount, `confMAX_HOP', `17') 26938032Speter 27038032Speter# location of help file 27164562SgshapiroO HelpFile=ifdef(`HELP_FILE', HELP_FILE, `MAIL_SETTINGS_DIR`'helpfile') 27238032Speter 27338032Speter# ignore dots as terminators in incoming messages? 27464562Sgshapiro_OPTION(IgnoreDots, `confIGNORE_DOTS', `False') 27538032Speter 27638032Speter# name resolver options 27764562Sgshapiro_OPTION(ResolverOptions, `confBIND_OPTS', `+AAONLY') 27838032Speter 27938032Speter# deliver MIME-encapsulated error messages? 28064562Sgshapiro_OPTION(SendMimeErrors, `confMIME_FORMAT_ERRORS', `True') 28138032Speter 28238032Speter# Forward file search path 28364562Sgshapiro_OPTION(ForwardPath, `confFORWARD_PATH', `/var/forward/$u:$z/.forward.$w:$z/.forward') 28438032Speter 28538032Speter# open connection cache size 28664562Sgshapiro_OPTION(ConnectionCacheSize, `confMCI_CACHE_SIZE', `2') 28738032Speter 28838032Speter# open connection cache timeout 28964562Sgshapiro_OPTION(ConnectionCacheTimeout, `confMCI_CACHE_TIMEOUT', `5m') 29038032Speter 29138032Speter# persistent host status directory 29264562Sgshapiro_OPTION(HostStatusDirectory, `confHOST_STATUS_DIRECTORY', `.hoststat') 29338032Speter 29438032Speter# single thread deliveries (requires HostStatusDirectory)? 29564562Sgshapiro_OPTION(SingleThreadDelivery, `confSINGLE_THREAD_DELIVERY', `False') 29638032Speter 29738032Speter# use Errors-To: header? 29864562Sgshapiro_OPTION(UseErrorsTo, `confUSE_ERRORS_TO', `False') 29938032Speter 30038032Speter# log level 30164562Sgshapiro_OPTION(LogLevel, `confLOG_LEVEL', `10') 30238032Speter 30338032Speter# send to me too, even in an alias expansion? 30464562Sgshapiro_OPTION(MeToo, `confME_TOO', `True') 30538032Speter 30638032Speter# verify RHS in newaliases? 30764562Sgshapiro_OPTION(CheckAliases, `confCHECK_ALIASES', `False') 30838032Speter 30938032Speter# default messages to old style headers if no special punctuation? 31064562Sgshapiro_OPTION(OldStyleHeaders, `confOLD_STYLE_HEADERS', `False') 31138032Speter 31238032Speter# SMTP daemon options 31364562Sgshapiroifelse(defn(`confDAEMON_OPTIONS'), `', `dnl', 31464562Sgshapiro`errprint(WARNING: `confDAEMON_OPTIONS' is no longer valid. See cf/README for more information. 31564562Sgshapiro)'dnl 31664562Sgshapiro`DAEMON_OPTIONS(`confDAEMON_OPTIONS')') 31764562Sgshapiroifelse(defn(`_DPO_'), `', `O DaemonPortOptions=Name=MTA', `_DPO_') 31864562Sgshapiroifdef(`_NO_MSA_', `dnl', `O DaemonPortOptions=Port=587, Name=MSA, M=E') 31938032Speter 32064562Sgshapiro# SMTP client options 32164562Sgshapiro_OPTION(ClientPortOptions, `confCLIENT_OPTIONS', `Address=0.0.0.0') 32264562Sgshapiro 32338032Speter# privacy flags 32464562Sgshapiro_OPTION(PrivacyOptions, `confPRIVACY_FLAGS', `authwarnings') 32538032Speter 32638032Speter# who (if anyone) should get extra copies of error messages 32764562Sgshapiro_OPTION(PostmasterCopy, `confCOPY_ERRORS_TO', `Postmaster') 32838032Speter 32938032Speter# slope of queue-only function 33064562Sgshapiro_OPTION(QueueFactor, `confQUEUE_FACTOR', `600000') 33138032Speter 33238032Speter# queue directory 33364562SgshapiroO QueueDirectory=ifdef(`QUEUE_DIR', QUEUE_DIR, `/var/spool/mqueue') 33438032Speter 33538032Speter# timeouts (many of these) 33664562Sgshapiro_OPTION(Timeout.initial, `confTO_INITIAL', `5m') 33764562Sgshapiro_OPTION(Timeout.connect, `confTO_CONNECT', `5m') 33864562Sgshapiro_OPTION(Timeout.iconnect, `confTO_ICONNECT', `5m') 33964562Sgshapiro_OPTION(Timeout.helo, `confTO_HELO', `5m') 34064562Sgshapiro_OPTION(Timeout.mail, `confTO_MAIL', `10m') 34164562Sgshapiro_OPTION(Timeout.rcpt, `confTO_RCPT', `1h') 34264562Sgshapiro_OPTION(Timeout.datainit, `confTO_DATAINIT', `5m') 34364562Sgshapiro_OPTION(Timeout.datablock, `confTO_DATABLOCK', `1h') 34464562Sgshapiro_OPTION(Timeout.datafinal, `confTO_DATAFINAL', `1h') 34564562Sgshapiro_OPTION(Timeout.rset, `confTO_RSET', `5m') 34664562Sgshapiro_OPTION(Timeout.quit, `confTO_QUIT', `2m') 34764562Sgshapiro_OPTION(Timeout.misc, `confTO_MISC', `2m') 34864562Sgshapiro_OPTION(Timeout.command, `confTO_COMMAND', `1h') 34964562Sgshapiro_OPTION(Timeout.ident, `confTO_IDENT', `5s') 35064562Sgshapiro_OPTION(Timeout.fileopen, `confTO_FILEOPEN', `60s') 35164562Sgshapiro_OPTION(Timeout.control, `confTO_CONTROL', `2m') 35264562Sgshapiro_OPTION(Timeout.queuereturn, `confTO_QUEUERETURN', `5d') 35364562Sgshapiro_OPTION(Timeout.queuereturn.normal, `confTO_QUEUERETURN_NORMAL', `5d') 35464562Sgshapiro_OPTION(Timeout.queuereturn.urgent, `confTO_QUEUERETURN_URGENT', `2d') 35564562Sgshapiro_OPTION(Timeout.queuereturn.non-urgent, `confTO_QUEUERETURN_NONURGENT', `7d') 35664562Sgshapiro_OPTION(Timeout.queuewarn, `confTO_QUEUEWARN', `4h') 35764562Sgshapiro_OPTION(Timeout.queuewarn.normal, `confTO_QUEUEWARN_NORMAL', `4h') 35864562Sgshapiro_OPTION(Timeout.queuewarn.urgent, `confTO_QUEUEWARN_URGENT', `1h') 35964562Sgshapiro_OPTION(Timeout.queuewarn.non-urgent, `confTO_QUEUEWARN_NONURGENT', `12h') 36064562Sgshapiro_OPTION(Timeout.hoststatus, `confTO_HOSTSTATUS', `30m') 36164562Sgshapiro_OPTION(Timeout.resolver.retrans, `confTO_RESOLVER_RETRANS', `5s') 36264562Sgshapiro_OPTION(Timeout.resolver.retrans.first, `confTO_RESOLVER_RETRANS_FIRST', `5s') 36364562Sgshapiro_OPTION(Timeout.resolver.retrans.normal, `confTO_RESOLVER_RETRANS_NORMAL', `5s') 36464562Sgshapiro_OPTION(Timeout.resolver.retry, `confTO_RESOLVER_RETRY', `4') 36564562Sgshapiro_OPTION(Timeout.resolver.retry.first, `confTO_RESOLVER_RETRY_FIRST', `4') 36664562Sgshapiro_OPTION(Timeout.resolver.retry.normal, `confTO_RESOLVER_RETRY_NORMAL', `4') 36738032Speter 36838032Speter# should we not prune routes in route-addr syntax addresses? 36964562Sgshapiro_OPTION(DontPruneRoutes, `confDONT_PRUNE_ROUTES', `False') 37038032Speter 37138032Speter# queue up everything before forking? 37264562Sgshapiro_OPTION(SuperSafe, `confSAFE_QUEUE', `True') 37338032Speter 37438032Speter# status file 37564562SgshapiroO StatusFile=ifdef(`STATUS_FILE', `STATUS_FILE', `MAIL_SETTINGS_DIR`'statistics') 37638032Speter 37738032Speter# time zone handling: 37838032Speter# if undefined, use system default 37938032Speter# if defined but null, use TZ envariable passed in 38038032Speter# if defined and non-null, use that info 38138032Speterifelse(confTIME_ZONE, `USE_SYSTEM', `#O TimeZoneSpec=', 38238032Speter confTIME_ZONE, `USE_TZ', `O TimeZoneSpec=', 38338032Speter `O TimeZoneSpec=confTIME_ZONE') 38438032Speter 38538032Speter# default UID (can be username or userid:groupid) 38664562Sgshapiro_OPTION(DefaultUser, `confDEF_USER_ID', `mailnull') 38738032Speter 38838032Speter# list of locations of user database file (null means no lookup) 38964562Sgshapiro_OPTION(UserDatabaseSpec, `confUSERDB_SPEC', `MAIL_SETTINGS_DIR`'userdb') 39038032Speter 39138032Speter# fallback MX host 39264562Sgshapiro_OPTION(FallbackMXhost, `confFALLBACK_MX', `fall.back.host.net') 39338032Speter 39438032Speter# if we are the best MX host for a site, try it directly instead of config err 39564562Sgshapiro_OPTION(TryNullMXList, `confTRY_NULL_MX_LIST', `False') 39638032Speter 39738032Speter# load average at which we just queue messages 39864562Sgshapiro_OPTION(QueueLA, `confQUEUE_LA', `8') 39938032Speter 40038032Speter# load average at which we refuse connections 40164562Sgshapiro_OPTION(RefuseLA, `confREFUSE_LA', `12') 40238032Speter 40338032Speter# maximum number of children we allow at one time 40464562Sgshapiro_OPTION(MaxDaemonChildren, `confMAX_DAEMON_CHILDREN', `12') 40538032Speter 40638032Speter# maximum number of new connections per second 40764562Sgshapiro_OPTION(ConnectionRateThrottle, `confCONNECTION_RATE_THROTTLE', `3') 40838032Speter 40938032Speter# work recipient factor 41064562Sgshapiro_OPTION(RecipientFactor, `confWORK_RECIPIENT_FACTOR', `30000') 41138032Speter 41238032Speter# deliver each queued job in a separate process? 41364562Sgshapiro_OPTION(ForkEachJob, `confSEPARATE_PROC', `False') 41438032Speter 41538032Speter# work class factor 41664562Sgshapiro_OPTION(ClassFactor, `confWORK_CLASS_FACTOR', `1800') 41738032Speter 41838032Speter# work time factor 41964562Sgshapiro_OPTION(RetryFactor, `confWORK_TIME_FACTOR', `90000') 42038032Speter 42138032Speter# shall we sort the queue by hostname first? 42264562Sgshapiro_OPTION(QueueSortOrder, `confQUEUE_SORT_ORDER', `priority') 42338032Speter 42438032Speter# minimum time in queue before retry 42564562Sgshapiro_OPTION(MinQueueAge, `confMIN_QUEUE_AGE', `30m') 42638032Speter 42738032Speter# default character set 42864562Sgshapiro_OPTION(DefaultCharSet, `confDEF_CHAR_SET', `iso-8859-1') 42938032Speter 43038032Speter# service switch file (ignored on Solaris, Ultrix, OSF/1, others) 43164562Sgshapiro_OPTION(ServiceSwitchFile, `confSERVICE_SWITCH_FILE', `MAIL_SETTINGS_DIR`'service.switch') 43238032Speter 43338032Speter# hosts file (normally /etc/hosts) 43464562Sgshapiro_OPTION(HostsFile, `confHOSTS_FILE', `/etc/hosts') 43538032Speter 43638032Speter# dialup line delay on connection failure 43764562Sgshapiro_OPTION(DialDelay, `confDIAL_DELAY', `10s') 43838032Speter 43938032Speter# action to take if there are no recipients in the message 44064562Sgshapiro_OPTION(NoRecipientAction, `confNO_RCPT_ACTION', `add-to-undisclosed') 44138032Speter 44238032Speter# chrooted environment for writing to files 44364562Sgshapiro_OPTION(SafeFileEnvironment, `confSAFE_FILE_ENV', `/arch') 44438032Speter 44538032Speter# are colons OK in addresses? 44664562Sgshapiro_OPTION(ColonOkInAddr, `confCOLON_OK_IN_ADDR', `True') 44738032Speter 44838032Speter# how many jobs can you process in the queue? 44964562Sgshapiro_OPTION(MaxQueueRunSize, `confMAX_QUEUE_RUN_SIZE', `10000') 45038032Speter 45138032Speter# shall I avoid expanding CNAMEs (violates protocols)? 45264562Sgshapiro_OPTION(DontExpandCnames, `confDONT_EXPAND_CNAMES', `False') 45338032Speter 45438032Speter# SMTP initial login message (old $e macro) 45564562Sgshapiro_OPTION(SmtpGreetingMessage, `confSMTP_LOGIN_MSG', `$j Sendmail $v ready at $b') 45638032Speter 45738032Speter# UNIX initial From header format (old $l macro) 45864562Sgshapiro_OPTION(UnixFromLine, `confFROM_LINE', `From $g $d') 45938032Speter 46038032Speter# From: lines that have embedded newlines are unwrapped onto one line 46164562Sgshapiro_OPTION(SingleLineFromHeader, `confSINGLE_LINE_FROM_HEADER', `False') 46238032Speter 46338032Speter# Allow HELO SMTP command that does not `include' a host name 46464562Sgshapiro_OPTION(AllowBogusHELO, `confALLOW_BOGUS_HELO', `False') 46538032Speter 46638032Speter# Characters to be quoted in a full name phrase (@,;:\()[] are automatic) 46764562Sgshapiro_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.') 46838032Speter 46938032Speter# delimiter (operator) characters (old $o macro) 47064562Sgshapiro_OPTION(OperatorChars, `confOPERATORS', `.:@[]') 47138032Speter 47238032Speter# shall I avoid calling initgroups(3) because of high NIS costs? 47364562Sgshapiro_OPTION(DontInitGroups, `confDONT_INIT_GROUPS', `False') 47438032Speter 47538032Speter# are group-writable `:include:' and .forward files (un)trustworthy? 47664562Sgshapiro_OPTION(UnsafeGroupWrites, `confUNSAFE_GROUP_WRITES', `True') 47738032Speter 47838032Speter# where do errors that occur when sending errors get sent? 47964562Sgshapiro_OPTION(DoubleBounceAddress, `confDOUBLE_BOUNCE_ADDRESS', `postmaster') 48038032Speter 48164562Sgshapiro# where to save bounces if all else fails 48264562Sgshapiro_OPTION(DeadLetterDrop, `confDEAD_LETTER_DROP', `/var/tmp/dead.letter') 48364562Sgshapiro 48438032Speter# what user id do we assume for the majority of the processing? 48564562Sgshapiro_OPTION(RunAsUser, `confRUN_AS_USER', `sendmail') 48638032Speter 48738032Speter# maximum number of recipients per SMTP envelope 48864562Sgshapiro_OPTION(MaxRecipientsPerMessage, `confMAX_RCPTS_PER_MESSAGE', `100') 48938032Speter 49038032Speter# shall we get local names from our installed interfaces? 49164562Sgshapiro_OPTION(DontProbeInterfaces, `confDONT_PROBE_INTERFACES', `False') 49238032Speter 49364562Sgshapiro# Return-Receipt-To: header implies DSN request 49464562Sgshapiro_OPTION(RrtImpliesDsn, `confRRT_IMPLIES_DSN', `False') 49564562Sgshapiro 49664562Sgshapiro# override connection address (for testing) 49764562Sgshapiro_OPTION(ConnectOnlyTo, `confCONNECT_ONLY_TO', `0.0.0.0') 49864562Sgshapiro 49964562Sgshapiro# Trusted user for file ownership and starting the daemon 50064562Sgshapiro_OPTION(TrustedUser, `confTRUSTED_USER', `root') 50164562Sgshapiro 50264562Sgshapiro# Control socket for daemon management 50364562Sgshapiro_OPTION(ControlSocketName, `confCONTROL_SOCKET_NAME', `/var/spool/mqueue/.control') 50464562Sgshapiro 50564562Sgshapiro# Maximum MIME header length to protect MUAs 50664562Sgshapiro_OPTION(MaxMimeHeaderLength, `confMAX_MIME_HEADER_LENGTH', `0/0') 50764562Sgshapiro 50864562Sgshapiro# Maximum length of the sum of all headers 50964562Sgshapiro_OPTION(MaxHeadersLength, `confMAX_HEADERS_LENGTH', `32768') 51064562Sgshapiro 51164562Sgshapiro# Maximum depth of alias recursion 51264562Sgshapiro_OPTION(MaxAliasRecursion, `confMAX_ALIAS_RECURSION', `10') 51364562Sgshapiro 51464562Sgshapiro# location of pid file 51564562Sgshapiro_OPTION(PidFile, `confPID_FILE', `/var/run/sendmail.pid') 51664562Sgshapiro 51764562Sgshapiro# Prefix string for the process title shown on 'ps' listings 51864562Sgshapiro_OPTION(ProcessTitlePrefix, `confPROCESS_TITLE_PREFIX', `prefix') 51964562Sgshapiro 52064562Sgshapiro# Data file (df) memory-buffer file maximum size 52164562Sgshapiro_OPTION(DataFileBufferSize, `confDF_BUFFER_SIZE', `4096') 52264562Sgshapiro 52364562Sgshapiro# Transcript file (xf) memory-buffer file maximum size 52464562Sgshapiro_OPTION(XscriptFileBufferSize, `confXF_BUFFER_SIZE', `4096') 52564562Sgshapiro 52664562Sgshapiro# list of authentication mechanisms 52764562Sgshapiro_OPTION(AuthMechanisms, `confAUTH_MECHANISMS', `GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5') 52864562Sgshapiro 52964562Sgshapiro# default authentication information for outgoing connections 53064562Sgshapiro_OPTION(DefaultAuthInfo, `confDEF_AUTH_INFO', `MAIL_SETTINGS_DIR`'default-auth-info') 53164562Sgshapiro 53264562Sgshapiro# SMTP AUTH flags 53364562Sgshapiro_OPTION(AuthOptions, `confAUTH_OPTIONS', `') 53464562Sgshapiro 53564562Sgshapiroifdef(`_FFR_MILTER', ` 53664562Sgshapiro# Input mail filters 53764562Sgshapiro_OPTION(InputMailFilters, `confINPUT_MAIL_FILTERS', `') 53864562Sgshapiro 53964562Sgshapiro# Milter options 54064562Sgshapiro_OPTION(Milter.macros.connect, `confMILTER_MACROS_CONNECT', `') 54164562Sgshapiro_OPTION(Milter.macros.helo, `confMILTER_MACROS_HELO', `') 54264562Sgshapiro_OPTION(Milter.macros.envfrom, `confMILTER_MACROS_ENVFROM', `') 54364562Sgshapiro_OPTION(Milter.macros.envrcpt, `confMILTER_MACROS_ENVRCPT', `')') 54464562Sgshapiro 54564562Sgshapiro# CA directory 54664562Sgshapiro_OPTION(CACERTPath, `confCACERT_PATH', `') 54764562Sgshapiro# CA file 54864562Sgshapiro_OPTION(CACERTFile, `confCACERT', `') 54964562Sgshapiro# Server Cert 55064562Sgshapiro_OPTION(ServerCertFile, `confSERVER_CERT', `') 55164562Sgshapiro# Server private key 55264562Sgshapiro_OPTION(ServerKeyFile, `confSERVER_KEY', `') 55364562Sgshapiro# Client Cert 55464562Sgshapiro_OPTION(ClientCertFile, `confCLIENT_CERT', `') 55564562Sgshapiro# Client private key 55664562Sgshapiro_OPTION(ClientKeyFile, `confCLIENT_KEY', `') 55764562Sgshapiro# DHParameters (only required if DSA/DH is used) 55864562Sgshapiro_OPTION(DHParameters, `confDH_PARAMETERS', `') 55964562Sgshapiro# Random data source (required for systems without /dev/urandom under OpenSSL) 56064562Sgshapiro_OPTION(RandFile, `confRAND_FILE', `') 56164562Sgshapiro 56264562Sgshapiroifdef(`confQUEUE_FILE_MODE', 56364562Sgshapiro`# queue file mode (qf files) 56464562SgshapiroO QueueFileMode=confQUEUE_FILE_MODE 56542575Speter') 56642575Speter 56738032Speter########################### 56838032Speter# Message precedences # 56938032Speter########################### 57038032Speter 57138032SpeterPfirst-class=0 57238032SpeterPspecial-delivery=100 57338032SpeterPlist=-30 57438032SpeterPbulk=-60 57538032SpeterPjunk=-100 57638032Speter 57738032Speter##################### 57838032Speter# Trusted users # 57938032Speter##################### 58038032Speter 58138032Speter# this is equivalent to setting class "t" 58264562Sgshapiroifdef(`_USE_CT_FILE_', `', `#')Ft`'ifdef(`confCT_FILE', confCT_FILE, `MAIL_SETTINGS_DIR`'trusted-users') 58338032SpeterTroot 58438032SpeterTdaemon 58538032Speterifdef(`_NO_UUCP_', `dnl', `Tuucp') 58638032Speterifdef(`confTRUSTED_USERS', `T`'confTRUSTED_USERS', `dnl') 58738032Speter 58838032Speter######################### 58938032Speter# Format of headers # 59038032Speter######################### 59138032Speter 59238032Speterifdef(`confFROM_HEADER',, `define(`confFROM_HEADER', `$?x$x <$g>$|$g$.')')dnl 59338032SpeterH?P?Return-Path: <$g> 59438032SpeterHReceived: confRECEIVED_HEADER 59538032SpeterH?D?Resent-Date: $a 59638032SpeterH?D?Date: $a 59738032SpeterH?F?Resent-From: confFROM_HEADER 59838032SpeterH?F?From: confFROM_HEADER 59938032SpeterH?x?Full-Name: $x 60038032Speter# HPosted-Date: $a 60138032Speter# H?l?Received-Date: $b 60238032SpeterH?M?Resent-Message-Id: <$t.$i@$j> 60338032SpeterH?M?Message-Id: <$t.$i@$j> 60464562Sgshapiro 60538032Speter# 60638032Speter###################################################################### 60738032Speter###################################################################### 60838032Speter##### 60938032Speter##### REWRITING RULES 61038032Speter##### 61138032Speter###################################################################### 61238032Speter###################################################################### 61338032Speter 61438032Speter############################################ 61538032Speter### Ruleset 3 -- Name Canonicalization ### 61638032Speter############################################ 61764562SgshapiroScanonify=3 61838032Speter 61938032Speter# handle null input (translate to <@> special case) 62038032SpeterR$@ $@ <@> 62138032Speter 62238032Speter# strip group: syntax (not inside angle brackets!) and trailing semicolon 62338032SpeterR$* $: $1 <@> mark addresses 62438032SpeterR$* < $* > $* <@> $: $1 < $2 > $3 unmark <addr> 62538032SpeterR@ $* <@> $: @ $1 unmark @host:... 62638032SpeterR$* :: $* <@> $: $1 :: $2 unmark node::addr 62738032SpeterR:`include': $* <@> $: :`include': $1 unmark :`include':... 62864562SgshapiroR$* [ IPv6 $- ] <@> $: $1 [ IPv6 $2 ] unmark IPv6 addr 62938032SpeterR$* : $* [ $* ] $: $1 : $2 [ $3 ] <@> remark if leading colon 63038032SpeterR$* : $* <@> $: $2 strip colon if marked 63138032SpeterR$* <@> $: $1 unmark 63238032SpeterR$* ; $1 strip trailing semi 63338032SpeterR$* < $* ; > $1 < $2 > bogus bracketed semi 63438032Speter 63538032Speter# null input now results from list:; syntax 63638032SpeterR$@ $@ :; <@> 63738032Speter 63838032Speter# strip angle brackets -- note RFC733 heuristic to get innermost item 63938032SpeterR$* $: < $1 > housekeeping <> 64038032SpeterR$+ < $* > < $2 > strip excess on left 64138032SpeterR< $* > $+ < $1 > strip excess on right 64238032SpeterR<> $@ < @ > MAIL FROM:<> case 64338032SpeterR< $+ > $: $1 remove housekeeping <> 64438032Speter 64564562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 64638032Speter# make sure <@a,@b,@c:user@d> syntax is easy to parse -- undone later 64738032SpeterR@ $+ , $+ @ $1 : $2 change all "," to ":" 64838032Speter 64938032Speter# localize and dispose of route-based addresses 65064562SgshapiroR@ $+ : $+ $@ $>Canonify2 < @$1 > : $2 handle <route-addr> 65164562Sgshapirodnl',`dnl 65264562Sgshapiro# strip route address <@a,@b,@c:user@d> -> <user@d> 65364562SgshapiroR@ $+ , $+ $2 65464562SgshapiroR@ $+ : $+ $2 65564562Sgshapirodnl') 65638032Speter 65738032Speter# find focus for list syntax 65864562SgshapiroR $+ : $* ; @ $+ $@ $>Canonify2 $1 : $2 ; < @ $3 > list syntax 65938032SpeterR $+ : $* ; $@ $1 : $2; list syntax 66038032Speter 66138032Speter# find focus for @ syntax addresses 66238032SpeterR$+ @ $+ $: $1 < @ $2 > focus on domain 66338032SpeterR$+ < $+ @ $+ > $1 $2 < @ $3 > move gaze right 66464562SgshapiroR$+ < @ $+ > $@ $>Canonify2 $1 < @ $2 > already canonical 66538032Speter 66638032Speter# do some sanity checking 66738032SpeterR$* < @ $* : $* > $* $1 < @ $2 $3 > $4 nix colons in addrs 66838032Speter 66938032Speterifdef(`_NO_UUCP_', `dnl', 67038032Speter`# convert old-style addresses to a domain-based address 67164562SgshapiroR$- ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > resolve uucp names 67264562SgshapiroR$+ . $- ! $+ $@ $>Canonify2 $3 < @ $1 . $2 > domain uucps 67364562SgshapiroR$+ ! $+ $@ $>Canonify2 $2 < @ $1 .UUCP > uucp subdomains 67438032Speter') 67538032Speterifdef(`_USE_DECNET_SYNTAX_', 67638032Speter`# convert node::user addresses into a domain-based address 67764562SgshapiroR$- :: $+ $@ $>Canonify2 $2 < @ $1 .DECNET > resolve DECnet names 67864562SgshapiroR$- . $- :: $+ $@ $>Canonify2 $3 < @ $1.$2 .DECNET > numeric DECnet addr 67938032Speter', 68038032Speter `dnl') 68138032Speter# if we have % signs, take the rightmost one 68238032SpeterR$* % $* $1 @ $2 First make them all @s. 68338032SpeterR$* @ $* @ $* $1 % $2 @ $3 Undo all but the last. 68464562SgshapiroR$* @ $* $@ $>Canonify2 $1 < @ $2 > Insert < > and finish 68538032Speter 68638032Speter# else we must be a local name 68764562SgshapiroR$* $@ $>Canonify2 $1 68838032Speter 68938032Speter 69038032Speter################################################ 69138032Speter### Ruleset 96 -- bottom half of ruleset 3 ### 69238032Speter################################################ 69338032Speter 69464562SgshapiroSCanonify2=96 69538032Speter 69638032Speter# handle special cases for local names 69738032SpeterR$* < @ localhost > $* $: $1 < @ $j . > $2 no domain at all 69838032SpeterR$* < @ localhost . $m > $* $: $1 < @ $j . > $2 local domain 69938032Speterifdef(`_NO_UUCP_', `dnl', 70038032Speter`R$* < @ localhost . UUCP > $* $: $1 < @ $j . > $2 .UUCP domain') 70164562Sgshapiro 70264562Sgshapiro# check for IPv6 domain literal (save quoted form) 70364562SgshapiroR$* < @ [ IPv6 $- ] > $* $: $2 $| $1 < @@ [ $(dequote $2 $) ] > $3 mark IPv6 addr 70464562SgshapiroR$- $| $* < @@ $=w > $* $: $2 < @ $j . > $4 self-literal 70564562SgshapiroR$- $| $* < @@ [ $+ ] > $* $@ $2 < @ [ IPv6 $1 ] > $4 canon IP addr 70664562Sgshapiro 70764562Sgshapiro# check for IPv4 domain literal 70838032SpeterR$* < @ [ $+ ] > $* $: $1 < @@ [ $2 ] > $3 mark [a.b.c.d] 70938032SpeterR$* < @@ $=w > $* $: $1 < @ $j . > $3 self-literal 71038032SpeterR$* < @@ $+ > $* $@ $1 < @ $2 > $3 canon IP addr 71138032Speter 71264562Sgshapiroifdef(`_DOMAIN_TABLE_', `dnl 71338032Speter# look up domains in the domain table 71438032SpeterR$* < @ $+ > $* $: $1 < @ $(domaintable $2 $) > $3', `dnl') 71538032Speter 71664562Sgshapiroundivert(2)dnl LOCAL_RULE_3 71738032Speter 71864562Sgshapiroifdef(`_BITDOMAIN_TABLE_', `dnl 71938032Speter# handle BITNET mapping 72038032SpeterR$* < @ $+ .BITNET > $* $: $1 < @ $(bitdomain $2 $: $2.BITNET $) > $3', `dnl') 72138032Speter 72264562Sgshapiroifdef(`_UUDOMAIN_TABLE_', `dnl 72338032Speter# handle UUCP mapping 72438032SpeterR$* < @ $+ .UUCP > $* $: $1 < @ $(uudomain $2 $: $2.UUCP $) > $3', `dnl') 72538032Speter 72638032Speterifdef(`_NO_UUCP_', `dnl', 72738032Speter`ifdef(`UUCP_RELAY', 72838032Speter`# pass UUCP addresses straight through 72938032SpeterR$* < @ $+ . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', 73038032Speter`# if really UUCP, handle it immediately 73138032Speterifdef(`_CLASS_U_', 73238032Speter`R$* < @ $=U . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 73338032Speterifdef(`_CLASS_V_', 73438032Speter`R$* < @ $=V . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 73538032Speterifdef(`_CLASS_W_', 73638032Speter`R$* < @ $=W . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 73738032Speterifdef(`_CLASS_X_', 73838032Speter`R$* < @ $=X . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 73938032Speterifdef(`_CLASS_Y_', 74038032Speter`R$* < @ $=Y . UUCP > $* $@ $1 < @ $2 . UUCP . > $3', `dnl') 74138032Speter 74238032Speterifdef(`_NO_CANONIFY_', `dnl', `dnl 74338032Speter# try UUCP traffic as a local address 74438032SpeterR$* < @ $+ . UUCP > $* $: $1 < @ $[ $2 $] . UUCP . > $3 74538032SpeterR$* < @ $+ . . UUCP . > $* $@ $1 < @ $2 . > $3') 74638032Speter')') 74764562Sgshapiro# hostnames ending in class P are always canonical 74864562SgshapiroR$* < @ $* $=P > $* $: $1 < @ $2 $3 . > $4 74964562Sgshapirodnl apply the next rule only for hostnames not in class P 75064562Sgshapirodnl this even works for phrases in class P since . is in class P 75164562Sgshapirodnl which daemon flags are set? 75264562SgshapiroR$* < @ $* $~P > $* $: $&{daemon_flags} $| $1 < @ $2 $3 > $4 75364562Sgshapirodnl the other rules in this section only apply if the hostname 75464562Sgshapirodnl does not end in class P hence no further checks are done here 75564562Sgshapirodnl if this ever changes make sure the lookups are "protected" again! 75664562Sgshapiroifdef(`_NO_CANONIFY_', `dnl 75764562Sgshapirodnl do not canonify unless: 75864562Sgshapirodnl domain ends in class {Canonify} (this does not work if the intersection 75964562Sgshapirodnl with class P is non-empty) 76064562Sgshapirodnl or {daemon_flags} has c set 76164562Sgshapiro# pass to name server to make hostname canonical if in class {Canonify} 76264562SgshapiroR$* $| $* < @ $* $={Canonify} > $* $: $2 < @ $[ $3 $4 $] > $5 76364562Sgshapiro# pass to name server to make hostname canonical if requested 76464562SgshapiroR$* c $* $| $* < @ $* > $* $: $3 < @ $[ $4 $] > $5 76564562Sgshapirodnl trailing dot? -> do not apply _CANONIFY_HOSTS_ 76664562SgshapiroR$* $| $* < @ $+ . > $* $: $2 < @ $3 . > $4 76764562Sgshapiro# add a trailing dot to qualified hostnames so other rules will work 76864562SgshapiroR$* $| $* < @ $+.$+ > $* $: $2 < @ $3.$4 . > $5 76964562Sgshapiroifdef(`_CANONIFY_HOSTS_', `dnl 77064562Sgshapirodnl this should only apply to unqualified hostnames 77164562Sgshapirodnl but if a valid character inside an unqualified hostname is an OperatorChar 77264562Sgshapirodnl then $- does not work. 77364562Sgshapiro# lookup unqualified hostnames 77464562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4', `dnl')', `dnl 77564562Sgshapirodnl _NO_CANONIFY_ is not set: canonify unless: 77664562Sgshapirodnl {daemon_flags} contains CC (do not canonify) 77764562SgshapiroR$* CC $* $| $* $: $3 77838032Speter# pass to name server to make hostname canonical 77964562SgshapiroR$* $| $* < @ $* > $* $: $2 < @ $[ $3 $] > $4') 78064562Sgshapirodnl remove {daemon_flags} for other cases 78164562SgshapiroR$* $| $* $: $2 78238032Speter 78338032Speter# local host aliases and pseudo-domains are always canonical 78438032SpeterR$* < @ $=w > $* $: $1 < @ $2 . > $3 78538032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 78638032Speter`R$* < @ $* $=M > $* $: $1 < @ $2 $3 . > $4', 78738032Speter`R$* < @ $=M > $* $: $1 < @ $2 . > $3') 78864562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 78964562Sgshapirodnl virtual hosts are also canonical 79064562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 79164562Sgshapiro`R$* < @ $* $={VirtHost} > $* $: $1 < @ $2 $3 . > $4', 79264562Sgshapiro`R$* < @ $={VirtHost} > $* $: $1 < @ $2 . > $3')', 79364562Sgshapiro`dnl') 79464562Sgshapirodnl remove superfluous dots (maybe repeatedly) which may have been added 79564562Sgshapirodnl by one of the rules before 79638032SpeterR$* < @ $* . . > $* $1 < @ $2 . > $3 79738032Speter 79838032Speter 79938032Speter################################################## 80038032Speter### Ruleset 4 -- Final Output Post-rewriting ### 80138032Speter################################################## 80264562SgshapiroSfinal=4 80338032Speter 80438032SpeterR$* <@> $@ handle <> and list:; 80538032Speter 80638032Speter# strip trailing dot off possibly canonical name 80738032SpeterR$* < @ $+ . > $* $1 < @ $2 > $3 80838032Speter 80964562Sgshapiro# eliminate internal code 81038032SpeterR$* < @ *LOCAL* > $* $1 < @ $j > $2 81138032Speter 81238032Speter# externalize local domain info 81338032SpeterR$* < $+ > $* $1 $2 $3 defocus 81438032SpeterR@ $+ : @ $+ : $+ @ $1 , @ $2 : $3 <route-addr> canonical 81538032SpeterR@ $* $@ @ $1 ... and exit 81638032Speter 81738032Speterifdef(`_NO_UUCP_', `dnl', 81838032Speter`# UUCP must always be presented in old form 81938032SpeterR$+ @ $- . UUCP $2!$1 u@h.UUCP => h!u') 82038032Speter 82138032Speterifdef(`_USE_DECNET_SYNTAX_', 82238032Speter`# put DECnet back in :: form 82338032SpeterR$+ @ $+ . DECNET $2 :: $1 u@h.DECNET => h::u', 82438032Speter `dnl') 82538032Speter# delete duplicate local names 82638032SpeterR$+ % $=w @ $=w $1 @ $2 u%host@host => u@host 82738032Speter 82838032Speter 82938032Speter 83038032Speter############################################################## 83138032Speter### Ruleset 97 -- recanonicalize and call ruleset zero ### 83238032Speter### (used for recursive calls) ### 83338032Speter############################################################## 83438032Speter 83564562SgshapiroSRecurse=97 83664562SgshapiroR$* $: $>canonify $1 83764562SgshapiroR$* $@ $>parse $1 83838032Speter 83938032Speter 84038032Speter###################################### 84138032Speter### Ruleset 0 -- Parse Address ### 84238032Speter###################################### 84338032Speter 84464562SgshapiroSparse=0 84538032Speter 84638032SpeterR$* $: $>Parse0 $1 initial parsing 84738032SpeterR<@> $#_LOCAL_ $: <@> special case error msgs 84864562SgshapiroR$* $: $>ParseLocal $1 handle local hacks 84938032SpeterR$* $: $>Parse1 $1 final parsing 85038032Speter 85138032Speter# 85238032Speter# Parse0 -- do initial syntax checking and eliminate local addresses. 85338032Speter# This should either return with the (possibly modified) input 85438032Speter# or return with a #error mailer. It should not return with a 85538032Speter# #mailer other than the #error mailer. 85638032Speter# 85738032Speter 85838032SpeterSParse0 85938032SpeterR<@> $@ <@> special case error msgs 86064562SgshapiroR$* : $* ; <@> $#error $@ 5.1.3 $: "553 List:; syntax illegal for recipient addresses" 86164562SgshapiroR@ <@ $* > < @ $1 > catch "@@host" bogosity 86264562SgshapiroR<@ $+> $#error $@ 5.1.3 $: "553 User address required" 86338032SpeterR$* $: <> $1 86438032SpeterR<> $* < @ [ $+ ] > $* $1 < @ [ $2 ] > $3 86564562SgshapiroR<> $* <$* : $* > $* $#error $@ 5.1.3 $: "553 Colon illegal in host name part" 86638032SpeterR<> $* $1 86764562SgshapiroR$* < @ . $* > $* $#error $@ 5.1.2 $: "553 Invalid host name" 86864562SgshapiroR$* < @ $* .. $* > $* $#error $@ 5.1.2 $: "553 Invalid host name" 86964562Sgshapirodnl comma only allowed before @; this check is not complete 87064562SgshapiroR$* , $~O $* $#error $@ 5.1.2 $: "553 Invalid route address" 87138032Speter 87238032Speter# now delete the local info -- note $=O to find characters that cause forwarding 87364562SgshapiroR$* < @ > $* $@ $>Parse0 $>canonify $1 user@ => user 87464562SgshapiroR< @ $=w . > : $* $@ $>Parse0 $>canonify $2 @here:... -> ... 87538032SpeterR$- < @ $=w . > $: $(dequote $1 $) < @ $2 . > dequote "foo"@here 87664562SgshapiroR< @ $+ > $#error $@ 5.1.3 $: "553 User address required" 87764562SgshapiroR$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ... 87838032SpeterR$- $: $(dequote $1 $) < @ *LOCAL* > dequote "foo" 87964562SgshapiroR< @ *LOCAL* > $#error $@ 5.1.3 $: "553 User address required" 88038032SpeterR$* $=O $* < @ *LOCAL* > 88164562Sgshapiro $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ... 88238032SpeterR$* < @ *LOCAL* > $: $1 88338032Speter 88438032Speter# 88538032Speter# Parse1 -- the bottom half of ruleset 0. 88638032Speter# 88738032Speter 88838032SpeterSParse1 88964562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 89064562Sgshapiro# handle LDAP routing for hosts in $={LDAPRoute} 89164562SgshapiroR$+ < @ $={LDAPRoute} . > $: $>LDAPExpand <$1 < @ $2 . >> <$1 @ $2>', 89264562Sgshapiro`dnl') 89364562Sgshapiro 89464562Sgshapiro 89538032Speterifdef(`_MAILER_smtp_', 89638032Speter`# handle numeric address spec 89764562Sgshapirodnl there is no check whether this is really an IP number 89864562SgshapiroR$* < @ [ $+ ] > $* $: $>ParseLocal $1 < @ [ $2 ] > $3 numeric internet spec 89964562SgshapiroR$* < @ [ $+ ] > $* $1 < @ [ $2 ] : $S > $3 Add smart host to path 90064562SgshapiroR$* < @ [ IPv6 $- ] : > $* 90164562Sgshapiro $#_SMTP_ $@ [ $(dequote $2 $) ] $: $1 < @ [IPv6 $2 ] > $3 no smarthost: send 90264562SgshapiroR$* < @ [ $+ ] : > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 no smarthost: send 90364562SgshapiroR$* < @ [ $+ ] : $- : $*> $* $#$3 $@ $4 $: $1 < @ [$2] > $5 smarthost with mailer 90464562SgshapiroR$* < @ [ $+ ] : $+ > $* $#_SMTP_ $@ $3 $: $1 < @ [$2] > $4 smarthost without mailer', 90538032Speter `dnl') 90638032Speter 90764562Sgshapiroifdef(`_VIRTUSER_TABLE_', `dnl 90838032Speter# handle virtual users 90964562SgshapiroR$+ $: <!> $1 Mark for lookup 91064562Sgshapiroifdef(`_VIRTUSER_ENTIRE_DOMAIN_', 91164562Sgshapiro`R<!> $+ < @ $* $={VirtHost} . > $: < $(virtuser $1 @ $2 $3 $@ $1 $: @ $) > $1 < @ $2 $3 . >', 91264562Sgshapiro`R<!> $+ < @ $={VirtHost} . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >') 91364562SgshapiroR<!> $+ < @ $=w . > $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 91438032SpeterR<@> $+ + $* < @ $* . > 91564562Sgshapiro $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 91638032SpeterR<@> $+ + $* < @ $* . > 91738032Speter $: < $(virtuser $1 @ $3 $@ $1 $: @ $) > $1 + $2 < @ $3 . > 91864562Sgshapirodnl try default entry: @domain 91964562Sgshapirodnl +*@domain 92064562SgshapiroR<@> $+ + $+ < @ $+ . > $: < $(virtuser + * @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 92164562Sgshapirodnl @domain if +detail exists 92264562SgshapiroR<@> $+ + $* < @ $+ . > $: < $(virtuser @ $3 $@ $1 $@ $2 $: @ $) > $1 + $2 < @ $3 . > 92364562Sgshapirodnl without +detail (or no match) 92438032SpeterR<@> $+ < @ $+ . > $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . > 92538032SpeterR<@> $+ $: $1 92664562SgshapiroR<!> $+ $: $1 92764562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 92838032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 92964562SgshapiroR< $+ > $+ < @ $+ > $: $>Recurse $1', 93038032Speter`dnl') 93138032Speter 93238032Speter# short circuit local delivery so forwarded email works 93338032Speterifdef(`_MAILER_usenet_', `dnl 93464562SgshapiroR$+ . USENET < @ $=w . > $#usenet $@ usenet $: $1 handle usenet specially', `dnl') 93538032Speterifdef(`_STICKY_LOCAL_DOMAIN_', 93638032Speter`R$+ < @ $=w . > $: < $H > $1 < @ $2 . > first try hub 93764562SgshapiroR< $+ > $+ < $+ > $>MailerToTriple < $1 > $2 < $3 > yep .... 93864562Sgshapirodnl $H empty (but @$=w.) 93938032SpeterR< > $+ + $* < $+ > $#_LOCAL_ $: $1 + $2 plussed name? 94038032SpeterR< > $+ < $+ > $#_LOCAL_ $: @ $1 nope, local address', 94164562Sgshapiro`R$=L < @ $=w . > $#_LOCAL_ $: @ $1 special local names 94238032SpeterR$+ < @ $=w . > $#_LOCAL_ $: $1 regular local name') 94338032Speter 94464562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 94538032Speter# not local -- try mailer table lookup 94638032SpeterR$* <@ $+ > $* $: < $2 > $1 < @ $2 > $3 extract host name 94738032SpeterR< $+ . > $* $: < $1 > $2 strip trailing dot 94838032SpeterR< $+ > $* $: < $(mailertable $1 $) > $2 lookup 94964562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 95064562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 check -- resolved? 95164562SgshapiroR< $+ > $* $: $>Mailertable <$1> $2 try domain', 95238032Speter`dnl') 95364562Sgshapiroundivert(4)dnl UUCP rules from `MAILER(uucp)' 95438032Speter 95538032Speterifdef(`_NO_UUCP_', `dnl', 95638032Speter`# resolve remotely connected UUCP links (if any) 95738032Speterifdef(`_CLASS_V_', 95864562Sgshapiro`R$* < @ $=V . UUCP . > $* $: $>MailerToTriple < $V > $1 <@$2.UUCP.> $3', 95938032Speter `dnl') 96038032Speterifdef(`_CLASS_W_', 96164562Sgshapiro`R$* < @ $=W . UUCP . > $* $: $>MailerToTriple < $W > $1 <@$2.UUCP.> $3', 96238032Speter `dnl') 96338032Speterifdef(`_CLASS_X_', 96464562Sgshapiro`R$* < @ $=X . UUCP . > $* $: $>MailerToTriple < $X > $1 <@$2.UUCP.> $3', 96538032Speter `dnl')') 96638032Speter 96738032Speter# resolve fake top level domains by forwarding to other hosts 96838032Speterifdef(`BITNET_RELAY', 96964562Sgshapiro`R$*<@$+.BITNET.>$* $: $>MailerToTriple < $B > $1 <@$2.BITNET.> $3 user@host.BITNET', 97038032Speter `dnl') 97138032Speterifdef(`DECNET_RELAY', 97264562Sgshapiro`R$*<@$+.DECNET.>$* $: $>MailerToTriple < $C > $1 <@$2.DECNET.> $3 user@host.DECNET', 97338032Speter `dnl') 97438032Speterifdef(`_MAILER_pop_', 97538032Speter`R$+ < @ POP. > $#pop $: $1 user@POP', 97638032Speter `dnl') 97738032Speterifdef(`_MAILER_fax_', 97838032Speter`R$+ < @ $+ .FAX. > $#fax $@ $2 $: $1 user@host.FAX', 97938032Speter`ifdef(`FAX_RELAY', 98064562Sgshapiro`R$*<@$+.FAX.>$* $: $>MailerToTriple < $F > $1 <@$2.FAX.> $3 user@host.FAX', 98138032Speter `dnl')') 98238032Speter 98338032Speterifdef(`UUCP_RELAY', 98438032Speter`# forward non-local UUCP traffic to our UUCP relay 98564562SgshapiroR$*<@$*.UUCP.>$* $: $>MailerToTriple < $Y > $1 <@$2.UUCP.> $3 uucp mail', 98638032Speter`ifdef(`_MAILER_uucp_', 98738032Speter`# forward other UUCP traffic straight to UUCP 98838032SpeterR$* < @ $+ .UUCP. > $* $#_UUCP_ $@ $2 $: $1 < @ $2 .UUCP. > $3 user@host.UUCP', 98938032Speter `dnl')') 99038032Speterifdef(`_MAILER_usenet_', ` 99138032Speter# addresses sent to net.group.USENET will get forwarded to a newsgroup 99264562SgshapiroR$+ . USENET $#usenet $@ usenet $: $1', 99338032Speter `dnl') 99438032Speter 99538032Speterifdef(`_LOCAL_RULES_', 99638032Speter`# figure out what should stay in our local mail system 99738032Speterundivert(1)', `dnl') 99838032Speter 99938032Speter# pass names that still have a host to a smarthost (if defined) 100064562SgshapiroR$* < @ $* > $* $: $>MailerToTriple < $S > $1 < @ $2 > $3 glue on smarthost name 100138032Speter 100238032Speter# deal with other remote names 100338032Speterifdef(`_MAILER_smtp_', 100464562Sgshapiro`R$* < @$* > $* $#_SMTP_ $@ $2 $: $1 < @ $2 > $3 user@host.domain', 100564562Sgshapiro`R$* < @$* > $* $#error $@ 5.1.2 $: "553 Unrecognized host name " $2') 100638032Speter 100738032Speter# handle locally delivered names 100864562SgshapiroR$=L $#_LOCAL_ $: @ $1 special local names 100938032SpeterR$+ $#_LOCAL_ $: $1 regular local names 101038032Speter 101138032Speter########################################################################### 101238032Speter### Ruleset 5 -- special rewriting after aliases have been expanded ### 101338032Speter########################################################################### 101438032Speter 101564562SgshapiroSLocal_localaddr 101664562SgshapiroSlocaladdr=5 101764562SgshapiroR$+ $: $1 $| $>"Local_localaddr" $1 101864562SgshapiroR$+ $| $#$* $#$2 101964562SgshapiroR$+ $| $* $: $1 102038032Speter 102138032Speter# deal with plussed users so aliases work nicely 102238032SpeterR$+ + * $#_LOCAL_ $@ $&h $: $1 102338032SpeterR$+ + $* $#_LOCAL_ $@ + $2 $: $1 + * 102438032Speter 102538032Speter# prepend an empty "forward host" on the front 102638032SpeterR$+ $: <> $1 102738032Speter 102838032Speterifdef(`LUSER_RELAY', `dnl 102938032Speter# send unrecognized local users to a relay host 103064562SgshapiroR< > $+ $: < $L > $(user $1 $) look up user 103164562SgshapiroR< $* > $+ <> $: < > $2 found; strip $L', 103238032Speter`dnl') 103338032Speter 103438032Speter# see if we have a relay or a hub 103538032SpeterR< > $+ $: < $H > $1 try hub 103638032SpeterR< > $+ $: < $R > $1 try relay 103764562SgshapiroR< > $+ $: < > < $1 <> $&h > nope, restore +detail 103864562SgshapiroR< > < $+ <> + $* > $: < > < $1 + $2 > check whether +detail 103964562SgshapiroR< > < $+ <> $* > $: < > < $1 > else discard 104038032SpeterR< > < $+ + $* > $* < > < $1 > + $2 $3 find the user part 104138032SpeterR< > < $+ > + $* $#_LOCAL_ $@ $2 $: @ $1 strip the extra + 104238032SpeterR< > < $+ > $@ $1 no +detail 104343730SpeterR$+ $: $1 <> $&h add +detail back in 104443730SpeterR$+ <> + $* $: $1 + $2 check whether +detail 104543730SpeterR$+ <> $* $: $1 else discard 104664562SgshapiroR< local : $* > $* $: $>MailerToTriple < local : $1 > $2 no host extension 104764562SgshapiroR< error : $* > $* $: $>MailerToTriple < error : $1 > $2 no host extension 104864562SgshapiroR< $- : $+ > $+ $: $>MailerToTriple < $1 : $2 > $3 < @ $2 > 104964562SgshapiroR< $+ > $+ $@ $>MailerToTriple < $1 > $2 < @ $1 > 105038032Speter 105164562Sgshapiroifdef(`_MAILER_TABLE_', `dnl 105238032Speter################################################################### 105338032Speter### Ruleset 90 -- try domain part of mailertable entry ### 105464562Sgshapirodnl input: LeftPartOfDomain <RightPartOfDomain> FullAddress 105538032Speter################################################################### 105638032Speter 105764562SgshapiroSMailertable=90 105864562Sgshapirodnl shift and check 105964562Sgshapirodnl %2 is not documented in cf/README 106038032SpeterR$* <$- . $+ > $* $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4 106164562Sgshapirodnl it is $~[ instead of $- to avoid matches on IPv6 addresses 106264562SgshapiroR$* <$~[ : $* > $* $>MailerToTriple < $2 : $3 > $4 check -- resolved? 106364562SgshapiroR$* < . $+ > $* $@ $>Mailertable $1 . <$2> $3 no -- strip & try again 106464562Sgshapirodnl is $2 always empty? 106538032SpeterR$* < $* > $* $: < $(mailertable . $@ $1$2 $) > $3 try "." 106664562SgshapiroR< $~[ : $* > $* $>MailerToTriple < $1 : $2 > $3 "." found? 106764562Sgshapirodnl return full address 106838032SpeterR< $* > $* $@ $2 no mailertable match', 106938032Speter`dnl') 107038032Speter 107138032Speter################################################################### 107238032Speter### Ruleset 95 -- canonify mailer:[user@]host syntax to triple ### 107364562Sgshapirodnl input: in general: <[mailer:]host> lp<@domain>rest 107464562Sgshapirodnl <> address -> address 107564562Sgshapirodnl <error:d.s.n:text> -> error 107664562Sgshapirodnl <error:text> -> error 107764562Sgshapirodnl <mailer:user@host> lp<@domain>rest -> mailer host user 107864562Sgshapirodnl <mailer:host> address -> mailer host address 107964562Sgshapirodnl <localdomain> address -> address 108064562Sgshapirodnl <[IPv6 number]> address -> relay number address 108164562Sgshapirodnl <host> address -> relay host address 108238032Speter################################################################### 108338032Speter 108464562SgshapiroSMailerToTriple=95 108538032SpeterR< > $* $@ $1 strip off null relay 108664562SgshapiroR< error : $-.$-.$- : $+ > $* $#error $@ $1.$2.$3 $: $4 108738032SpeterR< error : $- $+ > $* $#error $@ $(dequote $1 $) $: $2 108838032SpeterR< local : $* > $* $>CanonLocal < $1 > $2 108938032SpeterR< $- : $+ @ $+ > $*<$*>$* $# $1 $@ $3 $: $2<@$3> use literal user 109038032SpeterR< $- : $+ > $* $# $1 $@ $2 $: $3 try qualified mailer 109138032SpeterR< $=w > $* $@ $2 delete local host 109264562SgshapiroR< [ IPv6 $+ ] > $* $#_RELAY_ $@ $(dequote $1 $) $: $2 use unqualified mailer 109338032SpeterR< $+ > $* $#_RELAY_ $@ $1 $: $2 use unqualified mailer 109438032Speter 109538032Speter################################################################### 109638032Speter### Ruleset CanonLocal -- canonify local: syntax ### 109764562Sgshapirodnl input: <user> address 109864562Sgshapirodnl <x> <@host> : rest -> Recurse rest 109964562Sgshapirodnl <x> p1 $=O p2 <@host> -> Recurse p1 $=O p2 110064562Sgshapirodnl <> user <@host> rest -> local user@host user 110164562Sgshapirodnl <> user -> local user user 110264562Sgshapirodnl <user@host> lp <@domain> rest -> <user> lp <@host> [cont] 110364562Sgshapirodnl <user> lp <@host> rest -> local lp@host user 110464562Sgshapirodnl <user> lp -> local lp user 110538032Speter################################################################### 110638032Speter 110738032SpeterSCanonLocal 110843730Speter# strip local host from routed addresses 110964562SgshapiroR< $* > < @ $+ > : $+ $@ $>Recurse $3 111064562SgshapiroR< $* > $+ $=O $+ < @ $+ > $@ $>Recurse $2 $3 $4 111143730Speter 111238032Speter# strip trailing dot from any host name that may appear 111338032SpeterR< $* > $* < @ $* . > $: < $1 > $2 < @ $3 > 111438032Speter 111538032Speter# handle local: syntax -- use old user, either with or without host 111638032SpeterR< > $* < @ $* > $* $#_LOCAL_ $@ $1@$2 $: $1 111738032SpeterR< > $+ $#_LOCAL_ $@ $1 $: $1 111838032Speter 111938032Speter# handle local:user@host syntax -- ignore host part 112038032SpeterR< $+ @ $+ > $* < @ $* > $: < $1 > $3 < @ $4 > 112138032Speter 112238032Speter# handle local:user syntax 112338032SpeterR< $+ > $* <@ $* > $* $#_LOCAL_ $@ $2@$3 $: $1 112438032SpeterR< $+ > $* $#_LOCAL_ $@ $2 $: $1 112538032Speter 112638032Speter################################################################### 112738032Speter### Ruleset 93 -- convert header names to masqueraded form ### 112838032Speter################################################################### 112938032Speter 113064562SgshapiroSMasqHdr=93 113138032Speter 113264562Sgshapiroifdef(`_GENERICS_TABLE_', `dnl 113338032Speter# handle generics database 113438032Speterifdef(`_GENERICS_ENTIRE_DOMAIN_', 113564562Sgshapirodnl if generics should be applied add a @ as mark 113638032Speter`R$+ < @ $* $=G . > $: < $1@$2$3 > $1 < @ $2$3 . > @ mark', 113738032Speter`R$+ < @ $=G . > $: < $1@$2 > $1 < @ $2 . > @ mark') 113838032SpeterR$+ < @ *LOCAL* > $: < $1@$j > $1 < @ *LOCAL* > @ mark 113964562Sgshapirodnl workspace: either user<@domain> or <user@domain> user <@domain> @ 114064562Sgshapirodnl ignore the first case for now 114164562Sgshapirodnl if it has the mark lookup full address 114264562SgshapiroR< $+ > $+ < $* > @ $: < $(generics $1 $: @ $1 $) > $2 < $3 > 114364562Sgshapirodnl workspace: ... or <match|@user@domain> user <@domain> 114464562Sgshapirodnl no match, try user+detail@domain 114564562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 114664562Sgshapiro $: < $(generics $1+*@$3 $@ $2 $:@$1 + $2@$3 $) > $4 < @ $5 > 114764562SgshapiroR<@$+ + $* @ $+> $+ < @ $+ > 114864562Sgshapiro $: < $(generics $1@$3 $: $) > $4 < @ $5 > 114964562Sgshapirodnl no match, remove mark 115064562SgshapiroR<@$+ > $+ < @ $+ > $: < > $2 < @ $3 > 115164562Sgshapirodnl no match, try @domain for exceptions 115264562SgshapiroR< > $+ < @ $+ . > $: < $(generics @$2 $@ $1 $: $) > $1 < @ $2 . > 115364562Sgshapirodnl workspace: ... or <match> user <@domain> 115464562Sgshapirodnl no match, try local part 115538032SpeterR< > $+ < @ $+ > $: < $(generics $1 $: $) > $1 < @ $2 > 115664562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1+* $@ $2 $: $) > $1 + $2 < @ $3 > 115764562SgshapiroR< > $+ + $* < @ $+ > $: < $(generics $1 $: $) > $1 + $2 < @ $3 > 115864562SgshapiroR< $* @ $* > $* < $* > $@ $>canonify $1 @ $2 found qualified 115964562SgshapiroR< $+ > $* < $* > $: $>canonify $1 @ *LOCAL* found unqualified 116038032SpeterR< > $* $: $1 not found', 116138032Speter`dnl') 116238032Speter 116364562Sgshapiro# do not masquerade anything in class N 116464562SgshapiroR$* < @ $* $=N . > $@ $1 < @ $2 $3 . > 116564562Sgshapiro 116638032Speter# special case the users that should be exposed 116738032SpeterR$=E < @ *LOCAL* > $@ $1 < @ $j . > leave exposed 116838032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 116938032Speter`R$=E < @ $* $=M . > $@ $1 < @ $2 $3 . >', 117038032Speter`R$=E < @ $=M . > $@ $1 < @ $2 . >') 117138032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 117238032Speter`R$=E < @ $=w . > $@ $1 < @ $2 . >') 117338032Speter 117438032Speter# handle domain-specific masquerading 117538032Speterifdef(`_MASQUERADE_ENTIRE_DOMAIN_', 117638032Speter`R$* < @ $* $=M . > $* $: $1 < @ $2 $3 . @ $M > $4 convert masqueraded doms', 117738032Speter`R$* < @ $=M . > $* $: $1 < @ $2 . @ $M > $3 convert masqueraded doms') 117838032Speterifdef(`_LIMITED_MASQUERADE_', `dnl', 117938032Speter`R$* < @ $=w . > $* $: $1 < @ $2 . @ $M > $3') 118038032SpeterR$* < @ *LOCAL* > $* $: $1 < @ $j . @ $M > $2 118138032SpeterR$* < @ $+ @ > $* $: $1 < @ $2 > $3 $M is null 118238032SpeterR$* < @ $+ @ $+ > $* $: $1 < @ $3 . > $4 $M is not null 118338032Speter 118438032Speter################################################################### 118538032Speter### Ruleset 94 -- convert envelope names to masqueraded form ### 118638032Speter################################################################### 118738032Speter 118864562SgshapiroSMasqEnv=94 118938032Speterifdef(`_MASQUERADE_ENVELOPE_', 119064562Sgshapiro`R$+ $@ $>MasqHdr $1', 119138032Speter`R$* < @ *LOCAL* > $* $: $1 < @ $j . > $2') 119238032Speter 119338032Speter################################################################### 119438032Speter### Ruleset 98 -- local part of ruleset zero (can be null) ### 119538032Speter################################################################### 119638032Speter 119764562SgshapiroSParseLocal=98 119864562Sgshapiroundivert(3)dnl LOCAL_RULE_0 119938032Speter 120064562Sgshapiroifdef(`_LDAP_ROUTING_', `dnl 120164562SgshapiroSLDAPExpand 120264562Sgshapiro# do the LDAP lookups 120364562SgshapiroR<$+><$+> $: <$(ldapmra $2 $: $)> <$(ldapmh $2 $: $)> <$1> <$2> 120464562Sgshapiro 120564562Sgshapiro# if mailRoutingAddress and local or non-existant mailHost, 120664562Sgshapiro# return the new mailRoutingAddress 120764562SgshapiroR< $+ > < $=w > < $+ > < $+ > $@ $>Parse0 $>canonify $1 120864562SgshapiroR< $+ > < > < $+ > < $+ > $@ $>Parse0 $>canonify $1 120964562Sgshapiro 121064562Sgshapiro# if mailRoutingAddress and non-local mailHost, 121164562Sgshapiro# relay to mailHost with new mailRoutingAddress 121264562SgshapiroR< $+ > < $+ > < $+ > < $+ > $#_RELAY_ $@ $2 $: $>canonify $1 121364562Sgshapiro 121464562Sgshapiro# if no mailRoutingAddress and local mailHost, 121564562Sgshapiro# return original address 121664562SgshapiroR< > < $=w > <$+> <$+> $@ $2 121764562Sgshapiro 121864562Sgshapiro# if no mailRoutingAddress and non-local mailHost, 121964562Sgshapiro# relay to mailHost with original address 122064562SgshapiroR< > < $+ > <$+> <$+> $#_RELAY_ $@ $1 $: $2 122164562Sgshapiro 122264562Sgshapiro# if no mailRoutingAddress and no mailHost, 122364562Sgshapiro# try @domain 122464562SgshapiroR< > < > <$+> <$+ @ $+> $@ $>LDAPExpand <$1> <@ $3> 122564562Sgshapiro 122664562Sgshapiro# if no mailRoutingAddress and no mailHost and this was a domain attempt, 122764562Sgshapiroifelse(_LDAP_ROUTING_, `_MUST_EXIST_', `dnl 122864562Sgshapiro# user does not exist 122964562SgshapiroR< > < > <$+> <@ $+> $#error $@ nouser $: "550 User unknown"', 123064562Sgshapiro`dnl 123164562Sgshapiro# return the original address 123264562SgshapiroR< > < > <$+> <@ $+> $@ $1')', 123364562Sgshapiro`dnl') 123464562Sgshapiro 123564562Sgshapiroifelse(substr(confDELIVERY_MODE,0,1), `d', `errprint(`WARNING: Antispam rules not available in deferred delivery mode. 123664562Sgshapiro')') 123764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 123838032Speter###################################################################### 123938032Speter### LookUpDomain -- search for domain in access database 124038032Speter### 124138032Speter### Parameters: 124238032Speter### <$1> -- key (domain name) 124338032Speter### <$2> -- default (what to return if not found in db) 124464562Sgshapirodnl must not be empty 124538032Speter### <$3> -- passthru (additional data passed unchanged through) 124664562Sgshapiro### <$4> -- mark (must be <(!|+) single-token>) 124764562Sgshapiro### ! does lookup only with tag 124864562Sgshapiro### + does lookup with and without tag 124964562Sgshapirodnl returns: <default> <passthru> 125064562Sgshapirodnl <result> <passthru> 125138032Speter###################################################################### 125238032Speter 125338032SpeterSLookUpDomain 125464562Sgshapirodnl remove IPv6 mark and dequote address 125564562Sgshapirodnl it is a bit ugly because it is checked on each "iteration" 125664562SgshapiroR<[IPv6 $-]> <$+> <$*> <$*> $: <[$(dequote $1 $)]> <$2> <$3> <$4> 125764562Sgshapirodnl workspace <key> <default> <passthru> <mark> 125864562Sgshapirodnl lookup with tag (in front, no delimiter here) 125964562SgshapiroR<$*> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5> 126064562Sgshapirodnl workspace <result-of-lookup|?> <key> <default> <passthru> <mark> 126164562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest 126264562SgshapiroR<?> <$+.$+> <$+> <$*> <$- $-> $: < $(access $5`'_TAG_DELIM_`'.$2 $: ? $) > <$1.$2> <$3> <$4> <$5 $6>', `dnl') 126364562Sgshapirodnl lookup without tag? 126464562SgshapiroR<?> <$+> <$+> <$*> <+ $*> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4> 126564562Sgshapiroifdef(`_FFR_LOOKUPDOTDOMAIN', `dnl omit first component: lookup .rest 126664562SgshapiroR<?> <$+.$+> <$+> <$*> <+ $*> $: < $(access .$2 $: ? $) > <$1.$2> <$3> <$4> <+ $5>', `dnl') 126764562Sgshapirodnl lookup IP address (no check is done whether it is an IP number!) 126864562SgshapiroR<?> <[$+.$-]> <$+> <$*> <$*> $@ $>LookUpDomain <[$1]> <$3> <$4> <$5> 126964562Sgshapirodnl lookup IPv6 address 127064562SgshapiroR<?> <[$+:$-]> <$+> <$*> <$*> $: $>LookUpDomain <[$1]> <$3> <$4> <$5> 127164562Sgshapirodnl not found, but subdomain: try again 127264562SgshapiroR<?> <$+.$+> <$+> <$*> <$*> $@ $>LookUpDomain <$2> <$3> <$4> <$5> 127364562Sgshapirodnl not found, no subdomain: return default 127464562SgshapiroR<?> <$+> <$+> <$*> <$*> $@ <$2> <$3> 127564562Sgshapirodnl return result of lookup 127664562SgshapiroR<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4> 127738032Speter 127838032Speter###################################################################### 127938032Speter### LookUpAddress -- search for host address in access database 128038032Speter### 128138032Speter### Parameters: 128238032Speter### <$1> -- key (dot quadded host address) 128338032Speter### <$2> -- default (what to return if not found in db) 128464562Sgshapirodnl must not be empty 128538032Speter### <$3> -- passthru (additional data passed through) 128664562Sgshapiro### <$4> -- mark (must be <(!|+) single-token>) 128764562Sgshapiro### ! does lookup only with tag 128864562Sgshapiro### + does lookup with and without tag 128964562Sgshapirodnl returns: <default> <passthru> 129064562Sgshapirodnl <result> <passthru> 129138032Speter###################################################################### 129238032Speter 129338032SpeterSLookUpAddress 129464562Sgshapirodnl lookup with tag 129564562SgshapiroR<$+> <$+> <$*> <$- $+> $: < $(access $5`'_TAG_DELIM_`'$1 $: ? $) > <$1> <$2> <$3> <$4 $5> 129664562Sgshapirodnl lookup without tag 129764562SgshapiroR<?> <$+> <$+> <$*> <+ $+> $: < $(access $1 $: ? $) > <$1> <$2> <$3> <+ $4> 129864562Sgshapirodnl no match; IPv6: remove last part 129964562SgshapiroR<?> <$+:$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 130064562Sgshapirodnl no match; IPv4: remove last part 130164562SgshapiroR<?> <$+.$-> <$+> <$*> <$*> $@ $>LookUpAddress <$1> <$3> <$4> <$5> 130264562Sgshapirodnl no match: return default 130364562SgshapiroR<?> <$+> <$+> <$*> <$*> $@ <$2> <$3> 130464562Sgshapirodnl match: return result 130564562SgshapiroR<$*> <$+> <$+> <$*> <$*> $@ <$1> <$4>', 130638032Speter`dnl') 130738032Speter 130838032Speter###################################################################### 130942575Speter### CanonAddr -- Convert an address into a standard form for 131042575Speter### relay checking. Route address syntax is 131142575Speter### crudely converted into a %-hack address. 131242575Speter### 131342575Speter### Parameters: 131442575Speter### $1 -- full recipient address 131542575Speter### 131642575Speter### Returns: 131742575Speter### parsed address, not in source route form 131864562Sgshapirodnl user%host%host<@domain> 131964562Sgshapirodnl host!user<@domain> 132042575Speter###################################################################### 132142575Speter 132242575SpeterSCanonAddr 132364562SgshapiroR$* $: $>Parse0 $>canonify $1 make domain canonical 132464562Sgshapiroifdef(`_USE_DEPRECATED_ROUTE_ADDR_',`dnl 132542575SpeterR< @ $+ > : $* @ $* < @ $1 > : $2 % $3 change @ to % in src route 132642575SpeterR$* < @ $+ > : $* : $* $3 $1 < @ $2 > : $4 change to % hack. 132742575SpeterR$* < @ $+ > : $* $3 $1 < @ $2 > 132864562Sgshapirodnl') 132942575Speter 133042575Speter###################################################################### 133138032Speter### ParseRecipient -- Strip off hosts in $=R as well as possibly 133238032Speter### $* $=m or the access database. 133338032Speter### Check user portion for host separators. 133438032Speter### 133538032Speter### Parameters: 133638032Speter### $1 -- full recipient address 133738032Speter### 133838032Speter### Returns: 133938032Speter### parsed, non-local-relaying address 134038032Speter###################################################################### 134138032Speter 134238032SpeterSParseRecipient 134364562Sgshapirodnl mark and canonify address 134442575SpeterR$* $: <?> $>CanonAddr $1 134564562Sgshapirodnl workspace: <?> localpart<@domain[.]> 134642575SpeterR<?> $* < @ $* . > <?> $1 < @ $2 > strip trailing dots 134764562Sgshapirodnl workspace: <?> localpart<@domain> 134842575SpeterR<?> $- < @ $* > $: <?> $(dequote $1 $) < @ $2 > dequote local part 134938032Speter 135038032Speter# if no $=O character, no host in the user portion, we are done 135142575SpeterR<?> $* $=O $* < @ $* > $: <NO> $1 $2 $3 < @ $4> 135264562Sgshapirodnl no $=O in localpart: return 135342575SpeterR<?> $* $@ $1 135438032Speter 135564562Sgshapirodnl workspace: <?> localpart<@domain>, where localpart contains $=O 135664562Sgshapirodnl mark everything which has an "authorized" domain with <RELAY> 135738032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 135838032Speter# if we relay, check username portion for user%host so host can be checked also 135942575SpeterR<NO> $* < @ $* $=m > $: <RELAY> $1 < @ $2 $3 >', `dnl') 136042575Speter 136142575Speterifdef(`_RELAY_MX_SERVED_', `dnl 136264562Sgshapirodnl do "we" ($=w) act as backup MX server for the destination domain? 136342575SpeterR<NO> $* < @ $+ > $: <MX> < : $(mxserved $2 $) : > < $1 < @$2 > > 136442575SpeterR<MX> < : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 136564562Sgshapirodnl yes: mark it as <RELAY> 136642575SpeterR<MX> < $* : $=w. : $* > < $+ > $: <RELAY> $4 136764562Sgshapirodnl no: put old <NO> mark back 136842575SpeterR<MX> < : $* : > < $+ > $: <NO> $2', `dnl') 136942575Speter 137064562Sgshapirodnl workspace: <(NO|RELAY)> localpart<@domain>, where localpart contains $=O 137164562Sgshapirodnl if mark is <NO> then change it to <RELAY> if domain is "authorized" 137238032Speterifdef(`_RELAY_HOSTS_ONLY_', 137342575Speter`R<NO> $* < @ $=R > $: <RELAY> $1 < @ $2 > 137464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 137564562SgshapiroR<NO> $* < @ $+ > $: <$(access To:$2 $: NO $)> $1 < @ $2 > 137642575SpeterR<NO> $* < @ $+ > $: <$(access $2 $: NO $)> $1 < @ $2 >',`dnl')', 137742575Speter`R<NO> $* < @ $* $=R > $: <RELAY> $1 < @ $2 $3 > 137864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 137964562SgshapiroR<NO> $* < @ $+ > $: $>LookUpDomain <$2> <NO> <$1 < @ $2 >> <+To> 138042575SpeterR<$+> <$+> $: <$1> $2',`dnl')') 138138032Speter 138264562Sgshapiro 138342575SpeterR<RELAY> $* < @ $* > $@ $>ParseRecipient $1 138442575SpeterR<$-> $* $@ $2 138542575Speter 138664562Sgshapiro 138738032Speter###################################################################### 138838032Speter### check_relay -- check hostname/address on SMTP startup 138938032Speter###################################################################### 139038032Speter 139138032SpeterSLocal_check_relay 139264562SgshapiroScheck`'_U_`'relay 139338032SpeterR$* $: $1 $| $>"Local_check_relay" $1 139438032SpeterR$* $| $* $| $#$* $#$3 139538032SpeterR$* $| $* $| $* $@ $>"Basic_check_relay" $1 $| $2 139638032Speter 139738032SpeterSBasic_check_relay 139838032Speter# check for deferred delivery mode 139938032SpeterR$* $: < ${deliveryMode} > $1 140038032SpeterR< d > $* $@ deferred 140138032SpeterR< $* > $* $: $2 140238032Speter 140364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 140464562SgshapiroR$+ $| $+ $: $>LookUpDomain < $1 > <?> < $2 > <+Connect> 140564562SgshapiroR<?> <$+> $: $>LookUpAddress < $1 > <?> < $1 > <+Connect> no: another lookup 140664562SgshapiroR<?> < $+ > $: $1 found nothing 140764562SgshapiroR<$={Accept}> < $* > $@ $1 140864562SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 140938032SpeterR<DISCARD> $* $#discard $: discard 141064562Sgshapirodnl error tag 141164562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 141264562SgshapiroR<ERROR:$+> $* $#error $: $1 141364562Sgshapirodnl generic error from access map 141464562SgshapiroR<$+> $* $#error $: $1', `dnl') 141538032Speter 141664562Sgshapiroifdef(`_RBL_',`dnl 141764562Sgshapiro# DNS based IP address spam list 141838032SpeterR$* $: $&{client_addr} 141964562SgshapiroR::ffff:$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 142064562SgshapiroR$-.$-.$-.$- $: <?> $(host $4.$3.$2.$1._RBL_. $: OK $) 142164562SgshapiroR<?>OK $: OKSOFAR 142264562SgshapiroR<?>$+ $#error $@ 5.7.1 $: "550 Mail from " $&{client_addr} " refused by blackhole site _RBL_"', 142338032Speter`dnl') 142464562Sgshapiroundivert(8) 142538032Speter 142638032Speter###################################################################### 142738032Speter### check_mail -- check SMTP ``MAIL FROM:'' command argument 142838032Speter###################################################################### 142938032Speter 143038032SpeterSLocal_check_mail 143164562SgshapiroScheck`'_U_`'mail 143238032SpeterR$* $: $1 $| $>"Local_check_mail" $1 143338032SpeterR$* $| $#$* $#$2 143438032SpeterR$* $| $* $@ $>"Basic_check_mail" $1 143538032Speter 143638032SpeterSBasic_check_mail 143738032Speter# check for deferred delivery mode 143838032SpeterR$* $: < ${deliveryMode} > $1 143938032SpeterR< d > $* $@ deferred 144038032SpeterR< $* > $* $: $2 144138032Speter 144264562Sgshapiro# authenticated? 144364562Sgshapirodnl done first: we can require authentication for every mail transaction 144464562Sgshapirodnl workspace: address as given by MAIL FROM: (sender) 144564562SgshapiroR$* $: $1 $| $>"tls_client" $&{verify} $| MAIL 144664562SgshapiroR$* $| $#$+ $#$2 144764562Sgshapirodnl undo damage: remove result of tls_client call 144864562SgshapiroR$* $| $* $: $1 144938032Speter 145064562Sgshapirodnl workspace: address as given by MAIL FROM: 145164562SgshapiroR<> $@ <OK> we MUST accept <> (RFC 1123) 145238032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 145364562Sgshapirodnl do some additional checks 145464562Sgshapirodnl no user@host 145564562Sgshapirodnl no user@localhost (if nonlocal sender) 145664562Sgshapirodnl this is a pretty simple canonification, it will not catch every case 145764562Sgshapirodnl just make sure the address has <> around it (which is required by 145864562Sgshapirodnl the RFC anyway, maybe we should complain if they are missing...) 145964562Sgshapirodnl dirty trick: if it is user@host, just add a dot: user@host. this will 146064562Sgshapirodnl not be modified by host lookups. 146164562SgshapiroR$+ $: <?> $1 146264562SgshapiroR<?><$+> $: <@> <$1> 146364562SgshapiroR<?>$+ $: <@> <$1> 146464562Sgshapirodnl workspace: <@> <address> 146564562Sgshapirodnl prepend daemon_flags 146664562SgshapiroR$* $: $&{daemon_flags} $| $1 146764562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 146864562Sgshapirodnl do not allow these at all or only from local systems? 146964562SgshapiroR$* f $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 147064562Sgshapirodnl accept unqualified sender: change mark to avoid test 147164562SgshapiroR$* u $* $| <@> < $* > $: <?> < $3 > 147264562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 147364562Sgshapirodnl or: <? ${client_name} > <address> 147464562Sgshapirodnl or: <?> <address> 147564562Sgshapirodnl remove daemon_flags 147664562SgshapiroR$* $| $* $: $2 147738032Speter# handle case of @localhost on address 147864562SgshapiroR<@> < $* @ localhost > $: < ? $&{client_name} > < $1 @ localhost > 147964562SgshapiroR<@> < $* @ [127.0.0.1] > 148064562Sgshapiro $: < ? $&{client_name} > < $1 @ [127.0.0.1] > 148164562SgshapiroR<@> < $* @ localhost.$m > 148264562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.$m > 148338032Speterifdef(`_NO_UUCP_', `dnl', 148464562Sgshapiro`R<@> < $* @ localhost.UUCP > 148564562Sgshapiro $: < ? $&{client_name} > < $1 @ localhost.UUCP >') 148664562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 148764562Sgshapirodnl or: <@> <address> 148864562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 148964562SgshapiroR<@> $* $: $1 no localhost as domain 149064562Sgshapirodnl workspace: < ? $&{client_name} > <user@localhost|host> 149164562Sgshapirodnl or: <address> 149264562Sgshapirodnl or: <?> <address> (thanks to u in ${daemon_flags}) 149364562SgshapiroR<? $=w> $* $: $2 local client: ok 149464562SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "553 Real domain name required" 149564562Sgshapirodnl remove <?> (happens only if ${client_name} == "" or u in ${daemon_flags}) 149664562SgshapiroR<?> $* $: $1') 149764562Sgshapirodnl workspace: address (or <address>) 149864562SgshapiroR$* $: <?> $>CanonAddr $1 canonify sender address and mark it 149964562Sgshapirodnl workspace: <?> CanonicalAddress (i.e. address in canonical form localpart<@host>) 150064562Sgshapirodnl there is nothing behind the <@host> so no trailing $* needed 150164562SgshapiroR<?> $* < @ $+ . > <?> $1 < @ $2 > strip trailing dots 150264562Sgshapiro# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc) 150364562SgshapiroR<?> $* < @ $* $=P > $: <OK> $1 < @ $2 $3 > 150464562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ? or OK 150564562Sgshapiroifdef(`_ACCEPT_UNRESOLVABLE_DOMAINS_', 150664562Sgshapiro`R<?> $* < @ $+ > $: <OK> $1 < @ $2 > ... unresolvable OK', 150764562Sgshapiro`R<?> $* < @ $+ > $: <? $(resolve $2 $: $2 <PERM> $) > $1 < @ $2 > 150864562SgshapiroR<? $* <$->> $* < @ $+ > 150964562Sgshapiro $: <$2> $3 < @ $4 >') 151064562Sgshapirodnl workspace <mark> CanonicalAddress where mark is ?, OK, PERM, TEMP 151164562Sgshapirodnl mark is ? iff the address is user (wo @domain) 151238032Speter 151364562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 151464562Sgshapiro# check sender address: user@address, user@, address 151564562Sgshapirodnl should we remove +ext from user? 151664562Sgshapirodnl workspace: <mark> CanonicalAddress where mark is: ?, OK, PERM, TEMP 151764562SgshapiroR<$+> $+ < @ $* > $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <H:$3> 151864562SgshapiroR<$+> $+ $: @<$1> <$2> $| <U:$2@> 151964562Sgshapirodnl workspace: @<mark> <CanonicalAddress> $| <@type:address> .... 152064562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 152164562Sgshapirodnl will only return user<@domain when "reversing" the args 152264562SgshapiroR@ <$+> <$*> $| <$+> $: <@> <$1> <$2> $| $>SearchList <+From> $| <$3> <> 152364562Sgshapirodnl workspace: <@><mark> <CanonicalAddress> $| <result> 152464562SgshapiroR<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2> reverse result 152564562Sgshapirodnl workspace: <result> <mark> <CanonicalAddress> 152638032Speter# retransform for further use 152764562Sgshapirodnl required form: 152864562Sgshapirodnl <ResultOfLookup|mark> CanonicalAddress 152964562SgshapiroR<?> <$+> <$*> $: <$1> $2 no match 153064562SgshapiroR<$+> <$+> <$*> $: <$1> $3 relevant result, keep it', `dnl') 153164562Sgshapirodnl workspace <ResultOfLookup|mark> CanonicalAddress 153264562Sgshapirodnl mark is ? iff the address is user (wo @domain) 153338032Speter 153438032Speterifdef(`_ACCEPT_UNQUALIFIED_SENDERS_',`dnl',`dnl 153538032Speter# handle case of no @domain on address 153664562Sgshapirodnl prepend daemon_flags 153764562SgshapiroR<?> $* $: $&{daemon_flags} $| <?> $1 153864562Sgshapirodnl accept unqualified sender: change mark to avoid test 153964562SgshapiroR$* u $* $| <?> $* $: <OK> $3 154064562Sgshapirodnl remove daemon_flags 154164562SgshapiroR$* $| $* $: $2 154238032SpeterR<?> $* $: < ? $&{client_name} > $1 154338032SpeterR<?> $* $@ <OK> ...local unqualed ok 154438032SpeterR<? $+> $* $#error $@ 5.5.4 $: "553 Domain name required" 154538032Speter ...remote is not') 154638032Speter# check results 154764562SgshapiroR<?> $* $: @ $1 mark address: nothing known about it 154838032SpeterR<OK> $* $@ <OK> 154964562SgshapiroR<TEMP> $* $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve" 155064562SgshapiroR<PERM> $* $#error $@ 5.1.8 $: "501 Domain of sender address " $&f " does not exist" 155164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 155264562SgshapiroR<$={Accept}> $* $# $1 155338032SpeterR<DISCARD> $* $#discard $: discard 155464562SgshapiroR<REJECT> $* $#error ifdef(`confREJECT_MSG', `$: "confREJECT_MSG"', `$@ 5.7.1 $: "550 Access denied"') 155564562Sgshapirodnl error tag 155664562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 155764562SgshapiroR<ERROR:$+> $* $#error $: $1 155864562Sgshapirodnl generic error from access map 155964562SgshapiroR<$+> $* $#error $: $1 error from access db', 156038032Speter`dnl') 156138032Speter 156238032Speter###################################################################### 156338032Speter### check_rcpt -- check SMTP ``RCPT TO:'' command argument 156438032Speter###################################################################### 156538032Speter 156638032SpeterSLocal_check_rcpt 156764562SgshapiroScheck`'_U_`'rcpt 156838032SpeterR$* $: $1 $| $>"Local_check_rcpt" $1 156938032SpeterR$* $| $#$* $#$2 157038032SpeterR$* $| $* $@ $>"Basic_check_rcpt" $1 157138032Speter 157238032SpeterSBasic_check_rcpt 157338032Speter# check for deferred delivery mode 157438032SpeterR$* $: < ${deliveryMode} > $1 157538032SpeterR< d > $* $@ deferred 157638032SpeterR< $* > $* $: $2 157738032Speter 157864562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 157964562Sgshapiro# require qualified recipient? 158064562SgshapiroR$+ $: <?> $1 158164562SgshapiroR<?><$+> $: <@> <$1> 158264562SgshapiroR<?>$+ $: <@> <$1> 158364562Sgshapirodnl prepend daemon_flags 158464562SgshapiroR$* $: $&{daemon_flags} $| $1 158564562Sgshapirodnl workspace: ${daemon_flags} $| <@> <address> 158664562Sgshapirodnl do not allow these at all or only from local systems? 158764562SgshapiroR$* r $* $| <@> < $* @ $- > $: < ? $&{client_name} > < $3 @ $4 > 158864562SgshapiroR<?> < $* > $: <$1> 158964562SgshapiroR<? $=w> < $* > $: <$1> 159064562SgshapiroR<? $+> <$+> $#error $@ 5.5.4 $: "553 Domain name required" 159164562Sgshapirodnl remove daemon_flags for other cases 159264562SgshapiroR$* $| <@> $* $: $2', `dnl') 159364562Sgshapiro 159438032Speterifdef(`_LOOSE_RELAY_CHECK_',`dnl 159542575SpeterR$* $: $>CanonAddr $1 159638032SpeterR$* < @ $* . > $1 < @ $2 > strip trailing dots', 159738032Speter`R$* $: $>ParseRecipient $1 strip relayable hosts') 159838032Speter 159942575Speterifdef(`_BESTMX_IS_LOCAL_',`dnl 160042575Speterifelse(_BESTMX_IS_LOCAL_, `', `dnl 160142575Speter# unlimited bestmx 160242575SpeterR$* < @ $* > $* $: $1 < @ $2 @@ $(bestmx $2 $) > $3', 160342575Speter`dnl 160442575Speter# limit bestmx to $=B 160543730SpeterR$* < @ $* $=B > $* $: $1 < @ $2 $3 @@ $(bestmx $2 $3 $) > $4') 160664562SgshapiroR$* $=O $* < @ $* @@ $=w . > $* $@ $>"Basic_check_rcpt" $1 $2 $3 160742575SpeterR$* < @ $* @@ $=w . > $* $: $1 < @ $3 > $4 160842575SpeterR$* < @ $* @@ $* > $* $: $1 < @ $2 > $4') 160942575Speter 161038032Speterifdef(`_BLACKLIST_RCPT_',`dnl 161164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 161238032Speter# blacklist local users or any host from receiving mail 161338032SpeterR$* $: <?> $1 161464562Sgshapirodnl user is now tagged with @ to be consistent with check_mail 161564562Sgshapirodnl and to distinguish users from hosts (com would be host, com@ would be user) 161664562SgshapiroR<?> $+ < @ $=w > $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <H:$2> 161764562SgshapiroR<?> $+ < @ $* > $: <> <$1 < @ $2 >> $| <F:$1@$2> <H:$2> 161864562SgshapiroR<?> $+ $: <> <$1> $| <U:$1@> 161964562Sgshapirodnl $| is used as delimiter, otherwise false matches may occur: <user<@domain>> 162064562Sgshapirodnl will only return user<@domain when "reversing" the args 162164562SgshapiroR<> <$*> $| <$+> $: <@> <$1> $| $>SearchList <+To> $| <$2> <> 162264562SgshapiroR<@> <$*> $| <$*> $: <$2> <$1> reverse result 162364562SgshapiroR<?> <$*> $: @ $1 mark address as no match 162464562SgshapiroR<$={Accept}> <$*> $: @ $2 mark address as no match 162564562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 162664562Sgshapirodnl we have to filter these because otherwise they would be interpreted 162764562Sgshapirodnl as generic error message... 162864562Sgshapirodnl error messages should be "tagged" by prefixing them with error: ! 162964562Sgshapirodnl that would make a lot of things easier. 163064562Sgshapirodnl maybe we should stop checks already here (if SPAM_xyx)? 163164562SgshapiroR<$={SpamTag}> <$*> $: @ $2 mark address as no match') 163238032SpeterR<REJECT> $* $#error $@ 5.2.1 $: "550 Mailbox disabled for this recipient" 163364562SgshapiroR<DISCARD> $* $#discard $: discard 163464562Sgshapirodnl error tag 163564562SgshapiroR<ERROR:$-.$-.$-:$+> $* $#error $@ $1.$2.$3 $: $4 163664562SgshapiroR<ERROR:$+> $* $#error $: $1 163764562Sgshapirodnl generic error from access map 163864562SgshapiroR<$+> $* $#error $: $1 error from access db 163964562SgshapiroR@ $* $1 remove mark', `dnl')', `dnl') 164038032Speter 164164562Sgshapiroifdef(`_PROMISCUOUS_RELAY_', `divert(-1)') 164264562Sgshapiro# authenticated? 164364562Sgshapirodnl do this unconditionally? this requires to manage CAs carefully 164464562Sgshapirodnl just because someone has a CERT signed by a "trusted" CA 164564562Sgshapirodnl does not mean we want to allow relaying for her, 164664562Sgshapirodnl either use a subroutine or provide something more sophisticated 164764562Sgshapirodnl this could for example check the DN (maybe an access map lookup) 164864562SgshapiroR$* $: $1 $| $>RelayAuth $1 $| $&{verify} client authenticated? 164964562SgshapiroR$* $| $# $+ $# $2 error/ok? 165064562SgshapiroR$* $| $* $: $1 no 165164562Sgshapiro 165264562Sgshapiro# authenticated by a trusted mechanism? 165364562SgshapiroR$* $: $1 $| $&{auth_type} 165464562Sgshapirodnl empty ${auth_type}? 165564562SgshapiroR$* $| $: $1 165664562Sgshapirodnl mechanism ${auth_type} accepted? 165764562Sgshapirodnl use $# to override further tests (delay_checks): see check_rcpt below 165864562SgshapiroR$* $| $={TrustAuthMech} $# RELAYAUTH 165964562Sgshapirodnl undo addition of ${auth_type} 166064562SgshapiroR$* $| $* $: $1 166164562Sgshapirodnl workspace: localpart<@domain> 166264562Sgshapiroifelse(defn(`_NO_UUCP_'), `r', 166364562Sgshapiro`R$* ! $* < @ $* > $: <REMOTE> $2 < @ BANG_PATH >', `dnl') 166438032Speter# anything terminating locally is ok 166538032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 166664562SgshapiroR$+ < @ $* $=m > $@ RELAYTO', `dnl') 166764562SgshapiroR$+ < @ $=w > $@ RELAYTO 166838032Speterifdef(`_RELAY_HOSTS_ONLY_', 166964562Sgshapiro`R$+ < @ $=R > $@ RELAYTO 167064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 167164562SgshapiroR$+ < @ $+ > $: <$(access To:$2 $: ? $)> <$1 < @ $2 >> 167264562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 167364562SgshapiroR<?> <$+ < @ $+ >> $: <$(access $2 $: ? $)> <$1 < @ $2 >>',`dnl')', 167464562Sgshapiro`R$+ < @ $* $=R > $@ RELAYTO 167564562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 167664562SgshapiroR$+ < @ $+ > $: $>LookUpDomain <$2> <?> <$1 < @ $2 >> <+To>',`dnl')') 167764562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 167864562Sgshapirodnl workspace: <Result-of-lookup | ?> <localpart<@domain>> 167964562SgshapiroR<RELAY> $* $@ RELAYTO 168038032SpeterR<$*> <$*> $: $2',`dnl') 168138032Speter 168264562Sgshapiro 168338032Speterifdef(`_RELAY_MX_SERVED_', `dnl 168438032Speter# allow relaying for hosts which we MX serve 168564562SgshapiroR$+ < @ $+ > $: < : $(mxserved $2 $) : > $1 < @ $2 > 168664562Sgshapirodnl this must not necessarily happen if the client is checked first... 168738032SpeterR< : $* <TEMP> : > $* $#error $@ 4.7.1 $: "450 Can not check MX records for recipient host " $1 168864562SgshapiroR<$* : $=w . : $*> $* $@ RELAYTO 168942575SpeterR< : $* : > $* $: $2', 169038032Speter`dnl') 169138032Speter 169238032Speter# check for local user (i.e. unqualified address) 169338032SpeterR$* $: <?> $1 169442575SpeterR<?> $* < @ $+ > $: <REMOTE> $1 < @ $2 > 169538032Speter# local user is ok 169664562Sgshapirodnl is it really? the standard requires user@domain, not just user 169764562Sgshapirodnl but we should accept it anyway (maybe making it an option: 169864562Sgshapirodnl RequireFQDN ?) 169964562Sgshapirodnl postmaster must be accepted without domain (DRUMS) 170064562Sgshapiroifdef(`_REQUIRE_QUAL_RCPT_', `dnl 170164562SgshapiroR<?> postmaster $@ TOPOSTMASTER 170264562Sgshapiro# require qualified recipient? 170364562Sgshapirodnl prepend daemon_flags 170464562SgshapiroR<?> $+ $: $&{daemon_flags} $| <?> $1 170564562Sgshapirodnl workspace: ${daemon_flags} $| <?> localpart 170664562Sgshapirodnl do not allow these at all or only from local systems? 170764562Sgshapirodnl r flag? add client_name 170864562SgshapiroR$* r $* $| <?> $+ $: < ? $&{client_name} > <?> $3 170964562Sgshapirodnl no r flag: relay to local user (only local part) 171064562Sgshapiro# no qualified recipient required 171164562SgshapiroR$* $| <?> $+ $@ RELAYTOLOCAL 171264562Sgshapirodnl client_name is empty 171364562SgshapiroR<?> <?> $+ $@ RELAYTOLOCAL 171464562Sgshapirodnl client_name is local 171564562SgshapiroR<? $=w> <?> $+ $@ RELAYTOLOCAL 171664562Sgshapirodnl client_name is not local 171764562SgshapiroR<? $+> $+ $#error $@ 5.5.4 $: "553 Domain name required"', `dnl 171864562Sgshapirodnl no qualified recipient required 171964562SgshapiroR<?> $+ $@ RELAYTOLOCAL') 172064562Sgshapirodnl it is a remote user: remove mark and then check client 172138032SpeterR<$+> $* $: $2 172264562Sgshapirodnl currently the recipient address is not used below 172338032Speter 172438032Speter# anything originating locally is ok 172564562Sgshapiro# check IP address 172664562SgshapiroR$* $: $&{client_addr} 172764562SgshapiroR$@ $@ RELAYFROM originated locally 172864562SgshapiroR0 $@ RELAYFROM originated locally 172964562SgshapiroR$=R $* $@ RELAYFROM relayable IP address 173064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 173164562SgshapiroR$* $: $>LookUpAddress <$1> <?> <$1> <+Connect> 173264562SgshapiroR<RELAY> $* $@ RELAYFROM relayable IP address 173364562SgshapiroR<$*> <$*> $: $2', `dnl') 173464562SgshapiroR$* $: [ $1 ] put brackets around it... 173564562SgshapiroR$=w $@ RELAYFROM ... and see if it is local 173664562Sgshapiro 173764562Sgshapiroifdef(`_RELAY_DB_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 173864562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `define(`_RELAY_MAIL_FROM_', `1')')dnl 173964562Sgshapiroifdef(`_RELAY_MAIL_FROM_', `dnl 174064562Sgshapirodnl input: {client_addr} or something "broken" 174164562Sgshapirodnl just throw the input away; we do not need it. 174264562Sgshapiro# check whether FROM is allowed to use system as relay 174364562SgshapiroR$* $: <?> $>CanonAddr $&f 174464562Sgshapiroifdef(`_RELAY_LOCAL_FROM_', `dnl 174564562Sgshapiro# check whether local FROM is ok 174664562SgshapiroR<?> $+ < @ $=w . > $@ RELAYFROMMAIL FROM local', `dnl') 174764562Sgshapiroifdef(`_RELAY_DB_FROM_', `dnl 174864562SgshapiroR<?> $+ < @ $+ . > <?> $1 < @ $2 > remove trailing dot 174964562SgshapiroR<?> $+ < @ $+ > $: $1 < @ $2 > $| $>SearchList <! From> $| <F:$1@$2> ifdef(`_RELAY_DB_FROM_DOMAIN_', `<H:$2>') <> 175064562SgshapiroR$* <RELAY> $@ RELAYFROMMAIL RELAY FROM sender ok', `dnl 175164562Sgshapiroifdef(`_RELAY_DB_FROM_DOMAIN_', `errprint(`*** ERROR: _RELAY_DB_FROM_DOMAIN_ requires _RELAY_DB_FROM_ 175264562Sgshapiro')', 175364562Sgshapiro`dnl') 175464562Sgshapirodnl')', `dnl') 175564562Sgshapiro 175664562Sgshapiro# check client name: first: did it resolve? 175764562Sgshapirodnl input: ignored 175864562SgshapiroR$* $: < $&{client_resolve} > 175964562SgshapiroR<TEMP> $#error $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr} 176064562SgshapiroR<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name} 176164562SgshapiroR<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name} 176264562Sgshapirodnl ${client_resolve} should be OK, so go ahead 176338032SpeterR$* $: <?> $&{client_name} 176438032Speter# pass to name server to make hostname canonical 176564562SgshapiroR<?> $* $~P $:<?> $[ $1 $2 $] 176664562SgshapiroR$* . $1 strip trailing dots 176764562Sgshapirodnl should not be necessary since it has been done for client_addr already 176864562SgshapiroR<?> $@ RELAYFROM 176938032Speterifdef(`_RELAY_ENTIRE_DOMAIN_', `dnl 177064562SgshapiroR<?> $* $=m $@ RELAYFROM', `dnl') 177164562SgshapiroR<?> $=w $@ RELAYFROM 177238032Speterifdef(`_RELAY_HOSTS_ONLY_', 177364562Sgshapiro`R<?> $=R $@ RELAYFROM 177464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 177564562SgshapiroR<?> $* $: <$(access Connect:$1 $: ? $)> <$1> 177664562SgshapiroR<?> <$*> $: <$(access $1 $: ? $)> <$1>',`dnl')', 177764562Sgshapiro`R<?> $* $=R $@ RELAYFROM 177864562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 177964562SgshapiroR<?> $* $: $>LookUpDomain <$1> <?> <$1> <+Connect>',`dnl')') 178064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 178164562SgshapiroR<RELAY> $* $@ RELAYFROM 178238032SpeterR<$*> <$*> $: $2',`dnl') 178338032Speter 178464562Sgshapiro# anything else is bogus 178564562SgshapiroR$* $#error $@ 5.7.1 $: confRELAY_MSG 178664562Sgshapirodivert(0) 178764562Sgshapiroifdef(`_DELAY_CHECKS_',`dnl 178864562Sgshapiro# turn a canonical address in the form user<@domain> 178964562Sgshapiro# qualify unqual. addresses with $j 179064562Sgshapirodnl it might have been only user (without <@domain>) 179164562SgshapiroSFullAddr 179264562SgshapiroR$* <@ $+ . > $1 <@ $2 > 179364562SgshapiroR$* <@ $* > $@ $1 <@ $2 > 179464562SgshapiroR$+ $@ $1 <@ $j > 179538032Speter 179664562Sgshapiro# call all necessary rulesets 179764562SgshapiroScheck_rcpt 179864562Sgshapirodnl this test should be in the Basic_check_rcpt ruleset 179964562Sgshapirodnl which is the correct DSN code? 180064562Sgshapiro# R$@ $#error $@ 5.1.3 $: "553 Recipient address required" 180164562SgshapiroR$+ $: $1 $| $>checkrcpt $1 180264562Sgshapirodnl now we can simply stop checks by returning "$# xyz" instead of just "ok" 180364562SgshapiroR$+ $| $#$* $#$2 180464562SgshapiroR$+ $| $* $: <?> $>FullAddr $>CanonAddr $1 180564562Sgshapiroifdef(`_SPAM_FH_', 180664562Sgshapiro`dnl lookup user@ and user@address 180764562Sgshapiroifdef(`_ACCESS_TABLE_', `', 180864562Sgshapiro`errprint(`*** ERROR: FEATURE(`delay_checks', `argument') requires FEATURE(`access_db') 180964562Sgshapiro')')dnl 181064562Sgshapirodnl one of the next two rules is supposed to match 181164562Sgshapirodnl this code has been copied from BLACKLIST... etc 181264562Sgshapirodnl and simplified by omitting some < >. 181364562SgshapiroR<?> $+ < @ $=w > $: <> $1 < @ $2 > $| <F: $1@$2 > <U: $1@> 181464562SgshapiroR<?> $+ < @ $* > $: <> $1 < @ $2 > $| <F: $1@$2 > 181564562Sgshapirodnl R<?> $@ something_is_very_wrong_here 181664562Sgshapiro# lookup the addresses only with To tag 181764562SgshapiroR<> $* $| <$+> $: <@> $1 $| $>SearchList <!To> $| <$2> <> 181864562SgshapiroR<@> $* $| $* $: $2 $1 reverse result 181964562Sgshapirodnl', `dnl') 182064562Sgshapiroifdef(`_SPAM_FRIEND_', 182164562Sgshapiro`# is the recipient a spam friend? 182264562Sgshapiroifdef(`_SPAM_HATER_', 182364562Sgshapiro `errprint(`*** ERROR: define either SpamHater or SpamFriend 182464562Sgshapiro')', `dnl') 182564562SgshapiroR<SPAMFRIEND> $+ $@ SPAMFRIEND 182664562SgshapiroR<$*> $+ $: $2', 182764562Sgshapiro`dnl') 182864562Sgshapiroifdef(`_SPAM_HATER_', 182964562Sgshapiro`# is the recipient no spam hater? 183064562SgshapiroR<SPAMHATER> $+ $: $1 spam hater: continue checks 183164562SgshapiroR<$*> $+ $@ NOSPAMHATER everyone else: stop 183264562Sgshapirodnl',`dnl') 183364562Sgshapirodnl run further checks: check_mail 183464562Sgshapirodnl should we "clean up" $&f? 183564562SgshapiroR$* $: $1 $| $>checkmail <$&f> 183664562SgshapiroR$* $| $#$* $#$2 183764562Sgshapirodnl run further checks: check_relay 183864562SgshapiroR$* $: $1 $| $>checkrelay $&{client_name} $| $&{client_addr} 183964562SgshapiroR$* $| $#$* $#$2 184038032SpeterR$* $| $* $: $1 184138032Speter', `dnl') 184264562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 184364562Sgshapiro###################################################################### 184464562Sgshapiro### SearchList: search a list of items in the access map 184564562Sgshapiro### Parameters: 184664562Sgshapiro### <exact tag> $| <mark:address> <mark:address> ... <> 184764562Sgshapirodnl maybe we should have a @ (again) in front of the mark to 184864562Sgshapirodnl avoid errorneous matches (with error messages?) 184964562Sgshapirodnl if we can make sure that tag is always a single token 185064562Sgshapirodnl then we can omit the delimiter $|, otherwise we need it 185164562Sgshapirodnl to avoid errorneous matchs (first rule: H: if there 185264562Sgshapirodnl is that mark somewhere in the list, it will be taken). 185364562Sgshapirodnl moreover, we can do some tricks to enforce lookup with 185464562Sgshapirodnl the tag only, e.g.: 185564562Sgshapiro### where "exact" is either "+" or "!": 185664562Sgshapiro### <+ TAG> lookup with and w/o tag 185764562Sgshapiro### <! TAG> lookup with tag 185864562Sgshapirodnl Warning: + and ! should be in OperatorChars (otherwise there must be 185964562Sgshapirodnl a blank between them and the tag. 186064562Sgshapiro### possible values for "mark" are: 186164562Sgshapiro### H: recursive host lookup (LookUpDomain) 186264562Sgshapirodnl A: recursive address lookup (LookUpAddress) [not yet required] 186364562Sgshapiro### E: exact lookup, no modifications 186464562Sgshapiro### F: full lookup, try user+ext@domain and user@domain 186564562Sgshapiro### U: user lookup, try user+ext and user (input must have trailing @) 186664562Sgshapiro### return: <RHS of lookup> or <?> (not found) 186764562Sgshapiro###################################################################### 186838032Speter 186964562Sgshapiro# class with valid marks for SearchList 187064562Sgshapirodnl if A is activated: add it 187164562SgshapiroC{src}E F H U 187264562SgshapiroSSearchList 187364562Sgshapiro# mark H: lookup domain 187464562SgshapiroR<$+> $| <H:$+> <$*> $: <$1> $| <@> $>LookUpDomain <$2> <?> <$3> <$1> 187564562SgshapiroR<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> 187664562Sgshapirodnl A: NOT YET REQUIRED 187764562Sgshapirodnl R<$+> $| <A:$+> <$*> $: <$1> $| <@> $>LookUpAddress <$2> <?> <$3> <$1> 187864562Sgshapirodnl R<$+> $| <@> <$+> <$*> $: <$1> $| <$2> <$3> 187964562Sgshapirodnl lookup of the item with tag 188064562Sgshapirodnl this applies to F: U: E: 188164562SgshapiroR<$- $-> $| <$={src}:$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$4 $: $3:$4 $)> <$5> 188264562Sgshapirodnl no match, try without tag 188364562SgshapiroR<+ $-> $| <$={src}:$+> <$*> $: <+ $1> $| <$(access $3 $: $2:$3 $)> <$4> 188464562Sgshapirodnl do we really have to distinguish these cases? 188564562Sgshapirodnl probably yes, there might be a + in the domain part (is that allowed?) 188664562Sgshapirodnl user+detail lookups: should it be: 188764562Sgshapirodnl user+detail, user+*, user; just like aliases? 188864562SgshapiroR<$- $-> $| <F:$* + $*@$+> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@$5 $: F:$3 + $4@$5$)> <$6> 188964562SgshapiroR<+ $-> $| <F:$* + $*@$+> <$*> $: <+ $1> $| <$(access $2@$4 $: F:$2 + $3@$4$)> <$5> 189064562Sgshapirodnl user lookups are always with trailing @ 189164562Sgshapirodnl do not remove the @ from the lookup: 189264562Sgshapirodnl it is part of the +detail@ which is omitted for the lookup 189364562SgshapiroR<$- $-> $| <U:$* + $*> <$*> $: <$1 $2> $| <$(access $2`'_TAG_DELIM_`'$3@ $: U:$3 + $4$)> <$5> 189464562Sgshapirodnl no match, try without tag 189564562SgshapiroR<+ $-> $| <U:$* + $*> <$*> $: <+ $1> $| <$(access $2@ $: U:$2 + $3$)> <$4> 189664562Sgshapirodnl no match, try rest of list 189764562SgshapiroR<$+> $| <$={src}:$+> <$+> $@ $>SearchList <$1> $| <$4> 189864562Sgshapirodnl no match, list empty: return failure 189964562SgshapiroR<$+> $| <$={src}:$+> <> $@ <?> 190064562Sgshapirodnl got result, return it 190164562SgshapiroR<$+> $| <$+> <$*> $@ <$2> 190264562Sgshapirodnl return result from recursive invocation 190364562SgshapiroR<$+> $| <$+> $@ <$2>', `dnl') 190438032Speter 190564562Sgshapiro# is user trusted to authenticate as someone else? 190664562Sgshapirodnl AUTH= parameter from MAIL command 190764562SgshapiroStrust_auth 190864562SgshapiroR$* $: $&{auth_type} $| $1 190964562Sgshapiro# required by RFC 2554 section 4. 191064562SgshapiroR$@ $| $* $#error $@ 5.7.1 $: "550 not authenticated" 191164562Sgshapirodnl seems to be useful... 191264562SgshapiroR$* $| $&{auth_authen} $@ identical 191364562SgshapiroR$* $| <$&{auth_authen}> $@ identical 191464562Sgshapirodnl call user supplied code 191564562SgshapiroR$* $| $* $: $1 $| $>"Local_trust_auth" $1 191664562SgshapiroR$* $| $#$* $#$2 191764562Sgshapirodnl default: error 191864562SgshapiroR$* $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author} 191964562Sgshapiro 192064562Sgshapirodnl empty ruleset definition so it can be called 192164562SgshapiroSLocal_trust_auth 192264562Sgshapiro 192364562Sgshapiroifdef(`_FFR_TLS_O_T', `dnl 192464562SgshapiroSoffer_tls 192564562SgshapiroR$* $: $>LookUpDomain <$&{client_name}> <?> <> <! TLS_OFF_TAG> 192664562SgshapiroR<?>$* $: $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_OFF_TAG> 192764562SgshapiroR<?>$* $: <$(access TLS_OFF_TAG: $: ? $)> 192864562SgshapiroR<?>$* $@ OK 192964562SgshapiroR<NO> <> $#error $@ 5.7.1 $: "550 do not offer TLS for " $&{client_name} " ["$&{client_addr}"]" 193064562Sgshapiro 193164562SgshapiroStry_tls 193264562SgshapiroR$* $: $>LookUpDomain <$&{server_name}> <?> <> <! TLS_TRY_TAG> 193364562SgshapiroR<?>$* $: $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_TRY_TAG> 193464562SgshapiroR<?>$* $: <$(access TLS_TRY_TAG: $: ? $)> 193564562SgshapiroR<?>$* $@ OK 193664562SgshapiroR<NO> <> $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]" 193764562Sgshapiro')dnl 193864562Sgshapiro 193964562Sgshapiro# is connection with client "good" enough? (done in server) 194064562Sgshapiro# input: ${verify} $| (MAIL|STARTTLS) 194164562Sgshapirodnl MAIL: called from check_mail 194264562Sgshapirodnl STARTTLS: called from smtp() after STARTTLS has been accepted 194364562SgshapiroStls_client 194464562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 194564562Sgshapirodnl ignore second arg for now 194664562Sgshapirodnl maybe use it to distinguish permanent/temporary error? 194764562Sgshapirodnl if MAIL: permanent (STARTTLS has not been offered) 194864562Sgshapirodnl if STARTTLS: temporary (offered but maybe failed) 194964562SgshapiroR$* $| $* $: $1 $| $>LookUpDomain <$&{client_name}> <?> <> <! TLS_CLT_TAG> 195064562SgshapiroR$* $| <?>$* $: $1 $| $>LookUpAddress <$&{client_addr}> <?> <> <! TLS_CLT_TAG> 195164562Sgshapirodnl do a default lookup: just TLS_CLT_TAG 195264562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_CLT_TAG`'_TAG_DELIM_ $: ? $)> 195364562SgshapiroR$* $@ $>"tls_connection" $1', `dnl 195464562SgshapiroR$* $| $* $@ $>"tls_connection" $1') 195564562Sgshapiro 195664562Sgshapiro# is connection with server "good" enough? (done in client) 195764562Sgshapirodnl i.e. has the server been authenticated and is encryption active? 195864562Sgshapirodnl called from deliver() after STARTTLS command 195964562Sgshapiro# input: ${verify} 196064562SgshapiroStls_server 196164562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 196264562SgshapiroR$* $: $1 $| $>LookUpDomain <$&{server_name}> <?> <> <! TLS_SRV_TAG> 196364562SgshapiroR$* $| <?>$* $: $1 $| $>LookUpAddress <$&{server_addr}> <?> <> <! TLS_SRV_TAG> 196464562Sgshapirodnl do a default lookup: just TLS_SRV_TAG 196564562SgshapiroR$* $| <?>$* $: $1 $| <$(access TLS_SRV_TAG`'_TAG_DELIM_ $: ? $)> 196664562SgshapiroR$* $@ $>"tls_connection" $1', `dnl 196764562SgshapiroR$* $@ $>"tls_connection" $1') 196864562Sgshapiro 196964562SgshapiroStls_connection 197064562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 197164562Sgshapirodnl common ruleset for tls_{client|server} 197264562Sgshapirodnl input: $&{verify} $| <ResultOfLookup> [<>] 197364562Sgshapirodnl remove optional <> 197464562SgshapiroR$* $| <$*>$* $: $1 $| <$2> 197564562Sgshapirodnl permanent or temporary error? 197664562SgshapiroR$* $| <PERM + $={tls} $*> $: $1 $| <503:5.7.0> <$2 $3> 197764562SgshapiroR$* $| <TEMP + $={tls} $*> $: $1 $| <403:4.7.0> <$2 $3> 197864562Sgshapirodnl default case depends on TLS_PERM_ERR 197964562SgshapiroR$* $| <$={tls} $*> $: $1 $| <ifdef(`TLS_PERM_ERR', `503:5.7.0', `403:4.7.0')> <$2 $3> 198064562Sgshapirodnl deal with TLS handshake failures: abort 198164562SgshapiroRSOFTWARE $| <$-:$+> $* $#error $@ $2 $: $1 " TLS handshake failed." 198264562Sgshapirodnl no <reply:dns> i.e. not requirements in the access map 198364562Sgshapirodnl use default error 198464562SgshapiroRSOFTWARE $| $* $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake failed." 198564562SgshapiroR$* $| <$*> <VERIFY> $: <$2> <VERIFY> $1 198664562SgshapiroR$* $| <$*> <$={tls}:$->$* $: <$2> <$3:$4> $1 198764562Sgshapirodnl some other value in access map: accept 198864562Sgshapirodnl this also allows to override the default case (if used) 198964562SgshapiroR$* $| $* $@ OK 199064562Sgshapiro# authentication required: give appropriate error 199164562Sgshapiro# other side did authenticate (via STARTTLS) 199264562Sgshapirodnl workspace: <SMTP:ESC> <{VERIFY,ENCR}[:BITS]> ${verify} 199364562Sgshapirodnl only verification required and it succeeded 199464562SgshapiroR<$*><VERIFY> OK $@ OK 199564562Sgshapirodnl verification required + some level of encryption 199664562SgshapiroR<$*><VERIFY:$-> OK $: <$1> <REQ:$2> 199764562Sgshapirodnl just some level of encryption required 199864562SgshapiroR<$*><ENCR:$-> $* $: <$1> <REQ:$2> 199964562Sgshapirodnl verification required but ${verify} is not set 200064562SgshapiroR<$-:$+><VERIFY $*> $#error $@ $2 $: $1 " authentication required" 200164562SgshapiroR<$-:$+><VERIFY $*> FAIL $#error $@ $2 $: $1 " authentication failed" 200264562SgshapiroR<$-:$+><VERIFY $*> NO $#error $@ $2 $: $1 " not authenticated" 200364562SgshapiroR<$-:$+><VERIFY $*> NONE $#error $@ $2 $: $1 " other side does not support STARTTLS" 200464562Sgshapirodnl some other value for ${verify} 200564562SgshapiroR<$-:$+><VERIFY $*> $+ $#error $@ $2 $: $1 " authentication failure " $4 200664562Sgshapirodnl some level of encryption required: get the maximum level 200764562SgshapiroR<$*><REQ:$-> $: <$1> <REQ:$2> $>max $&{cipher_bits} : $&{auth_ssf} 200864562Sgshapirodnl compare required bits with actual bits 200964562SgshapiroR<$*><REQ:$-> $- $: <$1> <$2:$3> $(arith l $@ $3 $@ $2 $) 201064562SgshapiroR<$-:$+><$-:$-> TRUE $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3 201164562Sgshapiro 201264562SgshapiroSmax 201364562Sgshapirodnl compute the max of two values separated by : 201464562SgshapiroR: $: 0 201564562SgshapiroR:$- $: $1 201664562SgshapiroR$-: $: $1 201764562SgshapiroR$-:$- $: $(arith l $@ $1 $@ $2 $) : $1 : $2 201864562SgshapiroRTRUE:$-:$- $: $2 201964562SgshapiroR$-:$-:$- $: $2', 202064562Sgshapiro`dnl use default error 202164562Sgshapirodnl deal with TLS handshake failures: abort 202264562SgshapiroRSOFTWARE $#error $@ ifdef(`TLS_PERM_ERR', `5.7.0', `4.7.0') $: "ifdef(`TLS_PERM_ERR', `503', `403') TLS handshake."') 202364562Sgshapiro 202464562SgshapiroSRelayAuth 202564562Sgshapiro# authenticated? 202664562Sgshapirodnl we do not allow relaying for anyone who can present a cert 202764562Sgshapirodnl signed by a "trusted" CA. For example, even if we put verisigns 202864562Sgshapirodnl CA in CERTPath so we can authenticate users, we do not allow 202964562Sgshapirodnl them to abuse our server (they might be easier to get hold of, 203064562Sgshapirodnl but anyway). 203164562Sgshapirodnl so here is the trick: if the verification succeeded 203264562Sgshapirodnl we look up the cert issuer in the access map 203364562Sgshapirodnl (maybe after extracting a part with a regular expression) 203464562Sgshapirodnl if this returns RELAY we relay without further questions 203564562Sgshapirodnl if it returns SUBJECT we perform a similar check on the 203664562Sgshapirodnl cert subject. 203764562SgshapiroR$* $| OK $: $1 203864562SgshapiroR$* $| $* $@ NO not authenticated 203964562Sgshapiroifdef(`_ACCESS_TABLE_', `dnl 204064562Sgshapiroifdef(`_CERT_REGEX_ISSUER_', `dnl 204164562SgshapiroR$* $: $1 $| $(CERTIssuer $&{cert_issuer} $)', 204264562Sgshapiro`R$* $: $1 $| $&{cert_issuer}') 204364562SgshapiroR$* $| $+ $: $1 $| $(access CERTISSUER:$2 $) 204464562Sgshapirodnl use $# to stop further checks (delay_check) 204564562SgshapiroR$* $| RELAY $# RELAYCERTISSUER 204664562Sgshapiroifdef(`_CERT_REGEX_SUBJECT_', `dnl 204764562SgshapiroR$* $| SUBJECT $: $1 $| <@> $(CERTSubject $&{cert_subject} $)', 204864562Sgshapiro`R$* $| SUBJECT $: $1 $| <@> $&{cert_subject}') 204964562SgshapiroR$* $| <@> $+ $: $1 $| <@> $(access CERTSUBJECT:$&{cert_subject} $) 205064562SgshapiroR$* $| <@> RELAY $# RELAYCERTSUBJECT 205164562SgshapiroR$* $| $* $: $1', `dnl') 205264562Sgshapiro 205364562Sgshapiroundivert(9)dnl LOCAL_RULESETS 205464562Sgshapiroifdef(`_FFR_MILTER', ` 205538032Speter# 205638032Speter###################################################################### 205738032Speter###################################################################### 205838032Speter##### 205964562Sgshapiro`##### MAIL FILTER DEFINITIONS' 206064562Sgshapiro##### 206164562Sgshapiro###################################################################### 206264562Sgshapiro###################################################################### 206364562Sgshapiro_MAIL_FILTERS_') 206464562Sgshapiro# 206564562Sgshapiro###################################################################### 206664562Sgshapiro###################################################################### 206764562Sgshapiro##### 206838032Speter`##### MAILER DEFINITIONS' 206938032Speter##### 207038032Speter###################################################################### 207138032Speter###################################################################### 207264562Sgshapiroundivert(7)dnl MAILER_DEFINITIONS 2073