1
0
mirror of https://github.com/mail-in-a-box/mailinabox.git synced 2025-04-01 23:57:05 +00:00
This commit is contained in:
bilogic 2025-02-19 11:35:17 +08:00 committed by GitHub
commit 9a1237a29f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 47 additions and 39 deletions

View File

@ -291,7 +291,7 @@ def build_zone(domain, domain_properties, additional_records, env, is_zone=True)
# Append the DKIM TXT record to the zone as generated by OpenDKIM. # Append the DKIM TXT record to the zone as generated by OpenDKIM.
# Skip if the user has set a DKIM record already. # Skip if the user has set a DKIM record already.
opendkim_record_file = os.path.join(env['STORAGE_ROOT'], 'mail/dkim/mail.txt') opendkim_record_file = os.path.join(env['STORAGE_ROOT'], 'mail/dkim/' + env['DKIM_SELECTOR'] + '.txt')
with open(opendkim_record_file, encoding="utf-8") as orf: with open(opendkim_record_file, encoding="utf-8") as orf:
m = re.match(r'(\S+)\s+IN\s+TXT\s+\( ((?:"[^"]+"\s+)+)\)', orf.read(), re.S) m = re.match(r'(\S+)\s+IN\s+TXT\s+\( ((?:"[^"]+"\s+)+)\)', orf.read(), re.S)
val = "".join(re.findall(r'"([^"]+)"', m.group(2))) val = "".join(re.findall(r'"([^"]+)"', m.group(2)))
@ -752,12 +752,13 @@ def write_opendkim_tables(domains, env):
# Append a record to OpenDKIM's KeyTable and SigningTable for each domain # Append a record to OpenDKIM's KeyTable and SigningTable for each domain
# that we send mail from (zones and all subdomains). # that we send mail from (zones and all subdomains).
opendkim_key_file = os.path.join(env['STORAGE_ROOT'], 'mail/dkim/mail.private') opendkim_key_file = os.path.join(env['STORAGE_ROOT'], 'mail/dkim/' + env['DKIM_SELECTOR'] + '.private')
if not os.path.exists(opendkim_key_file): if not os.path.exists(opendkim_key_file):
# Looks like OpenDKIM is not installed. # Looks like OpenDKIM is not installed.
return False return False
selector=env['DKIM_SELECTOR']
config = { config = {
# The SigningTable maps email addresses to a key in the KeyTable that # The SigningTable maps email addresses to a key in the KeyTable that
# specifies signing information for matching email addresses. Here we # specifies signing information for matching email addresses. Here we
@ -777,7 +778,7 @@ def write_opendkim_tables(domains, env):
# signing domain must match the sender's From: domain. # signing domain must match the sender's From: domain.
"KeyTable": "KeyTable":
"".join( "".join(
f"{domain} {domain}:mail:{opendkim_key_file}\n" f"{domain} {domain}:{selector}:{opendkim_key_file}\n"
for domain in domains for domain in domains
), ),
} }

View File

@ -6,7 +6,7 @@
# #
# The DNS configuration for DKIM is done in the management daemon. # The DNS configuration for DKIM is done in the management daemon.
source setup/functions.sh # load our functions source setup/functions.sh # load our functions
source /etc/mailinabox.conf # load global vars source /etc/mailinabox.conf # load global vars
# Install DKIM... # Install DKIM...
@ -14,12 +14,12 @@ echo "Installing OpenDKIM/OpenDMARC..."
apt_install opendkim opendkim-tools opendmarc apt_install opendkim opendkim-tools opendmarc
# Make sure configuration directories exist. # Make sure configuration directories exist.
mkdir -p /etc/opendkim; mkdir -p /etc/opendkim
mkdir -p "$STORAGE_ROOT/mail/dkim" mkdir -p "$STORAGE_ROOT/mail/dkim"
# Used in InternalHosts and ExternalIgnoreList configuration directives. # Used in InternalHosts and ExternalIgnoreList configuration directives.
# Not quite sure why. # Not quite sure why.
echo "127.0.0.1" > /etc/opendkim/TrustedHosts echo "127.0.0.1" >/etc/opendkim/TrustedHosts
# We need to at least create these files, since we reference them later. # We need to at least create these files, since we reference them later.
# Otherwise, opendkim startup will fail # Otherwise, opendkim startup will fail
@ -30,7 +30,7 @@ if grep -q "ExternalIgnoreList" /etc/opendkim.conf; then
true # already done #NODOC true # already done #NODOC
else else
# Add various configuration options to the end of `opendkim.conf`. # Add various configuration options to the end of `opendkim.conf`.
cat >> /etc/opendkim.conf << EOF; cat >>/etc/opendkim.conf <<EOF
Canonicalization relaxed/simple Canonicalization relaxed/simple
MinimumKeyBits 1024 MinimumKeyBits 1024
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
@ -52,8 +52,8 @@ fi
# A 1024-bit key is seen as a minimum standard by several providers # A 1024-bit key is seen as a minimum standard by several providers
# such as Google. But they and others use a 2048 bit key, so we'll # such as Google. But they and others use a 2048 bit key, so we'll
# do the same. Keys beyond 2048 bits may exceed DNS record limits. # do the same. Keys beyond 2048 bits may exceed DNS record limits.
if [ ! -f "$STORAGE_ROOT/mail/dkim/mail.private" ]; then if [ ! -f "$STORAGE_ROOT/mail/dkim/$DKIM_SELECTOR.private" ]; then
opendkim-genkey -b 2048 -r -s mail -D "$STORAGE_ROOT/mail/dkim" opendkim-genkey -b 2048 -r -s $DKIM_SELECTOR -D $STORAGE_ROOT/mail/dkim
fi fi
# Ensure files are owned by the opendkim user and are private otherwise. # Ensure files are owned by the opendkim user and are private otherwise.
@ -71,7 +71,7 @@ tools/editconf.py /etc/opendmarc.conf -s \
# used by spamassassin to evaluate the mail for spamminess. # used by spamassassin to evaluate the mail for spamminess.
tools/editconf.py /etc/opendmarc.conf -s \ tools/editconf.py /etc/opendmarc.conf -s \
"SPFIgnoreResults=true" "SPFIgnoreResults=true"
# SPFSelfValidate causes the filter to perform a fallback SPF check itself # SPFSelfValidate causes the filter to perform a fallback SPF check itself
# when it can find no SPF results in the message header. If SPFIgnoreResults # when it can find no SPF results in the message header. If SPFIgnoreResults
@ -80,13 +80,13 @@ tools/editconf.py /etc/opendmarc.conf -s \
# spamassassin to evaluate the mail for spamminess. # spamassassin to evaluate the mail for spamminess.
tools/editconf.py /etc/opendmarc.conf -s \ tools/editconf.py /etc/opendmarc.conf -s \
"SPFSelfValidate=true" "SPFSelfValidate=true"
# Disables generation of failure reports for sending domains that publish a # Disables generation of failure reports for sending domains that publish a
# "none" policy. # "none" policy.
tools/editconf.py /etc/opendmarc.conf -s \ tools/editconf.py /etc/opendmarc.conf -s \
"FailureReportsOnNone=false" "FailureReportsOnNone=false"
# AlwaysAddARHeader Adds an "Authentication-Results:" header field even to # AlwaysAddARHeader Adds an "Authentication-Results:" header field even to
# unsigned messages from domains with no "signs all" policy. The reported DKIM # unsigned messages from domains with no "signs all" policy. The reported DKIM
@ -95,7 +95,7 @@ tools/editconf.py /etc/opendmarc.conf -s \
# is used by spamassassin to evaluate the mail for spamminess. # is used by spamassassin to evaluate the mail for spamminess.
tools/editconf.py /etc/opendkim.conf -s \ tools/editconf.py /etc/opendkim.conf -s \
"AlwaysAddARHeader=true" "AlwaysAddARHeader=true"
# Add OpenDKIM and OpenDMARC as milters to postfix, which is how OpenDKIM # Add OpenDKIM and OpenDMARC as milters to postfix, which is how OpenDKIM
# intercepts outgoing mail to perform the signing (by adding a mail header) # intercepts outgoing mail to perform the signing (by adding a mail header)
@ -110,7 +110,7 @@ tools/editconf.py /etc/opendkim.conf -s \
# configuring smtpd_milters there to only list the OpenDKIM milter # configuring smtpd_milters there to only list the OpenDKIM milter
# (see mail-postfix.sh). # (see mail-postfix.sh).
tools/editconf.py /etc/postfix/main.cf \ tools/editconf.py /etc/postfix/main.cf \
"smtpd_milters=inet:127.0.0.1:8891 inet:127.0.0.1:8893"\ "smtpd_milters=inet:127.0.0.1:8891 inet:127.0.0.1:8893" \
non_smtpd_milters=\$smtpd_milters \ non_smtpd_milters=\$smtpd_milters \
milter_default_action=accept milter_default_action=accept
@ -121,4 +121,3 @@ hide_output systemctl enable opendmarc
restart_service opendkim restart_service opendkim
restart_service opendmarc restart_service opendmarc
restart_service postfix restart_service postfix

View File

@ -14,9 +14,9 @@ source setup/preflight.sh
# Python may not be able to read/write files. This is also # Python may not be able to read/write files. This is also
# in the management daemon startup script and the cron script. # in the management daemon startup script and the cron script.
if ! locale -a | grep en_US.utf8 > /dev/null; then if ! locale -a | grep en_US.utf8 >/dev/null; then
# Generate locale if not exists # Generate locale if not exists
hide_output locale-gen en_US.UTF-8 hide_output locale-gen en_US.UTF-8
fi fi
export LANGUAGE=en_US.UTF-8 export LANGUAGE=en_US.UTF-8
@ -35,16 +35,23 @@ if [ -f /etc/mailinabox.conf ]; then
# Load the old .conf file to get existing configuration options loaded # Load the old .conf file to get existing configuration options loaded
# into variables with a DEFAULT_ prefix. # into variables with a DEFAULT_ prefix.
cat /etc/mailinabox.conf | sed s/^/DEFAULT_/ > /tmp/mailinabox.prev.conf cat /etc/mailinabox.conf | sed s/^/DEFAULT_/ >/tmp/mailinabox.prev.conf
source /tmp/mailinabox.prev.conf source /tmp/mailinabox.prev.conf
rm -f /tmp/mailinabox.prev.conf rm -f /tmp/mailinabox.prev.conf
# Since this is a second run, attempt to read overridden settings from $STORAGE_ROOT/mailinabox.conf
if [ -f $DEFAULT_STORAGE_ROOT/mailinabox.conf ]; then
cat $DEFAULT_STORAGE_ROOT/mailinabox.conf | sed s/^/DEFAULT_/ >/tmp/mailinabox.prev.conf
source /tmp/mailinabox.prev.conf
rm -f /tmp/mailinabox.prev.conf
fi
else else
FIRST_TIME_SETUP=1 FIRST_TIME_SETUP=1
fi fi
# Put a start script in a global location. We tell the user to run 'mailinabox' # Put a start script in a global location. We tell the user to run 'mailinabox'
# in the first dialog prompt, so we should do this before that starts. # in the first dialog prompt, so we should do this before that starts.
cat > /usr/local/bin/mailinabox << EOF; cat >/usr/local/bin/mailinabox <<EOF
#!/bin/bash #!/bin/bash
cd $PWD cd $PWD
source setup/start.sh source setup/start.sh
@ -61,9 +68,9 @@ source setup/questions.sh
# Skip on existing installs since we don't want this to block the ability to # Skip on existing installs since we don't want this to block the ability to
# upgrade, and these checks are also in the control panel status checks. # upgrade, and these checks are also in the control panel status checks.
if [ -z "${DEFAULT_PRIMARY_HOSTNAME:-}" ]; then if [ -z "${DEFAULT_PRIMARY_HOSTNAME:-}" ]; then
if [ -z "${SKIP_NETWORK_CHECKS:-}" ]; then if [ -z "${SKIP_NETWORK_CHECKS:-}" ]; then
source setup/network-checks.sh source setup/network-checks.sh
fi fi
fi fi
# Create the STORAGE_USER and STORAGE_ROOT directory if they don't already exist. # Create the STORAGE_USER and STORAGE_ROOT directory if they don't already exist.
@ -82,9 +89,12 @@ if [ ! -d "$STORAGE_ROOT" ]; then
mkdir -p "$STORAGE_ROOT" mkdir -p "$STORAGE_ROOT"
fi fi
f=$STORAGE_ROOT f=$STORAGE_ROOT
while [[ $f != / ]]; do chmod a+rx "$f"; f=$(dirname "$f"); done; while [[ $f != / ]]; do
chmod a+rx "$f"
f=$(dirname "$f")
done
if [ ! -f "$STORAGE_ROOT/mailinabox.version" ]; then if [ ! -f "$STORAGE_ROOT/mailinabox.version" ]; then
setup/migrate.py --current > "$STORAGE_ROOT/mailinabox.version" setup/migrate.py --current >"$STORAGE_ROOT/mailinabox.version"
chown "$STORAGE_USER:$STORAGE_USER" "$STORAGE_ROOT/mailinabox.version" chown "$STORAGE_USER:$STORAGE_USER" "$STORAGE_ROOT/mailinabox.version"
fi fi
@ -92,7 +102,7 @@ fi
# tools know where to look for data. The default MTA_STS_MODE setting # tools know where to look for data. The default MTA_STS_MODE setting
# is blank unless set by an environment variable, but see web.sh for # is blank unless set by an environment variable, but see web.sh for
# how that is interpreted. # how that is interpreted.
cat > /etc/mailinabox.conf << EOF; cat >/etc/mailinabox.conf <<EOF
STORAGE_USER=$STORAGE_USER STORAGE_USER=$STORAGE_USER
STORAGE_ROOT=$STORAGE_ROOT STORAGE_ROOT=$STORAGE_ROOT
PRIMARY_HOSTNAME=$PRIMARY_HOSTNAME PRIMARY_HOSTNAME=$PRIMARY_HOSTNAME
@ -101,6 +111,7 @@ PUBLIC_IPV6=$PUBLIC_IPV6
PRIVATE_IP=$PRIVATE_IP PRIVATE_IP=$PRIVATE_IP
PRIVATE_IPV6=$PRIVATE_IPV6 PRIVATE_IPV6=$PRIVATE_IPV6
MTA_STS_MODE=${DEFAULT_MTA_STS_MODE:-enforce} MTA_STS_MODE=${DEFAULT_MTA_STS_MODE:-enforce}
DKIM_SELECTOR=${DEFAULT_DKIM_SELECTOR:-mail}
EOF EOF
# Start service configuration. # Start service configuration.
@ -120,8 +131,7 @@ source setup/management.sh
source setup/munin.sh source setup/munin.sh
# Wait for the management daemon to start... # Wait for the management daemon to start...
until nc -z -w 4 127.0.0.1 10222 until nc -z -w 4 127.0.0.1 10222; do
do
echo "Waiting for the Mail-in-a-Box management daemon to start..." echo "Waiting for the Mail-in-a-Box management daemon to start..."
sleep 2 sleep 2
done done
@ -143,13 +153,13 @@ source setup/firstuser.sh
# run in the recommended curl-pipe-to-bash method there is no TTY and # run in the recommended curl-pipe-to-bash method there is no TTY and
# certbot will fail if it tries to ask. # certbot will fail if it tries to ask.
if [ ! -d "$STORAGE_ROOT/ssl/lets_encrypt/accounts/acme-v02.api.letsencrypt.org/" ]; then if [ ! -d "$STORAGE_ROOT/ssl/lets_encrypt/accounts/acme-v02.api.letsencrypt.org/" ]; then
echo echo
echo "-----------------------------------------------" echo "-----------------------------------------------"
echo "Mail-in-a-Box uses Let's Encrypt to provision free SSL/TLS certificates" echo "Mail-in-a-Box uses Let's Encrypt to provision free SSL/TLS certificates"
echo "to enable HTTPS connections to your box. We're automatically" echo "to enable HTTPS connections to your box. We're automatically"
echo "agreeing you to their subscriber agreement. See https://letsencrypt.org." echo "agreeing you to their subscriber agreement. See https://letsencrypt.org."
echo echo
certbot register --register-unsafely-without-email --agree-tos --config-dir "$STORAGE_ROOT/ssl/lets_encrypt" certbot register --register-unsafely-without-email --agree-tos --config-dir "$STORAGE_ROOT/ssl/lets_encrypt"
fi fi
# Done. # Done.
@ -166,16 +176,14 @@ if management/status_checks.py --check-primary-hostname; then
echo echo
echo "If you have a DNS problem put the box's IP address in the URL" echo "If you have a DNS problem put the box's IP address in the URL"
echo "(https://$PUBLIC_IP/admin) but then check the TLS fingerprint:" echo "(https://$PUBLIC_IP/admin) but then check the TLS fingerprint:"
openssl x509 -in "$STORAGE_ROOT/ssl/ssl_certificate.pem" -noout -fingerprint -sha256\ openssl x509 -in "$STORAGE_ROOT/ssl/ssl_certificate.pem" -noout -fingerprint -sha256 | sed "s/SHA256 Fingerprint=//i"
| sed "s/SHA256 Fingerprint=//i"
else else
echo "https://$PUBLIC_IP/admin" echo "https://$PUBLIC_IP/admin"
echo echo
echo "You will be alerted that the website has an invalid certificate. Check that" echo "You will be alerted that the website has an invalid certificate. Check that"
echo "the certificate fingerprint matches:" echo "the certificate fingerprint matches:"
echo echo
openssl x509 -in "$STORAGE_ROOT/ssl/ssl_certificate.pem" -noout -fingerprint -sha256\ openssl x509 -in "$STORAGE_ROOT/ssl/ssl_certificate.pem" -noout -fingerprint -sha256 | sed "s/SHA256 Fingerprint=//i"
| sed "s/SHA256 Fingerprint=//i"
echo echo
echo "Then you can confirm the security exception and continue." echo "Then you can confirm the security exception and continue."
echo echo