複数のsudoおよびsuコマンドを使用して元のユーザーをどのように見つけますか?


93

sudoまたはsuを介してスクリプトを実行する場合、元のユーザーを取得したいと思います。これは、複数に関係なく発生するsudosu、相互に実行される必要がありますsudo su -

回答:


136

結果:

他の方法は保証されていないため、who am i | awk '{print $1}'ORlognameを使用してください。

自己としてログイン:

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
その場合は、次を使用できますwho | awk '{print $1}'
SiegeX 2011年

2
...ログインしているのがあなただけの場合(そしてそれは一度だけです)。
追って通知があるまで一時停止します。

9
必要なのは2つの引数だけです:はとwho am i同じwho smells badです。また、STDINがTTYに関連付けられている場合にのみ機能します。したがって、実行するecho "hello" | who am iと、単に機能しません。
tylerl 2011

1
あなたは実行されないでしょうecho "hello" | who am i、あなたのスクリプトは搭載していない環境で実行されていない限り、通常は。次にwho am i、読み取り不可能なstdinに何らかの問題があるために機能していないエラーが表示される場合があります。その場合、who am istdin要件を満たすために、必死になってデータをパイプで接続してみてください。tylerlは、彼がすでにその道を進んでいることを指摘しているだけであり、stdinは読み取り可能であり、TTYに関連付けられている必要があるため、パイプは機能しません。
エドウィンバック

4
@even Trueですが、必要な構成をできるだけ少なくしたいのでlogname、現在使用who am iしています。これは、実際には機能しますが、機能しない場合もあります。
Bart van Heukelom 2011

18

完璧な答えはありません。ユーザー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)

tomsuルートに到達し、プログラムを実行するために使用されます。STDINがリダイレクトされない場合、のようなプログラムはlognameを出力しますtom。それが(例えばファイルから)リダイレクトされた場合:

logname < /some/file

no login name入力が端末ではないため、結果は「」になります。ただし、さらに興味深いのは、ユーザーが別のログインユーザーを装う可能性があるという事実です。ジョーはpts / 1にログインしているので、トムは走って彼のふりをすることができます

logname < /dev/pts1

さて、joeトムがコマンドを実行したのに、それは言います。言い換えれば、このメカニズムを何らかのセキュリティの役割で使用すると、頭がおかしくなります。


2
スクリプトを自分で実行している場合(使用されているコマンドから明らかなように)、セキュリティは問題ではありません。もしそうなら、彼らはsudoアクセスも持っているので、あなたはもっと多くの問題を抱えています。その人は、スクリプトをコピーして、好きなように変更することができます。これは、スクリプトで使用するためにログインした名前を取得する方法にすぎません。それとも私はあなたが言っていることについて何かが欠けていますか?
evan 2011

1
@evan:sudoアクセスがあるからといって、ファイルを上書きできるわけではありません。
Flimzy 2013年

@Flimzyどのような場合、rootにはファイルを上書きする機能がありませんか?
evan 2013年

1
@evan:sudoアクセスでシェルや、ファイルを上書きできるその他のコマンドにアクセスできない場合は、明らかに。
Flimzy 2013年

@evan sudoアクセスは、常に(ほとんどの管理者の場合はそうではないはずですが)完全なルートアクセスであるとは限りません。これは、構成可能な制限付き実行コンテキストのセットです。
DylanYoung

8

これはksh私がHP-UXで書いた関数です。BashLinuxでどのように機能するかわかりません。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
}

元の質問はずっと前のものだったと思いますが、(私のような)人々はまだ質問をしていて、これは解決策を置くのに良い場所のように見えました。


5

logname(1)を使用してユーザーのログイン名を取得するのはどうですか?


logname(1)動作しませんが、lognameない-上記の結果を追加
エヴァン

もともと試し$LOGNAMEたのですが、うまくいきませんでした。上記の結果にも追加されました。
evan 2011年

lognameまだ端末を必要と?私のテストでは、常に合格です。(多分私は何か間違っているかもしれません。)私はcoreutils8.26でLinuxを実行しています。
simohe

私のログ名は常に戻ります"LOGNAME:なしログイン名"に(GNUのcoreutilsの)8.28(Ubuntuの18.04.2)
sondra.kinsey


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"

参考:この関数(およびそれが基づいていた関数)は、互いにネストされたsudoによって生成された複数のシェルを循環しません。
asdfghjkl 2013

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
}

lognameまたはwho am i特にないの長いリストに、私に必要な答えを与えていませんsu user1su user2su user3...

元の質問はずっと前のものだったと思いますが、(私のような)人々はまだ質問をしていて、これは解決策を置くのに良い場所のように見えました。


2

psを複数回呼び出す代わりに:1回のpstree呼び出しを行う

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

出力(偶数としてログインした場合): (evan)

pstree引数:

  • -l:長い行(短縮しない)
  • -u:ユーザーが変更されたときに(userName)として表示します
  • -s $$:このプロセスの親を表示します

grep -oおよびを使用して最初のユーザー変更(ログイン)を取得しますhead

制限:コマンドには中括弧を含める()ことはできません(通常は含まれません)


pstree -lu -s $$ | head -n1 | sed -e's / [^(] *(([^)] *))。* / \ 1 / '
Alexx Roche 2018

0

を実行しているシステムsystemd-logindでは、systemdAPIがこの情報を提供します。シェルスクリプトからこの情報にアクセスする場合は、次のようなものを使用する必要があります。

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

session-statusおよびshow-ssessionシステムコマンドは、loginctl引数なしで動作が異なります。session-status現在のセッションをshow-ssession使用しますが、マネージャを使用します。ただし、show-sessionスクリプトの使用には、機械可読な出力があるため、使用することをお勧めします。これが、の2回の呼び出しloginctlが必要な理由です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.