Hi all. In OpenSMTPD, the semi-unofficial filter-dkimsign filter provides basic DKIM mail signing. However, the filter signs all mails it sees regardless of user authentication. The standard configuration is to only enable this filter on a Unix domain socket (or on a private submission port not used for incoming mails, or requires authentication on a public port, etc).
However, often it's desirable to support DKIM signing for logged-in users from the public Internet via a standard port, too. The following patches introduce a new option "-u", when enabled, only mails from authenticated users are signed, mails from unauthenticated users are passed unmodified, making filter-dkimsign more useful simple option for servers with simple needs. Hopefully I did everything correctly, please review the patches attached in the thread, one for for filter-dkimsign, another for libopensmtpd. Although both codebases are not strictly an official part of OpenSMTPD, the patches may be of general interest, so I CCed both the mailing list and the original author. Note that these patch must be applied on top of the latest development versions of libopensmtpd and filter-dkimsign at https://imperialat.at/ because it requires the field "username" in struct osmtpd_ctx, which has not appeared in any stable releases to my best knowledge. Furthermore, libopensmtpd itself must be patched first (see thread reply for patch) due to a pre-existing bug. I was unable to find the anonymous CVS access to the server, so for reference my copy was obtained via: wget --no-parent -r https://imperialat.at/dev/libopensmtpd/ wget --no-parent -r https://imperialat.at/dev/filter-dkimsign/ Cheers, Tom Li --- filter-dkimsign.8 | 6 ++++++ main.c | 34 ++++++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/filter-dkimsign.8 b/filter-dkimsign.8 index 024829c..cdffc10 100644 --- a/filter-dkimsign.8 +++ b/filter-dkimsign.8 @@ -88,6 +88,12 @@ The selector within the _domainkey subdomain of where the public key can be found. .It Fl t Add the time of signing to the dkim header. +.It Fl u +Only sign mails from authenticated users. This option should only +be used with TCP/IP, not a Unix domain socket, since all submitted +mails to the latter source are unauthenticated. If mail signing of +both sources is desired, use two separate filter definitions for +each. .It Fl x Ar seconds Add the amount of .Ar seconds diff --git a/main.c b/main.c index 2961793..d6d7211 100644 --- a/main.c +++ b/main.c @@ -86,6 +86,7 @@ static int canonbody = CANON_SIMPLE; static int addtime = 0; static long long addexpire = 0; static int addheaders = 0; +static int authonly = 0; static char **domain = NULL; static size_t ndomains = 0; @@ -110,6 +111,7 @@ void dkim_message_free(struct osmtpd_ctx *, void *); void dkim_parse_header(struct dkim_message *, char *, int); void dkim_parse_body(struct dkim_message *, char *); void dkim_sign(struct osmtpd_ctx *); +void dkim_append_original(struct osmtpd_ctx *); int dkim_signature_printheader(struct dkim_message *, const char *); int dkim_signature_printf(struct dkim_message *, char *, ...) __attribute__((__format__ (printf, 2, 3))); @@ -128,7 +130,7 @@ main(int argc, char *argv[]) ssize_t linelen; const char *errstr; - while ((ch = getopt(argc, argv, "a:c:D:d:h:k:s:tx:z")) != -1) { + while ((ch = getopt(argc, argv, "a:c:D:d:h:k:s:tux:z")) != -1) { switch (ch) { case 'a': if (strncmp(optarg, "rsa-", 4) == 0) { @@ -208,6 +210,9 @@ main(int argc, char *argv[]) case 't': addtime = 1; break; + case 'u': + authonly = 1; + break; case 'x': addexpire = strtonum(optarg, 1, INT64_MAX, &errstr); if (addexpire == 0) @@ -238,6 +243,7 @@ main(int argc, char *argv[]) osmtpd_register_filter_dataline(dkim_dataline); osmtpd_register_filter_commit(dkim_commit); osmtpd_local_message(dkim_message_new, dkim_message_free); + osmtpd_need(OSMTPD_NEED_USERNAME); osmtpd_run(); return 0; @@ -271,7 +277,10 @@ dkim_dataline(struct osmtpd_ctx *ctx, const char *line) dkim_errx(message, "Couldn't write to tempfile"); if (line[0] == '.' && line[1] =='\0') { - dkim_sign(ctx); + if (ctx->username || !authonly) + dkim_sign(ctx); + else + dkim_append_original(ctx); } else if (linelen != 0 && message->parsing_headers) { if (line[0] == '.') line++; @@ -750,17 +759,26 @@ dkim_sign(struct osmtpd_ctx *ctx) osmtpd_filter_dataline(ctx, "%s", tmp); tmp = tmp2 + 2; } - tmp = NULL; - linelen = 0; + dkim_append_original(ctx); + return; +fail: + osmtpd_filter_dataline(ctx, "."); +} + +void +dkim_append_original(struct osmtpd_ctx *ctx) +{ + char *tmp = NULL; + size_t linelen = 0; + struct dkim_message *message = ctx->local_message; + ssize_t i; + rewind(message->origf); while ((i = getline(&tmp, &linelen, message->origf)) != -1) { tmp[i - 1] = '\0'; osmtpd_filter_dataline(ctx, "%s", tmp); } free(tmp); - return; -fail: - osmtpd_filter_dataline(ctx, "."); } int @@ -960,7 +978,7 @@ dkim_signature_need(struct dkim_message *message, size_t len) __dead void usage(void) { - fprintf(stderr, "usage: filter-dkimsign [-tz] [-a signalg] " + fprintf(stderr, "usage: filter-dkimsign [-tuz] [-a signalg] " "[-c canonicalization] \n [-h headerfields]" "[-x seconds] -D file -d domain -k keyfile -s selector\n"); exit(1); -- 2.46.1