81

我有一个 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.")

这是进行检查的最佳方法吗?还有其他最佳做法吗?

4

10 回答 10

82

os.geteuid获取有效的用户 ID,这正是您想要的,所以我想不出更好的方法来执行这样的检查。不确定的一点是标题中的“root-like”:您的代码检查是否准确 root,没有“like”,实际上我不知道“root-like but not root”是什么意思——所以,如果您的意思与“完全根”不同,也许您可​​以澄清一下,谢谢!

于 2010-05-10T22:39:20.520 回答
34

在“请求原谅比许可更容易”的原则下:

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

于 2010-05-10T22:41:07.793 回答
17

您可以提示用户进行 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

于 2013-11-22T20:26:31.307 回答
9

对于 Linux:

def is_root():
    return os.geteuid() == 0
于 2018-10-03T07:29:11.657 回答
8

我喜欢在环境变量中检查 sudo:

如果不是 os.environ.keys() 中的“SUDO_UID”:
  print "这个程序需要超级用户权限。"
  系统退出(1)
于 2013-07-15T13:26:51.107 回答
7

如果你真的希望你的代码在各种 Linux 配置中保持健壮,我建议你考虑一下有人可能使用 SELinux、文件系统 ACL 或 Linux 内核中的“功能”特性的极端情况从 v. 2.2 左右开始。您的进程可能在使用 SELinux 的某个包装器下运行,或者某些 Linux 功能库(例如libcap2 libcap-ngfscapselfcap)通过更奇特的东西(例如 Niels Provos 的精彩且遗憾地被低估的systrace系统)运行。

所有这些都是您的代码可能以非 root 身份运行的方式,但您的进程可能已被委派了必要的访问权限以在没有 EUID==0 的情况下执行其工作。

因此,我建议您考虑通过包装可能因权限或异常处理代码的其他问题而失败的操作,以更 Python 的方式编写代码。如果您打算执行各种操作(例如使用subprocess模块),您可能会提供给所有此类调用添加前缀sudo(例如,作为命令行、环境或 .rc 文件选项)。如果它以交互方式运行,您可以提供重新执行任何引发权限相关异常的命令sudo(可选地,仅当您sudo在 os.environ['PATH'] 上找到时)。

总的来说,大多数 Linux 和 UNIX 系统的大部分管理仍然由“root”特权用户完成。然而,这是老派,作为程序员,我们应该尝试支持更新的模型。尝试您的操作并让异常处理完成其工作允许您的代码在任何透明地允许您需要的操作的系统下工作,并且意识到并准备好使用sudo是一个很好的接触(因为它是迄今为止最普遍的用于控制系统权限委派的工具)。

于 2010-05-10T23:53:06.467 回答
5
import os

def check_privileges():

    if not os.environ.get("SUDO_UID") and os.geteuid() != 0:
        raise PermissionError("You need to run this script with sudo or as root.")

SUDO_UID如果脚本未使用sudo.

于 2021-09-10T15:03:24.823 回答
3

我的应用程序使用以下代码:

import os
user = os.getenv("SUDO_USER")
if user is None:
    print "This program need 'sudo'"
    exit()
于 2014-10-03T16:24:18.300 回答
3

回答问题的第二部分

(抱歉评论框太小了)

保罗霍夫曼,你是对的,我只解决了你关于内在函数的问题的一部分,但如果它不能处理,它就不是一种有价值的脚本语言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'

ButPopen是一个通用工具,可以为方便起见进行包装:

$ 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 的过度通用性。

于 2010-05-12T16:15:58.007 回答
0

这完全取决于您希望应用程序的便携性。如果您的意思是业务,我们必须假设管理员帐户并不总是等于 0。这意味着检查 euid 0 是不够的。问题是,在某些情况下,一个命令的行为就像您是 root 一样,而下一个命令将因权限被拒绝而失败(想想 SELinux & co.)。因此,最好在适当的时候优雅地失败并检查 EPERM errno。

于 2010-05-10T22:52:27.850 回答