def run(self): if self.gate.restricted: self.demote('nobody') else: if self.gate.initial_identity: AuthenticationService.get(self.context).login( self.gate.initial_identity, demote=True) try: socket_namespaces = {} while True: rq = self.stream.recv() if not rq: return if rq.object['type'] == 'http': gevent.spawn(self.handle_http_request, rq) if rq.object['type'] == 'socket': msg = rq.object['message'] nsid = rq.object['namespace'] event = rq.object['event'] if event == 'connect': socket_namespaces[nsid] = WorkerSocketNamespace( self.context, nsid) socket_namespaces[nsid].process_event(event, msg) if event == 'disconnect': socket_namespaces[nsid].destroy() logging.debug( 'Socket disconnected, destroying endpoints') # pylint: disable=W0703 except Exception: logging.error('Worker crashed!') traceback.print_exc()
def handle_api_identity(self, http_context): """ Collect user and server informations from authentication service and ajenti config file. :param http_context: HttpContext :type http_context: HttpContext :return: User and server informations and profil. :rtype: dict """ return { 'identity': { 'user': AuthenticationService.get(self.context).get_identity(), 'uid': os.getuid(), 'effective': os.geteuid(), 'elevation_allowed': aj.config.data['auth'].get('allow_sudo', False), 'profile': AuthenticationService.get( self.context).get_provider().get_profile( AuthenticationService.get( self.context).get_identity()), }, 'machine': { 'name': aj.config.data['name'], 'hostname': socket.gethostname(), }, 'color': aj.config.data.get('color', None), }
def handle_api_logout(self, http_context): """ Logout by closing associated worker. :param http_context: HttpContext :type http_context: HttpContext """ AuthenticationService.get(self.context).get_provider().signout() self.context.worker.terminate()
def run(self): if self.gate.restricted: restricted_user = aj.config.data['restricted_user'] self.demote(pwd.getpwnam(restricted_user).pw_uid) else: if self.gate.initial_identity: AuthenticationService.get(self.context).login( self.gate.initial_identity, demote=True) try: socket_namespaces = {} while True: rq = self.stream.recv() if not rq: return if rq.object['type'] == 'http': gevent.spawn(self.handle_http_request, rq) if rq.object['type'] == 'socket': msg = rq.object['message'] nsid = rq.object['namespace'] event = rq.object['event'] if event == 'connect': socket_namespaces[nsid] = WorkerSocketNamespace( self.context, nsid) socket_namespaces[nsid].process_event(event, msg) if event == 'disconnect': socket_namespaces[nsid].destroy() logging.debug( 'Socket disconnected, destroying endpoints') if rq.object['type'] == 'config-data': logging.debug('Received a config update') aj.config.data = rq.object['data']['config'] aj.users.data = rq.object['data']['users'] self._master_config_reloaded.set() if rq.object['type'] == 'session-list': logging.debug('Received a session list update') aj.sessions = rq.object['data'] # pylint: disable=W0703 except Exception: logging.error('Worker crashed!') traceback.print_exc()
def update_password(self, http_context): """ Update user's password in the auth provider. :param http_context: HttpContext :type http_context: HttpContext """ serial = json.loads(http_context.body.decode())['serial'] password = json.loads(http_context.body.decode())['password'] if serial and password: with open(SECRET_FILE, 'r') as f: secret = f.read().strip('\n') serializer = URLSafeTimedSerializer(secret) user = serializer.loads(serial, max_age=900)['user'] auth_provider = AuthenticationService.get( self.context).get_provider() answer = auth_provider.update_password(user, password) if not answer: http_context.respond_forbidden() return [b'403 Forbidden'] else: http_context.respond_ok() return [b'200 OK']
def handle_api_auth(self, http_context): """ Test user authentication to login or to elevate privileges. :param http_context: HttpContext :type http_context: HttpContext :return: Success status and username :rtype: dict """ body_data = json.loads(http_context.body.decode()) mode = body_data['mode'] username = body_data.get('username', None) password = body_data.get('password', None) auth = AuthenticationService.get(self.context) if mode == 'normal': auth_info = auth.check_password(username, password) if auth_info: auth.prepare_session_redirect(http_context, username, auth_info) return { 'success': True, 'username': username, } gevent.sleep(3) return { 'success': False, 'error': None, } elif mode == 'sudo': target = 'root' try: if auth.check_sudo_password(username, password): self.context.worker.terminate() auth.prepare_session_redirect(http_context, target, None) return { 'success': True, 'username': target, } gevent.sleep(3) return { 'success': False, 'error': _('Authorization failed'), } except SudoError as e: gevent.sleep(3) return { 'success': False, 'error': e.message, } return { 'success': False, 'error': 'Invalid mode', }
def handle_api_change_password(self, http_context): provider = AuthenticationService.get(self.context).get_provider() try: provider.change_password(self.context.identity, http_context.json_body()['password'], http_context.json_body()['new_password']) except Exception as e: raise EndpointError(None, str(e))
def run(self): if self.gate.restricted: restricted_user = aj.config.data['restricted_user'] self.demote(pwd.getpwnam(restricted_user).pw_uid) else: if self.gate.initial_identity: AuthenticationService.get(self.context).login( self.gate.initial_identity, demote=True ) try: socket_namespaces = {} while True: rq = self.stream.recv() if not rq: return if rq.object['type'] == 'http': gevent.spawn(self.handle_http_request, rq) if rq.object['type'] == 'socket': msg = rq.object['message'] nsid = rq.object['namespace'] event = rq.object['event'] if event == 'connect': socket_namespaces[nsid] = WorkerSocketNamespace( self.context, nsid ) socket_namespaces[nsid].process_event(event, msg) if event == 'disconnect': socket_namespaces[nsid].destroy() logging.debug('Socket disconnected, destroying endpoints') if rq.object['type'] == 'config-data': logging.debug('Received a config update') aj.config.data = rq.object['data'] self._master_config_reloaded.set() # pylint: disable=W0703 except Exception: logging.error('Worker crashed!') traceback.print_exc()
def handle_api_identity(self, http_context): return { 'identity': { 'user': AuthenticationService.get(self.context).get_identity(), 'uid': os.getuid(), 'effective': os.geteuid(), 'elevation_allowed': aj.config.data['auth'].get('allow_sudo', False), 'profile': AuthenticationService.get(self.context).get_provider().get_profile( AuthenticationService.get(self.context).get_identity() ), }, 'machine': { 'name': aj.config.data['name'], 'hostname': socket.gethostname(), }, 'color': aj.config.data.get('color', None), }
def handle_api_change_password(self, http_context): provider = AuthenticationService.get(self.context).get_provider() try: provider.change_password( self.context.identity, http_context.json_body()['password'], http_context.json_body()['new_password'] ) except Exception as e: raise EndpointError(None, str(e))
def run(self): if self.gate.restricted: restricted_user = aj.config.data["restricted_user"] self.demote(pwd.getpwnam(restricted_user).pw_uid) else: if self.gate.initial_identity: AuthenticationService.get(self.context).login(self.gate.initial_identity, demote=True) try: socket_namespaces = {} while True: rq = self.stream.recv() if not rq: return if rq.object["type"] == "http": gevent.spawn(self.handle_http_request, rq) if rq.object["type"] == "socket": msg = rq.object["message"] nsid = rq.object["namespace"] event = rq.object["event"] if event == "connect": socket_namespaces[nsid] = WorkerSocketNamespace(self.context, nsid) socket_namespaces[nsid].process_event(event, msg) if event == "disconnect": socket_namespaces[nsid].destroy() logging.debug("Socket disconnected, destroying endpoints") if rq.object["type"] == "config-data": logging.debug("Received a config update") aj.config.data = rq.object["data"] self._master_config_reloaded.set() # pylint: disable=W0703 except Exception: logging.error("Worker crashed!") traceback.print_exc()
def handle_api_identity(self, http_context): return { 'identity': { 'user': AuthenticationService.get(self.context).get_identity(), 'effective': os.geteuid(), }, 'machine': { 'name': aj.config.data['name'], 'hostname': socket.gethostname(), }, 'color': aj.config.data['color'], }
def handle_api_check_password_complexity(self, http_context): """ Check the password complexity requirements from the auth provider before saving a new password for the password reset functionality. :param http_context: HttpContext :type http_context: HttpContext :return: Error if test failed :rtype: basestring """ password = http_context.json_body()['password'] return AuthenticationService.get(self.context).get_provider().check_password_complexity(password)
def handle_api_auth(self, http_context): body_data = json.loads(http_context.body) mode = body_data['mode'] username = body_data.get('username', None) password = body_data.get('password', None) auth = AuthenticationService.get(self.context) if mode == 'normal': auth_info = auth.check_password(username, password) if auth_info: auth.prepare_session_redirect(http_context, username, auth_info) return { 'success': True, 'username': username, } else: gevent.sleep(3) return { 'success': False, 'error': None, } elif mode == 'sudo': target = 'root' try: if auth.check_sudo_password(username, password): auth.prepare_session_redirect(http_context, target, None) return { 'success': True, 'username': target, } else: gevent.sleep(3) return { 'success': False, 'error': _('Authorization failed'), } except SudoError as e: gevent.sleep(3) return { 'success': False, 'error': e.message, } return { 'success': False, 'error': 'Invalid mode', }
def load(self): if self.user == 'root': self.data = yaml.load(open('/root/.config/ajenti.yml'), Loader=yaml.Loader) else: ## Load ldap attribute webuidashboard userAttrs = AuthenticationService.get( self.context).get_provider()._get_ldap_user( self.user, context="userconfig") try: self.data = json.loads(userAttrs['sophomorixWebuiDashboard']) except Exception as e: logging.warning( 'Error retrieving userconfig from %s, value: %s. This will be overwritten', self.user, userAttrs['sophomorixWebuiDashboard']) self.data = {}
def handle_api_auth_providers(self, http_context): """ Load all authentication methods. :param http_context: HttpContext :type http_context: HttpContext :return: List of authenticator, one per dict :rtype: list of dict """ r = [] auth_service_id = AuthenticationService.get( self.context).get_provider().id for p in AuthenticationProvider.all(self.context): r.append({ 'id': p.id, 'name': p.name, 'used': True if p.id == auth_service_id else False, }) return r
def __init__(self, context): self.context = context self.auth_provider = AuthenticationService.get( self.context).get_provider() self.notifications = Mail() self.ensure_secret_key()
def handle_api_auth(self, http_context): body_data = json.loads(http_context.body) mode = body_data['mode'] username = body_data.get('username', None) password = body_data.get('password', None) auth = AuthenticationService.get(self.context) if mode == 'normal': if auth.check_password(username, password): auth.prepare_session_redirect(http_context, username) return { 'success': True, 'username': username, } else: gevent.sleep(3) return { 'success': False, 'error': None, } elif mode == 'sudo': target = 'root' try: auth.check_sudo_password(username, password) auth.prepare_session_redirect(http_context, target) return { 'success': True, 'username': target, } except SudoError as e: gevent.sleep(3) return { 'success': False, 'error': e.message, } elif mode == 'persona': assertion = body_data.get('assertion', None) audience = body_data.get('audience', None) if not assertion or not audience: return { 'success': False, 'error': 'Invalid params', } try: email = auth.check_persona_assertion(assertion, audience) except Exception as e: traceback.print_exc() return { 'success': False, 'error': 'Could not authenticate with Mozilla Persona: %s' % str(e), } emails = aj.config.data.get('emails', {}) if email in emails: username = emails[email] auth.prepare_session_redirect(http_context, username) return { 'success': True, 'username': username, } else: return { 'success': False, 'error': 'Unrecognized e-mail', } return { 'success': False, 'error': 'Invalid mode', }
def handle_api_auth(self, http_context): body_data = json.loads(http_context.body) mode = body_data['mode'] username = body_data.get('username', None) password = body_data.get('password', None) auth = AuthenticationService.get(self.context) if mode == 'normal': if auth.check_password(username, password): auth.prepare_session_redirect(http_context, username) return { 'success': True, 'username': username, } else: gevent.sleep(3) return { 'success': False, 'error': None, } elif mode == 'sudo': target = 'root' try: if auth.check_sudo_password(username, password): auth.prepare_session_redirect(http_context, target) return { 'success': True, 'username': target, } else: gevent.sleep(3) return { 'success': False, 'error': _('Authorization failed'), } except SudoError as e: gevent.sleep(3) return { 'success': False, 'error': e.message, } elif mode == 'persona': assertion = body_data.get('assertion', None) audience = body_data.get('audience', None) if not assertion or not audience: return { 'success': False, 'error': 'Invalid params', } try: email = auth.check_persona_assertion(assertion, audience) except Exception as e: traceback.print_exc() return { 'success': False, 'error': _('Could not authenticate with Mozilla Persona: %s') % str(e), } emails = aj.config.data['auth']['emails'] if email in emails: username = emails[email] auth.prepare_session_redirect(http_context, username) return { 'success': True, 'username': username, } else: return { 'success': False, 'error': _('Unrecognized e-mail'), } return { 'success': False, 'error': 'Invalid mode', }
def run(config=None, plugin_providers=None, product_name='ajenti', dev_mode=False, debug_mode=False, autologin=False): """ A global entry point for Ajenti. :param config: config file implementation instance to use :type config: :class:`aj.config.BaseConfig` :param plugin_providers: list of plugin providers to load plugins from :type plugin_providers: list(:class:`aj.plugins.PluginProvider`) :param str product_name: a product name to use :param bool dev_mode: enables dev mode (automatic resource recompilation) :param bool debug_mode: enables debug mode (verbose and extra logging) :param bool autologin: disables authentication and logs everyone in as the user running the panel. This is EXTREMELY INSECURE. """ if config is None: raise TypeError('`config` can\'t be None') reload(sys) sys.setdefaultencoding('utf8') aj.product = product_name aj.debug = debug_mode aj.dev = dev_mode aj.dev_autologin = autologin aj.init() aj.log.set_log_params(tag='master', master_pid=os.getpid()) aj.context = Context() aj.config = config aj.plugin_providers = plugin_providers or [] logging.info('Loading config from %s', aj.config) aj.config.load() aj.config.ensure_structure() if aj.debug: logging.warn('Debug mode') if aj.dev: logging.warn('Dev mode') try: locale.setlocale(locale.LC_ALL, '') except locale.Error: logging.warning('Couldn\'t set default locale') # install a passthrough gettext replacement since all localization is handled in frontend # and _() is here only for string extraction __builtins__['_'] = lambda x: x logging.info('Ajenti Core %s', aj.version) logging.info('Detected platform: %s / %s', aj.platform, aj.platform_string) # Load plugins PluginManager.get(aj.context).load_all_from(aj.plugin_providers) if len(PluginManager.get(aj.context)) == 0: logging.warn('No plugins were loaded!') if aj.config.data['bind']['mode'] == 'unix': path = aj.config.data['bind']['socket'] if os.path.exists(path): os.unlink(path) listener = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: listener.bind(path) except OSError: logging.error('Could not bind to %s', path) sys.exit(1) if aj.config.data['bind']['mode'] == 'tcp': host = aj.config.data['bind']['host'] port = aj.config.data['bind']['port'] listener = socket.socket( socket.AF_INET6 if ':' in host else socket.AF_INET, socket.SOCK_STREAM ) if aj.platform not in ['freebsd', 'osx']: try: listener.setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 1) except socket.error: logging.warn('Could not set TCP_CORK') listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) logging.info('Binding to [%s]:%s', host, port) try: listener.bind((host, port)) except socket.error as e: logging.error('Could not bind: %s', str(e)) sys.exit(1) # Fix stupid socketio bug (it tries to do *args[0][0]) socket.socket.__getitem__ = lambda x, y: None listener.listen(10) gateway = GateMiddleware.get(aj.context) application = HttpRoot(HttpMiddlewareAggregator([gateway])).dispatch aj.server = SocketIOServer( listener, log=open(os.devnull, 'w'), application=application, handler_class=RequestHandler, policy_server=False, transports=[ str('websocket'), str('flashsocket'), str('xhr-polling'), str('jsonp-polling'), ], ) if aj.config.data['ssl']['enable'] and aj.config.data['bind']['mode'] == 'tcp': try: context = SSL.Context(SSL.TLSv1_2_METHOD) except: context = SSL.Context(SSL.TLSv1_METHOD) context.set_session_id(str(id(context))) context.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3) context.set_cipher_list('ALL:!ADH:!EXP:!LOW:!RC2:!3DES:!SEED:!RC4:+HIGH:+MEDIUM') certificate = crypto.load_certificate( crypto.FILETYPE_PEM, open(aj.config.data['ssl']['certificate']).read() ) private_key = crypto.load_privatekey( crypto.FILETYPE_PEM, open(aj.config.data['ssl']['certificate']).read() ) context.use_certificate(certificate) context.use_privatekey(private_key) if aj.config.data['ssl']['client_auth']['enable']: # todo harden files logging.info('Enabling SSL client authentication') context.add_client_ca(certificate) context.get_cert_store().add_cert(certificate) verify_flags = SSL.VERIFY_PEER if aj.config.data['ssl']['client_auth']['force']: verify_flags |= SSL.VERIFY_FAIL_IF_NO_PEER_CERT context.set_verify(verify_flags, AuthenticationService.get(aj.context).client_certificate_callback) context.set_verify_depth(0) aj.server.ssl_args = {'server_side': True} aj.server.wrap_socket = lambda socket, **ssl: SSLSocket(context, socket) logging.info('SSL enabled') # auth.log try: syslog.openlog( ident=str(aj.product), facility=syslog.LOG_AUTH, ) except: syslog.openlog(aj.product) def cleanup(): if hasattr(cleanup, 'started'): return cleanup.started = True logging.info('Process %s exiting normally', os.getpid()) gevent.signal(signal.SIGINT, lambda: None) gevent.signal(signal.SIGTERM, lambda: None) if aj.master: gateway.destroy() p = psutil.Process(os.getpid()) for c in p.children(recursive=True): try: os.killpg(c.pid, signal.SIGTERM) os.killpg(c.pid, signal.SIGKILL) except OSError: pass def signal_handler(): cleanup() sys.exit(0) gevent.signal(signal.SIGINT, signal_handler) gevent.signal(signal.SIGTERM, signal_handler) aj.server.serve_forever() if not aj.master: # child process, server is stopped, wait until killed gevent.wait() if hasattr(aj.server, 'restart_marker'): logging.warn('Restarting by request') cleanup() fd = 20 # Close all descriptors. Creepy thing while fd > 2: try: os.close(fd) logging.debug('Closed descriptor #%i', fd) except OSError: pass fd -= 1 logging.warn('Will restart the process now') if '-d' in sys.argv: sys.argv.remove('-d') os.execv(sys.argv[0], sys.argv) else: if aj.master: logging.debug('Server stopped') cleanup()
def handle_api_auth(self, http_context): """ Test user authentication to login or to elevate privileges. :param http_context: HttpContext :type http_context: HttpContext :return: Success status and username :rtype: dict """ body_data = json.loads(http_context.body.decode()) mode = body_data['mode'] username = body_data.get('username', None) password = body_data.get('password', None) auth = AuthenticationService.get(self.context) if mode == 'normal': auth_info = auth.check_password(username, password) if auth_info: auth.prepare_session_redirect(http_context, username, auth_info) return { 'success': True, 'username': username, } # Log failed login for e.g. fail2ban remote_addr = http_context.env.get('REMOTE_ADDR', None) if len(aj.config.data['trusted_proxies']) > 0: if remote_addr in aj.config.data['trusted_proxies']: ip = http_context.env.get('HTTP_X_FORWARDED_FOR', '').split(',')[0] else: ip = remote_addr logging.warning(f"Failed login from {username} at IP : {ip}") gevent.sleep(3) return { 'success': False, 'error': None, } elif mode == 'sudo': target = 'root' try: if auth.check_sudo_password(username, password): self.context.worker.terminate() auth.prepare_session_redirect(http_context, target, None) return { 'success': True, 'username': target, } gevent.sleep(3) return { 'success': False, 'error': _('Authorization failed'), } except SudoError as e: gevent.sleep(3) return { 'success': False, 'error': e.message, } return { 'success': False, 'error': 'Invalid mode', }
def run(config=None, plugin_providers=None, product_name='ajenti', dev_mode=False, debug_mode=False, autologin=False): """ A global entry point for Ajenti. :param config: config file implementation instance to use :type config: :class:`aj.config.BaseConfig` :param plugin_providers: list of plugin providers to load plugins from :type plugin_providers: list(:class:`aj.plugins.PluginProvider`) :param product_name: a product name to use :param dev_mode: enables dev mode (automatic resource recompilation) :type dev_mode: bool :param debug_mode: enables debug mode (verbose and extra logging) :type debug_mode: bool :param autologin: disables authentication and logs everyone in as the user running the panel. This is EXTREMELY INSECURE. :type autologin: bool """ if config is None: raise TypeError('`config` can\'t be None') reload(sys) sys.setdefaultencoding('utf8') aj.product = product_name aj.debug = debug_mode aj.dev = dev_mode aj.dev_autologin = autologin aj.init() aj.log.set_log_params(tag='master', master_pid=os.getpid()) aj.context = Context() aj.config = config aj.plugin_providers = plugin_providers or [] logging.info('Loading config from %s', aj.config) aj.config.load() if aj.debug: logging.warn('Debug mode') if aj.dev: logging.warn('Dev mode') try: locale.setlocale(locale.LC_ALL, '') except locale.Error: logging.warning('Couldn\'t set default locale') logging.info('Ajenti Core %s', aj.version) logging.info('Detected platform: %s / %s', aj.platform, aj.platform_string) # Load plugins PluginManager.get(aj.context).load_all_from(aj.plugin_providers) if len(PluginManager.get(aj.context).get_all()) == 0: logging.warn('No plugins were loaded!') if aj.config.data['bind']['mode'] == 'unix': path = aj.config.data['bind']['socket'] if os.path.exists(path): os.unlink(path) listener = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: listener.bind(path) except OSError: logging.error('Could not bind to %s', path) sys.exit(1) if aj.config.data['bind']['mode'] == 'tcp': host = aj.config.data['bind']['host'] port = aj.config.data['bind']['port'] listener = socket.socket( socket.AF_INET6 if ':' in host else socket.AF_INET, socket.SOCK_STREAM ) if aj.platform not in ['freebsd', 'osx']: try: listener.setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 1) except socket.error: logging.warn('Could not set TCP_CORK') listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) logging.info('Binding to [%s]:%s', host, port) try: listener.bind((host, port)) except socket.error as e: logging.error('Could not bind: %s', str(e)) sys.exit(1) # Fix stupid socketio bug (it tries to do *args[0][0]) socket.socket.__getitem__ = lambda x, y: None listener.listen(10) gateway = GateMiddleware.get(aj.context) application = HttpRoot(HttpMiddlewareAggregator([gateway])).dispatch aj.server = SocketIOServer( listener, log=open(os.devnull, 'w'), application=application, handler_class=RequestHandler, policy_server=False, transports=[ str('websocket'), str('flashsocket'), str('xhr-polling'), str('jsonp-polling'), ], ) if aj.config.data['ssl']['enable'] and aj.config.data['bind']['mode'] == 'tcp': try: context = SSL.Context(SSL.TLSv1_2_METHOD) except: context = SSL.Context(SSL.TLSv1_METHOD) context.set_session_id(str(id(context))) context.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3) context.set_cipher_list('ALL:!ADH:!EXP:!LOW:!RC2:!3DES:!SEED:!RC4:+HIGH:+MEDIUM') certificate = crypto.load_certificate( crypto.FILETYPE_PEM, open(aj.config.data['ssl']['certificate']).read() ) private_key = crypto.load_privatekey( crypto.FILETYPE_PEM, open(aj.config.data['ssl']['certificate']).read() ) context.use_certificate(certificate) context.use_privatekey(private_key) if aj.config.data['ssl']['client_auth']['enable']: # todo harden files logging.info('Enabling SSL client authentication') context.add_client_ca(certificate) context.get_cert_store().add_cert(certificate) verify_flags = SSL.VERIFY_PEER if aj.config.data['ssl']['client_auth']['force']: verify_flags |= SSL.VERIFY_FAIL_IF_NO_PEER_CERT context.set_verify(verify_flags, AuthenticationService.get(aj.context).client_certificate_callback) context.set_verify_depth(0) aj.server.ssl_args = {'server_side': True} aj.server.wrap_socket = lambda socket, **ssl: SSLSocket(context, socket) logging.info('SSL enabled') # auth.log try: syslog.openlog( ident=str(aj.product), facility=syslog.LOG_AUTH, ) except: syslog.openlog(aj.product) def cleanup(): if hasattr(cleanup, 'started'): return cleanup.started = True logging.info('Process %s exiting normally', os.getpid()) gevent.signal(signal.SIGINT, lambda: None) gevent.signal(signal.SIGTERM, lambda: None) if aj.master: gateway.destroy() p = psutil.Process(os.getpid()) for c in p.children(recursive=True): try: os.killpg(c.pid, signal.SIGTERM) os.killpg(c.pid, signal.SIGKILL) except OSError: pass def signal_handler(): cleanup() sys.exit(0) gevent.signal(signal.SIGINT, signal_handler) gevent.signal(signal.SIGTERM, signal_handler) aj.server.serve_forever() if not aj.master: # child process, server is stopped, wait until killed gevent.wait() if hasattr(aj.server, 'restart_marker'): logging.warn('Restarting by request') cleanup() fd = 20 # Close all descriptors. Creepy thing while fd > 2: try: os.close(fd) logging.debug('Closed descriptor #%i', fd) except OSError: pass fd -= 1 logging.warn('Will restart the process now') if '-d' in sys.argv: sys.argv.remove('-d') os.execv(sys.argv[0], sys.argv) else: if aj.master: logging.debug('Server stopped') cleanup()