From 45730653020eb8b23090a731fc9e687efab850a5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Isma=C3=ABl=20Bouya?= Date: Tue, 4 Feb 2020 08:31:02 +0100 Subject: [PATCH] Add milter to verify from --- modules/private/mail/milters.nix | 14 +++++++ modules/private/mail/postfix.nix | 7 +++- modules/private/mail/verify_from.py | 60 ++++++++++++++++++++++++++++ overlays/python-packages/default.nix | 1 + pkgs/python-packages/default.nix | 1 + pkgs/python-packages/pymilter.nix | 11 +++++ 6 files changed, 93 insertions(+), 1 deletion(-) create mode 100755 modules/private/mail/verify_from.py create mode 100644 pkgs/python-packages/pymilter.nix diff --git a/modules/private/mail/milters.nix b/modules/private/mail/milters.nix index 16c8a7a..5de03cf 100644 --- a/modules/private/mail/milters.nix +++ b/modules/private/mail/milters.nix @@ -129,5 +129,19 @@ config.secrets.fullPaths."opendkim/eldiron.private" ]; }; + + systemd.services.milter_verify_from = { + description = "Verify from milter"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = "postfix"; + Group = "postfix"; + ExecStart = let python = pkgs.python3.withPackages (p: [ p.pymilter ]); + in "${python}/bin/python ${./verify_from.py} -s /run/milter_verify_from/verify_from.sock"; + RuntimeDirectory = "milter_verify_from"; + }; + }; }; } diff --git a/modules/private/mail/postfix.nix b/modules/private/mail/postfix.nix index 40a9577..e0347ec 100644 --- a/modules/private/mail/postfix.nix +++ b/modules/private/mail/postfix.nix @@ -377,7 +377,12 @@ ]; smtpd_recipient_restrictions = "permit_sasl_authenticated,reject"; milter_macro_daemon_name = "ORIGINATING"; - smtpd_milters = "unix:${config.myServices.mail.milters.sockets.opendkim}"; + smtpd_milters = builtins.concatStringsSep "," [ + # FIXME: put it back when opensmtpd is upgraded and able to + # rewrite the from header + #"unix:/run/milter_verify_from/verify_from.sock" + "unix:${config.myServices.mail.milters.sockets.opendkim}" + ]; }; destination = ["localhost"]; # This needs to reverse DNS diff --git a/modules/private/mail/verify_from.py b/modules/private/mail/verify_from.py new file mode 100755 index 0000000..b75001e --- /dev/null +++ b/modules/private/mail/verify_from.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +import Milter +import argparse +from email.header import decode_header +from email.utils import parseaddr + +class CheckMilter(Milter.Base): + def __init__(self): + self.envelope_from = None + self.header_from = None + + @Milter.noreply + def connect(self, IPname, family, hostaddr): + return Milter.CONTINUE + + def hello(self, heloname): + return Milter.CONTINUE + + def envfrom(self, mailfrom, *args): + self.envelope_from = parseaddr(mailfrom)[1] + return Milter.CONTINUE + + @Milter.noreply + def envrcpt(self, to, *str): + return Milter.CONTINUE + + @Milter.noreply + def header(self, name, hval): + if name.lower() == "from": + self.header_from = parseaddr(decode_header(hval)[-1][0])[1] + return Milter.CONTINUE + + def eoh(self): + if self.header_from is not None and self.header_from != "" and self.header_from != self.envelope_from: + self.setreply("553", xcode="5.7.1", msg="<%s>: From header rejected: not matching envelope From %s" + % (self.header_from, self.envelope_from)) + return Milter.REJECT + + return Milter.CONTINUE + + @Milter.noreply + def body(self, chunk): + return Milter.CONTINUE + + def eom(self): + return Milter.ACCEPT + + def close(self): + return Milter.CONTINUE + + def abort(self): + return Milter.CONTINUE + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--socket", "-s", type=str, help="socket to listen to") + config = parser.parse_args() + + Milter.factory = CheckMilter + Milter.runmilter("check_from", config.socket, timeout=300) diff --git a/overlays/python-packages/default.nix b/overlays/python-packages/default.nix index 8a9949e..0feff55 100644 --- a/overlays/python-packages/default.nix +++ b/overlays/python-packages/default.nix @@ -25,4 +25,5 @@ in apprise = fromMyPythonPackages "apprise"; buildbot = import ./buildbot.nix; wokkel = fromMyPythonPackages "wokkel"; + pymilter = fromMyPythonPackages "pymilter"; } diff --git a/pkgs/python-packages/default.nix b/pkgs/python-packages/default.nix index 747bbe6..2616d64 100644 --- a/pkgs/python-packages/default.nix +++ b/pkgs/python-packages/default.nix @@ -3,4 +3,5 @@ apprise = callPackage ./apprise { inherit mylibs; pythonPackages = python.pkgs; }; buildbot-plugins = callPackage ./buildbot/plugins { inherit mylibs python; }; wokkel = callPackage ./wokkel.nix { pythonPackages = python.pkgs; }; + pymilter = callPackage ./pymilter.nix { pythonPackages = python.pkgs; }; } diff --git a/pkgs/python-packages/pymilter.nix b/pkgs/python-packages/pymilter.nix new file mode 100644 index 0000000..736794e --- /dev/null +++ b/pkgs/python-packages/pymilter.nix @@ -0,0 +1,11 @@ +{ pythonPackages, libmilter }: with pythonPackages; +buildPythonPackage rec { + pname = "pymilter"; + version = "1.0.4"; + src = fetchPypi { + inherit pname version; + sha256 = "1bpcvq7d72q0zi7c8h5knhasywwz9gxc23n9fxmw874n5k8hsn7k"; + }; + doCheck = false; + buildInputs = [ libmilter ]; +} -- 2.41.0