在Python脚本中切换到sudo用户

29

我有一个问题。我正在编写一段软件,需要执行一个需要用户处于sudo模式下的操作。运行 'sudo python filename.py' 不是一个选项,这就引出了我的问题。是否有一种方法可以在Python脚本中间切换到sudo模式,安全性不是问题,因为用户将知道sudo密码,程序应按以下方式运行以说明问题:

  1. 以普通用户身份运行程序
  2. ...... 执行操作
  3. 用户输入sudo密码
  4. 用户变成sudo
  5. 运行需要sudo权限的子程序
  6. 在触发事件后(子程序结束)用户再次变成普通用户
  7. ...... 执行操作

我的问题出现在第3步,您能提供的任何指针或框架都将非常有帮助。

谢谢

克里斯


我认为一个完美的解决方案应该具备以下特点,无论是否可能:1. 不需要重新启动脚本。2. 不需要在Python脚本内调用第二个Python脚本。3. root权限仅适用于脚本的指定部分(不是开头,也不一定是结尾)。 - Brōtsyorfuzthrāx
9个回答

19

最好尽可能地减少以提升的权限运行程序的部分。 你可以使用 subprocess.call() 函数运行需要更多特权的小部分,例如:

import subprocess
returncode = subprocess.call(["/usr/bin/sudo", "/usr/bin/id"])

10

不要试图使自己成为sudo,只需检查一下自己是否是,并查看错误信息(如果你不是sudo)。

class NotSudo(Exception):
    pass

if os.getuid() != 0:
    raise NotSudo("This program is not run as sudo or elevated this it will not work")

4
这应该是os.geteuid() != 0,对吗? - Trevor Robinson
23
这不是一个很好的解决方案 - 如果只有脚本的某些部分需要root权限怎么办? - Timmmm
3
要求不以管理员权限运行整个程序。 - thorr18
3
@JakobBowyer 谁知道 sudo 还会继续存在? - thorr18
2
@thorr18 其他网站反对在旧帖中发布内容,但是Stack Overflow已经看到了光明,并鼓励提出那些对后来者有用的问题和答案,这意味着修复或指出旧答案中存在的问题非常重要。 - SilentVoid
显示剩余3条评论

5

最近我在编写系统安装脚本时遇到了这个问题。为了切换到超级用户权限,我使用了带有“sudo”的subprocess.call()函数:

#!/usr/bin/python

import subprocess
import shlex
import getpass

print "This script was called by: " + getpass.getuser()

print "Now do something as 'root'..."
subprocess.call(shlex.split('sudo id -nu'))

print "Now switch back to the calling user: " + getpass.getuser()

请注意,您需要使用 shlex.split() 使您的命令可用于 subprocess.call()。如果您想要使用命令的输出,则可以使用 subprocess.check_output()。同时,还有一个名为“sh” (http://amoffat.github.com/sh/) 的软件包可供使用。

1
sudo:没有 tty 存在,也没有指定 askpass 程序 - Jonathan

2
使用Tcl和Expect,再加上subprocess来提升权限。基本上就是这样:
sudo.tcl
spawn sudo
expect {
    "Password:" {
        send "password"
    }
}

sudo.py

import subprocess
subprocess.call(['tclsh', 'sudo.tcl'])

然后运行sudo.py。


当我按照你提供的一切完全相同的方式运行Python脚本时,出现了“无效命令名称'spawn'”的错误。我应该怎么做才能避免这种情况? - Brōtsyorfuzthrāx
也许使用Python的pexpect模块和pexpect.spawnu类可以帮助创建一个全Python解决方案。如果您知道如何使用它,请随意将其编辑到您的答案中。(并不是说我需要一个全Python解决方案。只要对我有用,那就太好了。) - Brōtsyorfuzthrāx
我需要一个完全基于Python的方案。你有吗? - answerSeeker

2
如果您能将需要提升特权的必要功能封装在单独的可执行文件中,那么您可以在该可执行程序上使用setuid位,并从用户级Python脚本中调用它。
这种方法只有在setuid可执行文件中运行的活动以root身份才能运行,但是执行此操作不需要sudo即root权限。只有创建/修改setuid可执行文件需要sudo。
有一些安全影响,比如确保您的setuid可执行程序正确地对任何用户输入(例如参数)进行了净化,以便它不能被欺骗做一些不应该做的事情(混淆代理问题)。
参考: http://en.wikipedia.org/wiki/Setuid#setuid_on_executables 编辑:setuid似乎只适用于编译后的可执行文件(二进制文件),而不适用于解释性脚本,因此您可能需要使用编译后的setuid包装器。

嗯,作者正在寻求Python脚本,因此-正如您所写的那样-setuid是无用的。 - Massimo

0
import subprocess
subprocess.check_output("sudo -i -u " + str(username) + " ls -l", shell=True).decode("utf-8").strip()

0

你可以使用setuid来设置用户的UID。但出于明显的安全原因,只有当你是root(或程序具有suid root权限)时才能这样做。这两种情况都可能是一个坏主意。

在这种情况下,你需要sudo权限来运行特定的程序。在这种情况下,只需将其替换为“sudo theprogram”即可。


0

不确定这个方法能帮到你什么,而且它并没有回答问题,但是当你遇到需要“root”用户权限才能读取/写入文件夹或文件的情况时,它可以作为一种解决方法。

你可以改变权限,并在需要时切换回来。我在一个docker-compose文件中遇到了这个问题,它启动了一个Python脚本,用于将应用部署到服务器上。这个解决方法是唯一让我成功运行起来的方式。我甚至不需要从容器bash更改权限,而是由脚本来完成,只需要输入密码两次。

在使用这个解决方法之前,我尝试过切换到root用户并使用root用户执行大块的代码,但都无法成功。

run("ls -ld /usr/local/my_project/")
run("sudo chmod o+wx /usr/local/my_project/")
run("ls -ld /usr/local/my_project/")
my_code_that_needed_root_rights_and_now_runs_without_root_user()
run("sudo chmod 774 /usr/local/my_project/")
run("ls -ld /usr/local/my_project/")

然后输出:

[server_connection] run: ls -ld /usr/local/my_project/
[server_connection] Login password for 'my_user': 
[server_connection] out: drwxrwxr-- 45 root 100005 4096 Apr 25 13:52 /usr/local/my_project/
[server_connection] out: 

[server_connection] run: sudo chmod o+wx /usr/local/my_project/
[server_connection] out: [sudo] password for my_user: 
[server_connection] out: 

[server_connection] run: ls -ld /usr/local/my_project/
[server_connection] out: drwxrwxrwx 45 root 100005 4096 Apr 25 13:52 /usr/local/my_project/
[server_connection] out: 

[...]    

[server_connection] run: sudo chmod 774 /usr/local/my_project/
[server_connection] out: [sudo] password for my_user: 
[server_connection] out: 

[server_connection] run: ls -ld /usr/local/my_project/
[server_connection] out: drwxrwxr-- 46 root 100005 4096 Apr 25 14:02 /usr/local/my_project/
[server_connection] out: 

在此之后,服务器文件夹的权限与之前相同,代码不需要通过root用户运行。


-5
你是在谈论让用户在执行过程中输入密码吗?raw_input() 可以从控制台获取用户输入,但它不会掩盖密码。
>>>> y = raw_input()
somehting
>>> y
'somehting'

不,我们正在谈论权限,尽管授予权限的程序倾向于要求密码(但这不是关键因素)。 (就像在程序中间使用sudo而不使用第二个脚本一样。) - Brōtsyorfuzthrāx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接