如何通过多个sudo和su命令找到原始用户?

时间:2011-01-04 20:17:13

标签: linux bash unix sudo su

当通过sudo或su运行脚本时,我想获得原始用户。无论多个sudosu在彼此内部运行,具体是sudo su -,都应该发生这种情况。

10 个答案:

答案 0 :(得分:123)

结果:

使用who am i | awk '{print $1}'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 - ;苏姆:

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$

答案 1 :(得分:13)

没有完美的答案。更改用户ID时,通常不会保留原始用户ID,因此信息会丢失。某些程序(例如lognamewho -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可以通过运行

假装成为他
logname < /dev/pts1

现在,它说joe即使汤姆是运行命令的人。换句话说,如果你在任何安全角色中使用这种机制,那你就疯了。

答案 2 :(得分:8)

这是我在HP-UX上编写的ksh函数。我不知道它在Linux中如何与Bash一起使用。我们的想法是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
}

我知道最初的问题是很久以前的问题,但人们(比如我)仍然在问,这看起来是一个提出解决方案的好地方。

答案 3 :(得分:5)

如何使用logname(1)获取用户的登录名?

答案 4 :(得分:3)

THIS_USER=`pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g'`

那是唯一对我有用的东西。

答案 5 :(得分:2)

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"

答案 6 :(得分:2)

骑车回来并提供用户列表

基于user1683793的回答

通过驱逐非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
}

lognamewho am i没有给出我想要的答案,特别是在su user1su user2su user3,{{1 }}

我知道最初的问题是很久以前的问题,但人们(比如我)仍然在问,这看起来是一个提出解决方案的好地方。

答案 7 :(得分:1)

多次调用ps的替代方法:执行一次pstree调用

pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1

输出(以偶数方式登录时):(evan)

pstree论点:

  • -l:长线(不缩短)
  • -u:当用户更改为(userName)
  • 时显示
  • -s $$:显示此过程的父母

使用grep -ohead获取第一次用户更改(即登录)。

限制:该命令可能不包含任何大括号()(通常不包含)

答案 8 :(得分:1)

您可以从控制终端的所有者那里获得。这是“whowasi”实用程序的旧 C 代码:http://sivann.gr/software/whowasi.c

答案 9 :(得分:0)

在运行systemd-logind的系统上,systemd API provides this information。如果要从Shell脚本访问此信息,则需要使用以下内容:

$ loginctl session-status \
  | (read session_id ignored; loginctl show-session -p User $session_id)
User=1000

loginctlsession-statusshow-ssession系统命令具有不带参数的不同行为:session-status使用当前会话,而show-ssession使用管理器。但是,使用show-session最好用于脚本,因为它的机器可读输出。这就是为什么需要两次调用loginctl的原因。