以非特权用户身份运行python守护程序并保持组成员身份

以非特权用户身份运行python守护程序并保持组成员身份,python,linux,ubuntu,python-daemon,Python,Linux,Ubuntu,Python Daemon,我正在使用这个包用python编写一个守护进程。守护进程在启动时(init.d)启动,需要访问各种设备。 守护进程将在运行ubuntu的嵌入式系统()上运行 现在我的问题是,我想以非特权用户的身份运行守护程序,而不是以root用户的身份运行(例如mydaemon) 为了允许守护进程访问设备,我将该用户添加到所需的组中。 在python代码中,我使用daemon.DaemonContext(uid=uidofmydamon) 由root启动的进程可以很好地进行后台监控,并由正确的用户拥有,但在尝试

我正在使用这个包用python编写一个守护进程。守护进程在启动时(init.d)启动,需要访问各种设备。 守护进程将在运行ubuntu的嵌入式系统()上运行

现在我的问题是,我想以非特权用户的身份运行守护程序,而不是以root用户的身份运行(例如
mydaemon

为了允许守护进程访问设备,我将该用户添加到所需的组中。 在python代码中,我使用daemon.DaemonContext(uid=uidofmydamon)

root
启动的进程可以很好地进行后台监控,并由正确的用户拥有,但在尝试访问设备时,我遇到了权限被拒绝的错误。 我编写了一个小的测试应用程序,该进程似乎没有继承用户的组成员身份

#!/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()))
当我以uid=1001的用户身份运行上述代码时,我得到如下结果

$ ./testdaemon.py
UID: 1001
groups: [29,107,1001]
而当我以root(或
su
)身份运行上述代码时,我得到:


如何创建由root启动但具有不同有效uid和完整组成员身份的守护进程?

我当前的解决方案包括在启动实际守护进程之前,使用
启动停止守护进程的
chuid
参数删除根权限:

 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
此解决方案的缺点是,我需要创建守护进程应该写入的所有目录(注意
/var/run/testdaemon
/var/log/testdaemon
),然后再启动实际的守护进程(使用适当的文件权限)

我宁愿用python而不是bash编写这种逻辑


现在这是可行的,但我认为这应该可以用一种更优雅的方式来解决。

这可以通过对守护程序模块进行猴子补丁来解决,代码如下:

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
然后是猴子补丁:

import daemon
daemon.daemon.change_process_owner = change_process_owner

Linux发行版的目的是什么?ubuntu和debian(我相应地更新了这个问题)在启动python守护程序之前,有什么原因不能更改为守护程序用户吗?也许类似(这个答案)[可以满足您的需要吗?@rkyser是的,我现在正在这样做(请参见我自己的答案),但它会使文件权限的一些事情变得复杂(PID文件通常创建在只有root用户才能写的地方)
import daemon
daemon.daemon.change_process_owner = change_process_owner