Make it possible to call utils.Daemonize with uid and gid to run as
authorRené Nussbaumer <rn@google.com>
Wed, 2 Jun 2010 08:34:15 +0000 (10:34 +0200)
committerRené Nussbaumer <rn@google.com>
Fri, 4 Jun 2010 14:22:46 +0000 (16:22 +0200)
Signed-off-by: René Nussbaumer <rn@google.com>
Reviewed-by: Guido Trotter <ultrotter@google.com>

lib/daemon.py
lib/utils.py

index dc41fdc..593e146 100644 (file)
@@ -24,7 +24,9 @@
 
 import asyncore
 import asynchat
+import grp
 import os
+import pwd
 import signal
 import logging
 import sched
@@ -38,6 +40,10 @@ from ganeti import constants
 from ganeti import errors
 
 
+_DEFAULT_RUN_USER = "root"
+_DEFAULT_RUN_GROUP = "root"
+
+
 class SchedulerBreakout(Exception):
   """Exception used to get out of the scheduler loop
 
@@ -434,7 +440,8 @@ class Mainloop(object):
 
 def GenericMain(daemon_name, optionparser, dirs, check_fn, exec_fn,
                 multithreaded=False, console_logging=False,
-                default_ssl_cert=None, default_ssl_key=None):
+                default_ssl_cert=None, default_ssl_key=None,
+                user=_DEFAULT_RUN_USER, group=_DEFAULT_RUN_GROUP):
   """Shared main function for daemons.
 
   @type daemon_name: string
@@ -460,6 +467,10 @@ def GenericMain(daemon_name, optionparser, dirs, check_fn, exec_fn,
   @param default_ssl_cert: Default SSL certificate path
   @type default_ssl_key: string
   @param default_ssl_key: Default SSL key path
+  @param user: Default user to run as
+  @type user: string
+  @param group: Default group to run as
+  @type group: string
 
   """
   optionparser.add_option("-f", "--foreground", dest="fork",
@@ -529,8 +540,14 @@ def GenericMain(daemon_name, optionparser, dirs, check_fn, exec_fn,
   utils.EnsureDirs(dirs)
 
   if options.fork:
+    try:
+      uid = pwd.getpwnam(user).pw_uid
+      gid = grp.getgrnam(group).gr_gid
+    except KeyError:
+      raise errors.ConfigurationError("User or group not existing on system:"
+                                      " %s:%s" % (user, group))
     utils.CloseFDs()
-    utils.Daemonize(logfile=constants.DAEMONS_LOGFILES[daemon_name])
+    utils.Daemonize(constants.DAEMONS_LOGFILES[daemon_name], uid, gid)
 
   utils.WritePidFile(daemon_name)
   try:
index ffb8b70..1ef35cb 100644 (file)
@@ -2192,7 +2192,7 @@ def Mlockall():
   logging.debug("Memory lock set")
 
 
-def Daemonize(logfile):
+def Daemonize(logfile, run_uid, run_gid):
   """Daemonize the current process.
 
   This detaches the current process from the controlling terminal and
@@ -2200,6 +2200,10 @@ def Daemonize(logfile):
 
   @type logfile: str
   @param logfile: the logfile to which we should redirect stdout/stderr
+  @type run_uid: int
+  @param run_uid: Run the child under this uid
+  @type run_gid: int
+  @param run_gid: Run the child under this gid
   @rtype: int
   @return: the value zero
 
@@ -2213,6 +2217,11 @@ def Daemonize(logfile):
   pid = os.fork()
   if (pid == 0):  # The first child.
     os.setsid()
+    # FIXME: When removing again and moving to start-stop-daemon privilege drop
+    #        make sure to check for config permission and bail out when invoked
+    #        with wrong user.
+    os.setgid(run_gid)
+    os.setuid(run_uid)
     # this might fail
     pid = os.fork() # Fork a second child.
     if (pid == 0):  # The second child.