检查脚本用户是否具有 root 权限的最佳方法是什么?

发布于 2024-09-01 00:33:58 字数 270 浏览 17 评论 0原文

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

这是进行检查的最佳方式吗?还有其他最佳实践吗?

I have a Python script that will be doing a lot of things that would require root-level privileges, such as moving files in /etc, installing with apt-get, and so on. I currently have:

if os.geteuid() != 0:
    exit("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.")

Is this the best way to do the check? Are there other best practices?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

岁月流歌 2024-09-08 00:33:58

os.geteuid 获取有效的用户id,这正是你想要的,所以我想不出任何更好的方法来执行这样的检查。不确定的一点是标题中的“类似 root”:您的代码完全 root 检查它,没有“类似”,事实上我不会知道“类似根但不是根”是什么意思 - 所以,如果您的意思与“完全根”不同,也许您可​​以澄清,谢谢!

os.geteuid gets the effective user id, which is exactly what you want, so I can't think of any better way to perform such a check. The one bit that's uncertain is that "root-like' in the title: your code checks for exactly root, no "like" about it, and indeed I wouldn't know what "root-like but not root" would mean -- so, if you mean something different than "exactly root", perhaps you can clarify, thanks!

清欢 2024-09-08 00:33:58

根据 EAFP(请求宽恕比请求许可更容易)原则:

import errno

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

Under the EAFP (Easier to Ask Forgiveness than Permission) principle:

import errno

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!")

If you are concerned about the non-portability of os.geteuid() you probably shouldn't be mucking with /etc anyway.

Oo萌小芽oO 2024-09-08 00:33:58

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

You can prompt the user for sudo access:

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?

The sudo -v switch update the user's cached credentials (see man sudo).

辞取 2024-09-08 00:33:58

对于Linux:

def is_root():
    return os.geteuid() == 0

For linux:

def is_root():
    return os.geteuid() == 0
昨迟人 2024-09-08 00:33:58

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

if not 'SUDO_UID' in os.environ:
    print "this program requires super user priv."
    sys.exit(1)

I like to check for sudo in the environmental variables:

if not 'SUDO_UID' in os.environ:
    print "this program requires super user priv."
    sys.exit(1)
稳稳的幸福 2024-09-08 00:33:58

如果您确实希望您的代码在各种 Linux 配置中都具有鲁棒性,我建议您考虑一些极端情况,即有人可能使用 SELinux、文件系统 ACL 或 Linux 内核中的“功能”功能从 v.2.2 左右开始。您的进程可能在使用 SELinux 的某些包装器或某些 Linux 功能库下运行,例如 libcap2 libcap-ng,或 fscapselfcap 通过更多内容像尼尔斯·普罗沃斯那样充满异国情调的美妙但令人遗憾的低估 systrace 系统上的 systrace 结果。

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

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

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

If you really want your code to be robust across a wide variety of Linux configurations I'd suggest that you consider the corner cases where someone may be using SELinux, or filesystem ACLs, or the "capabilities" features that have been in the Linux kernel since v. 2.2 or so. Your process might be running under some wrapper that has used SELinux, or some Linux capabilities library, such as libcap2 libcap-ng, or fscaps or elfcap via something more exotic like Niels Provos' wonderful and sadly under-appreciated systrace system.

All of these are ways that you code might be running as non-root and yet your process might have been delegated the necessary access to perform its work without EUID==0.

So I'd suggest that you consider writing your code more Pythonically, by wrapping operations that may fail due to permissions or other issues with exception handling code. If you're shelling out to perform various operations (e.g. using the subprocess module) you might offer to prefix all such calls with sudo (as a command line, environment, or .rc file option, for example). If it's being run interactively you can offer to re-execute any commands that raise permissions related exceptions using sudo (optionally only if you find sudo on the os.environ['PATH']).

Overall it's true that most Linux and UNIX systems still have most of their administration done by a 'root' privileged user. However, it's old school and we, as programmers, should try to support newer models. Trying your operations and letting the exception handling do its job allows your code to work under any system that transparently permits the operations you need, and being aware of and ready to use sudo is a nice touch (as it is, by far, the most widespread tool for controlled delegation of system privileges).

夏了南城 2024-09-08 00:33:58
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 运行,则 SUDO_UID 不可用。

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 is not available if script is not run with sudo.

私野 2024-09-08 00:33:58

回答问题的第二部分

(抱歉评论框太小)

Paul Hoffman,你是对的,我只解决了你的问题中涉及内在函数的一部分,但如果不能的话,它就不是一种有价值的脚本语言。 t 处理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

现在我们回到异常处理。我将拒绝对 subprocess 模块类似 Java 的过度通用性发表评论。

Answer to the second part of the question

(sorry the comment box was too small)

Paul Hoffman, you are correct, I only addressed one part of your question dealing with intrinsics, but it wouldn't be a worthy scripting language if it couldn't handle apt-get. The preferred library is a tad verbose but it does the job:

>>> 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'

But Popen is a generalized tool and can be wrapped for convenience:

$ 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

And now we're back to exception handling. I will decline to comment on the Java-like over-generality of the subprocess module.

无人问我粥可暖 2024-09-08 00:33:58

我的应用程序使用此代码:

import os
user = os.getenv("SUDO_USER")
if user is None:
    print "This program need 'sudo'"
    exit()

My app works with this code:

import os
user = os.getenv("SUDO_USER")
if user is None:
    print "This program need 'sudo'"
    exit()
格子衫的從容 2024-09-08 00:33:58

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

It all depends how portable you want you app to be. If you mean bussiness, the we have to assume that administrator account does not always equal 0. This means that checking for euid 0 is not enough. Problem is, there are situations where one command will behave as if you are root and next will fail with permission denied (think SELinux & co.). Therefore it's really better to fail gracefully and check for EPERM errno whenever it's appropriate.

清晰传感 2024-09-08 00:33:58

我们不需要把事情复杂化..

os.getuid() == 0:  # is root

We don't need to complicate things..

os.getuid() == 0:  # is root
土豪 2024-09-08 00:33:58

您可以使用此函数来检查:

#!/usr/bin/env python3
import os

def is_root() -> bool:
    if "posix" in os.name and os.geteuid() == 0:
        return True
    return False

参考:

此代码片段取自github.com/zulip/zulip
https://github.com/zulip/ zulip/blob/39c6a01c7493ba55277c31ba9034ebc05dcbd9c3/scripts/lib/zulip_tools.py#L545-L548

You can use this function to check:

#!/usr/bin/env python3
import os

def is_root() -> bool:
    if "posix" in os.name and os.geteuid() == 0:
        return True
    return False

Reference:

This code snippet was taken from github.com/zulip/zulip
https://github.com/zulip/zulip/blob/39c6a01c7493ba55277c31ba9034ebc05dcbd9c3/scripts/lib/zulip_tools.py#L545-L548

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文