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

发布于 2024-10-10 05:05:12 字数 121 浏览 10 评论 0原文

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

謌踐踏愛綪 2024-10-17 05:05:12

结果:

使用我是谁| awk '{print $1}'logname 因为不保证其他方法。

以 self 身份登录:

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$

Results:

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

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 $1}'
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 $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$
哭泣的笑容 2024-10-17 05:05:12

没有完美的答案。当您更改用户 ID 时,通常不会保留原始用户 ID,因此信息会丢失。一些程序,例如 lognamewho -m 实施了一种 hack,它们检查哪个终端连接到 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

那么结果是“无登录名”,因为输入不是终端。但更有趣的是,用户可以冒充不同的登录用户。由于 Joe 在 pts/1 上登录,Tom 可以通过运行

logname < /dev/pts1

Now 来假装是他,它会显示 joe,即使 Tom 是运行该命令的人。换句话说,如果您在任何类型的安全角色中使用此机制,您就疯了。

There's no perfect answer. When you change user IDs, the original user ID is not usually preserved, so the information is lost. Some programs, such as logname and who -m implement 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.

This solution often works, but isn't foolproof, and certainly shouldn't be considered secure. For example, imagine if who outputs the following:

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 used su to get to root, and runs your program. If STDIN is not redirected, then a program like logname will output tom. If it IS redirected (e.g. from a file) as so:

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

logname < /dev/pts1

Now, it says joe even 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.

深者入戏 2024-10-17 05:05:12

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

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

This is a ksh function I wrote on HP-UX. I don't know how it will work with Bash in Linux. The idea is that the sudo process 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.

#
# 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.

秋凉 2024-10-17 05:05:12

如果我们可以将进程生成层次结构排列成一棵树,那么我们就可以在该树的根部查找生成进程的用户。幸运的是,pstree 命令为我们做了这样的安排。

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

pstree 将正在运行的进程显示为树。该树以 pid 为根,此处给出为 $$,它在 bash 中扩展为当前 shell 的进程 id。因此,命令的第一部分列出了当前 shell 的所有祖先进程,并带有一些有趣的格式。该命令的其余部分放弃了有趣的格式,以挑选出拥有最旧祖先进程的用户的名称。

与其他基于 pstree 的答案相比,主要改进是输出中不包含无关的括号。

If we could arrange the process spawn hierarchy into a tree, then we could look for the user who spawned the process at the root of that tree. Luckily the pstree command does that arrangement for us.

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

pstree shows running processes as a tree. The tree is rooted at a pid, here given as $$, which in bash expands to the process id of the current shell. So the first part of the command lists all the ancestor processes of the current shell with some funny formatting. The rest of the command discards the funny formatting to pick out the name of the user that owns the oldest ancestor process.

The main improvement over the other pstree-based answer here is that extraneous parentheses are not included in the output.

胡渣熟男 2024-10-17 05:05:12

使用 logname(1) 获取用户的登录名怎么样?

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

听风念你 2024-10-17 05:05:12

在运行 systemd-logind 的系统上,systemd API 提供此信息。如果您想从 shell 脚本访问此信息,需要使用如下内容:

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

loginctl 在没有参数的情况下具有不同的行为:session-status< /code> 使用当前会话,但 show-ssession 使用管理器。但是,由于其机器可读的输出,使用 show-session 更适合脚本使用。这就是需要两次调用 loginctl 的原因。

On systems running systemd-logind, the systemd API provides this information. If you want to access this information from a shell script, need to use something like this:

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

The session-status and show-ssession system commands of loginctl have different behavior without arguments: session-status uses the current session, but show-ssession uses the manager. However, using show-session is preferable for script use due to its machine-readable output. This is why two invocations of loginctl are needed.

樱娆 2024-10-17 05:05:12

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"

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

#!/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"
揽月 2024-10-17 05:05:12

给出用户列表

循环返回并根据 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 user1, su user2, su user3, ...

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

cycling back and giving a list of users

based on user1683793's answer

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

#!/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 or who am i didn't give me the desired answer, especially not in longer lists of 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.

大海や 2024-10-17 05:05:12

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

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

输出(以 Even 身份登录时):(evan)

pstree 参数:

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

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

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

Alternative to calling ps multiple times: do one pstree call

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

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

pstree arguments:

  • -l: long lines (not shortening)
  • -u: show when user changes as (userName)
  • -s $$: show parents of this process

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

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

人间不值得 2024-10-17 05:05:12

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

You can get it from the owner of the controlling terminal. Here's an old C code for a "whowasi" utility: http://sivann.gr/software/whowasi.c

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文