以与长期运行的Python进程不同的用户身份运行子进程 [英] Run child processes as different user from a long running Python process

查看:245
本文介绍了以与长期运行的Python进程不同的用户身份运行子进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个长期运行的守护进程Python进程,该进程使用子进程在发生某些事件时生成新的子进程.长时间运行的过程由具有超级用户特权的用户启动.我需要它产生的子进程以其他用户身份(例如"nobody")运行,同时保留父进程的超级用户特权.

I've got a long running, daemonized Python process that uses subprocess to spawn new child processes when certain events occur. The long running process is started by a user with super user privileges. I need the child processes it spawns to run as a different user (e.g., "nobody") while retaining the super user privileges for the parent process.

我当前正在使用

su -m nobody -c <program to execute as a child>

但这似乎很重,而且不会很干净地死掉.

but this seems heavyweight and doesn't die very cleanly.

有没有一种方法可以通过编程而不是使用su来完成?我正在查看os.set * uid方法,但是Python std lib中的文档在该区域相当稀疏.

Is there a way to accomplish this programmatically instead of using su? I'm looking at the os.set*uid methods, but the doc in the Python std lib is quite sparse in that area.

推荐答案

由于您提到了守护程序,因此我可以得出结论,您正在运行在类似Unix的操作系统上.这很重要,因为如何执行此操作取决于所用的操作系统.此答案仅适用于 Unix ,包括Linux和Mac OS X.

Since you mentioned a daemon, I can conclude that you are running on a Unix-like operating system. This matters, because how to do this depends on the kind operating system. This answer applies only to Unix, including Linux, and Mac OS X.

  1. 定义一个函数,该函数将设置正在运行的进程的gid和uid.
  2. 将此函数作为preexec_fn参数传递给subprocess.Popen

subprocess.Popen将使用fork/exec模型来使用您的preexec_fn.这等效于按此顺序调用os.fork(),preexec_fn()(在子进程中)和os.exec()(在子进程中).由于os.setuid,os.setgid和preexec_fn仅在Unix上受支持,因此该解决方案无法移植到其他类型的操作系统上.

subprocess.Popen will use the fork/exec model to use your preexec_fn. That is equivalent to calling os.fork(), preexec_fn() (in the child process), and os.exec() (in the child process) in that order. Since os.setuid, os.setgid, and preexec_fn are all only supported on Unix, this solution is not portable to other kinds of operating systems.

以下代码是演示如何执行此操作的脚本(Python 2.4 +):

The following code is a script (Python 2.4+) that demonstrates how to do this:

import os
import pwd
import subprocess
import sys


def main(my_args=None):
    if my_args is None: my_args = sys.argv[1:]
    user_name, cwd = my_args[:2]
    args = my_args[2:]
    pw_record = pwd.getpwnam(user_name)
    user_name      = pw_record.pw_name
    user_home_dir  = pw_record.pw_dir
    user_uid       = pw_record.pw_uid
    user_gid       = pw_record.pw_gid
    env = os.environ.copy()
    env[ 'HOME'     ]  = user_home_dir
    env[ 'LOGNAME'  ]  = user_name
    env[ 'PWD'      ]  = cwd
    env[ 'USER'     ]  = user_name
    report_ids('starting ' + str(args))
    process = subprocess.Popen(
        args, preexec_fn=demote(user_uid, user_gid), cwd=cwd, env=env
    )
    result = process.wait()
    report_ids('finished ' + str(args))
    print 'result', result


def demote(user_uid, user_gid):
    def result():
        report_ids('starting demotion')
        os.setgid(user_gid)
        os.setuid(user_uid)
        report_ids('finished demotion')
    return result


def report_ids(msg):
    print 'uid, gid = %d, %d; %s' % (os.getuid(), os.getgid(), msg)


if __name__ == '__main__':
    main()

您可以像这样调用此脚本:

You can invoke this script like this:

以root身份启动...

Start as root...

(hale)/tmp/demo$ sudo bash --norc
(root)/tmp/demo$ ls -l
total 8
drwxr-xr-x  2 hale  wheel    68 May 17 16:26 inner
-rw-r--r--  1 hale  staff  1836 May 17 15:25 test-child.py

成为非root用户的子进程...

Become non-root in a child process...

(root)/tmp/demo$ python test-child.py hale inner /bin/bash --norc
uid, gid = 0, 0; starting ['/bin/bash', '--norc']
uid, gid = 0, 0; starting demotion
uid, gid = 501, 20; finished demotion
(hale)/tmp/demo/inner$ pwd
/tmp/demo/inner
(hale)/tmp/demo/inner$ whoami
hale

子进程退出时,我们回到父进程的根目录...

When the child process exits, we go back to root in parent ...

(hale)/tmp/demo/inner$ exit
exit
uid, gid = 0, 0; finished ['/bin/bash', '--norc']
result 0
(root)/tmp/demo$ pwd
/tmp/demo
(root)/tmp/demo$ whoami
root

请注意,让父进程等待子进程退出只是出于演示目的.我这样做是为了使父母和孩子可以共享一个终端.守护程序没有终端,几乎不需要等待子进程退出.

Note that having the parent process wait around for the child process to exit is for demonstration purposes only. I did this so that the parent and child could share a terminal. A daemon would have no terminal and would seldom wait around for a child process to exit.

这篇关于以与长期运行的Python进程不同的用户身份运行子进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆