如何通过多个 sudo 和 su 命令找到原始用户?
- 2024-10-24 08:50:00
- admin 原创
- 76
问题描述:
当通过 sudo 或 su 运行脚本时,我想获取原始用户。无论多个sudo
或su
彼此内部运行,特别是,这都应该发生sudo su -
。
解决方案 1:
结果:
使用who am i | awk '{print $1}'
OR,logname
因为没有其他方法可以保证。
以自我身份登录:
evan> echo $USER
evan
evan> echo $SUDO_USER
evan> echo $LOGNAME
evan
evan> whoami
evan
evan> who am i | awk '{print $1}'
evan
evan> logname
evan
evan>
正常 sudo:
evan> sudo -s
root> echo $USER
root
root> echo $SUDO_USER
evan
root> echo $LOGNAME
root
root> whoami
root
root> who am i | awk '{print $1}'
evan
root> logname
evan
root>
sudo su-:
evan> sudo su -
[root ]# echo $USER
root
[root ]# echo $SUDO_USER
[root ]# echo $LOGNAME
root
[root ]# whoami
root
[root ]# who am i | awk '{print $1}'
evan
[root ]# logname
evan
[root ]#
sudo su -; su tom :
evan> sudo su -
[root ]# su tom
tom$ echo $USER
tom
tom$ echo $SUDO_USER
tom$ echo $LOGNAME
tom
tom$ whoami
tom
tom$ who am i | awk '{print $1}'
evan
tom$ logname
evan
tom$
解决方案 2:
没有完美的答案。更改用户 ID 时,通常不会保留原始用户 ID,因此信息会丢失。某些程序(例如logname
和)who -m
实施了一种黑客攻击,它们会检查哪个终端连接到stdin
,然后检查哪个用户登录了该终端。
这种解决方案通常有效,但并非万无一失,当然不应被视为安全。例如,想象一下如果who
输出以下内容:
tom pts/0 2011-07-03 19:18 (1.2.3.4)
joe pts/1 2011-07-03 19:10 (5.6.7.8)
tom
用于su
获取 root 权限,并运行您的程序。如果STDIN
没有重定向,则类似这样的程序logname
将输出tom
。如果它被重定向(例如从文件重定向),如下所示:
logname < /some/file
那么结果就是“ no login name
”,因为输入不是终端。不过,更有趣的是,用户可以冒充其他登录用户。由于 Joe 登录的是 pts/1,Tom 可以通过运行以下命令假装是 Joe:
logname < /dev/pts1
现在,它表示,joe
尽管 tom 是运行该命令的人。换句话说,如果你在任何类型的安全角色中使用这种机制,那你就疯了。
解决方案 3:
这是ksh
我在 HP-UX 上编写的一个函数。我不知道它Bash
在 Linux 中会如何工作。其思路是,进程sudo
以原始用户身份运行,子进程是目标用户。通过循环返回父进程,我们可以找到原始进程的用户。
#
# The options of ps require UNIX_STD=2003. I am setting it
# in a subshell to avoid having it pollute the parent's namespace.
#
function findUser
{
thisPID=$$
origUser=$(whoami)
thisUser=$origUser
while [ "$thisUser" = "$origUser" ]
do
( export UNIX_STD=2003; ps -p$thisPID -ouser,ppid,pid,comm ) | grep $thisPID | read thisUser myPPid myPid myComm
thisPID=$myPPid
done
if [ "$thisUser" = "root" ]
then
thisUser=$origUser
fi
if [ "$#" -gt "0" ]
then
echo $origUser--$thisUser--$myComm
else
echo $thisUser
fi
return 0
}
我知道最初的问题是很久以前的,但人们(比如我)仍在询问,这看起来是一个提出解决方案的好地方。
解决方案 4:
如果我们可以将进程生成层次结构排列成一棵树,那么我们就可以在该树的根部查找生成该进程的用户。幸运的是,该pstree
命令为我们完成了这一安排。
pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g'
pstree
将正在运行的进程显示为一棵树。树的根是 pid,这里给出为$$
,在 bash 中,它将扩展为当前 shell 的进程 id。因此,该命令的第一部分列出了当前 shell 的所有祖先进程,格式有些奇怪。该命令的其余部分将丢弃这种奇怪的格式,以选出拥有最古老祖先进程的用户的名称。
与其他基于的答案相比,这里的主要改进pstree
是输出中不包含多余的括号。
解决方案 5:
如何使用 logname(1) 获取用户的登录名?
解决方案 6:
在运行 的系统上systemd-logind
,systemd API 提供了此信息。如果您想从 shell 脚本访问此信息,需要使用类似这样的脚本:
$ loginctl session-status \n | (read session_id ignored; loginctl show-session -p User $session_id)
User=1000
session-status
和 的show-ssession
系统命令在loginctl
没有参数的情况下有不同的行为:session-status
使用当前会话,但show-ssession
使用管理器。但是,使用show-session
更适合脚本使用,因为它具有机器可读的输出。这就是为什么loginctl
需要两次调用 的原因。
解决方案 7:
user1683793 的 findUser() 函数被移植bash
并扩展,因此它也能返回存储在 NSS 库中的用户名。
#!/bin/bash
function findUser() {
thisPID=$$
origUser=$(whoami)
thisUser=$origUser
while [ "$thisUser" = "$origUser" ]
do
ARR=($(ps h -p$thisPID -ouser,ppid;))
thisUser="${ARR[0]}"
myPPid="${ARR[1]}"
thisPID=$myPPid
done
getent passwd "$thisUser" | cut -d: -f1
}
user=$(findUser)
echo "logged in: $user"
解决方案 8:
返回并提供用户列表
根据用户 1683793 的回答
通过排除非 TTY 进程,我跳过了 root 作为登录发起者。我不确定在某些情况下这是否会排除太多
#!/bin/ksh
function findUserList
{
typeset userList prevUser thisPID thisUser myPPid myPid myTTY myComm
thisPID=$$ # starting with this process-ID
while [ "$thisPID" != 1 ] # and cycling back to the origin
do
( ps -p$thisPID -ouser,ppid,pid,tty,comm ) | grep $thisPID | read thisUser myPPid myPid myTTY myComm
thisPID=$myPPid
[[ $myComm =~ ^su ]] && continue # su is always run by root -> skip it
[[ $myTTY == '?' ]] && continue # skip what is running somewhere in the background (without a terminal)
if [[ $prevUser != $thisUser ]]; then # we only want the change of user
prevUser="$thisUser" # keep the user for comparing
userList="${userList:+$userList }$thisUser" # and add the new user to the list
fi
#print "$thisPID=$thisUser: $userList -> $thisUser -> $myComm " >&2
done
print "$userList"
return 0
}
logname
或者who am i
没有给我想要的答案,特别是在较长的列表中su user1
,,,su user2
`su user3`...
我知道最初的问题是很久以前的,但人们(比如我)仍在询问,这看起来是一个提出解决方案的好地方。
解决方案 9:
多次调用 ps 的替代方法:执行一次 pstree 调用
pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1
输出(以偶数身份登录时):(evan)
pstree 参数:
-l:长行(不缩短)
-u:显示用户何时更改为(用户名)
-s $$:显示此进程的父进程
grep -o
使用和获取第一个用户变更(即登录)head
。
限制:命令可能不包含任何括号()
(通常不包含)
解决方案 10:
您可以从控制终端的所有者处获取它。这是“whowasi”实用程序的旧 C 代码: http: //sivann.gr/software/whowasi.c
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件