Jak znaleźć oryginalnego użytkownika za pomocą wielu poleceń sudo i su?

93

Podczas uruchamiania skryptu przez sudo lub su chcę uzyskać oryginalnego użytkownika. Powinno to mieć miejsce niezależnie od wielu sudolub sudziała wewnątrz siebie, a konkretnie sudo su -.

evan
źródło

Odpowiedzi:

136

Wyniki:

Użyj who am i | awk '{print $1}'OR, lognameponieważ żadne inne metody nie są gwarantowane.

Zalogowany jako siebie:

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>

Normalne 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
źródło
1
W takim przypadku możesz po prostu użyćwho | awk '{print $1}'
SiegeX,
2
... jeśli jesteś jedyny zalogowany (i to tylko raz).
Wstrzymano do odwołania.
9
potrzebujesz tylko 2 argumentów: who am ito to samo, co who smells bad. Działa również tylko wtedy, gdy STDINjest powiązany z urządzeniem TTY. Więc jeśli uruchomisz echo "hello" | who am i, po prostu nie zadziała.
tylerl
1
Nie działałbyś echo "hello" | who am inormalnie, chyba że twój skrypt działa w środowisku, w którym nie ma terminala. Wtedy możesz zobaczyć błąd, który who am inie działa, ponieważ jest jakiś problem z nieczytelnym stdin, w takim przypadku możesz spróbować przesłać dane do who am iz desperacji, aby spełnić wymagania stdin. tylerl po prostu zauważa, że ​​już podążał tą ścieżką, a potok nie będzie działał, ponieważ stdin musi być zarówno czytelny, jak i powiązany z TTY.
Edwin Buck,
4
@even True, chociaż chciałbym, aby wymagało to jak najmniejszej konfiguracji, więc używam lognameteraz, co jak się okazuje działa, gdzie who am inie.
Bart van Heukelom
18

Nie ma idealnej odpowiedzi. Po zmianie identyfikatorów użytkownika pierwotny identyfikator użytkownika zwykle nie jest zachowywany, więc informacje są tracone. Niektóre programy, takie jak lognamei who -mimplementują hack, w którym sprawdzają, do którego terminala jest podłączony stdin, a następnie sprawdzają, który użytkownik jest zalogowany na tym terminalu.

To rozwiązanie często działa, ale nie jest niezawodne i na pewno nie powinno być uważane za bezpieczne. Na przykład wyobraź sobie, że whowyświetla następujący wynik:

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

tomużywany sudo dostać się do korzeni i uruchamia program. Jeśli STDINnie jest przekierowywany, potem program jak lognamepokaże na wyjściu tom. Jeśli JEST przekierowany (np. Z pliku) tak:

logname < /some/file

Wtedy wynikiem jest „ no login name”, ponieważ wejście nie jest terminalem. Jednak jeszcze ciekawsze jest to, że użytkownik może udawać innego zalogowanego użytkownika. Ponieważ Joe jest zalogowany na pts / 1, Tom mógłby udawać go biegając

logname < /dev/pts1

Teraz jest napisane, joeże to Tom jest tym, który zarządzał. Innymi słowy, jeśli używasz tego mechanizmu w jakiejkolwiek roli bezpieczeństwa, jesteś szalony.

tylerl
źródło
2
Jeśli sam uruchamiasz skrypt (o czym świadczą użyte polecenia), bezpieczeństwo nie jest problemem. Jeśli tak, masz znacznie większy problem, ponieważ mają one również dostęp do sudo. Osoba może po prostu skopiować skrypt i zmodyfikować go w dowolny sposób. Jest to po prostu sposób na uzyskanie nazwy użytkownika do użycia w skrypcie. A może brakuje mi czegoś w tym, co mówisz?
evan
1
@evan: Posiadanie dostępu do sudo nie oznacza możliwości nadpisywania plików.
Flimzy
@Flimzy W jakim przypadku root nie ma możliwości nadpisania plików?
evan
1
@evan: Za każdym razem, gdy twój dostęp do sudo nie daje ci dostępu do powłoki ani żadnego innego polecenia, które może oczywiście nadpisać pliki.
Flimzy
Dostęp do @evan sudo nie zawsze (nie powinien być w większości przypadków administracyjnych) z całkowitym dostępem jako root. Jest to zestaw konfigurowalnych kontekstów ograniczonego wykonywania.
DylanYoung
8

To jest kshfunkcja, którą napisałem w HP-UX. Nie wiem, jak to będzie działać Bashw Linuksie. Chodzi o to, że sudoproces działa jako oryginalny użytkownik, a procesy potomne są użytkownikiem docelowym. Przechodząc wstecz przez procesy nadrzędne, możemy znaleźć użytkownika pierwotnego procesu.

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

Wiem, że pierwotne pytanie było dawno temu, ale ludzie (tacy jak ja) wciąż o nie pytają, a to wyglądało na dobre miejsce na znalezienie rozwiązania.

user1683793
źródło
5

Co powiesz na użycie logname (1), aby uzyskać nazwę logowania użytkownika?

sam
źródło
logname(1)nie działa, ale lognamedziała - dodając wyniki powyżej
evan
początkowo próbowałem, $LOGNAMEale to nie zadziałało. Dodano również do powyższych wyników.
evan
Czy lognamenadal wymaga tty? Z moimi testami zawsze mija. (Może coś nie tak.) Używam Linuksa z Coreutils 8.26.
simohe
My logname (GNU coreutils) 8.28 on zawsze zwraca „logname: no login name” (Ubuntu 18.04.2)
sondra.kinsey
5
THIS_USER=`pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g'`

To jedyna rzecz, która mi pomogła.

Szary Christoforo
źródło
1
Brak wyjaśnienia i tylko minimalnie poprawiona w porównaniu z istniejącą odpowiedzią
sondra.kinsey
2

Funkcja findUser () użytkownika1683793 została przeniesiona bashi rozszerzona, więc zwraca również nazwy użytkowników przechowywane w bibliotekach 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"
asdfghjkl
źródło
FYI: ta funkcja (i ta, na której została oparta) nie będzie cyklicznie przechodzić przez wiele powłok utworzonych przez sudo zagnieżdżonych w sobie.
asdfghjkl,
2

z powrotem i podając listę użytkowników

na podstawie odpowiedzi użytkownika1683793

Pomijając procesy inne niż TTY, pomijam roota jako inicjatora logowania. Nie jestem pewien, czy w niektórych przypadkach może to zbytnio wydzielać

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

lognamelub who am inie da mi pożądaną odpowiedź, a zwłaszcza nie w dłuższych listach su user1, su user2, su user3,...

Wiem, że pierwotne pytanie było dawno temu, ale ludzie (tacy jak ja) wciąż o nie pytają, a to wyglądało na dobre miejsce na znalezienie rozwiązania.

ULick
źródło
2

Alternatywa dla wielokrotnego wywoływania ps: wykonaj jedno wywołanie pstree

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

wyjście (po zalogowaniu jako parzyste): (evan)

argumenty pstree:

  • -l: długie linie (nie skracane)
  • -u: pokaż, gdy użytkownik zmieni się jako (nazwa użytkownika)
  • -s $$: pokaż rodzicom tego procesu

Uzyskaj pierwszą zmianę użytkownika (czyli logowanie) za pomocą grep -oi head.

ograniczenie: polecenie nie może zawierać nawiasów klamrowych ()(normalnie nie)

simohe
źródło
pstree -lu -s $$ | head -n1 | sed -e 's / [^ (] * (([^)] *)). * / \ 1 /'
Alexx Roche
0

W systemach systemd-logindThe Systemd API udostępnia tę informację . Jeśli chcesz uzyskać dostęp do tych informacji ze skryptu powłoki, użyj czegoś takiego:

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

Te session-statusi show-ssessionsystemowe Komendy loginctlmieć różne zachowanie bez argumentów: session-statuskorzysta z bieżącej sesji, ale show-ssessionużywa menedżera. Jednak używanie show-sessionjest preferowane w przypadku używania skryptów ze względu na jego dane wyjściowe do odczytu maszynowego. Dlatego loginctlpotrzebne są dwie inwokacje .

Florian Weimer
źródło