def _daemonize(args): from slimta import system from gevent import sleep if args.daemon: system.redirect_stdio(args.logfile, args.errorfile) system.daemonize() sleep(0.1) system.drop_privileges(args.user, args.group)
def backmuncher(): "Run smtp that handle feedback loops, unsuscribes and more." import django django.setup() from django.conf import settings from slimta.edge.smtp import SmtpEdge from slimta.system import drop_privileges from slimta.util.proxyproto import ProxyProtocol from slimta.relay.blackhole import BlackholeRelay from munch.core.mail.backmuncher import Queue edge_class = SmtpEdge if settings.BACKMUNCHER.get('PROXYPROTO_ENABLED', False): class ProxyProtocolSmtpEdge(ProxyProtocol, SmtpEdge): pass edge_class = ProxyProtocolSmtpEdge edge = edge_class( (settings.BACKMUNCHER.get('SMTP_BIND_HOST'), settings.BACKMUNCHER.get('SMTP_BIND_PORT')), Queue(BlackholeRelay()), hostname=settings.BACKMUNCHER.get('EDGE_EHLO_AS', None), tls=False, ) log.info('Listening on {}:{}'.format( settings.BACKMUNCHER.get('SMTP_BIND_HOST'), settings.BACKMUNCHER.get('SMTP_BIND_PORT'))) edge.start() if settings.BACKMUNCHER.get('DROP_PRIVILEGES_USER') is not None: # If this command is run with root user (to be allowed to # open reserved ports like 25), we should then "switch" to a # normal user for security. drop_privileges(settings.BACKMUNCHER.get('DROP_PRIVILEGES_USER'), settings.BACKMUNCHER.get('DROP_PRIVILEGES_GROUP')) log.info('Dropping privileges to {}:{}'.format( settings.BACKMUNCHER.get('DROP_PRIVILEGES_USER'), settings.BACKMUNCHER.get('DROP_PRIVILEGES_GROUP'))) try: edge.get() except KeyboardInterrupt: try: edge.server.close() log.info('Stop accepting connections.') log.info('Edge stopped...') edge.server.stop(timeout=1) except KeyboardInterrupt: log.info('Forcing shutdown...') edge.server.stop(timeout=1)
def smtp(): "Run smtp smarthost for transactional service." from gevent import monkey # Do not patch threads, it may lead to Django DatabaseWrapper being # shared between threads. # See: https://code.djangoproject.com/ticket/17998#comment:6 monkey.patch_all(thread=False) import os import sys os.environ.setdefault("DJANGO_SETTINGS_MODULE", "munch.settings") from psycogreen.gevent import patch_psycopg patch_psycopg() sys.path.append( os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) import django django.setup() import time from django.conf import settings from gevent import sleep from gevent.pool import Pool from slimta.system import drop_privileges from munch.core.utils import monkey_patch_slimta_exception from munch.apps.transactional.queue import queue from munch.apps.transactional.edge import ( TransactionalSmtpEdge, ProxyProtocolTransactionalSmtpEdge) from munch.apps.transactional.edge import EdgeValidators monkey_patch_slimta_exception() tls_settings = settings.TRANSACTIONAL.get('SMTP_SMARTHOST_TLS') if tls_settings is not None: if not isinstance(tls_settings, dict): raise Exception( ('Setting SMTP_SMARTHOST_TLS should be a dict with ' '"keyfile" and "certfile" keys')) for i in ('keyfile', 'certfile'): if i not in tls_settings: raise Exception( '{} is required if you plan to offer STARTTLS support') else: path = tls_settings[i] if not os.access(path, os.R_OK): raise Exception( '{} is not readable or inexistant.'.format(path)) ssl_context = SSLContext(PROTOCOL_SSLv23) ssl_context.load_cert_chain(tls_settings.get('certfile'), keyfile=tls_settings.get('keyfile')) else: ssl_context = None pool = Pool(settings.TRANSACTIONAL.get('EDGE_MAX_CONN', 200)) edge_class = TransactionalSmtpEdge if settings.TRANSACTIONAL.get('PROXYPROTO_ENABLED', False): edge_class = ProxyProtocolTransactionalSmtpEdge edge = edge_class( (settings.TRANSACTIONAL.get('SMTP_BIND_HOST'), settings.TRANSACTIONAL.get('SMTP_BIND_PORT')), queue, data_timeout=settings.TRANSACTIONAL.get('EDGE_TIMEOUTS', {}).get('data_timeout'), command_timeout=settings.TRANSACTIONAL.get('EDGE_TIMEOUTS', {}).get('command_timeout'), pool=pool, hostname=settings.TRANSACTIONAL.get('EDGE_EHLO_AS', None), validator_class=EdgeValidators, context=ssl_context, auth=True, ) log.info('Listening on {}:{}'.format( settings.TRANSACTIONAL.get('SMTP_BIND_HOST'), settings.TRANSACTIONAL.get('SMTP_BIND_PORT'))) edge.start() if settings.TRANSACTIONAL.get('DROP_PRIVILEGES_USER') is not None: # ??? Really needed? See python-slimta/examples/slimta-mail.py... sleep(0.1) # If this command is run with root user (to be allowed to # open reserved ports like 25), we should then "switch" to a # normal user for security. drop_privileges(settings.TRANSACTIONAL.get('DROP_PRIVILEGES_USER'), settings.TRANSACTIONAL.get('DROP_PRIVILEGES_GROUP')) log.info('Dropping privileges to {}:{}'.format( settings.TRANSACTIONAL.get('DROP_PRIVILEGES_USER'), settings.TRANSACTIONAL.get('DROP_PRIVILEGES_GROUP'))) try: edge.get() except KeyboardInterrupt: try: stop_timeout = settings.TRANSACTIONAL.get('SMTP_STOP_TIMEOUT', 5) edge.server.close() ts = time.time() log.info('Stop accepting connections.') if stop_timeout > 0: log.info('Waiting {} seconds before timing out ' 'current connections...'.format(stop_timeout)) while time.time() - ts <= stop_timeout: sleep(1.0) log.info('Edge stopped...') edge.server.stop(timeout=1) except KeyboardInterrupt: log.info('Forcing shutdown...') edge.server.stop(timeout=1)