在 python 中以超级用户身份打开文件

发布于 2024-12-03 16:05:46 字数 118 浏览 0 评论 0 原文

我必须打开一个系统文件并从中读取。该文件通常只能由root(超级用户)读取。我有办法向用户询问超级用户密码。我想使用此凭据打开文件并从中读取文件,而无需让整个程序作为超级用户进程运行。有没有办法以多平台的方式实现这一目标?

I have to open a system file and read from it. This file is usually only readable by root (the super user). I have a way to ask the user for the superuser password. I would like to use this credentials to open the file and read from it without having my entire program running as a superuser process. Is there a way to achieve this in a multiplatform way?

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

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

发布评论

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

评论(4

堇年纸鸢 2024-12-10 16:05:46

由于权限在类 Unix 系统和 Windows 上的工作方式完全不同,因此您将需要具有特定于平台的代码。在任何情况下,您都需要将程序分解为两个单独的程序,其中一个以提升的权限运行,另一个以标准/降低的权限运行。

在类 Unix 系统(包括 Linux 和 Mac OS X)中,以提升权限运行的可执行文件应该执行以下操作:

  1. 假设您以 root 身份运行并打开文件进行读取。由于您提到该文件非常大,因此您实际上并没有读取整个文件,而只是保留一个打开的文件描述符。如果打开失败,则打印错误消息并退出。
  2. 使用 setreuid(2)setregid(2) 将您的用户 ID 和组 ID 设置回非特权用户。
  3. 使用 exec(3) 函数之一来执行非特权可执行文件。
  4. 如果您想在不使用 sudo 的情况下运行该程序,请使其归 root 所有,并使用 chown root the-program 将其设为设置用户 ID 可执行文件; chmod +s 程序。

非特权程序现在将以普通权限运行,但当它启动时,它将有一个打开的文件描述符(文件描述符#3),可用于从特殊文件中读取。

对于 Windows,它类似但略有不同:

  1. 假设您以 root 身份运行并使用 CreateFile。不要使用默认安全属性 - 创建一个 SECURITY_ATTRIBUTES 结构,并将 bInheritHandle 设置为 TRUE,以便子进程继承该句柄。如果打开文件失败,则打印错误消息并退出。
  2. 使用 CreateProcess 启动您的子进程。在命令行中传入上面的句柄(例如打印为数值);您还可以使用共享内存区域,但这对于这个问题来说是麻烦而不值得。
  3. 使用 requireAdministrator 在此可执行文件中嵌入清单设置为true。执行此操作后,当您运行该程序时,您将收到 UAC 提示,询问您是否允许该程序进行更改。

然后,子进程通过解析命令行来获取继承的句柄,然后它可以根据需要读取数据。

这种方法的一个问题是,当您继承句柄时,必须使用低级系统调用(Unix 上的 read(2),Windows 上的 ReadFile)来从中读取 - 您不能使用 C 的 fread(3) 或 C++ 的 iostream 等高级函数(好吧,Unix 有 fdopen(3) ,但没有等效的据我所知,在 Windows 上)。

我相信您现在已经注意到,上面的所有内容都是用 C 语言编写的。在 Unix 中,这可以非常直接地转换为 Python,因为 os 模块 有很多好东西,例如 setreuidexec*fdopen 。在 Windows 上,您也许可以使用 ctypes 模块和/或 Pywin32,但坚持使用 C 可能更容易。

Since privileges work completely differently on Unix-like systems and Windows, you're going to need to have platform-specific code. In any case, you'll need to break up your program into two separate programs, one of which runs with elevated permissions and the other of which runs with standard/reduced permissions.

In Unix-like systems (including Linux and Mac OS X), the executable that runs with elevated permissions should do this:

  1. Assume you're running as root and open the file for reading. Since you mentioned that the file is very large, you don't actually read the whole file in, you just keep an open file descriptor. If opening it fails, print an error message and exit.
  2. Use setreuid(2) and setregid(2) to set your user ID and group ID back to an unprivileged user.
  3. Use one of the exec(3) functions to execute the unprivileged executable.
  4. If you want to make it so that you can run this program without using sudo, then make it owned by root and make it a set-user-ID executable with chown root the-program; chmod +s the-program.

The unprivileged program will now be run with normal permissions, but when it starts up, it will have an open file descriptor (file descriptor #3) that can be used to read from your special file.

For Windows, it's similar but slightly different:

  1. Assume you're running as root and open the file for reading using CreateFile. Do not use default security attributes -- create a SECURITY_ATTRIBUTES structure with bInheritHandle set to TRUE so that the handle will be inherited by child processes. If opening the file failed, print an error message and exit.
  2. Use CreateProcess to launch your child process. Pass in the handle above on the command line (e.g. printed as a numerical value); you could also use a shared memory region, but that's more trouble than it's worth for this problem.
  3. Embed a manifest in this executable with requireAdministrator set to true. After you do this, when you run the program, you'll get a UAC prompt asking you if you want to allow the program to makes changes.

The child process then does grabs the inherited handle by parsing the command line, and it can then read in the data as it pleases.

One problem with this approach is that when you inherit a handle, you have to use the low-level system calls (read(2) on Unix, ReadFile on Windows) to read from it -- you can't use higher-level functions like C's fread(3) or C++'s iostreams (ok, Unix has fdopen(3), but there's no equivalent on Windows as far as I'm aware).

As I'm sure you've noticed by now, everything above has been in C. In Unix, this translates pretty straightforwardly into Python, since the os module has lots of goodies like setreuid, exec*, and fdopen. On Windows, you might be able to do some of this stuff with the ctypes module and/or Pywin32, but it's probably easier to stick with C.

旧城烟雨 2024-12-10 16:05:46

您正在寻找的称为权限升级,这在很大程度上取决于您所运行的平台。一般来说,您的程序必须做的是以超级用户身份运行一部分。例如,在 UNIX 系统上,您可以使用 sudo 来读取文件的内容。

但正如前面提到的,这实际上取决于您运行的系统。

What you're looking for is called privilege escalation, and it very much depends on the platform you're running on. In general, what your program would have to do is run a portion as the superuser. On unix systems, for instance, you might be able to use sudo to read the contents of the file.

But as mentioned, this really depends on what system you're running on.

最美不过初阳 2024-12-10 16:05:46

我会把这个程序分成两部分。

  1. 处理打开文件并访问内容。它可以假设它是以所需的权限启动的。
  2. 其他不需要特殊权限的一切。

放置一个配置条目,描述如何执行子处理需要额外权限的命令。 IE。

access_special_file:sudo access_special_file

access_special_file:runas /user:AccountWithPrivs access_special_file

这将一些用于权限升级的系统细节卸载到系统 shell,其中可能有更方便的方法来获取所需的权限。

I would split the program in two.

  1. Handles opening the file and accessing the contents. It can assume it's started with the privileges it needs.
  2. Everything else that doesn't require special privileges.

Put a config entry which describes how to exec or subprocess the command that requires extra privileges. ie.

access_special_file: sudo access_special_file

or

access_special_file: runas /user:AccountWithPrivs access_special_file

This offloads some of the system specifics for privilege escalation to the system shell where there may be more convenient ways of gaining the permissions you need.

不知所踪 2024-12-10 16:05:46

在 Linux 上,这是一个小问题,正如 @ViktorKerkez 所示。这就是我传输 WiFi 密码文件的方式(只能由 root/sudo 读取):

import subprocess
import sys

# substitute your Windoze/DOS/PowerlessShell command here:
cat_wifi_pws = 'sudo cat /etc/NetworkManager/system-connections/*'

process = subprocess.Popen(cat_wifi_pws, stdout=subprocess.PIPE, shell=True)
# read one line at a time, as it becomes available
for line in iter(process.stdout.readline, ''):
    sys.stdout.write(line)

当然,这会提示您输入 sudo 密码。如果您使用的系统有 gksudo 并且您更喜欢对话框,则可以使用 gksudo。作为奖励,如果您在 /etc/sudoers 中有一个不错的 timeout_default,并且您最近在启动 python 解释器的同一个 shell 中运行了 sudo,那么您就赢了根本不需要输入密码。

On linux it's a cynch, as @ViktorKerkez showed. This is how I streamed my WiFi passwords files (readable only by root/sudo):

import subprocess
import sys

# substitute your Windoze/DOS/PowerlessShell command here:
cat_wifi_pws = 'sudo cat /etc/NetworkManager/system-connections/*'

process = subprocess.Popen(cat_wifi_pws, stdout=subprocess.PIPE, shell=True)
# read one line at a time, as it becomes available
for line in iter(process.stdout.readline, ''):
    sys.stdout.write(line)

Of course this will prompt you for your sudo password. And you can use gksudo if you're on a system that has it and you prefer dialog boxes. As a bonus, if you have a decent timeout_default in /etc/sudoers, and you've recently run sudo in the same shell where you launched the python interpreter, you won't have to enter a password at all.

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