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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4598001/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 00:04:41  来源:igfitidea点击:

How do you find the original user through multiple sudo and su commands?

linuxbashunixsudosu

提问by evan

When running a script via sudo or su I want to get the original user. This should happen regardless of multiple sudoor suruns inside of each other and specifically sudo su -.

通过 sudo 或 su 运行脚本时,我想获取原始用户。这应该发生,无论多个sudo还是su在彼此内部运行,特别是sudo su -

采纳答案by evan

Results:

结果:

Use who am i | awk '{print $1}'OR lognameas no other methods are guaranteed.

使用who am i | awk '{print $1}'OR,logname因为不保证其他方法。

Logged in as self:

以自己的身份登录:

evan> echo $USER
evan
evan> echo $SUDO_USER

evan> echo $LOGNAME
evan
evan> whoami
evan
evan> who am i | awk '{print }'
evan
evan> logname
evan
evan>

Normal 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 }'
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 }'
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 }'
evan
tom$ logname
evan
tom$

回答by sam

How about using logname(1) to get the user's login name?

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

回答by tylerl

There's no perfectanswer. When you change user IDs, the original user ID is not usually preserved, so the information is lost. Some programs, such as lognameand who -mimplement a hack where they check to see which terminal is connected to stdin, and then check to see what user is logged in on that terminal.

没有完美的答案。更改用户 ID 时,通常不会保留原始用户 ID,因此信息会丢失。一些程序,例如lognamewho -m实现了一个hack,它们检查连接到哪个终端stdin,然后检查哪个用户登录到该终端。

This solution oftenworks, but isn't foolproof, and certainly shouldn't be considered secure. For example, imagine if whooutputs the following:

此解决方案通常有效,但并非万无一失,当然不应被视为安全。例如,想象一下如果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)

tomused suto get to root, and runs your program. If STDINis not redirected, then a program like lognamewill output tom. If it IS redirected (e.g. from a file) as so:

tom用于su获得root权限并运行您的程序。如果STDIN未重定向,则类似的程序logname将输出tom. 如果它被重定向(例如从文件),如下所示:

logname < /some/file

Then the result is "no login name", since the input isn't the terminal. More interestingly still, though, is the fact that the user could pose as a different logged in user. Since Joe is logged in on pts/1, Tom could pretend to be him by running

那么结果是“ no login name”,因为输入不是终端。然而,更有趣的是,用户可以伪装成不同的登录用户。由于 Joe 在 pts/1 上登录,Tom 可以通过运行来伪装成他

logname < /dev/pts1

Now, it says joeeven though tom is the one who ran the command. In other words, if you use this mechanism in any sort of security role, you're crazy.

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

回答by user1683793

This is a kshfunction I wrote on HP-UX. I don't know how it will work with Bashin Linux. The idea is that the sudoprocess is running as the original user and the child processes are the target user. By cycling back through parent processes, we can find the user of the original process.

这是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
}

I know the original question was from a long time ago but people (such as me) are still asking and this looked like a good place to put the solution.

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

回答by asdfghjkl

user1683793's findUser() function ported to bashand extended so it returns usernames stored in NSS libraries as well.

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"

回答by ULick

cycling back and giving a list of users

循环返回并提供用户列表

based on user1683793's answer

基于 user1683793 的回答

By exlcuding non-TTY processes, I skip root as the initiator of the login. I'm not sure if that may exlcude too much in some case

通过排除非 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
}

lognameor who am ididn't give me the desired answer, especially not in longer lists of su user1, su user2, su user3, ...

logname或者who am i没有给我想要的答案,尤其是在更长的su user1, su user2, su user3,列表中...

I know the original question was from a long time ago but people (such as me) are still asking and this looked like a good place to put the solution.

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

回答by simohe

Alternative to calling ps multiple times: do one pstree call

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

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

output (when logged in as even): (evan)

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

pstree arguments:

pstree 参数:

  • -l: long lines (not shortening)
  • -u: show when user changes as (userName)
  • -s $$: show parents of this process
  • -l:长行(不缩短)
  • -u:显示用户何时更改为(用户名)
  • -s $$:显示这个进程的父进程

Get the first user change (which is login) with grep -oand head.

获取与第一用户的变化(这是登录)grep -ohead

limitation:the command may not contain any braces ()(it does not normally)

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

回答by Grey Christoforo

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

That's the only thing that worked for me.

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