【问题标题】:python subprocess popen execute as different userpython子进程popen以不同用户身份执行
【发布时间】:2020-08-01 18:21:32
【问题描述】:

我正在尝试以 popensubprocess 的不同用户身份在 python 3.6 中执行命令,但它仍将以调用脚本的用户身份执行(我打算以 root 身份调用它)。我正在使用线程,因此当 2 个线程并行执行时,不要侵犯用户权限,这一点很重要。

proc = subprocess.Popen(['echo $USER; touch myFile.txt'],
                          shell=True,
                          env={'FOO':'bar', 'USER':'www-data'},
                          stdout=subprocess.PIPE)

上面的例子仍然会用我的user_id 1000创建myFile.txt

我尝试了不同的方法:

  1. 按照Run child processes as different user from a long running Python process 中的描述尝试通过复制 os.environment 并更改用户等
    (注意这是针对 python 2)

  2. 按照https://docs.python.org/3.6/library/subprocess.html#popen-constructor 中的描述尝试使用start_new_session=True

我最后的选择是在命令前加上sudo -u username command,但我认为这不是优雅的方式。

【问题讨论】:

  • sudo -u username command 确实是一种优雅的方式!
  • @lemonhead 我在 1 下提到过。
  • @Chris 是否有理由认为方法不能达到您的目标?我认为您在示例中缺少的部分是通过将函数传递给preexec_fn 进行降级
  • @lemonhead 正如我在 1 中提到的那样:我尝试了这种方法,但它也不起作用。我打电话给:subprocess.Popen(['echo $USER; touch myFile.txt'], shell=True, env={'FOO':'bar', 'USER':'www-data'}, stdout=subprocess.PIPE, preexec_fn=demote(33,33)) 并降级返回异常
    demote(33,33)
    <function demote.<locals>.result at 0x7f7f20cd1ea0>

标签: python python-3.x subprocess


【解决方案1】:

[仅 POSIX] 的标准方法是使用 preexec_fn 设置 gid 和 uid,如 this answer 中更详细描述的那样

这样的事情应该可以解决问题——为了完整起见,我还修改了您的初始 sn-p 以包含您可能想要设置的其他环境变量,但只需设置 preexec_fn 就足够了您正在运行的命令:

import os, pwd, subprocess

def demote(user_uid, user_gid):
    def result():
        os.setgid(user_gid)
        os.setuid(user_uid)
    return result

def exec_cmd(username):
    # get user info from username
    pw_record = pwd.getpwnam(username)
    homedir = pw_record.pw_dir
    user_uid = pw_record.pw_uid
    user_gid = pw_record.pw_gid
    env = os.environ.copy()
    env.update({'HOME': homedir, 'LOGNAME': username, 'PWD': os.getcwd(), 'FOO': 'bar', 'USER': username})

    # execute the command
    proc = subprocess.Popen(['echo $USER; touch myFile.txt'],
                              shell=True,
                              env=env,
                              preexec_fn=demote(user_uid, user_gid),
                              stdout=subprocess.PIPE)
    proc.wait()


exec_cmd('www-data')

请注意,您还需要确保降级用户可以访问当前工作目录(例如用于写入),因为没有明确覆盖它

【讨论】:

  • 好吧,这工作......即使在线程中。我添加了一个单独的睡眠时间,它起作用了。我不知道我以前做错了什么,但谢谢。您正在使用 preexec_fn 参数,但在 2 之下。在我的问题中,他们 docs 说您在使用线程时必须使用 start_new_session=True。你或其他人能给我解释一下吗?
  • pylint 打印警告:W1509:使用 preexec_fn 关键字,在存在线程的情况下可能不安全(subprocess-popen-pr eexec-fn)
  • 是否有类似的方法可以在 Windows 中运行子进程,而 suer 没有 piveleged ?即我的 python 脚本以管理员身份运行,我想以非特权用户身份运行子进程
猜你喜欢
  • 2021-04-02
  • 2010-12-18
  • 2012-11-29
  • 1970-01-01
  • 2011-06-05
  • 2010-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多