aboutsummaryrefslogtreecommitdiff
path: root/modules/private/mail
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2020-02-04 08:31:02 +0100
committerIsmaël Bouya <ismael.bouya@normalesup.org>2020-02-04 08:31:02 +0100
commit45730653020eb8b23090a731fc9e687efab850a5 (patch)
tree95e48856b0e5c8f4fc9dcff7e4116fcca92db7f4 /modules/private/mail
parentf119618358cdcbb56cebb84d5f6374d507e55682 (diff)
downloadNix-45730653020eb8b23090a731fc9e687efab850a5.tar.gz
Nix-45730653020eb8b23090a731fc9e687efab850a5.tar.zst
Nix-45730653020eb8b23090a731fc9e687efab850a5.zip
Add milter to verify from
Diffstat (limited to 'modules/private/mail')
-rw-r--r--modules/private/mail/milters.nix14
-rw-r--r--modules/private/mail/postfix.nix7
-rwxr-xr-xmodules/private/mail/verify_from.py60
3 files changed, 80 insertions, 1 deletions
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 @@
129 config.secrets.fullPaths."opendkim/eldiron.private" 129 config.secrets.fullPaths."opendkim/eldiron.private"
130 ]; 130 ];
131 }; 131 };
132
133 systemd.services.milter_verify_from = {
134 description = "Verify from milter";
135 after = [ "network.target" ];
136 wantedBy = [ "multi-user.target" ];
137
138 serviceConfig = {
139 User = "postfix";
140 Group = "postfix";
141 ExecStart = let python = pkgs.python3.withPackages (p: [ p.pymilter ]);
142 in "${python}/bin/python ${./verify_from.py} -s /run/milter_verify_from/verify_from.sock";
143 RuntimeDirectory = "milter_verify_from";
144 };
145 };
132 }; 146 };
133} 147}
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 @@
377 ]; 377 ];
378 smtpd_recipient_restrictions = "permit_sasl_authenticated,reject"; 378 smtpd_recipient_restrictions = "permit_sasl_authenticated,reject";
379 milter_macro_daemon_name = "ORIGINATING"; 379 milter_macro_daemon_name = "ORIGINATING";
380 smtpd_milters = "unix:${config.myServices.mail.milters.sockets.opendkim}"; 380 smtpd_milters = builtins.concatStringsSep "," [
381 # FIXME: put it back when opensmtpd is upgraded and able to
382 # rewrite the from header
383 #"unix:/run/milter_verify_from/verify_from.sock"
384 "unix:${config.myServices.mail.milters.sockets.opendkim}"
385 ];
381 }; 386 };
382 destination = ["localhost"]; 387 destination = ["localhost"];
383 # This needs to reverse DNS 388 # 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 @@
1#!/usr/bin/env python3
2import Milter
3import argparse
4from email.header import decode_header
5from email.utils import parseaddr
6
7class CheckMilter(Milter.Base):
8 def __init__(self):
9 self.envelope_from = None
10 self.header_from = None
11
12 @Milter.noreply
13 def connect(self, IPname, family, hostaddr):
14 return Milter.CONTINUE
15
16 def hello(self, heloname):
17 return Milter.CONTINUE
18
19 def envfrom(self, mailfrom, *args):
20 self.envelope_from = parseaddr(mailfrom)[1]
21 return Milter.CONTINUE
22
23 @Milter.noreply
24 def envrcpt(self, to, *str):
25 return Milter.CONTINUE
26
27 @Milter.noreply
28 def header(self, name, hval):
29 if name.lower() == "from":
30 self.header_from = parseaddr(decode_header(hval)[-1][0])[1]
31 return Milter.CONTINUE
32
33 def eoh(self):
34 if self.header_from is not None and self.header_from != "" and self.header_from != self.envelope_from:
35 self.setreply("553", xcode="5.7.1", msg="<%s>: From header rejected: not matching envelope From %s"
36 % (self.header_from, self.envelope_from))
37 return Milter.REJECT
38
39 return Milter.CONTINUE
40
41 @Milter.noreply
42 def body(self, chunk):
43 return Milter.CONTINUE
44
45 def eom(self):
46 return Milter.ACCEPT
47
48 def close(self):
49 return Milter.CONTINUE
50
51 def abort(self):
52 return Milter.CONTINUE
53
54if __name__ == "__main__":
55 parser = argparse.ArgumentParser()
56 parser.add_argument("--socket", "-s", type=str, help="socket to listen to")
57 config = parser.parse_args()
58
59 Milter.factory = CheckMilter
60 Milter.runmilter("check_from", config.socket, timeout=300)