From 19685591155f16878fd0d7460f763c3719a93476 Mon Sep 17 00:00:00 2001 From: harshadyeola Date: Mon, 1 Jun 2015 13:27:53 +0530 Subject: [PATCH] added mailstack and mailscanner stack --- ee/cli/plugins/mailscannerstack.py | 162 +++++++++++++++++++ ee/cli/plugins/mailstack.py | 248 +++++++++++++++++++++++++++++ 2 files changed, 410 insertions(+) create mode 100644 ee/cli/plugins/mailscannerstack.py create mode 100644 ee/cli/plugins/mailstack.py diff --git a/ee/cli/plugins/mailscannerstack.py b/ee/cli/plugins/mailscannerstack.py new file mode 100644 index 00000000..41d9c3e1 --- /dev/null +++ b/ee/cli/plugins/mailscannerstack.py @@ -0,0 +1,162 @@ +import os +import sys +import random +from ee.core.variables import EEVariables +from ee.core.aptget import EEAptGet +from ee.cli.plugins.eestack import EEStack +from ee.core.shellexec import EEShellExec +from ee.core.shellexec import CommandExecutionError +from ee.core.fileutils import EEFileUtils +from ee.core.git import EEGit +from ee.core.services import EEService +from ee.core.logging import Log +from ee.cli.main import app + + +class EEMailScannerStack(EEStack): + """ + EasyEngine MAILScanner stack + """ + packages_name = EEVariables.ee_mailscanner + app = app + log = app.log + + def __init__(self, packages_name=None): + """ + Initialize packages list in stack + pkgs_name : list of packages to be intialized for operations + in stack + """ + + self.packages_name = self._get_stack() + super(EEMailScannerStack, self).__init__(self.packages_name) + + def _get_stack(self): + return EEMailScannerStack.packages_name + + def _add_repo(self): + """ + Add repository for packages to be downloaded from + """ + self.log.info("Adding MAILScanner repository, please wait...") + + EEAptGet.update(self) + + def _pre_install_stack(self): + """ + Defines pre-install activities done before installing mail stack + """ + # Add mail repository + self._add_repo() + + + def _post_install_stack(self): + """ + Defines activities done after installing mail stack + """ + # Set up Custom amavis configuration + data = dict() + self.log.debug(self, "Configuring file /etc/amavis/conf.d" + "/15-content_filter_mode") + ee_amavis = open('/etc/amavis/conf.d/15-content_filter_mode', + encoding='utf-8', mode='w') + self.app.render((data), '15-content_filter_mode.mustache', + out=ee_amavis) + ee_amavis.close() + + # Amavis ViMbadmin configuration + if os.path.isfile("/etc/postfix/mysql/virtual_alias_maps.cf"): + vm_host = os.popen("grep hosts /etc/postfix/mysql/virtual_" + "alias_maps.cf | awk \'{ print $3 }\' |" + " tr -d '\\n'").read() + vm_pass = os.popen("grep password /etc/postfix/mysql/" + "virtual_alias_maps.cf | awk \'{ print " + "$3 }\' | tr -d '\\n'").read() + + data = dict(host=vm_host, password=vm_pass) + vm_config = open('/etc/amavis/conf.d/50-user', + encoding='utf-8', mode='w') + self.app.render((data), '50-user.mustache', out=vm_config) + vm_config.close() + + # Amavis postfix configuration + try: + EEShellExec.cmd_exec(self, "postconf -e \"content_filter =" + " smtp-amavis:[127.0.0.1]:10024\"") + EEShellExec.cmd_exec(self, "sed -i \"s/1 pickup/1 " + " pickup" + "\\n -o content_filter=\\n " + " -o receive_override_options=" + "no_header_body" + "_checks/\" /etc/postfix/master.cf") + except CommandExecutionError as e: + raise SiteError("Failed to update Amavis-Postfix config") + + amavis_master = ("""smtp-amavis unix - - n - 2 smtp +-o smtp_data_done_timeout=1200 +-o smtp_send_xforward_command=yes +-o disable_dns_lookups=yes +-o max_use=20 +127.0.0.1:10025 inet n - n - - smtpd +-o content_filter= +-o smtpd_delay_reject=no +-o smtpd_client_restrictions=permit_mynetworks,reject +-o smtpd_helo_restrictions= +-o smtpd_sender_restrictions= +-o smtpd_recipient_restrictions=permit_mynetworks,reject +-o smtpd_data_restrictions=reject_unauth_pipelining +-o smtpd_end_of_data_restrictions= +-o smtpd_restriction_classes= +-o mynetworks=127.0.0.0/8 +-o smtpd_error_sleep_time=0 +-o smtpd_soft_error_limit=1001 +-o smtpd_hard_error_limit=1000 +-o smtpd_client_connection_count_limit=0 +-o smtpd_client_connection_rate_limit=0 +-o local_header_rewrite_clients=""") + + with open("/etc/postfix/master.cf", + encoding='utf-8', mode='a') as am_config: + am_config.write(amavis_master) + + try: + # Amavis ClamAV configuration + self.log.debug(self, "Adding new user clamav amavis") + EEShellExec.cmd_exec(self, "adduser clamav amavis") + self.log.debug(self, "Adding new user amavis clamav") + EEShellExec.cmd_exec(self, "adduser amavis clamav") + self.log.debug(self, "Setting Privileges to /var/lib/amavis" + "/tmp") + EEFileUtils.chmod(self, "/var/lib/amavis/tmp", 0o755) + + # Update ClamAV database + self.log.debug(self, "Updating database") + EEShellExec.cmd_exec(self, "freshclam") + except CommandExecutionError as e: + raise SiteError(" Unable to update ClamAV-Amavis config") + + EEGit.add(self, ["/etc/amavis"], msg="Adding Amavis into Git") + EEService.restart_service(self, 'dovecot') + EEService.reload_service(self, 'postfix') + EEService.restart_service(self, 'amavis') + + + def install_stack(self): + """ + Install MAILScanner stack + """ + self.log.info("Installing MAILScanner stack, please wait...") + self._pre_install_stack() + super(EEMailScannerStack, self).install_stack() + self._post_install_stack() + + def remove_stack(self): + """ + Remove MAILScanner stack + """ + self.log.info("Removing MAILScanner stack, please wait...") + super(EEMailScannerStack, self).remove_stack() + + def purge_stack(self): + self.log.info("Purging MAILScanner stack, please wait...") + super(EEMailScannerStack, self).purge_stack() \ No newline at end of file diff --git a/ee/cli/plugins/mailstack.py b/ee/cli/plugins/mailstack.py new file mode 100644 index 00000000..c5aab4cc --- /dev/null +++ b/ee/cli/plugins/mailstack.py @@ -0,0 +1,248 @@ +import os +import sys +import random +from ee.core.variables import EEVariables +from ee.core.aptget import EEAptGet +from ee.cli.plugins.eestack import EEStack +from ee.core.shellexec import EEShellExec +from ee.core.shellexec import CommandExecutionError +from ee.core.fileutils import EEFileUtils +from ee.core.git import EEGit +from ee.core.services import EEService +from ee.core.logging import Log +from ee.cli.main import app + + +class EEMailStack(EEStack): + """ + EasyEngine MAIL stack + """ + packages_name = EEVariables.ee_mail + app = app + log = app.log + + def __init__(self, packages_name=None): + """ + Initialize packages list in stack + pkgs_name : list of packages to be intialized for operations + in stack + """ + + self.packages_name = self._get_stack() + super(EEMailStack, self).__init__(self.packages_name) + + def _get_stack(self): + return EEMailStack.packages_name + + def _add_repo(self): + """ + Add repository for packages to be downloaded from + """ + self.log.info("Adding MAIL repository, please wait...") + + EEAptGet.update(self) + + def _pre_install_stack(self): + """ + Defines pre-install activities done before installing mail stack + """ + # Add mail repository + self._add_repo() + + self.log.debug(self, 'Executing the command debconf-set-selections.') + try: + EEShellExec.cmd_exec(self, "echo \"dovecot-core dovecot-core/" + "create-ssl-cert boolean yes\" " + "| debconf-set-selections") + EEShellExec.cmd_exec(self, "echo \"dovecot-core dovecot-core" + "/ssl-cert-name string $(hostname -f)\"" + " | debconf-set-selections") + except CommandExecutionError as e: + self.log.error("Failed to initialize dovecot packages") + + def _post_install_stack(self): + """ + Defines activities done after installing mail stack + """ + self.log.debug(self, "Adding user") + try: + EEShellExec.cmd_exec(self, "adduser --uid 5000 --home /var" + "/vmail --disabled-password --gecos " + "'' vmail") + except CommandExecutionError as e: + self.log.error(self, "Unable to add vmail user for mail server") + try: + EEShellExec.cmd_exec(self, "openssl req -new -x509 -days" + " 3650 " + "-nodes -subj /commonName={hostname}" + "/emailAddress={email} -out /etc/ssl" + "/certs/dovecot." + "pem -keyout " + "/etc/ssl/private/dovecot.pem" + .format(hostname=EEVariables.ee_fqdn, + email=EEVariables.ee_email)) + except CommandExecutionError as e: + self.log.error(self, "Unable to generate PEM key for dovecot") + self.log.debug(self, "Setting Privileges to " + "/etc/ssl/private/dovecot.pem file ") + EEFileUtils.chmod(self, "/etc/ssl/private/dovecot.pem", 0o600) + + # Custom Dovecot configuration by EasyEngine + data = dict() + self.log.debug(self, "Writting configuration into file" + "/etc/dovecot/conf.d/auth-sql.conf.ext ") + ee_dovecot = open('/etc/dovecot/conf.d/auth-sql.conf.ext', + encoding='utf-8', mode='w') + app.render((data), 'auth-sql-conf.mustache', + out=ee_dovecot) + ee_dovecot.close() + + data = dict(email=EEVariables.ee_email) + self.log.debug(self, "Writting configuration into file" + "/etc/dovecot/conf.d/99-ee.conf ") + ee_dovecot = open('/etc/dovecot/conf.d/99-ee.conf', + encoding='utf-8', mode='w') + app.render((data), 'dovecot.mustache', out=ee_dovecot) + ee_dovecot.close() + try: + EEShellExec.cmd_exec(self, "sed -i \"s/\\!include " + "auth-system.conf.ext/#\\!include " + "auth-system.conf.ext/\" " + "/etc/dovecot/conf.d/10-auth.conf") + + EEShellExec.cmd_exec(self, "sed -i \"s\'/etc/dovecot/" + "dovecot.pem\'/etc/ssl/certs/" + "dovecot.pem" + "\'\" /etc/dovecot/conf.d/" + "10-ssl.conf") + EEShellExec.cmd_exec(self, "sed -i \"s\'/etc/dovecot/" + "private/dovecot.pem\'/etc/ssl/" + "private" + "/dovecot.pem\'\" /etc/dovecot/" + "conf.d/" + "10-ssl.conf") + + # Custom Postfix configuration needed with Dovecot + # Changes in master.cf + # TODO: Find alternative for sed in Python + EEShellExec.cmd_exec(self, "sed -i \'s/#submission/" + "submission/\'" + " /etc/postfix/master.cf") + EEShellExec.cmd_exec(self, "sed -i \'s/#smtps/smtps/\'" + " /etc/postfix/master.cf") + + EEShellExec.cmd_exec(self, "postconf -e \"smtpd_sasl_type " + "= dovecot\"") + EEShellExec.cmd_exec(self, "postconf -e \"smtpd_sasl_path " + "= private/auth\"") + EEShellExec.cmd_exec(self, "postconf -e \"" + "smtpd_sasl_auth_enable = " + "yes\"") + EEShellExec.cmd_exec(self, "postconf -e \"" + " smtpd_relay_restrictions =" + " permit_sasl_authenticated, " + " permit_mynetworks, " + " reject_unauth_destination\"") + + EEShellExec.cmd_exec(self, "postconf -e \"" + "smtpd_tls_mandatory_" + "protocols = !SSLv2,!SSLv3\"") + EEShellExec.cmd_exec(self, "postconf -e \"smtp_tls_" + "mandatory_protocols = !SSLv2," + "!SSLv3\"") + EEShellExec.cmd_exec(self, "postconf -e \"smtpd_tls" + "_protocols = !SSLv2,!SSLv3\"") + EEShellExec.cmd_exec(self, "postconf -e \"smtp_tls" + "_protocols = !SSLv2,!SSLv3\"") + EEShellExec.cmd_exec(self, "postconf -e \"mydestination " + "= localhost\"") + EEShellExec.cmd_exec(self, "postconf -e \"virtual" + "_transport " + "= lmtp:unix:private/dovecot-lmtp\"") + EEShellExec.cmd_exec(self, "postconf -e \"virtual_uid_" + "maps = static:5000\"") + EEShellExec.cmd_exec(self, "postconf -e \"virtual_gid_" + "maps = static:5000\"") + EEShellExec.cmd_exec(self, "postconf -e \"" + " virtual_mailbox_domains = " + "mysql:/etc/postfix/mysql/virtual_" + "domains_maps.cf\"") + EEShellExec.cmd_exec(self, "postconf -e \"virtual_mailbox" + "_maps" + " = mysql:/etc/postfix/mysql/virtual_" + "mailbox_maps.cf\"") + EEShellExec.cmd_exec(self, "postconf -e \"virtual_alias" + "_maps " + "= mysql:/etc/postfix/mysql/virtual_" + "alias_maps.cf\"") + EEShellExec.cmd_exec(self, "openssl req -new -x509 -days " + " 3650 -nodes -subj /commonName=" + "{hostname}/emailAddress={email}" + " -out /etc/ssl/certs/postfix.pem" + " -keyout /etc/ssl/private/" + "postfix.pem" + .format(hostname=EEVariables.ee_fqdn, + email=EEVariables.ee_email)) + EEShellExec.cmd_exec(self, "chmod 0600 /etc/ssl/private" + "/postfix.pem") + EEShellExec.cmd_exec(self, "postconf -e \"smtpd_tls_cert_" + "file = /etc/ssl/certs/postfix.pem\"") + EEShellExec.cmd_exec(self, "postconf -e \"smtpd_tls_key_" + "file = /etc/ssl/private/" + "postfix.pem\"") + + except CommandExecutionError as e: + self.log.error(self, "Failed to update Dovecot configuration") + + # Sieve configuration + if not os.path.exists('/var/lib/dovecot/sieve/'): + self.log.debug(self, 'Creating directory ' + '/var/lib/dovecot/sieve/ ') + os.makedirs('/var/lib/dovecot/sieve/') + + # Custom sieve configuration by EasyEngine + data = dict() + self.log.debug(self, "Writting configuration of EasyEngine into " + "file /var/lib/dovecot/sieve/default.sieve") + ee_sieve = open('/var/lib/dovecot/sieve/default.sieve', + encoding='utf-8', mode='w') + app.render((data), 'default-sieve.mustache', + out=ee_sieve) + ee_sieve.close() + + # Compile sieve rules + self.log.debug(self, "Setting Privileges to dovecot ") + # EEShellExec.cmd_exec(self, "chown -R vmail:vmail /var/lib" + # "/dovecot") + EEFileUtils.chown(self, "/var/lib/dovecot", 'vmail', 'vmail', + recursive=True) + try: + EEShellExec.cmd_exec(self, "sievec /var/lib/dovecot/" + "/sieve/default.sieve") + except CommandExecutionError as e: + raise SiteError("Failed to compile default.sieve") + + EEGit.add(self, ["/etc/postfix", "/etc/dovecot"], + msg="Installed mail server") + EEService.restart_service(self, 'dovecot') + EEService.reload_service(self, 'postfix') + + def install_stack(self): + """ + Install MAIL stack + """ + self.log.info("Installing MAIL stack, please wait...") + self._pre_install_stack() + super(EEMailStack, self).install_stack() + self._post_install_stack() + + def remove_stack(self): + """ + Remove MAIL stack + """ + self.log.info("Removing MAIL stack, please wait...") + super(EEMailStack, self).remove_stack() + + def purge_stack(self): + self.log.info("Purging MAIL stack, please wait...") + super(EEMailStack, self).purge_stack()