[Postfix] Remove Zeyple, base on Buster

master
andryyy 2019-08-09 14:08:58 +02:00
parent f21cf134dd
commit 3136e020f6
No known key found for this signature in database
GPG Key ID: 8EC34FF2794E25EF
5 changed files with 15 additions and 301 deletions

View File

@ -1,4 +1,4 @@
FROM ubuntu:bionic FROM debian:buster-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>" LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
@ -9,12 +9,17 @@ RUN dpkg-divert --local --rename --add /sbin/initctl \
&& dpkg-divert --local --rename --add /usr/bin/ischroot \ && dpkg-divert --local --rename --add /usr/bin/ischroot \
&& ln -sf /bin/true /usr/bin/ischroot && ln -sf /bin/true /usr/bin/ischroot
RUN apt-get update && apt-get install -y --no-install-recommends \ # Add groups and users before installing Postfix to not break compatibility
RUN groupadd -g 102 postfix \
&& groupadd -g 103 postdrop \
&& useradd -g postfix -u 101 -d /var/spool/postfix -s /usr/sbin/nologin postfix \
&& apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \ ca-certificates \
curl \ curl \
dirmngr \ dirmngr \
gnupg \ gnupg \
libsasl2-modules \ libsasl2-modules \
mariadb-client \
perl \ perl \
postfix \ postfix \
postfix-mysql \ postfix-mysql \
@ -32,16 +37,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
&& printf '#!/bin/bash\n/usr/sbin/postconf -c /opt/postfix/conf "$@"' > /usr/local/sbin/postconf \ && printf '#!/bin/bash\n/usr/sbin/postconf -c /opt/postfix/conf "$@"' > /usr/local/sbin/postconf \
&& chmod +x /usr/local/sbin/postconf && chmod +x /usr/local/sbin/postconf
RUN addgroup --system --gid 600 zeyple \
&& adduser --system --home /var/lib/zeyple --no-create-home --uid 600 --gid 600 --disabled-login zeyple \
&& touch /var/log/zeyple.log \
&& chown zeyple: /var/log/zeyple.log \
&& mkdir -p /opt/mailman/var/data \
&& touch /opt/mailman/var/data/postfix_lmtp \
&& touch /opt/mailman/var/data/postfix_domains
COPY zeyple.py /usr/local/bin/zeyple.py
COPY zeyple.conf /etc/zeyple.conf
COPY supervisord.conf /etc/supervisor/supervisord.conf COPY supervisord.conf /etc/supervisor/supervisord.conf
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
COPY postfix.sh /opt/postfix.sh COPY postfix.sh /opt/postfix.sh

View File

@ -4,6 +4,12 @@ trap "postfix stop" EXIT
[[ ! -d /opt/postfix/conf/sql/ ]] && mkdir -p /opt/postfix/conf/sql/ [[ ! -d /opt/postfix/conf/sql/ ]] && mkdir -p /opt/postfix/conf/sql/
# Wait for MySQL to warm-up
while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
echo "Waiting for database to come up..."
sleep 2
done
cat <<EOF > /etc/aliases cat <<EOF > /etc/aliases
# Autogenerated by mailcow # Autogenerated by mailcow
null: /dev/null null: /dev/null
@ -286,11 +292,6 @@ query = SELECT goto FROM spamalias
AND validity >= UNIX_TIMESTAMP() AND validity >= UNIX_TIMESTAMP()
EOF EOF
# Reset GPG key permissions
mkdir -p /var/lib/zeyple/keys
chmod 700 /var/lib/zeyple/keys
chown -R 600:600 /var/lib/zeyple/keys
# Fix Postfix permissions # Fix Postfix permissions
chown -R root:postfix /opt/postfix/conf/sql/ chown -R root:postfix /opt/postfix/conf/sql/
chmod 640 /opt/postfix/conf/sql/*.cf chmod 640 /opt/postfix/conf/sql/*.cf

View File

@ -1,9 +1,10 @@
@version: 3.13 @version: 3.19
@include "scl.conf" @include "scl.conf"
options { options {
chain_hostnames(off); chain_hostnames(off);
flush_lines(0); flush_lines(0);
use_dns(no); use_dns(no);
dns_cache(no);
use_fqdn(no); use_fqdn(no);
owner("root"); group("adm"); perm(0640); owner("root"); group("adm"); perm(0640);
stats_freq(0); stats_freq(0);

View File

@ -1,9 +0,0 @@
[zeyple]
log_file = /dev/null
[gpg]
home = /var/lib/zeyple/keys
[relay]
host = localhost
port = 10026

View File

@ -1,274 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
import logging
import email
import email.mime.multipart
import email.mime.application
import email.encoders
import smtplib
import copy
from io import BytesIO
try:
from configparser import SafeConfigParser # Python 3
except ImportError:
from ConfigParser import SafeConfigParser # Python 2
import gpgme
# Boiler plate to avoid dependency on six
# BBB: Python 2.7 support
PY3K = sys.version_info > (3, 0)
def message_from_binary(message):
if PY3K:
return email.message_from_bytes(message)
else:
return email.message_from_string(message)
def as_binary_string(email):
if PY3K:
return email.as_bytes()
else:
return email.as_string()
def encode_string(string):
if isinstance(string, bytes):
return string
else:
return string.encode('utf-8')
__title__ = 'Zeyple'
__version__ = '1.2.0'
__author__ = 'Cédric Félizard'
__license__ = 'AGPLv3+'
__copyright__ = 'Copyright 2012-2016 Cédric Félizard'
class Zeyple:
"""Zeyple Encrypts Your Precious Log Emails"""
def __init__(self, config_fname='zeyple.conf'):
self.config = self.load_configuration(config_fname)
log_file = self.config.get('zeyple', 'log_file')
logging.basicConfig(
filename=log_file, level=logging.DEBUG,
format='%(asctime)s %(process)s %(levelname)s %(message)s'
)
logging.info("Zeyple ready to encrypt outgoing emails")
def load_configuration(self, filename):
"""Reads and parses the config file"""
config = SafeConfigParser()
config.read([
os.path.join('/etc/', filename),
filename,
])
if not config.sections():
raise IOError('Cannot open config file.')
return config
@property
def gpg(self):
protocol = gpgme.PROTOCOL_OpenPGP
if self.config.has_option('gpg', 'executable'):
executable = self.config.get('gpg', 'executable')
else:
executable = None # Default value
home_dir = self.config.get('gpg', 'home')
ctx = gpgme.Context()
ctx.set_engine_info(protocol, executable, home_dir)
ctx.armor = True
return ctx
def process_message(self, message_data, recipients):
"""Encrypts the message with recipient keys"""
message_data = encode_string(message_data)
in_message = message_from_binary(message_data)
logging.info(
"Processing outgoing message %s", in_message['Message-id'])
if not recipients:
logging.warn("Cannot find any recipients, ignoring")
sent_messages = []
for recipient in recipients:
logging.info("Recipient: %s", recipient)
key_id = self._user_key(recipient)
logging.info("Key ID: %s", key_id)
if key_id:
out_message = self._encrypt_message(in_message, key_id)
# Delete Content-Transfer-Encoding if present to default to
# "7bit" otherwise Thunderbird seems to hang in some cases.
del out_message["Content-Transfer-Encoding"]
else:
logging.warn("No keys found, message will be sent unencrypted")
out_message = copy.copy(in_message)
self._add_zeyple_header(out_message)
self._send_message(out_message, recipient)
sent_messages.append(out_message)
return sent_messages
def _get_version_part(self):
ret = email.mime.application.MIMEApplication(
'Version: 1\n',
'pgp-encrypted',
email.encoders.encode_noop,
)
ret.add_header(
'Content-Description',
"PGP/MIME version identification",
)
return ret
def _get_encrypted_part(self, payload):
ret = email.mime.application.MIMEApplication(
payload,
'octet-stream',
email.encoders.encode_noop,
name="encrypted.asc",
)
ret.add_header('Content-Description', "OpenPGP encrypted message")
ret.add_header(
'Content-Disposition',
'inline',
filename='encrypted.asc',
)
return ret
def _encrypt_message(self, in_message, key_id):
if in_message.is_multipart():
# get the body (after the first \n\n)
payload = in_message.as_string().split("\n\n", 1)[1].strip()
# prepend the Content-Type including the boundary
content_type = "Content-Type: " + in_message["Content-Type"]
payload = content_type + "\n\n" + payload
message = email.message.Message()
message.set_payload(payload)
payload = message.get_payload()
else:
payload = in_message.get_payload()
payload = encode_string(payload)
quoted_printable = email.charset.Charset('ascii')
quoted_printable.body_encoding = email.charset.QP
message = email.mime.nonmultipart.MIMENonMultipart(
'text', 'plain', charset='utf-8'
)
message.set_payload(payload, charset=quoted_printable)
mixed = email.mime.multipart.MIMEMultipart(
'mixed',
None,
[message],
)
# remove superfluous header
del mixed['MIME-Version']
payload = as_binary_string(mixed)
encrypted_payload = self._encrypt_payload(payload, [key_id])
version = self._get_version_part()
encrypted = self._get_encrypted_part(encrypted_payload)
out_message = copy.copy(in_message)
out_message.preamble = "This is an OpenPGP/MIME encrypted " \
"message (RFC 4880 and 3156)"
if 'Content-Type' not in out_message:
out_message['Content-Type'] = 'multipart/encrypted'
else:
out_message.replace_header(
'Content-Type',
'multipart/encrypted',
)
out_message.set_param('protocol', 'application/pgp-encrypted')
out_message.set_payload([version, encrypted])
return out_message
def _encrypt_payload(self, payload, key_ids):
"""Encrypts the payload with the given keys"""
payload = encode_string(payload)
plaintext = BytesIO(payload)
ciphertext = BytesIO()
self.gpg.armor = True
recipient = [self.gpg.get_key(key_id) for key_id in key_ids]
self.gpg.encrypt(recipient, gpgme.ENCRYPT_ALWAYS_TRUST,
plaintext, ciphertext)
return ciphertext.getvalue()
def _user_key(self, email):
"""Returns the GPG key for the given email address"""
logging.info("Trying to encrypt for %s", email)
keys = [key for key in self.gpg.keylist(email)]
if keys:
key = keys.pop() # NOTE: looks like keys[0] is the master key
key_id = key.subkeys[0].keyid
return key_id
return None
def _add_zeyple_header(self, message):
if self.config.has_option('zeyple', 'add_header') and \
self.config.getboolean('zeyple', 'add_header'):
message.add_header(
'X-Zeyple',
"processed by {0} v{1}".format(__title__, __version__)
)
def _send_message(self, message, recipient):
"""Sends the given message through the SMTP relay"""
logging.info("Sending message %s", message['Message-id'])
smtp = smtplib.SMTP(self.config.get('relay', 'host'),
self.config.get('relay', 'port'))
smtp.sendmail(message['From'], recipient, message.as_string())
smtp.quit()
logging.info("Message %s sent", message['Message-id'])
if __name__ == '__main__':
recipients = sys.argv[1:]
# BBB: Python 2.7 support
binary_stdin = sys.stdin.buffer if PY3K else sys.stdin
message = binary_stdin.read()
zeyple = Zeyple()
zeyple.process_message(message, recipients)