我有一个Python脚本,它将执行许多需要root级权限的事情,例如在/ 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.")
这是进行检查的最佳方法吗?还有其他最佳做法吗?
Answers:
根据“比许可更容易请求宽恕”原则:
try:
os.rename('/etc/foo', '/etc/bar')
except IOError as e:
if (e[0] == errno.EPERM):
sys.exit("You need root permissions to do this, laterz!")
如果您担心自己的不可携带性,则无论如何os.geteuid()
都不应对此感到厌烦/etc
。
os.geteuid
获取有效的用户ID,这正是您想要的,所以我想不出任何更好的方法来执行这种检查。不确定的一点是标题中的“ root-like”:您的代码检查的是 root
“完全”,而不是“ like”,实际上我不知道“ root-like but not root”是什么意思-因此,如果您的意思不同于“完全扎根”,也许可以澄清一下,谢谢!
您可以提示用户进行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
)。
如果您确实希望您的代码在各种Linux配置中都具有鲁棒性,那么建议您考虑一些极端的情况,即有人在使用SELinux,文件系统ACL或Linux内核中已有的“功能”功能从v。2.2左右开始。您的进程可能正在使用SELinux的某些包装器下运行,或者在Linux功能库(例如libcap2 libcap-ng或fscaps或elfcap)下通过诸如Niels Provos精彩而令人遗憾的被低估的systrace之类的东西运行系统。
所有这些都是您的代码可能以非超级用户身份运行的方式,但是您的进程可能已经被委派了执行EU工作的必要访问权限,而无需EUID == 0。
因此,我建议您考虑通过包装可能由于权限或异常处理代码的其他问题而失败的操作,以更Python的方式编写代码。如果您打算执行各种操作(例如使用subprocess
模块),则可以为所有此类调用添加前缀sudo
(例如,命令行,环境或.rc文件选项)。如果它是交互式运行的,则可以提供使用以下命令重新执行任何引发权限相关异常的命令sudo
(仅当发现sudo
在os.environ ['PATH']上,。
总体而言,大多数Linux和UNIX系统的大部分管理工作都是由“ root”特权用户完成的。但是,这是一门古老的书,作为程序员,我们应该尝试支持较新的模型。尝试操作并让异常处理发挥作用,可以使您的代码在可以透明地允许您进行所需操作的任何系统下工作,并且意识到并准备使用它sudo
是一种不错的感觉(到目前为止,这是最广泛的应用用于控制系统特权的委派工具)。
(对不起,评论框太小)
保罗·霍夫曼(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通用性。
我的应用程序使用以下代码:
import os
user = os.getenv("SUDO_USER")
if user is None:
print "This program need 'sudo'"
exit()
TypeError
,因为如果您不是以root身份运行,则os.getenv("SUDO_USER")
返回None
类型为的返回值NoneType
,并且您无法将str
and连接在一起NoneType
。如果您想使用它os.getenv("SUDO_USER")
来解决问题,则应这样做:if os.getenv("SUDO_USER") == None: print "This program need 'sudo'"; exit()
os.getenv('HOME')
,这将告诉您当前用户是root
还是sudo
您的脚本通常需要知道的用户。