将python-daemon作为非特权用户运行并保留组成员身份

时间:2013-07-01 12:07:35

标签: python linux ubuntu python-daemon

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

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

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

root daemonizes开始的进程很好并且由正确的用户拥有,但在尝试访问设备时我得到权限被拒绝错误。 我写了一个小测试应用程序,似乎该进程没有继承用户的组成员资格。

#!/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)运行上述代码时,我得到:

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

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

2 个答案:

答案 0 :(得分:2)

我当前的解决方案是在启动实际守护程序之前使用chuid的{​​{1}}参数删除root权限:

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 /var/run/testdaemon),实际的守护进程(具有适当的文件权限)。

我宁愿在python而不是bash中编写该逻辑。

现在有效,但我认为这应该以更优雅的方式解决。

答案 1 :(得分:0)

可以通过猴子修补守护程序模块来解决此问题,代码如下:

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