Wie finden Sie den ursprünglichen Benutzer über mehrere sudo- und su-Befehle?

89

Wenn ich ein Skript über sudo oder su ausführe, möchte ich den ursprünglichen Benutzer erhalten. Dies sollte unabhängig von mehreren sudooder suineinander und spezifisch geschehen sudo su -.

evan
quelle

Antworten:

132

Ergebnisse:

Verwenden Sie who am i | awk '{print $1}'OR, lognameda keine anderen Methoden garantiert sind.

Als Selbst angemeldet:

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>

Normaler 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$
evan
quelle
In diesem Fall können Sie einfachwho | awk '{print $1}'
SiegeX
2
... wenn Sie der einzige sind, der angemeldet ist (und es ist nur einmal).
Bis auf weiteres angehalten.
9
Alles was Sie brauchen sind 2 Argumente: who am iist das gleiche wie who smells bad. Außerdem funktioniert es nur, wenn STDINes einem TTY zugeordnet ist. Wenn Sie es ausführen echo "hello" | who am i, funktioniert es einfach nicht.
Tyler
1
Sie würden nicht echo "hello" | who am inormal ausgeführt, es sei denn, Ihr Skript wird in einer Umgebung ausgeführt, in der kein Terminal vorhanden ist. Dann sehen Sie möglicherweise den Fehler, der who am inicht funktioniert, weil es ein Problem mit dem nicht lesbaren Standard gibt. In diesem Fall können Sie versuchen, Daten who am iaus Verzweiflung weiterzuleiten, um die Standardanforderungen zu erfüllen. tylerl bemerkt nur, dass er diesen weg bereits eingeschlagen hat und die Pipe nicht funktioniert, da stdin sowohl lesbar als auch mit einem TTY verknüpft sein muss.
Edwin Buck
3
@even Stimmt, obwohl ich möchte, dass so wenig Konfiguration wie möglich erforderlich ist, verwende ich lognamejetzt, was, wie sich herausstellt, funktioniert, wo who am inicht.
Bart van Heukelom
17

Es gibt keine perfekte Antwort. Wenn Sie Benutzer-IDs ändern, wird die ursprüngliche Benutzer-ID normalerweise nicht beibehalten, sodass die Informationen verloren gehen. Einige Programme, wie z. B. lognameund who -mimplementieren einen Hack, bei dem überprüft wird, mit welchem ​​Terminal verbunden ist stdin, und anschließend überprüft wird, welcher Benutzer an diesem Terminal angemeldet ist.

Diese Lösung funktioniert oft , ist aber nicht kinderleicht und sollte auf keinen Fall als sicher angesehen werden. Stellen Sie sich zum Beispiel vor, Sie geben whoFolgendes aus:

tom     pts/0        2011-07-03 19:18 (1.2.3.4)
joe     pts/1        2011-07-03 19:10 (5.6.7.8)

tomwird verwendet su, um zu root zu gelangen, und führt Ihr Programm aus. Wenn STDINnicht umgeleitet wird, wird ein Programm wie lognameausgegeben tom. Wenn es wie folgt umgeleitet wird (z. B. aus einer Datei):

logname < /some/file

Dann ist das Ergebnis " no login name", da der Eingang nicht das Terminal ist. Interessanter ist jedoch die Tatsache, dass sich der Benutzer als ein anderer angemeldeter Benutzer ausgeben könnte. Da Joe bei pts / 1 angemeldet ist, könnte Tom vorgeben, er zu sein, indem er rennt

logname < /dev/pts1

Jetzt heißt es, joeobwohl Tom derjenige ist, der den Befehl ausgeführt hat. Mit anderen Worten, wenn Sie diesen Mechanismus in irgendeiner Sicherheitsrolle verwenden, sind Sie verrückt.

tylerl
quelle
2
Wenn Sie das Skript selbst ausführen (wie aus den verwendeten Befehlen hervorgeht), ist Sicherheit nicht das Problem. Wenn ja, haben Sie ein viel größeres Problem, da sie auch Sudo-Zugriff haben. Die Person kann das Skript einfach kopieren und nach Belieben ändern. Dies ist einfach eine Möglichkeit, den angemeldeten Namen zur Verwendung in einem Skript abzurufen. Oder fehlt mir etwas an dem, was du sagst?
Eva
1
@evan: Sudo-Zugriff bedeutet nicht, dass Dateien überschrieben werden können.
Flimzy
@Flimzy In welchem ​​Fall kann root keine Dateien überschreiben?
Evans
1
@evan: Jedes Mal, wenn Ihr Sudo-Zugriff Ihnen keinen Zugriff auf eine Shell oder einen anderen Befehl gewährt, der Dateien offensichtlich überschreiben kann.
Flimzy
@evan sudo access ist nicht immer (sollte es in den meisten Admin-Fällen nicht sein) totaler Root-Zugriff. Es handelt sich um eine Reihe konfigurierbarer Kontexte mit eingeschränkter Ausführung.
DylanYoung
8

Dies ist eine kshFunktion, die ich unter HP-UX geschrieben habe. Ich weiß nicht, wie es unter BashLinux funktionieren wird . Die Idee ist, dass der sudoProzess als der ursprüngliche Benutzer ausgeführt wird und die untergeordneten Prozesse der Zielbenutzer sind. Durch Zurücklaufen durch übergeordnete Prozesse können wir den Benutzer des ursprünglichen Prozesses finden.

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

Ich weiß, dass die ursprüngliche Frage von vor langer Zeit stammt, aber Leute (wie ich) fragen immer noch und dies schien ein guter Ort zu sein, um die Lösung zu finden.

user1683793
quelle
5

Wie wäre es mit logname (1), um den Anmeldenamen des Benutzers zu erhalten?

Sam
quelle
logname(1)funktioniert nicht, funktioniert aber logname- die obigen Ergebnisse hinzufügen
am
ursprünglich hatte ich es versucht, $LOGNAMEaber das hat nicht funktioniert. Auch zu den obigen Ergebnissen hinzugefügt.
Evans
Benötigt lognamenoch ein tty? Bei meinen Tests besteht es immer. (Vielleicht habe ich etwas falsch gemacht.) Ich verwende Linux mit Coreutils 8.26.
Simohe
Mein logname (GNU coreutils) 8.28 on gibt immer "logname: no login name" (Ubuntu 18.04.2) zurück
sondra.kinsey
5
THIS_USER=`pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g'`

Das ist das einzige, was für mich funktioniert hat.

Grauer Christoforo
quelle
1
Keine Erklärung und nur minimal verbessert von einer bestehenden Antwort
sondra.kinsey
2

Die findUser () -Funktion von user1683793 wurde portiert bashund erweitert, sodass auch in NSS-Bibliotheken gespeicherte Benutzernamen zurückgegeben werden.

#!/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"
asdfghjkl
quelle
Zu Ihrer Information: Diese Funktion (und die, auf der sie basiert) wird nicht durch mehrere Shells zurückkehren, die von ineinander verschachteltem Sudo erzeugt wurden.
Asdfghjkl
2

zurückfahren und eine Liste der Benutzer geben

basierend auf der Antwort von user1683793

Durch das Ausschließen von Nicht-TTY-Prozessen überspringe ich root als Initiator der Anmeldung. Ich bin mir nicht sicher, ob dies in einigen Fällen zu viel ausschließen kann

#!/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
}

lognameoder who am ihabe ich nicht die gewünschte Antwort, vor allem nicht in längeren Listen su user1, su user2, su user3,...

Ich weiß, dass die ursprüngliche Frage von vor langer Zeit stammt, aber Leute (wie ich) fragen immer noch und dies schien ein guter Ort zu sein, um die Lösung zu finden.

ULick
quelle
2

Alternative zum mehrmaligen Aufruf von ps: Führen Sie einen pstree-Aufruf durch

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

Ausgabe (wenn als gerade angemeldet): (evan)

pstree Argumente:

  • -l: lange Schlangen (nicht verkürzen)
  • -u: Zeigt an, wann sich der Benutzer ändert als (Benutzername)
  • -s $$: Zeigt die Eltern dieses Prozesses

Holen Sie sich die erste Benutzeränderung (die Anmeldung ist) mit grep -ound head.

Einschränkung: Der Befehl darf keine geschweiften Klammern enthalten ()(normalerweise nicht).

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