MVMTR(1) 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) designed 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 control 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 lan- guage, which is a sort of mongrelization of C and Sieve. mfl, which is described in another document, allows pro- grammed 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 number given is constrained to lie between a minimum and maximum specified at compile time. The actual limit is somewhat fuzzy: regard- less of the number specified and regardless of the total number already cached, there is also a mini- mum 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 control). If this option is omitted, a default is used if configured 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 iden- tify 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 decimal parts separated by periods: first a major version number, next a minor version num- ber, 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 incremented 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 ini- tial release features or that may not yet be con- sidered 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 configura- tion. 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 earlier). 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, however, 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 connec- tion, 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 program that give information about the connection, and other variables 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 incom- ing 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 environment variables that describe the connection to the client and offer some guid- ance about how to treat the client. Each of the variable names listed below is followed in parentheses by an indi- cation of whether it's required or optional, plus an indi- cation of the reference application from which this vari- able use is derived. For example, a note of "(required, ucspi-tcp)" means that the environment variable is manda- tory, and that the use of this variable stems from prece- dent 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 destinations. If this vari- able 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 capa- bility 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 oper- ation 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 control 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 pro- vided 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 specified 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 corresponds to the entry. The result values are analagous to the mail disposition values described elsewhere in this doc- ument, and are as follows: accept -- this address is valid and will be accepted (subject to any further test that mvmtr per- forms). deny -- this address is known to be invalid and will be rejected. defer -- this address is probably valid, but not for this particular server. (This corresponds to the "known" mail disposition 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 per- mission). Otherwise it returns a "known" result, which is likely to produce a tempo- rary 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 contain- ing the email address key and the map value sepa- rated by a colon. You can then use the cdbgen utility that's included with the mvmf kit to gener- ate the cdb file from that source. Consider this source file named "addrmap": .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 submissions 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_ functions (see the mfl language documentation for more info on those). Control values are typically set when the mvmtr program is started, by invoking the $con- trol_ 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 fol- lows 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" log- file. 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 mvm- cas, 1 enables it. Default is 0. Only available if mvmcas support has been configured into mvmtr at compile 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 compile 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 privileged program, and so the one specified here might actually be a wrapper program that is only available to whatever uid/gid mvmtr runs as. The second path, if given, is to the program that the checkpassword program 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 dis- ables this compatibility, 1 enables it; default is 1. If this is enabled, the qmail-smtpd startup files in qmail's "control" directory are consulted and used in ways similar 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 replacement for a stock qmail-smtpd. Only available if qmail-smtpd compatibility has been con- figured 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 response after a bad RCPT-TO has been received. This is an attempt to delay 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 session. 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 immediately. 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 spec- ifies the checks to perform, in order. An "accept" check- list 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 discon- nect. Any other checklist result 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 issuing the greeting, the connection will be considered suspicious and the con- versation 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 sup- pressed. 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). Default 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 particular 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 accom- plished 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 database. 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 session 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 con- tinue; other results will function the same as "reject" 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 rea- sonable alternative 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 sec- tion) 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 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 reply severity. (The context name is usually the name of the command being 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 REJEC- TION 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 con- trol'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 termi- nated until the client ends (via QUIT or disconnect). This is required by RFCs but is one of the many require- ments that is often set aside due to today's pragmatism. Some controls or other parameters might terminate a ses- sion when this is disabled; when it is enabled, the effect of those controls will be delayed appropriately. Default is 1. smtp_server_timeout (integer) -- General smtpd server timeout. The maximum time, in seconds, to wait for data from the client for general command states (i.e., not cov- ered 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 connection will be closed. Default is 30 (seconds). CHECKS mvmtr supports a number of built-in checks that may be initiated at various 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, reflecting what it does, and it makes a decision about what to do with a particular SMTP dialog element or param- eter. All checks are defined to take an optional argu- ment, 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 else- where). 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) accumulat- ing 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 description 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 con- necting client; fails otherwise. 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 optional 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 impersonation 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 (with- out 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 characters 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 failures will not cause rejection. mail-hook -- Invokes the MFL hook $hook_mail_from if it has been defined. 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 com- patible 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 optional argument will be taken as an alternative name for this hook. rcpt-qmail -- Checks the RCPT TO address in a way compati- ble with qmail's check, e.g. its rcpthosts and mor- ercpthosts 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 speci- fied via certain string controls that are referred to at certain 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 administrator) 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 administrator, 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 anno- tations 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 argu- ments). The set of annotations is a comma- or slash- sep- arated 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 annota- tions 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 entire 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 out- right, accumulates 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 argument 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 authenti- cated; 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 customized via certain control values, as described earlier for the smtp_server_reply_[cccc]_[ssss] controls. As mentioned there, the affected SMTP commands are "DATA", "MAIL FROM", and "RCPT TO". While these replies aren't completely cus- tomizable, this mechanism provides a way to tailor them somewhat. (Later versions of mvmtr may indeed carry this further). The standard rejection message format approximately fol- lows this template: 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_reply_[cccc]_[ssss] con- trol). 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 constructed according to the template smtp_server_reply_[cccc]_[ssss] with [cccc] being replaced with a string representing the SMTP command involved, 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 char- acter 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 key- word/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 reply, 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 associ- ated with each reason that has been accumulated for this rejection. The list will be comma-separated. This is intented to be suitable for interpretation 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 information, 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 sec- tion 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 reasons. disposition Used mainly (exclusively?) for logging, this is a code that indicates the nature of the input. Typi- cally 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 anno- tated 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 exists (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 defer- ral 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 return- ing a string, and the string that is returned should match this form: mdv[:keyword[:detail]] Here, mdv is a mail disposition value, as previously dis- cussed. keyword, 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 infor- mation set. Hooks The hooks are: $hook_client is called via the "client-hook" check function (e.g. in an annotated checklist) to make a judge- ment about the connecting client. This hook is defined as string $hook_client( string mdv, string ip ) { ... }; mdv is any mail disposition value already deter- mined (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, typically 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" com- mand from the client. This hook is defined as string $hook_data( string mdv ) { ... }; mdv is any mail disposition value already deter- mined (which the hook can choose to take into account). This function is expected to return a dialog return string. The only legitimate mdv returns 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 deter- mined (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 host- name 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 assess- ment 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 contains 3 or 4 of the adjacent IP address octets in deci- mal or hex representation, 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 generically assigned names. Note that this initial assessment may be overly broad for most environments. This hook may be used to further dis- prove 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 annotated 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 deter- mined (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 annotated checklist), in order to make some judgement about the address that the client has given to mvmtr in the MAIL FROM command. This hook is defined as string $hook_mail_from( string mdv, string rpath ) { ... }; mdv is any mail disposition value already deter- mined (which the hook can choose to take into account). rpath is the email address given in the "MAIL FROM" command. Some firm decisions made by this hook may still be over- ridden. For example, this hook may not refuse a null MAIL FROM address. This function is expect to return a dialog return string. The only legitimate mdv returns 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 annotated checklist), in order to make some judgement about the latest 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 function is expect to return a dialog return string. The only legitimate mdv returns are "dunno", "accept", and "reject". The "known" disposition value will be interpreted as a request to defer the RCPT TO; "unknown" indi- cates 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 disposition indication such as a "+" for acceptance or "-" for rejection. 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 sec- tion). 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 appro- priate 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 con- tributes 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 start- file. /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@mv.mv.com) 2003,2004,2005,2006,2007 BUGS You tell me..