我有一个Python脚本,它将执行许多需要根级权限的事情,例如在/ etc中移动文件,使用apt-get安装等等。我目前有:
if os.geteuid() != 0:
exit("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.")
这是检查的最佳方式吗?还有其他最佳做法吗?
答案 0 :(得分:57)
os.geteuid
获得有效的用户ID,这正是您想要的,所以我想不出更好的方法来执行这样的检查。一点不确定的是标题中的“root-like”:你的代码检查完全 root
,没有“喜欢”它,我确实不知道是什么root-like但不是root“意思是 - 所以,如果你的意思不同于”完全根“,也许你可以澄清一下,谢谢!
答案 1 :(得分:29)
在“更容易请求宽恕而非许可”原则下:
try:
os.rename('/etc/foo', '/etc/bar')
except IOError as e:
if (e[0] == errno.EPERM):
print >> sys.stderr, "You need root permissions to do this, laterz!"
sys.exit(1)
如果您担心os.geteuid()
的不可移植性,那么您可能不应该与/etc
混淆。
答案 2 :(得分:10)
您可以提示用户进行sudo访问:
import os, subprocess
def prompt_sudo():
ret = 0
if os.geteuid() != 0:
msg = "[sudo] password for %u:"
ret = subprocess.check_call("sudo -v -p '%s'" % msg, shell=True)
return ret
if prompt_sudo() != 0:
# the user wasn't authenticated as a sudoer, exit?
sudo -v
开关更新用户的缓存凭据(请参阅man sudo
)。
答案 3 :(得分:7)
如果您真的希望您的代码在各种Linux配置中都很健壮,我建议您考虑有人可能正在使用SELinux,或文件系统ACL或已经使用的“功能”功能的极端情况。自2.2以后的Linux内核。您的进程可能正在使用SELinux或某些Linux功能库(例如libcap2 libcap-ng或fscaps或elfcap的某个包装器下运行,如Niels之类的更具异国情调的东西普罗沃斯的精彩和令人遗憾的低估systrace系统。
所有这些都是您的代码可能以非root身份运行的方式,但您的流程可能已被委派了必要的访问权限,无需EUID == 0即可执行其工作。
因此,我建议您考虑通过包装由于权限或异常处理代码的其他问题而可能失败的操作来更加Python地编写代码。如果您正在进行各种操作(例如使用subprocess
模块),您可以使用sudo
为所有此类调用添加前缀(作为命令行,环境或.rc文件选项,用于例)。如果它以交互方式运行,您可以使用sudo
重新执行任何引发权限相关异常的命令(仅当您在os.environ ['PATH']上找到sudo
时才可选。)
总的来说,大多数Linux和UNIX系统的大多数管理仍由“root”特权用户完成。然而,它是老派,作为程序员,我们应该尝试支持更新的模型。尝试操作并让异常处理完成它的工作允许您的代码在透明地允许您需要的操作的任何系统下工作,并且知道并准备好使用sudo
是一个很好的接触(因为它,通过远,用于控制系统权限委派的最广泛的工具。)
答案 4 :(得分:3)
(抱歉评论框太小了)
Paul Hoffman,你是对的,我只讨论了你处理内在函数的问题的一部分,但如果它无法处理apt-get
,它就不是一本有价值的脚本语言。首选的库有点冗长,但它完成了这项工作:
>>> apt_get = ['/usr/bin/apt-get', 'install', 'python']
>>> p = subprocess.Popen(apt_get, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> p.wait()
100 # Houston, we have a problem.
>>> p.stderr.read()
'E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)'
'E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?\n'
但是Popen
是一个通用工具,可以为方便起见包装:
$ cat apt.py
import errno
import subprocess
def get_install(package):
cmd = '/usr/bin/apt-get install'.split()
cmd.append(package)
output_kw = {'stdout': subprocess.PIPE, 'stderr': subprocess.PIPE}
p = subprocess.Popen(cmd, **output_kw)
status = p.wait()
error = p.stderr.read().lower()
if status and 'permission denied' in error:
raise OSError(errno.EACCES, 'Permission denied running apt-get')
# other conditions here as you require
$ python
>>> import apt
>>> apt.get_install('python')
Traceback ...
OSError: [Errno 13] Permission denied running apt-get
现在我们又回到了异常处理。我将拒绝评论类似Java的子进程模块的过度通用性。
答案 5 :(得分:2)
我喜欢在环境变量中检查sudo:
if not 'SUDO_UID' in os.environ.keys(): print "this program requires super user priv." sys.exit(1)
答案 6 :(得分:2)
我的应用使用此代码:
import os
user = os.getenv("SUDO_USER")
if user is None:
print "This program need 'sudo'"
exit()
答案 7 :(得分:0)
这一切都取决于您希望应用程序具有多大的便携性。如果你的意思是业务,我们必须假设管理员帐户并不总是等于0.这意味着检查euid 0是不够的。问题是,在某些情况下,一个命令的行为就像你是root用户,而next会因权限被拒绝而失败(想想SELinux& co。)。因此,优雅地失败并在适当的时候检查EPERM errno真的更好。
答案 8 :(得分:0)
对于Linux:
def is_root():
return os.geteuid() == 0