【问题标题】:How to jump between users, including root, in a perlscript?如何在 perlscript 中在用户(包括 root)之间跳转?
【发布时间】:2022-11-11 01:03:09
【问题描述】:

这个问题已在此处以多种形式提出。我再问一次,因为所有这些问题都有太多细节。因此,答案都归结为如何解决这些特定问题,而无需在用户之间跳转。
这就是我为什么将其作为一个新问题发布(并在下面立即回答),以供其他有此问题的人使用。

假设您有一个以 root 身份运行的 perl 脚本,您首先要以 root 身份运行,然后以普通用户身份运行,然后再次以 root 身份运行。

例如:

#!/usr/bin/perl
#Problem 1: Make sure to start as root
system("whoami");
#Problem 2: Become your regular user
system("whoami");
#Problem 3: Become root again
system("whoami);

应更改为显示:

root
your_username
root

【问题讨论】:

  • 你想做什么?大多数服务器进程以 root 身份启动,以 root 身份执行它们需要执行的操作(例如,绑定到特权端口),然后删除 root 特权。这样做是出于安全原因 --- 如果代码中存在错误,如果进程在有限的服务帐户下运行,而不是 root,则损害是有限的。
  • 就我而言,它是我在 linux live 媒体上运行的脚本,它在硬盘上创建了一个完全定制的发行版。有些事情我可以作为 root 完成,有些事情应该作为另一个用户完成。其他解决方案是可能的(例如,使用多个脚本并使用 system("sudo -u someuser otherscript.pl)"); 调用它们,但对于我的用例 1 脚本是最好的。
  • 如果我曾经在系统中看到某些东西试图做这样的事情,我会让他们想出一种不同的方法来做这件事。
  • 其他问题的链接?很好奇这里发生了什么。
  • @briandfoy 我必须同意,对于大多数问题,存在更好/更安全的解决方案。但对于我的用例来说,这是一个很好的方法。作为其他问题(GIYF)的答案,通常很糟糕(因为他们正在使用“真实”系统)

标签: perl sudo su setuid


【解决方案1】:

这是我能想到的最好的解决方案。

如果您想以 root 身份启动,请成为普通用户并再次成为 root:

#!/usr/bin/perl
use POSIX qw/setuid waitpid/;
exec("sudo", $0, @ARGV) unless($< == 0);  #Restart the program as root if you are a regular user
system("whoami");
my $pid = fork;  #create a extra copy of the program
if($pid == 0) {
  #This block will contain code that should run as a regular user
  setuid(1000);  #So switch to that user (e.g. the one with UID 1000)
  system("whoami");
  exit;  #make sure the child stops running once the task for the regular user are done
}
#Everything after this will run in the parent where we are still root
waitpid($pid, 0); #wait until the code of the child has finished
system("whoami");

以普通用户身份开始时,最好确保父母保持普通用户身份,而孩子成为 root 用户。你可以这样做:

#!/usr/bin/perl
use POSIX qw/setuid waitpid/;
unless($< == 0) {
  #regular user code, this is the first code that will run
  system("whoami");
  #now fork, let the child become root and let the parent wait for the child
  my $pid = fork;
  exec("sudo", $0, @ARGV) if($pid == 0);
  waitpid($pid, 0);
  #continue with regular user code, this is the 3th part that will run
  system("whoami");
  exit; #the end of the program has been reached, exit or we would continue with code meant for root
}
#code for root, this is the 2nd part that will run
system("whoami");
  
  

【讨论】:

  • $^X, '--', $0, @ARGV 会比 $0, @ARGV 更安全可靠
  • POSIX::WUNTRACED 而不是 0 传递给 waitpid 似乎是错误的。你真的是想在孩子离开之前停止等待吗?
  • 提示:无需从 POSIX.pm 导入 waitpid。它只是调用内置的waitpid,如果你没有从 POSIX.pm 导入同名的子组件,它就会被调用。
  • @ikegami关于你的第一条评论:这也可以,但我不明白为什么它会更安全/可靠,你已经指定了你在脚本的shebang中使用的perl解释器。
  • @ikegami关于您的第二条评论:我确实想等到孩子退出,应该是这样。在孩子的system("whoami"); 之前放一个sleep 10; 以检查它。不过好像0也有同样的效果,谢谢 不知道这个。
最近更新 更多