summaryrefslogtreecommitdiff
path: root/hosts/surtr/email
diff options
context:
space:
mode:
Diffstat (limited to 'hosts/surtr/email')
-rw-r--r--hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py35
-rw-r--r--hosts/surtr/email/default.nix57
2 files changed, 68 insertions, 24 deletions
diff --git a/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py b/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py
index f481090c..00182523 100644
--- a/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py
+++ b/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py
@@ -27,20 +27,27 @@ class PolicyHandler(StreamRequestHandler):
27 logger.info('Connection parameters: %s', self.args) 27 logger.info('Connection parameters: %s', self.args)
28 28
29 allowed = False 29 allowed = False
30 with self.server.db_pool.connection() as conn: 30 user = None
31 local, domain = self.args['sender'].split(sep='@', maxsplit=1) 31 if self.args['sasl_username']:
32 extension = None 32 user = self.args['sasl_username']
33 if '+' in local: 33 if self.args['ccert_subject']:
34 local, extension = local.split(sep='+', maxsplit=1) 34 user = self.args['ccert_subject']
35 35
36 logger.debug('Parsed address: %s', {'local': local, 'extension': extension, 'domain': domain}) 36 if user:
37 37 with self.server.db_pool.connection() as conn:
38 with conn.cursor() as cur: 38 local, domain = self.args['sender'].split(sep='@', maxsplit=1)
39 cur.row_factory = namedtuple_row 39 extension = None
40 cur.execute('SELECT "mailbox"."mailbox" as "user", "local", "extension", "domain" FROM "mailbox" INNER JOIN "mailbox_mapping" ON "mailbox".id = "mailbox_mapping"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s', params = {'user': self.args['ccert_subject'], 'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare=True) 40 if '+' in local:
41 for record in cur: 41 local, extension = local.split(sep='+', maxsplit=1)
42 logger.debug('Received result: %s', record) 42
43 allowed = True 43 logger.debug('Parsed address: %s', {'local': local, 'extension': extension, 'domain': domain})
44
45 with conn.cursor() as cur:
46 cur.row_factory = namedtuple_row
47 cur.execute('SELECT "mailbox"."mailbox" as "user", "local", "extension", "domain" FROM "mailbox" INNER JOIN "mailbox_mapping" ON "mailbox".id = "mailbox_mapping"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s', params = {'user': user, 'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare=True)
48 for record in cur:
49 logger.debug('Received result: %s', record)
50 allowed = True
44 51
45 action = '550 5.7.0 Sender address not authorized for current user' 52 action = '550 5.7.0 Sender address not authorized for current user'
46 if allowed: 53 if allowed:
diff --git a/hosts/surtr/email/default.nix b/hosts/surtr/email/default.nix
index 9c3e8849..66c39e8f 100644
--- a/hosts/surtr/email/default.nix
+++ b/hosts/surtr/email/default.nix
@@ -204,17 +204,15 @@ in {
204 postscreen_greet_action = "enforce"; 204 postscreen_greet_action = "enforce";
205 }; 205 };
206 masterConfig = { 206 masterConfig = {
207 smtps = { 207 "465" = {
208 type = "inet"; 208 type = "inet";
209 private = false; 209 private = false;
210 command = "smtpd"; 210 command = "smtpd -v";
211 args = [ 211 args = [
212 "-o" "smtpd_tls_security_level=encrypt" 212 "-o" "smtpd_tls_security_level=encrypt"
213 "-o" "{smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2}" 213 "-o" "{smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2}"
214 "-o" "{smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2}" 214 "-o" "{smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1, !TLSv1.2}"
215 "-o" "smtpd_tls_mandatory_ciphers=high" 215 "-o" "smtpd_tls_mandatory_ciphers=high"
216 "-o" "smtpd_tls_dh1024_param_file=${toString config.security.dhparams.params."postfix-smtps-1024".path}"
217 "-o" "smtpd_tls_dh512_param_file=${toString config.security.dhparams.params."postfix-smtps-512".path}"
218 "-o" "{tls_eecdh_auto_curves = X25519 X448}" 216 "-o" "{tls_eecdh_auto_curves = X25519 X448}"
219 217
220 "-o" "smtpd_tls_wrappermode=yes" 218 "-o" "smtpd_tls_wrappermode=yes"
@@ -223,16 +221,46 @@ in {
223 "-o" "smtpd_tls_received_header=no" 221 "-o" "smtpd_tls_received_header=no"
224 "-o" "cleanup_service_name=subcleanup" 222 "-o" "cleanup_service_name=subcleanup"
225 "-o" "smtpd_client_restrictions=permit_tls_all_clientcerts,reject" 223 "-o" "smtpd_client_restrictions=permit_tls_all_clientcerts,reject"
226 "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}"
227 "-o" "smtpd_relay_restrictions=permit_tls_all_clientcerts,reject"
228 "-o" "{smtpd_sender_restrictions = reject_unknown_sender_domain,reject_unverified_sender,check_policy_service unix:/run/postfix-ccert-sender-policy.sock}" 224 "-o" "{smtpd_sender_restrictions = reject_unknown_sender_domain,reject_unverified_sender,check_policy_service unix:/run/postfix-ccert-sender-policy.sock}"
225 "-o" ''{smtpd_recipient_restrictions=reject_unauth_pipelining,reject_non_fqdn_recipient,reject_unknown_recipient_domain,check_recipient_access pgsql:${pkgs.writeText "check_recipient_access.cf" ''
226 hosts = postgresql:///email
227 dbname = email
228 query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s'))
229 ''},permit_tls_all_clientcerts,reject}''
230 "-o" "smtpd_relay_restrictions=permit_tls_all_clientcerts,reject"
231 "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}"
229 "-o" "unverified_sender_reject_code=550" 232 "-o" "unverified_sender_reject_code=550"
230 "-o" "unverified_sender_reject_reason={Sender address rejected: undeliverable address}" 233 "-o" "unverified_sender_reject_reason={Sender address rejected: undeliverable address}"
234 "-o" "milter_macro_daemon_name=surtr.yggdrasil.li"
235 "-o" ''smtpd_milters=${config.services.opendkim.socket}''
236 ];
237 };
238 "466" = {
239 type = "inet";
240 private = false;
241 command = "smtpd -v";
242 args = [
243 "-o" "smtpd_tls_security_level=encrypt"
244
245 "-o" "smtpd_tls_wrappermode=yes"
246 "-o" "smtpd_tls_ask_ccert=no"
247 "-o" "smtpd_tls_req_ccert=no"
248 "-o" "smtpd_sasl_type=dovecot"
249 "-o" "smtpd_sasl_path=/run/dovecot-sasl"
250 "-o" "smtpd_sasl_auth_enable=yes"
251 "-o" "smtpd_tls_received_header=no"
252 "-o" "cleanup_service_name=subcleanup"
253 "-o" "smtpd_client_restrictions=permit_sasl_authenticated,reject"
254 "-o" "{smtpd_sender_restrictions = reject_unknown_sender_domain,reject_unverified_sender,check_policy_service unix:/run/postfix-ccert-sender-policy.sock}"
231 "-o" ''{smtpd_recipient_restrictions=reject_unauth_pipelining,reject_non_fqdn_recipient,reject_unknown_recipient_domain,check_recipient_access pgsql:${pkgs.writeText "check_recipient_access.cf" '' 255 "-o" ''{smtpd_recipient_restrictions=reject_unauth_pipelining,reject_non_fqdn_recipient,reject_unknown_recipient_domain,check_recipient_access pgsql:${pkgs.writeText "check_recipient_access.cf" ''
232 hosts = postgresql:///email 256 hosts = postgresql:///email
233 dbname = email 257 dbname = email
234 query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s')) 258 query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s'))
235 ''},permit_tls_all_clientcerts,reject}'' 259 ''},permit_sasl_authenticated,reject}''
260 "-o" "smtpd_relay_restrictions=permit_sasl_authenticated,reject"
261 "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}"
262 "-o" "unverified_sender_reject_code=550"
263 "-o" "unverified_sender_reject_reason={Sender address rejected: undeliverable address}"
236 "-o" "milter_macro_daemon_name=surtr.yggdrasil.li" 264 "-o" "milter_macro_daemon_name=surtr.yggdrasil.li"
237 "-o" ''smtpd_milters=${config.services.opendkim.socket}'' 265 "-o" ''smtpd_milters=${config.services.opendkim.socket}''
238 ]; 266 ];
@@ -256,7 +284,7 @@ in {
256 smtp_pass = { 284 smtp_pass = {
257 name = "smtpd"; 285 name = "smtpd";
258 type = "pass"; 286 type = "pass";
259 command = "smtpd"; 287 command = "smtpd -v";
260 }; 288 };
261 postscreen = { 289 postscreen = {
262 name = "smtp"; 290 name = "smtp";
@@ -413,7 +441,7 @@ in {
413 dovecotSqlConf = pkgs.writeText "dovecot-sql.conf" '' 441 dovecotSqlConf = pkgs.writeText "dovecot-sql.conf" ''
414 driver = pgsql 442 driver = pgsql
415 connect = dbname=email 443 connect = dbname=email
416 password_query = SELECT NULL as password, 'Y' as nopassword, "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n' 444 password_query = SELECT (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN NULL ELSE "password" END) as password, (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN true WHEN password IS NULL THEN true ELSE NULL END) as nopassword, "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n'
417 user_query = SELECT "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n' 445 user_query = SELECT "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n'
418 iterate_query = SELECT "user" FROM imap_user 446 iterate_query = SELECT "user" FROM imap_user
419 ''; 447 '';
@@ -445,7 +473,7 @@ in {
445 473
446 auth_ssl_username_from_cert = yes 474 auth_ssl_username_from_cert = yes
447 ssl_cert_username_field = commonName 475 ssl_cert_username_field = commonName
448 auth_mechanisms = external 476 auth_mechanisms = plain login external
449 477
450 auth_verbose = yes 478 auth_verbose = yes
451 verbose_ssl = yes 479 verbose_ssl = yes
@@ -501,6 +529,15 @@ in {
501 group = postfix 529 group = postfix
502 } 530 }
503 } 531 }
532 service auth {
533 vsz_limit = 2G
534
535 unix_listener /run/dovecot-sasl {
536 mode = 0600
537 user = postfix
538 group = postfix
539 }
540 }
504 541
505 namespace inbox { 542 namespace inbox {
506 separator = / 543 separator = /