mirror of
https://github.com/Mailu/Mailu.git
synced 2024-12-14 10:53:30 +02:00
0839490beb
2479: Rework the anti-spoofing rule r=mergify[bot] a=nextgens ## What type of PR? Feature ## What does this PR do? We shouldn't assume that Mailu is the only MTA allowed to send emails on behalf of the domains it hosts. We should also ensure that it's non-trivial for email-spoofing of hosted domains to happen Previously we were preventing any spoofing of the envelope from; Now we are preventing spoofing of both the envelope from and the header from unless some form of authentication passes (is a RELAYHOST, SPF, DKIM, ARC) ### Related issue(s) - close #2475 ## Prerequisites Before we can consider review and merge, please make sure the following list is done and checked. If an entry in not applicable, you can check it or remove it from the list. - [x] In case of feature or enhancement: documentation updated accordingly - [x] Unless it's docs or a minor change: add [changelog](https://mailu.io/master/contributors/workflow.html#changelog) entry file. Co-authored-by: Florent Daigniere <nextgens@freenetproject.org>
109 lines
4.5 KiB
Python
Executable File
109 lines
4.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import os
|
|
import glob
|
|
import shutil
|
|
import multiprocessing
|
|
import logging as log
|
|
import sys
|
|
import re
|
|
|
|
from podop import run_server
|
|
from pwd import getpwnam
|
|
from socrate import system, conf
|
|
|
|
log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
|
|
|
|
def start_podop():
|
|
os.setuid(getpwnam('postfix').pw_uid)
|
|
os.makedirs('/dev/shm/postfix',mode=0o700, exist_ok=True)
|
|
url = "http://" + os.environ["ADMIN_ADDRESS"] + "/internal/postfix/"
|
|
# TODO: Remove verbosity setting from Podop?
|
|
run_server(0, "postfix", "/tmp/podop.socket", [
|
|
("transport", "url", url + "transport/§"),
|
|
("alias", "url", url + "alias/§"),
|
|
("dane", "url", url + "dane/§"),
|
|
("domain", "url", url + "domain/§"),
|
|
("mailbox", "url", url + "mailbox/§"),
|
|
("recipientmap", "url", url + "recipient/map/§"),
|
|
("sendermap", "url", url + "sender/map/§"),
|
|
("senderlogin", "url", url + "sender/login/§"),
|
|
("senderrate", "url", url + "sender/rate/§")
|
|
])
|
|
|
|
def start_mta_sts_daemon():
|
|
os.chmod("/root/", 0o755) # read access to /root/.netrc required
|
|
os.setuid(getpwnam('postfix').pw_uid)
|
|
from postfix_mta_sts_resolver import daemon
|
|
daemon.main()
|
|
|
|
def is_valid_postconf_line(line):
|
|
return not line.startswith("#") \
|
|
and not line == ''
|
|
|
|
# Actual startup script
|
|
os.environ['DEFER_ON_TLS_ERROR'] = os.environ['DEFER_ON_TLS_ERROR'] if 'DEFER_ON_TLS_ERROR' in os.environ else 'True'
|
|
os.environ["FRONT_ADDRESS"] = system.get_host_address_from_environment("FRONT", "front")
|
|
os.environ["ADMIN_ADDRESS"] = system.get_host_address_from_environment("ADMIN", "admin")
|
|
os.environ["ANTISPAM_MILTER_ADDRESS"] = system.get_host_address_from_environment("ANTISPAM_MILTER", "antispam:11332")
|
|
os.environ["LMTP_ADDRESS"] = system.get_host_address_from_environment("LMTP", "imap:2525")
|
|
os.environ["POSTFIX_LOG_SYSLOG"] = os.environ.get("POSTFIX_LOG_SYSLOG","local")
|
|
os.environ["POSTFIX_LOG_FILE"] = os.environ.get("POSTFIX_LOG_FILE", "")
|
|
|
|
# Postfix requires IPv6 addresses to be wrapped in square brackets
|
|
if 'RELAYNETS' in os.environ:
|
|
os.environ["RELAYNETS"] = re.sub(r'([0-9a-fA-F]+:[0-9a-fA-F:]+)/', '[\\1]/', os.environ["RELAYNETS"])
|
|
|
|
for postfix_file in glob.glob("/conf/*.cf"):
|
|
conf.jinja(postfix_file, os.environ, os.path.join("/etc/postfix", os.path.basename(postfix_file)))
|
|
|
|
if os.path.exists("/overrides/postfix.cf"):
|
|
for line in open("/overrides/postfix.cf").read().strip().split("\n"):
|
|
if is_valid_postconf_line(line):
|
|
os.system('postconf -e "{}"'.format(line))
|
|
|
|
if os.path.exists("/overrides/postfix.master"):
|
|
for line in open("/overrides/postfix.master").read().strip().split("\n"):
|
|
if is_valid_postconf_line(line):
|
|
os.system('postconf -Me "{}"'.format(line))
|
|
|
|
for map_file in glob.glob("/overrides/*.map"):
|
|
destination = os.path.join("/etc/postfix", os.path.basename(map_file))
|
|
shutil.copyfile(map_file, destination)
|
|
os.system("postmap {}".format(destination))
|
|
os.remove(destination)
|
|
|
|
if os.path.exists("/overrides/mta-sts-daemon.yml"):
|
|
shutil.copyfile("/overrides/mta-sts-daemon.yml", "/etc/mta-sts-daemon.yml")
|
|
else:
|
|
conf.jinja("/conf/mta-sts-daemon.yml", os.environ, "/etc/mta-sts-daemon.yml")
|
|
|
|
for policy in ['tls_policy', 'transport']:
|
|
if not os.path.exists(f'/etc/postfix/{policy}.map.lmdb'):
|
|
open(f'/etc/postfix/{policy}.map', 'a').close()
|
|
os.system(f'postmap /etc/postfix/{policy}.map')
|
|
|
|
if "RELAYUSER" in os.environ:
|
|
path = "/etc/postfix/sasl_passwd"
|
|
conf.jinja("/conf/sasl_passwd", os.environ, path)
|
|
os.system("postmap {}".format(path))
|
|
|
|
# Configure and start local rsyslog server
|
|
conf.jinja("/conf/rsyslog.conf", os.environ, "/etc/rsyslog.conf")
|
|
os.system("/usr/sbin/rsyslogd -niNONE &")
|
|
# Configure logrotate and start crond
|
|
if os.environ["POSTFIX_LOG_FILE"] != "":
|
|
conf.jinja("/conf/logrotate.conf", os.environ, "/etc/logrotate.d/postfix.conf")
|
|
os.system("/usr/sbin/crond")
|
|
if os.path.exists("/overrides/logrotate.conf"):
|
|
shutil.copyfile("/overrides/logrotate.conf", "/etc/logrotate.d/postfix.conf")
|
|
|
|
# Run Podop and Postfix
|
|
multiprocessing.Process(target=start_podop).start()
|
|
multiprocessing.Process(target=start_mta_sts_daemon).start()
|
|
os.system("/usr/libexec/postfix/post-install meta_directory=/etc/postfix create-missing")
|
|
# Before starting postfix, we need to check permissions on /queue
|
|
# in the event that postfix,postdrop id have changed
|
|
os.system("postfix set-permissions")
|
|
os.system("postfix start-fg")
|