zdkimfilter(8)

NAME
zdkimfilter - DKIM filter for the Courier mail server

SYNOPSIS
filterctl ("start" | "stop") zdkimfilter

ln -s zdkimfilter other-name; filterctl ("start" | "stop") other-name

/usr/lib/filters/zdkimfilter OPTION

The second form is for running multiple filters. See "MULTIPLE FILTERS" below.

The third form is used for scripting or testing. See "COMMAND LINE OPTIONS" below.

DESCRIPTION
zdkimfilter is a global filter, in the sense that it works for all users. It works in either signing or verifying mode, based on whether the sender has relaying privileges.

A DKIM signature on a message associates a domain with the message, thereby allowing domain owners to claim some responsibility for the messages.

  Signing
The signing domain can be inferred in three ways, by SMTP authentication, by setting the default_domain configuration parameter or by setting a value in RELAYCLIENT, in the smtpaccess file. In any case, the signing domain can be overridden by the key_choice_header configuration parameter.

For SMTP authentication, the domain name is determined after the user id, if it contains an "@" or from default_domain.

For non-empty RELAYCLIENT variable, typically set in smtpaccess files, zdkimfilter signs only if the value of RELAYCLIENT starts with "@". In that case, the domain name is the rest of the string. The local part of the user id is set to "postmaster" (e.g. for db_sql_check_user). CAUTION: this setting may conflict with Courier appending the value of RELAYCLIENT to message recipient(s). That is meant to force the message through local delivery, possibly using percentrelay. The filter removes the appended values as long as it is installed. To prevent that behavior set let_relayclient_alone. At any rate, when a client uses SMTP authentication, any RELAYCLIENT content is reset.

In any case, the domain name can be obtained from a suitable header field of the message, such as "From:". Use the key_choice_header configuration option to specify that.

The domain name is then looked up in the domain_keys directory. It should be a soft link to the actual key. The basename of the linked-to file contains the selector. See examples in zdkimgenkey(8). If the file is not a soft link, zdkimfilter will use a default selector "s=s", configurable with "selector" in zdkimfilter.conf.

The user-id used for SMTP authentication is also reported in Courier's "Received:" header field. If the redact_received_auth configuration option is set, zdkimfilter obscures it. See redact(1).

After signing an outgoing message, zdkimfilter logs to the database the list of domains that appeared in any RCPT command. The database can be used for whitelisting and for rate-limiting users. See zfilter_db(1) for more details.

  Verifying
Messages not qualified as RELAYCLIENT are candidate for DKIM verification. zdkimfilter sorts signatures by domain, putting author domain and whitelisted domains first. It then verifies domain's signatures, optionally all or until a valid one. If the database is used, an attempt is made to authenticate each domain unless verify_one_domain is set. If report_all_sigs is set, all signatures are processed. Normally, there are only a few signatures in each message, so these settings don't actually change much. However, messages having an unreasonable number of signatures are rejected (max_signatures). That's the only rejection done by default.

Messages can be rejected or dropped according to DMARC, ADSP, and NXDOMAIN configurations, summarized below, and also according to an action_header (see zdkimfilter.conf(5)) or the shoot_on_sight feature (see whitelisted in zfilter_db(1)). The decision to reject or drop a message can be revoked after DNSWL (see dnswl_worthiness_pass and whitelisted_pass in zdkimfilter.conf(5)). So, if a domain is tagged shoot_on_sight, but the message is authenticated by a domain which is whitelisted or DNSWL-worth, the latter wins and the message is not rejected. However, if the sender is DNSWL-worth but tagged shoot_on_sight, it worthiness is discarded and the message is rejected.

By default, zdkimfilter adds an "Authentication-Results:" (A-R) header field only when there are noticeable results to report. It uses the host name that Courier uses in its "Received:" field. Other A-R fields with that same name get zapped from the message, if found.

While per-domain flags (whitelisted, do_dmarc, do_adsp) are read during the verification process, the resulting data is logged to the database after handing the message back to Courier. Those results are used to send aggregate reports, and in general can contribute some insight on the email traffic. See zfilter_db(1) for the details.

  DMARC and ADSP policies
These policies deal with the "From:" domain. It is not advisable to honor them indiscriminately, because users of a domain with a strict policy can subscribe to a mailing list that invalidates their signatures. Rejecting that mail would then cause local users to be unsubscribed from such mailing list. As an alternative to whitelisting each mailing list, it is possible to enable or disable DMARC or ADSP on a per-domain basis. Recall that ADSP was declared "Historic" in November 2013. Albeit deprecated, "dkim-adsp" is the only authentication method that provides for nxdomain.

Options honor_dmarc and honor_author_domain set to 0 or 1 the corresponding flags. Then a query db_sql_domain_flags can increase or decrease those values. A DMARC record is looked up unless DMARC flag is less than ADSP's. If no record is found, an ADSP record is looked up unless ADSP flag is less than DMARC's. Thus, if the flags are equal an ADSP record is looked up for domains that still don't have DMARC. Then, if its flag is greater than 0, the policy is honored. However, if an authenticated domain is whitelisted or DNSWL allowed, the message is delivered even though the policy failed.

DMARC record lookup is done through a Tree Walk procedure. This is the new method specified in the upcoming specification, replacing the use of the Public Suffix List (PSL). Its implementation here comprises querying a suite of TXT records in parallel (up to 8) in order to determine the organizational domain of the "From:" domain. The query parameters, hosts, timeout and number of attempts are read from resolv.conf, see resolv.conf(5). The PSL file should still be available and configured in publicsuffix in order to produce aggregate records. See zaggregate(1) and zdkimfilter.conf(5).

A DMARC policy can ask to quarantine a message. If DMARC is honored, the filter just adds an A-R field contains a "(QUARANTINE)" comment right after "dmarc=fail" and the message is delivered normally. This can be dealt with on delivery, for example like so:

    if (/^Authentication-Results:.*dmarc=fail..QUARANTINE/:H)
    {
        KEYWORDS='$Junk';
    }

  MLM transformation experiment
Since version 3, zdkimfilter tries and recognize when a mailing list manager (MLM) added a subject tag and/or a footer. Sometimes the original signature can be verified. That depends on which header fields were signed, which ones were changed, and which ones were saved as Original-field.

Unless this feature is disabled by setting disable_experimental, such fields are saved on signing and checked on verifiying. For signatures recovered by undoing transformations, a "reason=" tag is added in A-R. In case the "From:" field was changed by the MLM and recovered, the reason mentions "Original-From:". The value can be restored on delivery, for example like so:

    if (/^Authentication-Results:.*dkim=pass reason="Original-From/:H)
    {
        xfilter "reformail -R From: Munged-From: | reformail -R Original-From: From:"
    }

Note: The value of "From:" must be restored after any external forwarding, otherwise an external DMARC filter might reject the message, thereby vanishing the reason why MLM munged "From:" in the first place.

OPTIONS
Configuration options are documented in zdkimfilter.conf(5) and zfilter_db(1).

  COURIER SETTINGS
The esmtpd configuration files can be tweaked to avoid rewritings that would break existing signatures.

ALLOW_EXCLUSIVE
    Set this value in esmtpd. See also "trust_a_r" in zdkimfilter.conf(5). Setting both flags allows smooth usage of A-R header fields.

MIME
    Setting MIME=none prevents rewriting the MIME structure. If you use this, you may want to override it in esmtpd-msa, e.g. by setting MIME=some.

NOADDRREWRITE
    Documented in esmtpd. It may be worth to also set opt NOADDRREWRITE=2 in bofh, for local messages signed before sending.

DMARC requires SPF, besides DKIM. To enable SPF checking in bofh see courier(8). The result of Courier's SPF check is read from Received-SPF header fields in the message. If SPF is not configured in Courier, turn off this behavior with no_spf, to avoid spurious authentications.

  MULTIPLE FILTERS
It is possible to run the same filter by a different name. Identified by a symbolic link, the copy will be memory mapped to the same file, but will consume its own CPU time. The two main reasons for running multiple copies are (i) to split verifying and signing and (ii) to apply multiple signatures.

A filter copy can use the same configuration file or a different one. As courierfilter does not pass arguments, the alternative filename is embedded in the other-name of the symbolic link: if the name includes the sequence "-f_" (hyphen, 'f', underscore, alluding to the -f command line option), the name formed by the characters after the sequence, in the /etc/courier/filters directory, will be used as configuration filename. If no characters follow the "-f_" sequence, then the whole basename is used to form the name of the configuration file. The extension ".conf" is added to the filename if not already present.

A different behavior can be obtained also using the same configuration file by using option "split_verify" in zdkimfilter.conf.

  COMMAND LINE OPTIONS
These are only useful for testing.

-f config-filename
    Override the default configuration file. If config-filename is an empty string (""), the program will use default values only. Otherwise, config-filename will be opened in the current directory.

    An alternative way to indicate a different filename is described above under "MULTIPLE FILTERS". In that case, the file will be searched in /etc/courier/filters.

    If given, the -f option overrides any config-filename embedded in the program name.

--save-files [filename]
    Save intermediate debug files. When retrying DKIM authentication by undoing a MLM transformation, the retried message or part of it is saved to the filename, if given.

    This option is used by zdkimverify's -o option.

    If the executable is compiled with debugging support, this option dumps the canonicalization results to files named "dkim.*.*".

    All files are created in the /tmp directory, possibly overridden by the corresponding configuration parameter.

--no-db
    Omit database processing.

--no-write
    When verifying, don't modify the mail file. Instead, write just the Authentication-Results file to stdout.

--help
    Print usage and exit.

--version
    Print version info and exit.

--no-fork
    Any following -t option will directly parse ctlfiles, rather than sending their names through a pipe to one child per mailfile. Albeit read from stdin, the mail file must be a regular file. It is copied to stdout even if not modified, unless errors occur.

--do-seal
    Write an ARC set rather than a DKIM signature.

-tN[,x] file...
    Scan the arguments that follow as N ctl and mail file(s). With ,x behave like batch test, that is non-interactively. Otherwise prompt the user with the id of the forked process, to ease attaching a debugger to it.

    If x starts with "zdkim", then configuration parameter split_verify is discarded. That's the mode used by zdkimsign.

--batch-test
    Enter batch test mode. This mode accepts a few commands from standard input, in addition of mail and ctl files. These cause DKIM keys (test2), and policies (test3) to be retrieved from files in the current directory rather than from the DNS. Fixed time (test4) affects the t= tag of signatures. This is the option used in the test suite run by make check.

SIGNALS
The HUP signal can be used to have zdkimfilter reload its configuration.

Upon receiving the signal, zdkimfilter reads its configuration file and opens new connections to OpenDKIM library and (possibly) to the database. If no error occurs, it then cleans up the old area, closing old connections, and writes LOG_INFO if verbosity is 2 or higher.

BUGS
Please report bugs to the author. Command-line options above should allow one to reproduce any misbehavior in a controlled fashion.

FILES

/var/spool/courier/tmp/zdkimfilter.pid
    The id of the parent zdkimfilter process. The basename of this file reflects the command name by which the filter was loaded.

/var/spool/courier/filters/zdkimfilter or /var/spool/courier/allfilters/zdkimfilter
    The socket where filter process listens to filtering requests. This socket is created in one or the other directory based on "all_mode" configuration option (see zdkimfilter.conf(5)). The basename of this file reflects the command name by which the filter was loaded.

/etc/courier/filters/keys
    Default directory for links to private keys.

/etc/courier/filters/zdkimfilter.conf
    Default configuration file.

AUTHOR
Alessandro Vesely <vesely@tana.it>

SEE ALSO

courier(8), courierfilter(8)
    Explain the "enablefiltering" configuration file, and how to start and stop filters.

zdkimgenkey(8)
    Generate an asymmetric key pair suitable for DKIM use.

zdkimfilter.conf(5)
    Explains each configuration option, excluding those for database.

zfilter_db(1)
    Explains the database configuration options and how to test them.

zdkimsign(1) and zdkimverify(1)
    Also useful for testing a configuration file.

redact(1)
    For retrieving an obfuscated user-id.

RFC 6376
    DomainKeys Identified Mail (DKIM) signatures.

RFC 7208
    Sender Policy Framework (SPF)

RFC 7489
    Domain-based Message Authentication, Reporting, and Conformance (DMARC).

RFC 8601
    Message header field for indicating message authentication status.

RFC 5617
    DomainKey Identified Mail (DKIM) Author Domain Signing Practices (ADSP).