mvmf: mvmtr man page
mvmf: mvmtr man page
MVMTR(1) General Commands Manual MVMTR(1)
NAME
mvmtr - mvmf's Mail Transport Agent (MTA) receiver
SYNOPSIS
mvmtr [-b bodycache] [-C startfile] [-h hostname] [-v] [-V]
DESCRIPTION
mvmtr implements a receiver portion of a mail transport agent (MTA) de-
signed to be used in conjunction with the mvmda mail delivery agent
(MDA). mvmtr, at least in its initial incarnation, is designed to be
used in place of qmail's qmail-smtpd program.
It is not a drop-in replacment for qmail-smtpd, as it uses its own con-
trol interface. However it can be configured at compile-time to use the
same control files as (and be generally drop-in-compatible with) stock,
unpatched qmail-smtpd version 1.03 . (See qmail-smtpd compatibility
notes elsewhere.)
mvmtr includes an interpreter for its built-in mfl language, which is a
sort of mongrelization of C and Sieve. mfl, which is described in an-
other document, allows programmed control over what happens to email,
and includes a number of intrinsics related to processing email.
Options which may be given are as follows:
-b bodycache
Says how many bytes of message body to cache in memory. The num-
ber given is constrained to lie between a minimum and maximum
specified at compile time. The actual limit is somewhat fuzzy:
regardless of the number specified and regardless of the total
number already cached, there is also a minimum amount that will
be cached in each MIME part.
-C startfile
The name of a startup file. The startup file is simply mfl code,
it is run in admin mode (with regards to the "admin" mfl con-
trol). If this option is omitted, a default is used if config-
ured at compile time. The startfile name must be found within
the system-wide mfl include path, and should therefore not be a
full path to the file.
This option will override any default startfile or one specified
via an environment variable.
-h hostname
specifies a host name to use in the SMTP dialog when accepting
email. The SMTP server must identify the server's host name to
the connecting client. If this option is not given, the host
name determined by a system call (e.g. gethostname()) is used.
-v prints mvtr's version number. The version number has three deci-
mal parts separated by periods: first a major version number,
next a minor version number, and finally a fix number. The fix
number is incremented whenever a new version contains only fixes
and enhancements to existing features. The minor number is in-
cremented whenever a new facility or technique is added, and the
major number is incremented when enough new things have been
added to consider it a major new edition of the program. A major
number of zero (0) indicates a prerelease version (one that
doesn't yet include all its initial release features or that may
not yet be considered fully tested).
-V prints mvmtr's version and control settings, in a form suitable
to be re-read via MFL. This will show the effects of any initial
startup configuration.
MODES and CONTROLS
mvmtr is controlled by its command line options, various environment
variables, and some control files. Each of these controls is described
in a separate section (command line options have been addressed ear-
lier).
mvmtr may operate in one of several modes, as described here. Of these
modes, only ucspi-tcp mode is implemented at this time; the others, how-
ever, are planned.
inetd mode
In this mode, there is some daemon process such as inetd, outside
of mvmtr's scope, that accepts incoming TCP/IP connections. For
each SMTP connection, that process invokes a specific program (in
this case, mvmtr) with the network connection set up on stdin and
stdout. No other information is given to mvmtr.
ucspi-tcp mode
is somewhat like inetd mode. Here, there is also a daemon
process, again outside of mvmtr's scope, that accepts incoming
TCP/IP connections. In this case, though, that daemon process is
known either to be the tcpserver program that's part of D. J.
Bernstein's ucspi-tcp package, or a functional equivalent of that
program. The network connection is set up on stdin and stdout,
but a number of environment variables are set by the parent pro-
gram that give information about the connection, and other vari-
ables may be set as control parameters. Additionally, stderr is
assumed to be set up to accept log messages.
daemon mode
assumes no parent process at all. In this mode, mvmtr listens on
specific network ports for incoming SMTP connections. It will
then handle each of these connections (specifically by forking a
child process of itself).
ENVIRONMENT VARIABLES
The following environment variables are significant to mvmtr. Not all
variables are relevant to all operating modes.
inetd mode
There are no specific environment variables associated with this mode.
ucspi-tcp mode
When operating in this mode, mvmtr is invoked once for each incoming
SMTP connection. The parent process is expected to set a number of en-
vironment variables that describe the connection to the client and offer
some guidance about how to treat the client. Each of the variable names
listed below is followed in parentheses by an indication of whether it's
required or optional, plus an indication of the reference application
from which this variable use is derived. For example, a note of "(re-
quired, ucspi-tcp)" means that the environment variable is mandatory,
and that the use of this variable stems from precedent set by the ucspi-
tcp utility.
TCPLOCALHOST (required, ucspi-tcp)
is the name of the local host.
TCPLOCALIP (required, ucspi-tcp)
is the IP address of the local system; i.e. the IP address on
which the SMTP connection arrived.
TCPREMOTEHOST (optional, ucspi-tcp)
is the DNS name of the client system.
TCPREMOTEIP (required, ucspi-tcp)
is the IP address of the client.
RELAYCLIENT (optional, qmail)
if this variable is set, the client has (somehow) been validated
as a host for whom it's OK to relay messages to unrelated desti-
nations. If this variable is not set, then the client is assumed
to be a foreign system unrelated to the receiving system, and
will be required to authenticate (using SMTP AUTH) before being
allowed to relay such messages. Use of this variable may be
phased out in the future (other than in qmail-smtpd compatibility
mode). Until that time, though, we simply support this value.
Unlike stock qmail-smtpd, mvmtr does not append the value of this
environment variable to all incoming addresses.
SUPPRESS_AUTH (optional, mvmtr and mem's qmail patches)
if this environment variable is present, mvmtr will not advertise
the SMTP AUTH capability in response to EHLO greetings from the
client. This should only be used if RELAYCLIENT is also set, and
is merely a workaround for some buggy clients that will always
attempt to do SMTP AUTH if that capability is advertised. As
with RELAYCLIENT, use of this variable is expected to be removed
when more explicit authorization controls are added.
daemon mode
There are no specific environment variables associated with this mode.
generic variables
This section lists variables that are may be relevant to any operating
mode.
MVMTR_RC (optional)
specifies a startup file for mvmtr. As with the -C command line
option, the startfile must be found within the system-wide mfl
include path. This environment variable (if present and non-
empty) will override any default startfile, but may itself be
overridden by the -C command line option.
CONTROL FILES
mvmtr reads some control files for instructions.
startfile
The startfile contains mfl code to affect the operation of mvmtr.
By default this file is /usr/local/sys/mvmf/mvmtr/mvmtr.mfl but
this may be changed during the installation process. (It may
also be overridden via an environment variable or a command line
option, as described elsewhere in this document.) This file
should contain calls to built-in mfl functions to set mvmtr con-
trol values, as described in the CONTROL VALUES section later on.
This file may also define mfl "hook" functions that may be called
by mvmtr at various points in its execution. The possible hook
functions are described in a later section called HOOKS
address map file
The address map file provides a database of known email addresses
and address patterns. It may be consulted via one of the checks
that is done at (or after) RCPT TO commands in the SMTP dialog.
This is an indexed file using D. J. Bernstein's constant database
file format (cdb). It is typically named addrmap.cdb in the
mvmtr system directory (e.g. /usr/local/sys/mvmf/mvmtr/) but
this may be changed during the installation process. Each entry
in this file has an address key and a map value.
Please note that this file and the format of its keys and values
are still subject to change while this utility is evolving. It
may also be removed entirely since its functionality can easily
be provided via an mfl hook (e.g., $hook_rcpt_to). On the other
hand, interesting ideas and suggestions are welcome!
Keys have the following formats:
user@domain --
matches an email address exactly.
user*@domain --
matches any email address with the specific domain name
where the local part begins with the the string "user".
domain --
matches any email address in the specified domain name.
.domain --
matches any email address in any subdomain of the speci-
fied domain name.
When mvmtr looks up an incoming email address in this database,
it finds the most exact match that it can. When it finds a
match, it returns a result depending on the map value that corre-
sponds to the entry. The result values are analagous to the mail
disposition values described elsewhere in this document, and are
as follows:
accept --
this address is valid and will be accepted (subject to any
further test that mvmtr performs).
deny --
this address is known to be invalid and will be rejected.
defer --
this address is probably valid, but not for this particu-
lar server. (This corresponds to the "known" mail dispo-
sition value.) mvmtr will only accept this address if the
client is allowed to relay (e.g. the client has AUTHed or
has otherwise has relay permission). Otherwise it returns
a "known" result, which is likely to produce a temporary
deferral SMTP dialog result, causing the sending system to
retry at some later time. A value of defer may be used on
any server that's not the primary MX destination for that
address. Deferring acceptance of addresses on backup MX
servers is way to politely refuse email, and can help turn
away connections from malware that tries to send to backup
MX servers only.
pass --
this address will be accepted, and it may also be eligible
for a pass from some of the other checks (connect, helo,
etc), if that check is configured to test for a pass (see
the description of various check controls).
The source for the address map file is typically maintained in a
text file, with each line containing the email address key and
the map value separated by a colon. You can then use the cdbgen
utility that's included with the mvmf kit to generate the cdb
file from that source. Consider this source file named "ad-
drmap":
.example.net:deny
example.net:deny
mark@example.net:accept
mem@example.org:defer
example.org:deny
.example.org:deny
An address of "mark@example.net" will be accepted; an address of
"mem@example.org" will be accepted only if it's OK to accept sub-
missions from (i.e. relay for) the client; any other addresses in
"example.net" and "example.org" and any of their subdomains will
be rejected. Any other address (i.e., anything not mentioned in
the address map file) are unknown and will only be accepted on a
submission basis.
This may be compiled into "addrmap.cdb" by issuing shell commands
such as:
cdbgen -o addrmap.tmp addrmap
if [ -s addrmap.tmp ] ; then
ln -f addrmap.cdb addrmap.cdb-;
chmod a+r addrmap.tmp;
mv -f addrmap.tmp addrmap.cdb;
fi
It's important to know a couple more things about how mvmtr looks
up wildcard local names in the address map file. Checking
against wildcards in this file has to be done iteratively. In
many environments, wildcards are only relevant when they follow a
particular separator character such as a hyphen (e.g., user
"mark" might be able to have any address "mark-*" but may not
have any address "mark*"), so mvmtr may be compiled and installed
so that it only checks for wildcards at particular points (such
as after hyphens). Also, mvmtr will never attempt to look up an
address key where the local part is just "*". If your intent is
to have a key such as "*@example.com" you must use just the naked
"example.com" instead.
CONTROL VALUES
Various control values may be set by mfl code using the $control_ func-
tions (see the mfl language documentation for more info on those). Con-
trol values are typically set when the mvmtr program is started, by in-
voking the $control_ functions directly in the startfile. Values may
also be adjusted as part of hook processing.
Control values are described below. Each description begins with the
name of the value and the type of the value (for example an integer or a
string) and then follows with a brief description of the control.
add_x_peer_info (integer) -- Whether to add an "X-Peer-Info" header on
the message. Default is 0.
X-Peer-Info is an MV-centric header, most people probably won't want it.
It simply inserts the local and remote host information in a convenient
format for downstream parsing. (This will likely be phased out in favor
of using a hook.)
admin (integer) -- This is a control that is required by MFL's control
system itself. It is set to 1, since it's expected that mvmtr is being
run by an administrator. Care must be taken (e.g. to revoke this) if
you want to invoke user-supplied scripts.
data_directory (string) -- specifies the data directory for some mfl
functions. Currently not really needed by mvmtr, but provided for mfl's
sake.
log_private_name (string) -- The name of a "private" logfile. This is
not relevant to mvmtr but the control has to exist for the benefit of
low-level logging functions. (Mentioned here only for completeness.)
log_program_name (string) -- The name of the program as reported when
logging. Default is mvmtr.
mvmcas (integer) -- Whether or not to consult mvmcas, the mail client
assessment server. 0 disables the use of mvmcas, 1 enables it. Default
is 0.
Only available if mvmcas support has been configured into mvmtr at com-
pile time.
mvmcas_host (string) -- The name of the host where the mvmcas server is
to be found. May include an optional colon and port number. Default is
"localhost:nnnn" where nnnn is the default port number.
Only available if mvmcas support has been configured into mvmtr at com-
pile time.
pipe_allow (integer) -- whether mfl code is allowed to open a pipe. Set
to 1 by default, since mvmtr is expected to be run by an admin.
prog_checkpassword (string) -- The path to the djb-style checkpassword
program that is used by AUTH commands. This may be one or two program
paths separated by spaces. The first path is the checkpassword program
to use. The underlying checkpassword program may need to run as a priv-
ileged program, and so the one specified here might actually be a wrap-
per program that is only available to whatever uid/gid mvmtr runs as.
The second path, if given, is to the program that the checkpassword pro-
gram takes as an argument when authentication is successful (typical
mvmtr use is /usr/bin/true or equivalent).
qmail_smtpd_compatibility (integer) -- Whether to enable compatibility
with qmail-smtpd's control files. 0 disables this compatibility, 1 en-
ables it; default is 1. If this is enabled, the qmail-smtpd startup
files in qmail's "control" directory are consulted and used in ways sim-
ilar to qmail-smtpd. Because this program is not qmail-smtpd, use of
the controls may not exactly mirror qmail-smtpd's use of them. (See the
QMAIL-COMPATIBILITY notes in the mvmtr source area for discussion.)
However, this setting will allow mvmtr to function as a drop-in replace-
ment for a stock qmail-smtpd.
Only available if qmail-smtpd compatibility has been configured into
mvmtr at compile time.
smtp_server_autoblock_enable (integer) -- Whether to honor autoblocks
(e.g. from mvmcas). Default is 1 (enabled).
smtp_server_badcmd_max (integer) -- How many bad (unknown) SMTP commands
to tolerate before closing the session. Default is 3.
smtp_server_badrcpt_delay (integer) -- Number of seconds to defer a re-
sponse after a bad RCPT-TO has been received. This is an attempt to de-
lay bad senders, but probably shouldn't be used if an assessment server
(e.g. mvmcas) is being consulted (as that will have a better, long-term
feedback process). Default is 5 (seconds).
smtp_server_badrcpt_max (integer) -- Maximum number of bad/deferred
RCPT-TO addresses allowed in a session before we declare this a bad ses-
sion. If this maximum is reached, further RCPT-TO commands will be
given a negative response, and the mail will be refused at DATA time.
Or, if strict SMTP sessions adherence is turned off (see the
smtp_server_strict_sessions control) the connection may be dropped imme-
diately. Default is 2.
smtp_server_connect_check (string) -- A list of checks to perform when a
connection begins. This is an annotated checklist (see the ANNOTATED
CHECKLIST section) that specifies the checks to perform, in order. An
"accept" checklist result will cause the dialog to proceed as normal. A
"reject" checklist return will cause mvmtr to respond to the client with
a 421 "go-away" greeting and then disconnect. Any other checklist re-
sult will cause the session to be dropped gracelessly (without notice).
The default value of this control is NULL (no checks).
smtp_server_greet_delay (integer) -- How many seconds the SMTP server
will delay after receiving a connection from an unknown client before
issuing the initial greeting. If any commands are received prior to is-
suing the greeting, the connection will be considered suspicious and the
conversation will not be accepted. (Legitimate SMTP clients will wait
for a greeting before beginning the SMTP dialog; malware often will
not). If the client has otherwise been identified as a local client,
this delay may be suppressed. When you use a greeting delay, you should
be aware of the negative effect that larger values will have on your
(and the senders') throughput. An intelligent assessment server (such
as mvmcas) will be able to adjust this value dynamically on a per-sender
basis. Default is 5 (which is only somewhat effective).
If the use of an mvmcas server is enabled, information from that server
will set the pre-greeting delay on a per-client basis.
smtp_server_greet_delay_max (integer) -- The maximum smtp server greet
delay, regardless of any other setting or input (e.g. from mvmcas). De-
fault is 60.
smtp_server_greeting (string) -- Additional SMTP greeting text. mvmtr
will always emit a first standard line of greeting; if any additional
greeting text is supplied, it follows that standard first line, and is
itself followed by another standard closing line. mvmtr adds its own
text around the additional greeting because RFC2821 requires a particu-
lar format of the first line, and in order to deal with potential client
problems many clients can not deal with a multi-line greeting without
particular formatting in either the first or last line. The additional
greeting text may itself be multi-line.
smtp_server_greylisting (integer) -- Whether to enable greylisting (0 =
off, 1 or 2 = on). Greylisting is accomplished by consulting an outside
agent (e.g. mvmcas); it is useful to disable greylisting for a good
amount of time (days or weeks) in order to train the greylisting data-
base. The greylisting used by mvmtr and mvmcas is a degenerate form
that only pays attention to the IP address and not to the specific email
addresses used. Because mvmcas makes other assessments, this form of
greylisting has proven to be quite effective.
When greylisting is enabled with a value of 1, mvmtr will honor the
smtp_server_strict_sessions control to decide whether to keep the ses-
sion open. Enabling with a value of 2 will cause mvmtr to issue a
greeting with a 421 code and exit immediately when greylisted.
smtp_server_helo_check (string) -- A list of checks to perform when a
HELO/EHLO command has been received. This is an annotated checklist
(see the ANNOTATED CHECKLIST section) that specifies checks to perform
in order. An "accept" or "dunno" checklist result will cause a positive
response to the command, and the dialog to continue; a "reject" result
will cause the HELO name to be rejected with an appropriate SMTP reply,
and the dialog to continue; other results will function the same as "re-
ject" but may be handled specially in future releases. See also the
controls smtp_server_strict_sessions and smtp_server_ss_helo.
The default value of this control is "helo-syntax helo-hook helo-me".
smtp_server_localip_host (string) -- The hostname that is substituted
for any bracketed IP address in a rcpt-to address, when the IP address
is one that belongs to the local host (is on an "up" interface on the
local host).
smtp_server_log_commands (integer) -- If non-zero, mvmtr will log all of
the commands received from the client. This was originally a debugging
instrument, but as of this writing most commands are logged by default
anyway.
smtp_server_mail_check (string) -- A list of checks to perform when a
MAIL FROM command has been received. This is an annotated checklist
(see the ANNOTATED CHECKLIST section) that specifies checks to perform
in order. An "accept" or "dunno" checklist result will cause a positive
response to the command, and the dialog to continue; a "reject" result
will cause the MAIL FROM name to be rejected with an appropriate SMTP
reply, and the dialog to continue; other results will function the same
as "reject" but may be handled specially in future releases. Also see
the smtp_server_strict_sessions control.
The default value of this control is "mail-hook". A reasonable alterna-
tive might be something like: "
Pc,A:
r0:mail-dns
mail-hook
"
Note that the a null MAIL FROM address, i.e. <>, will always be accepted
and is not subject to MAIL FROM checks.
smtp_server_msgsize_max (integer) -- The maximum message size, in bytes,
that we will accept, or zero for no limit. By default this is zero; you
should probably set it to something sane.
smtp_server_rcpt_check (string) -- A list of checks to perform when a
RCPT TO command has been received. This is an annotated checklist (see
the ANNOTATED CHECKLIST section) that specifies checks to perform in or-
der. An "accept" or "dunno" checklist result will cause a positive re-
sponse to the command, and the dialog to continue; a "reject" result
will cause the MAIL FROM name to be rejected with a reject SMTP reply
(5xx), and the dialog to continue; a "known" (aka "defer") result will
cause the MAIL FROM name to be given a deferral SMTP response (4xx), and
the dialog to continue; other results will function the same as "reject"
but may be handled specially in future releases.
The default value of this control is "rcpt-hook". It is likely that
you'll want to have something more elaborate instead.
smtp_server_reply_[cccc]_[ssss] (string) --
This is a set of controls that provide some guidance about how SMTP
replies are formatted for certain commands in certain situations. The
actual control names are formed by replacing [cccc] with the lowercased
context name and by replacing [ssss] with a string representing the re-
ply severity. (The context name is usually the name of the command be-
ing replied to.)
Valid values for [cccc] are data (for "DATA" command), mail (for "MAIL
FROM" command), and rcpt (for "RCPT TO" command). A special value of
grt is used to tailor the initial greeting message when the session is
rejected, in some circumstances.
Valid values for [ssss] are hard (for a 5xx return) and soft (for a 4xx
return).
The relevant control value is consulted whenever mvmtr issues an SMTP
reply that is a rejection and that uses the generic customizable format.
See the CUSTOMIZABLE REJECTION REPLIES section for a bit of a discussion
about how these are used.
smtp_server_ss_helo (integer) -- An override for the
smtp_server_strict_sessions control for the HELO command. If set to -1,
HELO processing will adhere to the smtp_server_strict_sessions control.
Otherwise this control's value will apply to HELO processing. Often it
is practical to drop the connection after identifying a bad HELO, rather
than continuing until the client quits as per RFCs. Default is -1.
smtp_server_strict_sessions (integer) -- Enable or disable strict SMTP
session adherence. When enabled, once a client has been greeted, the
sessions will not be terminated until the client ends (via QUIT or dis-
connect). This is required by RFCs but is one of the many requirements
that is often set aside due to today's pragmatism. Some controls or
other parameters might terminate a session when this is disabled; when
it is enabled, the effect of those controls will be delayed appropri-
ately. Default is 1.
smtp_server_timeout (integer) -- General smtpd server timeout. The max-
imum time, in seconds, to wait for data from the client for general com-
mand states (i.e., not covered by another timeout). Default is 300
(seconds).
smtp_server_timeout_helo (integer) -- How many seconds the SMTP server
will wait for a HELO or EHLO command after issuing a greeting. If this
number of seconds elapses before the HELO/EHLO is received, the connec-
tion will be closed. Default is 30 (seconds).
CHECKS
mvmtr supports a number of built-in checks that may be initiated at var-
ious times in the smtp dialog. The checks may be specified as part of
an annotated checklist (see that section), or they may be invoked from
an MFL hook (see the section on hooks). Each check has a name, reflect-
ing what it does, and it makes a decision about what to do with a par-
ticular SMTP dialog element or parameter. All checks are defined to
take an optional argument, however most checks are self-contained and
ignore (do nothing with) any argument given to them.
Each check returns a mail disposition value as described in the HOOKS
section (should probably be described elsewhere). Typically a check
will return either "accept" or "reject" (with the obvious meanings); in
some contexts some other returns may be valid. A check may also return
"dunno" to make no judgment. In the descriptions below, some checks are
described as "passing" or "failing" -- "pass" generally means returning
"accept" or "dunno" and "fail" generally means returning a "reject".
Each check, when returning a non-pass result (neither "accept" nor
"dunno"), will also "suggest" a score. This is a numerical value that
can be used in (say) accumulating a total before deciding to give up on
the client. The suggested score can be overridden in various ways (via
an annotation in an annotated checklist, or by MFL code which invokes
the check).
Checks are:
client-generic -- Tests whether the client is judged to be coming from
generic IP space. (See the discussion near the presentation of the
$hook_generic_ip hook for more.) Any optional argument is ignored.
client-hook -- Attempts to invokes the MFL $hook_client function, which
can be supplied by the administrator. See the HOOKS section for a de-
scription of how this function is called. Any optional argument will be
taken as an alternative name for this hook.
helo-dns -- Passes if the HELO name resolves to an A entry in the DNS;
fails otherwise.
helo-dnsclient -- Passes if the HELO name resolves to an A entry in the
DNS which matches the IP address of the connecting client; fails other-
wise.
helo-generic -- Tests whether the HELO name is judged to indicate a name
associated with generic IP space, taking the client's IP address into
account as well. (See the discussion near the presentation of the
$hook_generic_ip hook for more.)
helo-hook -- Invokes the MFL hook $hook_helo if it has been defined.
See the HOOKS section for more info on this and other hooks. Any op-
tional argument will be taken as an alternative name for this hook.
helo-me -- Looks at the HELO name to see if it is an invalid imperson-
ation of the receiving server (i.e., me). This is not an exhaustive
look, but it will catch HELO names that look like one of the local IP
addresses (without the required square brackets).
helo-syntax -- Does a strict syntax check on the HELO name. This is a
syntax check only, making sure that the HELO name contains valid charac-
ters put together in valid ways. This test is highly recommended.
mail-dns -- Passes if the domain name in the MAIL FROM address resolves
to an A or MX record; fails otherwise. Note that failure only occurs on
a definitive DNS response indicating lack of DNS record(s); soft fail-
ures will not cause rejection.
mail-hook -- Invokes the MFL hook $hook_mail_from if it has been de-
fined. See the HOOKS section for more info on this and other hooks.
Any optional argument will be taken as an alternative name for this
hook.
mail-qmail -- Checks the MAIL FROM address in a way compatible with
qmail's check, e.g. its badmailfrom check, as described in the QMAIL-
COMPATIBILITY notes provided with the mvmtr source kit.
rcpt-addrmap -- Consults the address map file for this RCPT TO address.
The address map handling is described elsewhere in this manpage.
rcpt-hook -- Invokes the MFL hook $hook_rcpt_to if it has been defined.
See the HOOKS section for more info on this and other hooks. Any op-
tional argument will be taken as an alternative name for this hook.
rcpt-qmail -- Checks the RCPT TO address in a way compatible with
qmail's check, e.g. its rcpthosts and morercpthosts check, as described
in the QMAIL-COMPATIBILITY notes provided with the mvmtr source kit.
Beware that many strict HELO checks are infeasible as of this writing,
since there are so many poorly configured email clients out in the
world.
ANNOTATED CHECKLISTS
An annotated checklist is simply a string that is a list of named checks
to be done, along with (you guessed it) some annotations that help to
control the interpretation and flow of the checks. Annotated checklists
are specified via certain string controls that are referred to at cer-
tain points in the SMTP dialog. (All of these controls and where they
are referenced have been described above.)
This facility provides a middle ground between having every operational
decision hard-coded in the mvmtr program and having you (the administra-
tor) write these decisions in terms of MFL hooks. 80% (or so) of what
most everyone might want in an SMTP server ought to be provided via
built-in facilities, but you might want have some degree of control over
them. The other 20% may vary widely from administrator to administra-
tor, and these are the things that are better done through external MFL
code.
The annotated checklist is simply a list of annotated checks separated
by whitespace (spaces, tabs, newlines). Each annotated check is the
name of check (as described in the CHECKS section), optionally preceded
by a set of annotations and a colon, and optionally followed by a colon
and a tail part. The tail part (if given) is used as an argument to the
check (but most checks don't take arguments). The set of annotations is
a comma- or slash- separated list of character notes, each of which may
have an argument. The check name may be left blank, in order to process
annotations only.
Each check is performed in turn, ignoring "accept" results, until one of
them returns a hard result (neither a "soft" return nor a "dunno").
"Accept" results are ignored so that subsequent checks can be processed,
as that's usually what's wanted; however, the 'y' note (see below) can
be used to force an "accept" to be taken. When a hard result is given,
the checklist processing stops and this return is the result of the
checklist. (Some annotations may cause hard returns to be ignored). If
the list ends before a hard result is obtained, any soft result will be
turned into a hard result and that will be returned. Otherwise the en-
tire list returns "dunno."
These are the note characters that can be used in a set of annotations:
# -- skip this check. This provides a way of commenting out a check.
A -- skip all remaining checks if client is authenticated.
a -- skip this check if client is authenticated.
I -- skip all remaining checks if client is allowed to relay (i.e., is
considered "internal).
i -- skip this check if the client is allowed to relay.
P[t..] -- skip all remaining checks if there is a pass of type t. The
pass types are 'c' for client (client has a pass, e.g. from mvmcas), and
'r' for recipient (recipient has a pass, e.g. from addrmap).
p[t..] -- skip this check if there is a pass of type 't'. Types are the
same as for the 'P' note character.
r[nn] -- any "reject" return, instead of being used outright, accumu-
lates a score. The 'r' may be followed by a score value, otherwise the
check's suggested score will be used. A value of 0 makes this a soft
check. If there is no 'r' annotation, a reject value return will be
used absolutely.
s -- set the maximum score value. If the cumulative score gets this
high or higher, stop processing the namelist and return a reject. This
value is sticky across the rest of the namelist (and may later be
changed via another
y -- any yes ("accept") return is a hard accept: the namelist ends and
the accept is returned. Otherwise, the accept return is advisory only
and is treated as a "dunno".
Consider this setting for the "smtp_server_rcpt_check" control:
@define RCPT_CHECKS "
Prc,a:mail-dns
y:rcpt-addrmap
rcpt-hook
"
$control_string_set( "smtp_server_rcpt_check", RCPT_CHECKS );
This says that whenever an RCPT TO command is taken, the MAIL FROM argu-
ment that was collected earlier will be tested for legitimate DNS unless
either the recipient or the client has a pass or the client has been au-
thenticated; the RCPT TO address will be tested via the address map and
an "accept" from the address map is considered absolute. The RCPT TO
address is potentially tested via any $hook_rcpt_to MFL hook.
CUSTOMIZABLE REJECTION REPLIES
For some SMTP commands where deliveries or transactions can be rejected,
mvmtr uses a standard reply format for such rejections that can be cus-
tomized via certain control values, as described earlier for the
smtp_server_reply_[cccc]_[ssss] controls. As mentioned there, the af-
fected SMTP commands are "DATA", "MAIL FROM", and "RCPT TO". While
these replies aren't completely customizable, this mechanism provides a
way to tailor them somewhat. (Later versions of mvmtr may indeed carry
this further).
The standard rejection message format approximately follows this tem-
plate:
nnn [brief] [extended] [built-in]
where
"nnn" is the standard SMTP reply code that begins the line; this may
include a continuation indicator and/or an extended reply code.
"brief"
is a brief explanation of the rejection, provided by mvmtr. This
brief string is only output if there is an extended string or if
there is no built-in string.
"extended"
is optional extended reply information dictated by the contents
of the relevant control (i.e., the appropriate smtp_server_re-
ply_[cccc]_[ssss] control). This control value may be encoded to
include certain variable information; see below.
"built-in"
is any detailed message provided internally by mvmtr.
To find the optional extended reply string, an appropriate control value
is consulted. As detailed earlier, the name of the control is con-
structed according to the template smtp_server_reply_[cccc]_[ssss] with
[cccc] being replaced with a string representing the SMTP command in-
volved, and [ssss] replaced by a string representing the severity of the
rejection (either "hard" or "soft"). The value of this control is then
used as the optional extended reply component. (A blank string value is
treated the same as a missing value.)
When supplied, the value is subject to interpretation. The value must
start with zero or more flag characters, ending with a comma. There is
only one defined flag character at present: 'l' (the letter 'l'), which
will cause the extended reply string to be followed by a line-item list
of the keywords and detail text for each rejection reason that has been
given for the rejection. (These keyword/text pairs are provided via the
mechanism of "RISET"s, aka result/reply information sets; see the RISETs
section.) The text following the comma is then given as part of the re-
ply, with some interpretation. Two-character sequences beginning with a
percent sign are given special treatment:
%% results in a single percent-sign;
%k will be replaced by a list of the keywords associated with each
reason that has been accumulated for this rejection. The list
will be comma-separated. This is intended to be suitable for in-
terpretation by a web page or by a human who might be receiving a
report of this message.
%i is replaced by the IP address of the client. This is likely to
be useful when a sender reports an error sending mail.
Let's say, for example, that a series of checks is done at the time the
"RCPT TO" command is processed, and that the command is hard-rejected
for two reasons: there is no DNS record associated with the domain
given in the "MAIL FROM" command (and thus the mail can not be replied
to), and the IP address has been listed on a DNSBL called the "xyz".
The relevant control for the extended part of this response is
smtp_server_reply_rcpt_hard. If it is defined like this (i.e. in the
mvmtr.mfl startup file):
$control_string_set( "smtp_server_reply_rcpt_hard",
"l,ip=%i reason[s]=%k" );
then the client, connecting from IP address 10.0.1.2, would likely see a
reply similar to this:
550-Recipient rejected -- ip=10.0.1.2 reason[s]=mail-dns,xyz
550- mail-dns -- MAIL FROM name has no DNS record
550 xyz -- Your IP address is on the xyz DNSBL
The first line is enough for a human at the receiving site to interpret.
Instead of simply a "reason[s]" string, this might be a pointer to a
website that is capable of explaining the rejection and perhaps doing
something about it.
RISETs
A lot of the decisions that mvmtr makes are the result of a number of
inputs. This is clear from the discussions of annotated checklists and
from descriptions of some of mvmtr's processes. This gives a lot of
flexibility to the decision making, but also creates some problems in
regards to what to say about those decisions. mvmtr addresses this with
the option of associating a set of information with each of the factors
that contribute to a decision. Each is known as reply/result informa-
tion, or just RI, and the set of these RI going into a decision is an
RISET.
Each RI can be either for logging or for replying to the client, and
there will usually be both kinds present in an RISET. Once a decision
is acted on (e.g., an SMTP command has completed), the log items in an
RISET may be discarded or they may be sent to the log. Similarly the
reply items may be used in the SMTP reply to the client (see the section
on CUSTOMIZABLE REJECTION REPLIES) or ignored.
Each RI consists of at least the following:
keyword
This is a short string that can be used to uniquely identify the
contributing reason. When logged, it is enclosed in square
brackets for easy analysis. When given as part of a reply, it
can be used as part of a keyword string (e.g. to give to a web
URL), and it can also be used as part of a line-item list of rea-
sons.
disposition
Used mainly (exclusively?) for logging, this is a code that indi-
cates the nature of the input. Typically it is either a plus
sign (for acceptance) or a minus sign (for rejection) but can
also be a "?nn" sequence which represents a contribution of nn to
a score. This disposition can be adjusted while the RI is queued
and before it is used, e.g. if a rejection is changed to a score.
detail This is any detail text associated with the RI. It is used both
in logging and in presenting a line-item list of reasons as part
of an SMTP reply.
HOOKS
At certain points in its execution, mvmtr may invoke specifically-named
mfl functions in order to give user or admin options at these control
points. In most cases, the hook function is invoked via one of the
checks in an annotated checklist -- e.g., you may define the
"smtp_server_mail_check" control to include the "mail-hook" check, and
this will likely result in calling the "$hook_mail_from" hook as part of
running checks at MAIL FROM time.
In a small number of other cases, the hook is simply called at a defined
point in mvmtr's execution if the appropriately-named MFL function ex-
ists (i.e., if you have defined it in the startup file or if it can be
found in the hook search path).
Mail Disposition Values
Some hook functions deal with a mail disposition value (also known as an
acceptance value). This is a string, one of the following (most have
fairly obvious meanings):
dunno -- no decision.
accept -- accept.
reject -- reject.
pass -- accept, and also exempt the sender from some checks.
known -- address is known, but neither accepted nor rejected. This
value is sometimes interpreted as a deferral request.
unknown -- address is unknown (probably foreign).
error -- some error has occured.
Often, the mail disposition value can be preceded with a tilde character
(~) to indicate a tentative decision that can be overridden by some
later step that chooses to.
hook dialog reply
Many hooks are documented as returning a "dialog reply". This means
that the function should be defined as returning a string, and the
string that is returned should match this form:
mdv[:keyword[:detail]]
Here, mdv is a mail disposition value, as previously discussed. key-
word, if given, is a keyword to associate with this reply, and detail,
if given, is a line of text that gives more detail about that keyword.
In most (all?) cases, the keyword and detail elements are only relevant
for rejections.
If keyword is given without detail, the keyword is added as a log item
to the current result information set (RISET) with some default text.
If keyword and detail are both provided, they are added as both log item
and return item to the current result information set.
Hooks
The hooks are:
$hook_client
is called via the "client-hook" check function (e.g. in an anno-
tated checklist) to make a judgement about the connecting client.
This hook is defined as
string $hook_client( string mdv, string ip ) { ... };
mdv is any mail disposition value already determined (which the
hook can choose to take into account). ip is the stringized IP
address (a.b.c.d) to check. This may be passed as 0.0.0.0 or
255.255.255.255 if unknown.
This function is expected to return a dialog return string, typi-
cally one of "dunno", "accept", or "reject".
An example:
string $hook_client( string mdv, string ip ) {
// Reject if it appears on some DNSBL. Better is to score
// multiple DNSBLs, as you might find in some examples
// outside this man page.
if ( sieve { dnsbl :ip [ip] "spamcop" "std" } )
return ( "reject:spamcop" );
return ( mdv );
};
$hook_data
is called after mvmtr receives an SMTP "DATA" command from the
client. This hook is defined as
string $hook_data( string mdv ) { ... };
mdv is any mail disposition value already determined (which the
hook can choose to take into account). This function is expected
to return a dialog return string. The only legitimate mdv re-
turns are "dunno", "accept", and "reject".
An example:
string $hook_data( string mdv ) {
if ( sieve { not exists "To" } )
return ( "reject:no-to" ); // We reject mail without "to"
// Send the message through clamav. Assumes that the cusp
// has been defined, and that string variables s and *sP
// and constant NULL have been declared.
s = $cuspu_message( "clamdif" );
if ( s != "" ) {
sP = $str_find_token_delimited( s, "", " " );
sP = $str_find_token_delimited( s, "", " " );
if ( sP != NULL )
return ( (string)"reject:clamav:detected " + *sP );
}
return ( mdv );
};
$hook_generic_ip
may be called to help determine whether an IP address looks
generically assigned. This hook is defined as
string $hook_generic_ip( string mdv, string ip, string hname ) { ... };
mdv is any mail disposition value already determined (which the
hook can choose to take into account). ip is the stringized IP
address (a.b.c.d) to check. This may be passed as 0.0.0.0 or
255.255.255.255 if unknown. hname is the hostname to check. In
some cases this function might be called several times for a
given IP address, e.g. if there are multiple PTR records for the
IP address.
This function is expected to return a dialog return string. The
only legitimate mdv returns are "dunno", "accept", "reject", and
"pass".
An example:
string $hook_generic_ip( string mdv, string ip, string hname ) {
// Override any bad judgement about this IP
if ( ip == "127.0.0.1" )
return ( "accept" );
// Cancel any bad judgement about names containing ".staticip."
if ( hname =?^ "*.staticip.*" )
return ( "dunno" );
// Accept the already-determined disposition
return ( mdv );
};
Before calling this hook, mvmtr makes an internal assessment about
whether the IP address looks generic. It makes this assessment based on
whether the reverse DNS name(s) seem to declare the IP address as being
generically assigned. Primarily, it checks to see whether the name con-
tains 3 or 4 of the adjacent IP address octets in decimal or hex repre-
sentation, separated by zero or more other characters, either in forward
or reverse order. If this sort of pattern is found, it then applies
some tests to try to disprove the assessment by looking for a few key
strings (such as "static") that will not ordinarily appear in generi-
cally assigned names.
Note that this initial assessment may be overly broad for most environ-
ments. This hook may be used to further disprove a positive initial
judgement. The hook can also completely disregard the initial internal
assessment and make one of its own, etc.
Note also that if an IP address has multiple reverse names in the DNS,
each name is tested until one is declared not to be generic (or until
all names have been tested). This means that a non-generic assessment
always wins.
$hook_helo
is called via the "helo-hook" check (e.g. appearing in an anno-
tated checklist), in order to make some judgement about the
HELO/EHLO name that the client has given to mvmtr. This hook is
defined as
string $hook_helo( string mdv, string heloname ) { ... };
mdv is any mail disposition value already determined (which the
hook can choose to take into account). heloname is the helo
string given in the "HELO" command. This function is expect to
return a dialog return string. The only legitimate mdv returns
are "dunno", "accept", and "reject".
An example:
string $hook_helo( string mdv, string heloname ) {
if ( heloname ==^ "friend" )
return ( (string)"reject:spamsign:
HELO (" + heloname + ") is a spam sign." );
if ( $cdbu_get_string( "bad-helo.cdb", heloname ) != 0 )
return ( "reject:bad-helo.cdb" );
return ( mdv );
};
$hook_mail_from
is called via the "mail-hook" check (e.g. appearing in an anno-
tated checklist), in order to make some judgement about the ad-
dress that the client has given to mvmtr in the MAIL FROM com-
mand. This hook is defined as
string $hook_mail_from( string mdv, string rpath ) { ... };
mdv is any mail disposition value already determined (which the
hook can choose to take into account). rpath is the email ad-
dress given in the "MAIL FROM" command.
Some firm decisions made by this hook may still be overridden. For ex-
ample, this hook may not refuse a null MAIL FROM address. This function
is expect to return a dialog return string. The only legitimate mdv re-
turns are "dunno", "accept", and "reject".
An example:
string $hook_mail_from( string mdv, string rpath ) {
if ( rpath =?^ "*@optinrealbig.com" ) {
return ( "reject:blocked:sender domain is blocked" );
return ( mdv );
};
$hook_rcpt_to
is called via the "rcpt-hook" check (e.g. appearing in an anno-
tated checklist), in order to make some judgement about the lat-
est address that the client has given to mvmtr in the RCPT TO
command. This hook is defined as
string $hook_rcpt_to( string mdv, string addr ) { ... };
mdv is any already-determined mail disposition value value. addr
is the email address given in the "RCPT TO" command. This func-
tion is expect to return a dialog return string. The only legit-
imate mdv returns are "dunno", "accept", and "reject". The
"known" disposition value will be interpreted as a request to de-
fer the RCPT TO; "unknown" indicates a relay attempt that will
only be honored if the client is OKed for relaying.
An example:
string $hook_rcpt_to( string mdv, string addr ) {
if ( addr =?^ "nobody@*" ) {
return ( "reject:silly" );
return ( mdv );
};
Your $hook_rcpt_to hook should be sure to accept the naked "postmaster"
address, per RFC2821, unless you specifically want to violate that rule
on your own say-so. Internally, mvmtr will accept "postmaster" if the
hook hasn't made a decision; other policy hooks (such as deferred HELO
name checks, etc) may still be able to override this decision. In this
hook you might also want to make note of certain addresses that
shouldn't be subject to later filtering.
BUILT-IN MFL FUNCTIONS
mvmtr defines a number of built-in functions for use by MFL code (e.g.
in for use in hooks). These are described in this section.
$mvmtr_log
Writes an entry to the mvmtr log. Each log entry has a number of
components, including a category (with disposition), a keyword,
and some detail text. The category string represents the general
area of thing being logged, e.g. "RCPT" along with some disposi-
tion indication such as a "+" for acceptance or "-" for rejec-
tion. Ordinarily the category and disposition are separate, but
for this function they are combined for simplicity.
The function is defined as
BOOL $mvmtr_log( string cat, string keyword, string detail )
and might be used like this:
$mvmtr_log( "INFO", "startup", "mvmtr starting up" );
$smtpd_riset_add
Adds an RI to the current RISET (see the RISET section). The
function is defined:
BOOL $smtpd_riset_add( string type, string cat, string catdisp,
string kwd, string detail)
type is the RI type, either "log" or "reply". cat is the log
category string for use with "log" type RIs. This may be passed
as blank to use an appropriate default. catdisp is a disposition
string somewhat indicative of the action taken; this is often "-"
or "+". kwd is the RI keyword, and detail is the RI detail.
For an example, let's say you have a client-hook that is called
at RCPT-TO time and it checks to see if the client address is
listed on a mythical DNSBL which we'll call the "zbl". It might
contain this fragment:
if ( $dns_query( $ip_rev(ip) + ".zbl.example.org", "a" ) != 0 ) {
$smtpd_riset_add( "reply", "", "", "zbl", "Your IP address is on the zbl" );
$smtpd_riset_add( "log", "", "-", "zbl", "IP is on the ZBL" );
return ( "reject" );
}
$smtpd_score1_set
This sets the "score1" value. Each check that contributes to an
annotated namelist set can declare a score value, which the
namelist processing can take into account. This score value is
called the "score1" value since it is associated with that single
check and not with the entire namelist. If you have an MFL hook
that is returning a reject, you might want to have it declare the
score1 value. This function is defined as:
BOOL $smtpd_score1_set( int value )
where value is the value to set.
FILES
/usr/local/sys/mvmf/mvmtr/mvmtr.mfl is the default startfile.
/usr/local/sys/mvmf/mvmtr/addrmap.cdb is the address map file.
SEE ALSO
mfl -- the mfl language description.
http://www.mvmf.org/ -- the official web site.
CREDITS TO
M. Mallett (mem@mvmf.org) 2003-2007,2023-2025
BUGS
You tell me..
MVMTR(1)