Page MenuHomePhorge

setup_mta.py
No OneTemporary

Authored By
Unknown
Size
22 KB
Referenced Files
None
Subscribers
None

setup_mta.py

# -*- coding: utf-8 -*-
# Copyright 2010-2013 Kolab Systems AG (http://www.kolabsys.com)
#
# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from augeas import Augeas
from Cheetah.Template import Template
import os
import shutil
import subprocess
from . import components
import pykolab
from pykolab import utils
from pykolab.constants import *
from pykolab.translate import _
log = pykolab.getLogger('pykolab.setup')
conf = pykolab.getConf()
def __init__():
components.register('mta', execute, description=description(), after=['ldap'])
def description():
return _("Setup MTA.")
def execute(*args, **kw):
group_filter = conf.get('ldap','kolab_group_filter')
if group_filter == None:
group_filter = conf.get('ldap','group_filter')
user_filter = conf.get('ldap','kolab_user_filter')
if user_filter == None:
user_filter = conf.get('ldap','user_filter')
resource_filter = conf.get('ldap', 'resource_filter')
sharedfolder_filter = conf.get('ldap', 'sharedfolder_filter')
server_host = utils.parse_ldap_uri(conf.get('ldap', 'ldap_uri'))[1]
files = {
"/etc/postfix/ldap/local_recipient_maps.cf": """
server_host = %(server_host)s
server_port = 389
version = 3
search_base = %(base_dn)s
scope = sub
domain = ldap:/etc/postfix/ldap/mydestination.cf
bind_dn = %(service_bind_dn)s
bind_pw = %(service_bind_pw)s
query_filter = (&(|(mail=%%s)(alias=%%s))(|%(kolab_user_filter)s%(kolab_group_filter)s%(resource_filter)s%(sharedfolder_filter)s))
result_attribute = mail
""" % {
"base_dn": conf.get('ldap', 'base_dn'),
"server_host": server_host,
"service_bind_dn": conf.get('ldap', 'service_bind_dn'),
"service_bind_pw": conf.get('ldap', 'service_bind_pw'),
"kolab_user_filter": user_filter,
"kolab_group_filter": group_filter,
"resource_filter": resource_filter,
"sharedfolder_filter": sharedfolder_filter,
},
"/etc/postfix/ldap/mydestination.cf": """
server_host = %(server_host)s
server_port = 389
version = 3
search_base = %(domain_base_dn)s
scope = sub
bind_dn = %(service_bind_dn)s
bind_pw = %(service_bind_pw)s
query_filter = %(domain_filter)s
result_attribute = %(domain_name_attribute)s
""" % {
"server_host": server_host,
"domain_base_dn": conf.get('ldap', 'domain_base_dn'),
"domain_filter": conf.get('ldap', 'domain_filter').replace('*', '%s'),
"domain_name_attribute": conf.get('ldap', 'domain_name_attribute'),
"service_bind_dn": conf.get('ldap', 'service_bind_dn'),
"service_bind_pw": conf.get('ldap', 'service_bind_pw'),
},
"/etc/postfix/ldap/mailenabled_distgroups.cf": """
server_host = %(server_host)s
server_port = 389
version = 3
search_base = %(group_base_dn)s
scope = sub
domain = ldap:/etc/postfix/ldap/mydestination.cf
bind_dn = %(service_bind_dn)s
bind_pw = %(service_bind_pw)s
# This finds the mail enabled distribution group LDAP entry
query_filter = (&(|(mail=%%s)(alias=%%s))(objectClass=kolabgroupofuniquenames)(objectclass=groupofuniquenames)(!(objectclass=groupofurls)))
# From this type of group, get all uniqueMember DNs
special_result_attribute = uniqueMember
# Only from those DNs, get the mail
result_attribute =
leaf_result_attribute = mail
""" % {
"server_host": server_host,
"group_base_dn": conf.get('ldap', 'group_base_dn'),
"service_bind_dn": conf.get('ldap', 'service_bind_dn'),
"service_bind_pw": conf.get('ldap', 'service_bind_pw'),
},
"/etc/postfix/ldap/mailenabled_dynamic_distgroups.cf": """
server_host = %(server_host)s
server_port = 389
version = 3
search_base = %(group_base_dn)s
scope = sub
domain = ldap:/etc/postfix/ldap/mydestination.cf
bind_dn = %(service_bind_dn)s
bind_pw = %(service_bind_pw)s
# This finds the mail enabled dynamic distribution group LDAP entry
query_filter = (&(|(mail=%%s)(alias=%%s))(objectClass=kolabgroupofuniquenames)(objectClass=groupOfURLs))
# From this type of group, get all memberURL searches/references
special_result_attribute = memberURL
# Only from those DNs, get the mail
result_attribute =
leaf_result_attribute = mail
""" % {
"server_host": server_host,
"group_base_dn": conf.get('ldap', 'group_base_dn'),
"service_bind_dn": conf.get('ldap', 'service_bind_dn'),
"service_bind_pw": conf.get('ldap', 'service_bind_pw'),
},
"/etc/postfix/ldap/transport_maps.cf": """
server_host = %(server_host)s
server_port = 389
version = 3
search_base = %(base_dn)s
scope = sub
domain = ldap:/etc/postfix/ldap/mydestination.cf
bind_dn = %(service_bind_dn)s
bind_pw = %(service_bind_pw)s
query_filter = (&(|(mailAlternateAddress=%%s)(alias=%%s)(mail=%%s))(objectclass=kolabinetorgperson))
result_attribute = mail
result_format = lmtp:unix:/var/lib/imap/socket/lmtp
""" % {
"base_dn": conf.get('ldap', 'base_dn'),
"server_host": server_host,
"service_bind_dn": conf.get('ldap', 'service_bind_dn'),
"service_bind_pw": conf.get('ldap', 'service_bind_pw'),
},
"/etc/postfix/ldap/virtual_alias_maps.cf": """
server_host = %(server_host)s
server_port = 389
version = 3
search_base = %(base_dn)s
scope = sub
domain = ldap:/etc/postfix/ldap/mydestination.cf
bind_dn = %(service_bind_dn)s
bind_pw = %(service_bind_pw)s
query_filter = (&(|(mail=%%s)(alias=%%s))(objectclass=kolabinetorgperson))
result_attribute = mail
""" % {
"base_dn": conf.get('ldap', 'base_dn'),
"server_host": server_host,
"service_bind_dn": conf.get('ldap', 'service_bind_dn'),
"service_bind_pw": conf.get('ldap', 'service_bind_pw'),
},
"/etc/postfix/ldap/virtual_alias_maps_mailforwarding.cf": """
server_host = %(server_host)s
server_port = 389
version = 3
search_base = %(base_dn)s
scope = sub
domain = ldap:/etc/postfix/ldap/mydestination.cf
bind_dn = %(service_bind_dn)s
bind_pw = %(service_bind_pw)s
query_filter = (&(|(mail=%%s)(alias=%%s))(objectclass=mailrecipient)(objectclass=inetorgperson)(mailforwardingaddress=*))
result_attribute = mailForwardingAddress
""" % {
"base_dn": conf.get('ldap', 'base_dn'),
"server_host": server_host,
"service_bind_dn": conf.get('ldap', 'service_bind_dn'),
"service_bind_pw": conf.get('ldap', 'service_bind_pw'),
},
"/etc/postfix/ldap/virtual_alias_maps_sharedfolders.cf": """
server_host = %(server_host)s
server_port = 389
version = 3
search_base = %(base_dn)s
scope = sub
domain = ldap:/etc/postfix/ldap/mydestination.cf
bind_dn = %(service_bind_dn)s
bind_pw = %(service_bind_pw)s
query_filter = (&(|(mail=%%s)(alias=%%s))(objectclass=kolabsharedfolder)(kolabFolderType=mail))
result_attribute = kolabtargetfolder
result_format = "shared+%%s"
""" % {
"base_dn": conf.get('ldap', 'base_dn'),
"server_host": server_host,
"service_bind_dn": conf.get('ldap', 'service_bind_dn'),
"service_bind_pw": conf.get('ldap', 'service_bind_pw'),
},
}
if not os.path.isfile('/etc/postfix/main.cf'):
if os.path.isfile('/usr/share/postfix/main.cf.debian'):
shutil.copy(
'/usr/share/postfix/main.cf.debian',
'/etc/postfix/main.cf'
)
if not os.path.isdir('/etc/postfix/ldap'):
os.mkdir('/etc/postfix/ldap/', 0o770)
for filename in files:
fp = open(filename, 'w')
fp.write(files[filename])
fp.close()
fp = open('/etc/postfix/transport', 'a')
fp.write("\n# Shared Folder Delivery for %(domain)s:\nshared@%(domain)s\t\tlmtp:unix:/var/lib/imap/socket/lmtp\n" % {'domain': conf.get('kolab', 'primary_domain')})
fp.close()
subprocess.call(["postmap", "/etc/postfix/transport"])
postfix_main_settings = {
"inet_interfaces": "all",
"recipient_delimiter": "+",
"local_recipient_maps": "ldap:/etc/postfix/ldap/local_recipient_maps.cf",
"mydestination": "ldap:/etc/postfix/ldap/mydestination.cf",
"transport_maps": "ldap:/etc/postfix/ldap/transport_maps.cf, hash:/etc/postfix/transport",
"virtual_alias_maps": "$alias_maps, ldap:/etc/postfix/ldap/virtual_alias_maps.cf, ldap:/etc/postfix/ldap/virtual_alias_maps_mailforwarding.cf, ldap:/etc/postfix/ldap/virtual_alias_maps_sharedfolders.cf, ldap:/etc/postfix/ldap/mailenabled_distgroups.cf, ldap:/etc/postfix/ldap/mailenabled_dynamic_distgroups.cf",
"smtpd_tls_auth_only": "yes",
"smtpd_tls_security_level": "may",
"smtp_tls_security_level": "may",
"smtpd_sasl_auth_enable": "yes",
"smtpd_sender_login_maps": "$local_recipient_maps",
"smtpd_data_restrictions": "permit_mynetworks, check_policy_service unix:private/recipient_policy_incoming",
"smtpd_recipient_restrictions": "permit_mynetworks, reject_unauth_pipelining, reject_rbl_client zen.spamhaus.org, reject_non_fqdn_recipient, reject_invalid_helo_hostname, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service unix:private/recipient_policy_incoming, permit",
"smtpd_sender_restrictions": "permit_mynetworks, reject_sender_login_mismatch, check_policy_service unix:private/sender_policy_incoming",
"submission_recipient_restrictions": "check_policy_service unix:private/submission_policy, permit_sasl_authenticated, reject",
"submission_sender_restrictions": "reject_non_fqdn_sender, check_policy_service unix:private/submission_policy, permit_sasl_authenticated, reject",
"submission_data_restrictions": "check_policy_service unix:private/submission_policy",
"content_filter": "smtp-amavis:[127.0.0.1]:10024"
}
if os.path.isfile('/etc/pki/tls/certs/make-dummy-cert') and not os.path.isfile('/etc/pki/tls/private/localhost.pem'):
subprocess.call(['/etc/pki/tls/certs/make-dummy-cert', '/etc/pki/tls/private/localhost.pem'])
if os.path.isfile('/etc/pki/tls/private/localhost.pem'):
postfix_main_settings['smtpd_tls_cert_file'] = "/etc/pki/tls/private/localhost.pem"
postfix_main_settings['smtpd_tls_key_file'] = "/etc/pki/tls/private/localhost.pem"
elif os.path.isfile('/etc/ssl/private/cyrus-imapd.pem'): # Debian 9
postfix_main_settings['smtpd_tls_cert_file'] = "/etc/ssl/private/cyrus-imapd.pem"
postfix_main_settings['smtpd_tls_key_file'] = "/etc/ssl/private/cyrus-imapd.pem"
# Copy header checks files
for hc_file in [ 'inbound', 'internal', 'submission' ]:
if not os.path.isfile("/etc/postfix/header_checks.%s" % (hc_file)):
if os.path.isfile('/etc/kolab/templates/header_checks.%s' % (hc_file)):
input_file = '/etc/kolab/templates/header_checks.%s' % (hc_file)
elif os.path.isfile('/usr/share/kolab/templates/header_checks.%s' % (hc_file)):
input_file = '/usr/share/kolab/templates/header_checks.%s' % (hc_file)
elif os.path.isfile(os.path.abspath(os.path.join(__file__, '..', '..', '..', 'share', 'templates', 'header_checks.%s' % (hc_file)))):
input_file = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'share', 'templates', 'header_checks.%s' % (hc_file)))
shutil.copy(input_file, "/etc/postfix/header_checks.%s" % (hc_file))
subprocess.call(["postmap", "/etc/postfix/header_checks.%s" % (hc_file)])
myaugeas = Augeas()
setting_base = '/files/etc/postfix/main.cf/'
for setting_key in postfix_main_settings:
setting = os.path.join(setting_base,setting_key)
current_value = myaugeas.get(setting)
if current_value == None:
try:
myaugeas.set(setting, postfix_main_settings[setting_key])
except:
insert_paths = myaugeas.match('/files/etc/postfix/main.cf/*')
insert_path = insert_paths[(len(insert_paths)-1)]
myaugeas.insert(insert_path, setting_key, False)
log.debug(_("Setting key %r to %r") % (setting_key, postfix_main_settings[setting_key]), level=8)
myaugeas.set(setting, postfix_main_settings[setting_key])
myaugeas.save()
postfix_master_settings = {
}
if os.path.exists('/usr/lib/postfix/kolab_smtp_access_policy'):
postfix_master_settings['kolab_sap_executable_path'] = '/usr/lib/postfix/kolab_smtp_access_policy'
else:
postfix_master_settings['kolab_sap_executable_path'] = '/usr/libexec/postfix/kolab_smtp_access_policy'
template_file = None
if os.path.isfile('/etc/kolab/templates/master.cf.tpl'):
template_file = '/etc/kolab/templates/master.cf.tpl'
elif os.path.isfile('/usr/share/kolab/templates/master.cf.tpl'):
template_file = '/usr/share/kolab/templates/master.cf.tpl'
elif os.path.isfile(os.path.abspath(os.path.join(__file__, '..', '..', '..', 'share', 'templates', 'master.cf.tpl'))):
template_file = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'share', 'templates', 'master.cf.tpl'))
if not template_file == None:
fp = open(template_file, 'r')
template_definition = fp.read()
fp.close()
t = Template(template_definition, searchList=[postfix_master_settings])
fp = open('/etc/postfix/master.cf', 'w')
fp.write(t.__str__())
fp.close()
else:
log.error(_("Could not write out Postfix configuration file /etc/postfix/master.cf"))
return
if os.path.isdir('/etc/postfix/sasl/'):
fp = open('/etc/postfix/sasl/smtpd.conf', 'w')
fp.write("pwcheck_method: saslauthd\n")
fp.write("mech_list: plain login\n")
fp.close()
amavisd_settings = {
'ldap_server': '%(server_host)s',
'ldap_bind_dn': conf.get('ldap', 'service_bind_dn'),
'ldap_bind_pw': conf.get('ldap', 'service_bind_pw'),
'primary_domain': conf.get('kolab', 'primary_domain'),
'ldap_filter': "(|(mail=%m)(alias=%m))",
'ldap_base_dn': conf.get('ldap', 'base_dn'),
'clamdsock': '/var/spool/amavisd/clamd.sock',
}
template_file = None
# On RPM installations, Amavis configuration is contained within a single file.
amavisconf_paths = [
"/etc/amavisd.conf",
"/etc/amavis/amavisd.conf",
"/etc/amavisd/amavisd.conf"
]
amavis_conf = ''
for amavisconf_path in amavisconf_paths:
if os.path.isfile(amavisconf_path):
amavis_conf = amavisconf_path
break
if os.path.isfile(amavis_conf):
if os.path.isfile('/etc/kolab/templates/amavisd.conf.tpl'):
template_file = '/etc/kolab/templates/amavisd.conf.tpl'
elif os.path.isfile('/usr/share/kolab/templates/amavisd.conf.tpl'):
template_file = '/usr/share/kolab/templates/amavisd.conf.tpl'
elif os.path.isfile(os.path.abspath(os.path.join(__file__, '..', '..', '..', 'share', 'templates', 'amavisd.conf.tpl'))):
template_file = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'share', 'templates', 'amavisd.conf.tpl'))
if not template_file == None:
fp = open(template_file, 'r')
template_definition = fp.read()
fp.close()
if os.path.isfile('/etc/clamd.d/amavisd.conf'):
amavisdconf_content = file('/etc/clamd.d/amavisd.conf')
for line in amavisdconf_content:
if line.startswith('LocalSocket'):
amavisd_settings['clamdsock'] = line[len('LocalSocket '):].strip()
t = Template(template_definition, searchList=[amavisd_settings])
fp = None
fp = open(amavis_conf, 'w')
if not fp == None:
fp.write(t.__str__())
fp.close()
else:
log.error(_("Could not write out Amavis configuration file amavisd.conf"))
return
# On APT installations, /etc/amavis/conf.d/ is a directory with many more files.
#
# Somebody could work on enhancement request #1080 to configure LDAP lookups,
# while really it isn't required.
else:
log.info(_("Not writing out any configuration for Amavis."))
# On debian wheezy amavisd-new expects '/etc/mailname' - possibly remediable through
# the #1080 enhancement mentioned above, but here's a quick fix.
f = open('/etc/mailname','w')
f.writelines(conf.get('kolab', 'primary_domain'))
f.close()
if os.path.isfile('/etc/default/spamassassin'):
myaugeas = Augeas()
setting = os.path.join('/files/etc/default/spamassassin','ENABLED')
if not myaugeas.get(setting) == '1':
myaugeas.set(setting,'1')
myaugeas.save()
myaugeas.close()
if os.path.isfile('/etc/default/wallace'):
myaugeas = Augeas()
setting = os.path.join('/files/etc/default/wallace','START')
if not myaugeas.get(setting) == 'yes':
myaugeas.set(setting,'yes')
myaugeas.save()
myaugeas.close()
if os.path.isfile('/usr/lib/systemd/system/clamd@.service'):
try:
from ConfigParser import SafeConfigParser
except ImportError:
from configparser import SafeConfigParser
unitfile = SafeConfigParser()
unitfile.optionxform = str
unitfile.read('/usr/lib/systemd/system/clamd@.service')
if not unitfile.has_section('Install'):
unitfile.add_section('Install')
if not unitfile.has_option('Install', 'WantedBy'):
unitfile.set('Install', 'WantedBy', 'multi-user.target')
with open('/etc/systemd/system/clamd@.service', 'wb') as f:
unitfile.write(f)
log.info(_("Configuring and refreshing Anti-Virus..."))
if os.path.isfile('/etc/kolab/templates/freshclam.conf.tpl'):
shutil.copy(
'/etc/kolab/templates/freshclam.conf.tpl',
'/etc/freshclam.conf'
)
elif os.path.isfile('/usr/share/kolab/templates/freshclam.conf.tpl'):
shutil.copy(
'/usr/share/kolab/templates/freshclam.conf.tpl',
'/etc/freshclam.conf'
)
else:
log.error(_("Could not find a ClamAV update configuration file"))
if os.path.isfile('/etc/freshclam.conf'):
subprocess.call([
'/usr/bin/freshclam',
'--quiet',
'--datadir="/var/lib/clamav"'
])
amavisservice = 'amavisd.service'
clamavservice = 'clamd@amavisd.service'
if os.path.isfile('/usr/lib/systemd/system/amavis.service'):
amavisservice = 'amavis.service'
if os.path.isfile('/lib/systemd/system/amavis.service'):
amavisservice = 'amavis.service'
if os.path.isfile('/etc/init.d/amavis'):
amavisservice = 'amavis.service'
if os.path.isfile('/usr/lib/systemd/system/clamd.service'):
clamavservice = 'clamd.service'
if os.path.isfile('/lib/systemd/system/clamd.service'):
clamavservice = 'clamd.service'
if os.path.isfile('/lib/systemd/system/clamav-daemon.service'):
clamavservice = 'clamav-daemon.service'
if os.path.isfile('/bin/systemctl'):
subprocess.call(['systemctl', 'restart', 'postfix.service'])
subprocess.call(['systemctl', 'restart', amavisservice])
subprocess.call(['systemctl', 'restart', clamavservice])
subprocess.call(['systemctl', 'restart', 'wallace.service'])
elif os.path.isfile('/sbin/service'):
subprocess.call(['service', 'postfix', 'restart'])
subprocess.call(['service', 'amavisd', 'restart'])
subprocess.call(['service', 'clamd.amavisd', 'restart'])
subprocess.call(['service', 'wallace', 'restart'])
elif os.path.isfile('/usr/sbin/service'):
subprocess.call(['/usr/sbin/service','postfix','restart'])
subprocess.call(['/usr/sbin/service','amavis','restart'])
subprocess.call(['/usr/sbin/service','clamav-daemon','restart'])
subprocess.call(['/usr/sbin/service','wallace','restart'])
else:
log.error(_("Could not start the postfix, clamav and amavisd services services."))
if os.path.isfile('/bin/systemctl'):
subprocess.call(['systemctl', 'enable', 'postfix.service'])
subprocess.call(['systemctl', 'enable', amavisservice])
subprocess.call(['systemctl', 'enable', clamavservice])
subprocess.call(['systemctl', 'enable', 'wallace.service'])
elif os.path.isfile('/sbin/chkconfig'):
subprocess.call(['chkconfig', 'postfix', 'on'])
subprocess.call(['chkconfig', 'amavisd', 'on'])
subprocess.call(['chkconfig', 'clamd.amavisd', 'on'])
subprocess.call(['chkconfig', 'wallace', 'on'])
elif os.path.isfile('/usr/sbin/update-rc.d'):
subprocess.call(['/usr/sbin/update-rc.d', 'postfix', 'defaults'])
subprocess.call(['/usr/sbin/update-rc.d', 'amavis', 'defaults'])
subprocess.call(['/usr/sbin/update-rc.d', 'clamav-daemon', 'defaults'])
subprocess.call(['/usr/sbin/update-rc.d', 'wallace', 'defaults'])
else:
log.error(_("Could not configure to start on boot, the " + \
"postfix, clamav and amavisd services."))

File Metadata

Mime Type
text/x-script.python
Expires
Mon, Apr 6, 1:48 AM (6 d, 12 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18831881
Default Alt Text
setup_mta.py (22 KB)

Event Timeline