From f69d2c18d1351d49f4c1ffd2a6c282df0fa3d8e3 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Fri, 16 Jan 2015 03:53:00 +0100 Subject: Server/Core: drop privileges even if not running as daemon --- src/lib/Bcfg2/Options.py | 4 +++- src/lib/Bcfg2/Server/CherryPyCore.py | 16 ++++++++++------ src/lib/Bcfg2/Server/Core.py | 17 ++++++++++++++++- src/lib/Bcfg2/Server/MultiprocessingCore.py | 3 +++ src/sbin/bcfg2-info | 2 ++ 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/lib/Bcfg2/Options.py b/src/lib/Bcfg2/Options.py index 652e216a5..fdc34eb95 100644 --- a/src/lib/Bcfg2/Options.py +++ b/src/lib/Bcfg2/Options.py @@ -1348,7 +1348,9 @@ TEST_COMMON_OPTIONS = dict(noseopts=TEST_NOSEOPTS, validate=CFG_VALIDATION) INFO_COMMON_OPTIONS = dict(ppath=PARANOID_PATH, - max_copies=PARANOID_MAX_COPIES) + max_copies=PARANOID_MAX_COPIES, + daemon_uid=SERVER_DAEMON_USER, + daemon_gid=SERVER_DAEMON_GROUP) INFO_COMMON_OPTIONS.update(CLI_COMMON_OPTIONS) INFO_COMMON_OPTIONS.update(SERVER_COMMON_OPTIONS) diff --git a/src/lib/Bcfg2/Server/CherryPyCore.py b/src/lib/Bcfg2/Server/CherryPyCore.py index d097fd08f..c1581679c 100644 --- a/src/lib/Bcfg2/Server/CherryPyCore.py +++ b/src/lib/Bcfg2/Server/CherryPyCore.py @@ -103,17 +103,21 @@ class Core(BaseCore): return cherrypy.serving.response.body def _daemonize(self): - """ Drop privileges with - :class:`cherrypy.process.plugins.DropPrivileges`, daemonize - with :class:`cherrypy.process.plugins.Daemonizer`, and write a + """ Drop privileges, daemonize + with :class:`cherrypy.process.plugins.Daemonizer` and write a PID file with :class:`cherrypy.process.plugins.PIDFile`. """ + self._drop_privileges() + Daemonizer(cherrypy.engine).subscribe() + PIDFile(cherrypy.engine, self.setup['daemon']).subscribe() + return True + + def _drop_privileges(self): + """ Drop privileges with + :class:`cherrypy.process.plugins.DropPrivileges` """ DropPrivileges(cherrypy.engine, uid=self.setup['daemon_uid'], gid=self.setup['daemon_gid'], umask=int(self.setup['umask'], 8)).subscribe() - Daemonizer(cherrypy.engine).subscribe() - PIDFile(cherrypy.engine, self.setup['daemon']).subscribe() - return True def _run(self): """ Start the server listening. """ diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 6dfe4df1f..0369da8f2 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -11,6 +11,7 @@ import threading import time import inspect import lxml.etree +import daemon import Bcfg2.settings import Bcfg2.Server import Bcfg2.Logger @@ -112,6 +113,7 @@ class BaseCore(object): :type setup: Bcfg2.Options.OptionParser .. automethod:: _daemonize + .. automethod:: _drop_privileges .. automethod:: _run .. automethod:: _block .. ----- @@ -803,7 +805,8 @@ class BaseCore(object): self.logger.debug("Slept %s seconds while handling FAM events" % slept) def run(self): - """ Run the server core. This calls :func:`_daemonize`, + """ Run the server core. This calls :func:`_daemonize` + (or :func:`_drop_privileges` if not in daemon mode), :func:`_run`, starts the :attr:`fam_thread`, and calls :func:`_block`, but note that it is the responsibility of the server core implementation to call :func:`shutdown` under @@ -830,6 +833,8 @@ class BaseCore(object): # dropped os.environ['HOME'] = pwd.getpwuid(self.setup['daemon_uid'])[5] else: + if os.getuid() == 0: + self._drop_privileges() os.umask(int(self.setup['umask'], 8)) if not self._run(): @@ -861,6 +866,16 @@ class BaseCore(object): overridden by a core implementation. """ raise NotImplementedError + def _drop_privileges(self): + """ This is called if not daemonized and running as root to + drop the privileges to the configured daemon_uid and daemon_gid. + """ + daemon.daemon.change_process_owner( + self.setup['daemon_uid'], + self.setup['daemon_gid']) + self.logger.debug("Dropped privileges to %s:%s." % + (os.getuid(), os.getgid())) + def _run(self): """ Start up the server; this method should return immediately. This must be overridden by a core diff --git a/src/lib/Bcfg2/Server/MultiprocessingCore.py b/src/lib/Bcfg2/Server/MultiprocessingCore.py index 2cb3adae3..4986aac60 100644 --- a/src/lib/Bcfg2/Server/MultiprocessingCore.py +++ b/src/lib/Bcfg2/Server/MultiprocessingCore.py @@ -210,6 +210,9 @@ class ChildCore(BaseCore): def _daemonize(self): return True + def _drop_privileges(self): + pass + def _dispatch(self, address, data): """ Method dispatcher used for commands received from the RPC queue. """ diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info index a6c3149bc..2c97a9b91 100755 --- a/src/sbin/bcfg2-info +++ b/src/sbin/bcfg2-info @@ -726,6 +726,8 @@ Bcfg2 client itself.""") def run(self, args): # pylint: disable=W0221 try: + if os.getuid() == 0: + self._drop_privileges() self.load_plugins() self.block_for_fam_events(handle_events=True) if args: -- cgit v1.2.3-1-g7c22