我可以使用sudo
或su
作为另一个用户执行命令。通过与exec
结合,我可以用sudo
或su
替换当前进程,以及运行该命令的子进程。但我想用另一个用户运行的命令替换当前进程。我该怎么做?
使用sleep inf
作为命令进行测试,并使用someguy
作为用户进行测试:
exec su someguy -c 'sleep inf'
这给了我pstree
:
bash───su───sleep
和
exec sudo -u someguy sleep inf
给出
bash───sudo───sleep
在这两种情况下,我只想要sleep
命令,bash
作为父命令。
我希望我可以使用setuid()
和exec()
的某些序列从C中执行此操作。
答案 0 :(得分:7)
sudo sleep
和exec sudo sleep
之间的区别在于,在第二个命令中sudo进程替换了bash映像并在sleep退出时调用shell进程退出
pstree -p $$
bash(8765)───pstree(8943)
((sleep 1; pstree -p $$ )&); sudo -u user sleep 2
bash(8765)───sudo(8897)───sleep(8899)
((sleep 1; pstree -p $$ )&); exec sudo -u user sleep 2
sudo(8765)───sleep(8993)
然而,sudo
或su
分叉新流程的事实取决于设计及其实现(某些来源here)。
来自sudo手册页:
流程模型
当sudo运行命令时,它调用fork(2),如上所述设置执行环境,并在子进程中调用execve系统调用。主要的sudo 进程等待命令完成,然后将命令的退出状态传递给安全策略的关闭函数并退出。如果I / O日志插件是配置 - 如果安全策略明确请求它,则创建一个新的伪终端(“pty”),并使用第二个sudo进程在两者之间中继作业控制信号。 用户现有的pty和新的pty命令正在运行。这个额外的过程使得例如暂停和恢复命令成为可能。没有它,com- mand将在POSIX术语中称为“孤立进程组”,它不会接收任何作业控制信号。作为一种特殊情况,如果策略插件没有定义 关闭函数并且不需要pty,sudo将直接执行命令而不是先调用fork(2)。 sudoers策略插件只定义一个close函数 启用I / O日志记录时,需要pty,或者启用pam_session或pam_setcred选项。请注意,在sys-上默认启用pam_session和pam_setcred tems使用PAM。
答案 1 :(得分:5)
我不同意观察和结论。见下文:
我创建了两个shellcripts:
$ cat just_sudo.sh
#!/bin/bash
sudo sleep inf
$ cat exec_sudo.sh
#!/bin/bash
exec sudo sleep inf
所以,一个有一个exec,一个没有。如果我做pstree
来查看起始情况,我会得到:
$ pstree $$
bash───pstree
$ echo $$
17250
这给了我基线。接下来我启动了两个脚本:
$ bash just_sudo.sh &
[1] 1218
$ bash exec_sudo.sh &
[2] 1220
然后,pstree
给出:
$ pstree $$
bash─┬─bash───sleep
├─pstree
└─sleep
第一个是just_sudo
,第二个是exec_sudo
。两者都以root身份运行:
$ ps -ef | grep sleep
root 1219 1218 0 14:01 pts/4 00:00:00 sleep inf
root 1220 17250 0 14:01 pts/4 00:00:00 sleep inf
第一个是just_sudo
,第二个是exec_sudo
。您可以看到exec_sudo
中睡眠的父PID是从中启动脚本的交互式shell,PID是1220,这是我们在后台启动脚本时看到的PID。 / p>
如果您使用两个终端窗口而不将它放在后台,这也可以:
terminal 1 terminal 2
$ echo $$
16053 $ pstree 16053
bash
$ sudo sleep inf
$ pstree 16053
bash───sleep
^C
$ exec sudo sleep inf
$ pstree 16053
sleep
^C
( window is closed )
所以,在我的 linux系统上,行为并不像你建议的那样.subdo可能保留在进程树中的唯一方法是它是否在现有的tty中运行(所以没有exec),或者如果用伪终端调用它,例如exec sudoedit
。
答案 2 :(得分:2)
为此,您可以关闭所有 stdin , stdout 和 stderr ,或让它们指向其他位置。
试试这个:
su - someguy -c 'exec nohup sleep 60 >/tmp/sleep.log 2>/tmp/sleep.err <<<"" &'
注意:
su - someguy -c 'exec nohup sleep 60 &'
够了,
su - someguy -c 'exec sleep 60 >/tmp/sleep.log 2>/tmp/sleep.err <<<"" &'
也会工作。
考虑查看man nohup
注意2:在bash下,您可以使用:
su - someguy -c 'exec sleep 60 & disown -h'
...并阅读help disown
或man bash
。
su - someguy -c 'exec 0<&- ; exec 1>&- ; exec 2>&- ; exec sleep 60 &'
pstree $(ps -C sleep ho pid)
sleep
答案 3 :(得分:2)
我不确定是否可以使用sudo
或su
完成此操作。但您可以使用简单的c
程序轻松实现此目的。我将展示一个非常简单的硬编码命令和用户ID,但您可以随时根据自己的喜好自定义
<强> test.c的强>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
int runAs(int gid, int uid, char *command[]) {
setgid(gid);
setuid(uid);
char *args[]={"sleep","inf",NULL};
execvp(args[0],args);
}
int main(int argc, char *argv[] )
{
runAs(1000, 65534, argv);
return 0;
}
注意:在我的计算机上
的uid和gid1000
是vagrant
用户和组的uid / gid。65534
是nobody
用户和群组
<强> build.sh 强>
#!/bin/bash
sudo gcc test.c -o sosu
sudo chown root:root sosu
sudo chmod u+s sosu
现在是时候进行测试了
$ pstree $$ -p
bash(23251)───pstree(28627)
$ ./sosu
现在来自另一个终端
$ pstree -p 23251
bash(23251)───sleep(28687)
$ ps aux | grep [2]8687
nobody 28687 0.0 0.0 7288 700 pts/0 S+ 11:40 0:00 sleep inf
正如您所见,该过程以nobody
运行,其子项为bash