Domanda

I'm writing a daemon in python, using the python-daemon package. the daemon is started at boot-time (init.d) and needs to access various devices. the daemon is to run on an embedded system (beaglebone) running ubuntu.

now my problem is that I want to run the daemon as an unprivileged user rather (e.g. mydaemon) than root.

in order to allow the daemon to access the devices I added that user to the required groups. in the python code I use daemon.DaemonContext(uid=uidofmydamon).

the process started by root daemonizes nicely and is owned by the correct user, but I get permission denied errors when trying to access the devices. I wrote a small test application, and it seems that the process does not inherit the group-memberships of the user.

#!/usr/bin/python
import logging, daemon, os

if __name__ == '__main__':
  lh=logging.StreamHandler()
  logger = logging.getLogger()
  logger.setLevel(logging.INFO)
  logger.addHandler(lh)

  uid=1001 ## UID of the daemon user
  with daemon.DaemonContext(uid=uid,
                            files_preserve=[lh.stream],
                            stderr=lh.stream):
    logger.warn("UID : %s" % str(os.getuid()))
    logger.warn("groups: %s" % str(os.getgroups()))

when i run the above code as the user with uid=1001 i get something like

$ ./testdaemon.py
UID: 1001
groups: [29,107,1001]

whereas when I run the above code as root (or su), I get:

$ sudo ./testdaemon.py
UID: 1001
groups: [0]

How can I create a daemon-process started by root but with a different effective uid and intact group memberships?

È stato utile?

Soluzione

my current solution involves dropping root priviliges before starting the actual daemon, using the chuid argument for start-stop-daemon:

 start-stop-daemon \
      --start \
      --chuid daemonuser \
      --name testdaemon \
      --pidfile /var/run/testdaemon/test.pid \
      --startas /tmp/testdaemon.py \
     -- \
      --pidfile /var/run/testdaemon/test.pid \
      --logfile=/var/log/testdaemon/testdaemon.log

the drawback of this solution is, that i need to create all directories, where the daemon ought to write to (noteably /var/run/testdaemon and /var/log/testdaemon), before starting the actual daemon (with the proper file permissions).

i would have preferred to write that logic in python rather than bash.

for now that works, but me thinketh that this should be solveable in a more elegant fashion.

Altri suggerimenti

This can be fixed by monkey patching the daemon module, the code is as follows:

import os, grp, pwd

class DaemonError(Exception):
    pass

class DaemonOSEnvironmentError(DaemonError, OSError):
    pass

def change_process_owner(uid, gid):
    try:
        # This line adds all the groups the user is member of
        # to keep the expected permissions
        os.setgroups(
            [g.gr_gid for g in grp.getgrall()
                if pwd.getpwuid(uid).pw_name in g.gr_mem
            ]
        )
        os.setgid(gid)
        os.setuid(uid)
    except Exception, exc:
        error = DaemonOSEnvironmentError(u"Unable to change process 
                    owner (%(exc)s)" % vars())
        raise error

And then the monkey patch:

import daemon
daemon.daemon.change_process_owner = change_process_owner
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top