Como você encontra o usuário original por meio de vários comandos sudo e su?

93

Ao executar um script via sudo ou su, desejo obter o usuário original. Isso deve acontecer independentemente de múltiplas sudoou suexecuções dentro umas das outras e especificamente sudo su -.

Evan
fonte

Respostas:

136

Resultados:

Use who am i | awk '{print $1}'OR, lognamepois nenhum outro método é garantido.

Conectado como eu:

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 normal:

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
fonte
1
Nesse caso, você pode apenas usarwho | awk '{print $1}'
SiegeX
2
... se você for o único conectado (e é apenas uma vez).
Pausado até novo aviso.
9
tudo que você precisa é de 2 argumentos: who am ié o mesmo que who smells bad. Além disso, só funciona se STDINestiver associado a um TTY. Portanto, se você executá- echo "hello" | who am ilo, simplesmente não funcionará.
tylerl
1
Você não executaria echo "hello" | who am inormalmente, a menos que seu script estivesse sendo executado em um ambiente onde não houvesse terminal. Em seguida, você pode ver o erro que who am inão está funcionando porque há algum tipo de problema com o stdin não legível, caso em que você pode tentar canalizar os dados para who am i, desesperado, para satisfazer seu requisito stdin. tylerl está apenas observando que já percorreu esse caminho e o pipe não funcionará porque stdin deve ser legível e associado a um TTY.
Edwin Buck
4
@even True, embora eu gostaria que exigisse o mínimo de configuração possível, então estou usando lognameagora, o que parece funcionar, onde who am inão funciona.
Bart van Heukelom
18

Não existe uma resposta perfeita . Quando você altera os IDs do usuário, o ID do usuário original geralmente não é preservado, portanto as informações são perdidas. Alguns programas, como lognamee who -mimplementam um hack onde verificam para ver qual terminal está conectado stdin, e então ver qual usuário está logado naquele terminal.

Essa solução geralmente funciona, mas não é infalível e certamente não deve ser considerada segura. Por exemplo, imagine se a whosaída for o seguinte:

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

tomusado supara fazer root e executa seu programa. Se STDINnão for redirecionado, um programa semelhante lognameserá gerado tom. Se for redirecionado (por exemplo, de um arquivo) da seguinte forma:

logname < /some/file

Então o resultado é " no login name", já que a entrada não é o terminal. Mais interessante ainda, porém, é o fato de que o usuário pode se passar por um usuário logado diferente. Como Joe está conectado em pts / 1, Tom poderia fingir ser ele executando

logname < /dev/pts1

Agora, ele diz joemesmo que Tom é quem executou o comando. Em outras palavras, se você usar esse mecanismo em qualquer tipo de função de segurança, você ficará louco.

tylerl
fonte
2
Se você mesmo estiver executando o script (conforme evidenciado pelos comandos usados), a segurança não é o problema. Se for, você terá muito mais problemas, pois eles também têm acesso ao sudo. A pessoa pode simplesmente copiar o script e modificá-lo da maneira que quiser. Esta é simplesmente uma maneira de obter o nome de login para uso em um script. Ou estou perdendo algo sobre o que você está dizendo?
evan
1
@evan: Ter acesso ao sudo não implica na capacidade de sobrescrever arquivos.
Flimzy de
@Flimzy Em que caso o root não tem a capacidade de sobrescrever arquivos?
evan
1
@evan: Sempre que o seu acesso sudo não dá acesso a um shell, ou qualquer outro comando que pode sobrescrever arquivos, obviamente.
Flimzy
O acesso @evan sudo não é sempre (não deveria ser na maioria dos casos de administrador) acesso root total. É um conjunto de contextos de execução restrita configuráveis.
DylanYoung
8

Esta é uma kshfunção que escrevi no HP-UX. Não sei como vai funcionar Bashno Linux. A ideia é que o sudoprocesso esteja sendo executado como o usuário original e os processos filhos sejam o usuário-alvo. Percorrendo os processos pais, podemos encontrar o usuário do processo original.

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

Sei que a pergunta original era de muito tempo atrás, mas as pessoas (como eu) ainda estão perguntando e este parecia um bom lugar para colocar a solução.

user1683793
fonte
5

Que tal usar logname (1) para obter o nome de login do usuário?

sam
fonte
logname(1)não funciona, mas lognamefunciona - adicionando os resultados acima
evan
originalmente eu tinha tentado, $LOGNAMEmas não funcionou. Também adicionado aos resultados acima.
evan
Será que lognameainda necessitam de um tty? Com meus testes sempre passa. (Talvez eu tenha algo errado.) Estou executando o Linux com coreutils 8.26.
simohe
Meu nome de log (GNU coreutils) 8.28 sempre retorna "logname: sem nome de login" (Ubuntu 18.04.2)
sondra.kinsey
5
THIS_USER=`pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g'`

Essa é a única coisa que funcionou para mim.

Gray Christoforo
fonte
1
Nenhuma explicação e apenas uma melhoria mínima em relação a uma resposta existente
sondra.kinsey
2

A função findUser () do user1683793 foi transferida bashe estendida para que também retorne nomes de usuários armazenados nas bibliotecas 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
fonte
Para sua informação: esta função (e aquela em que foi baseada) não irá percorrer vários shells gerados por sudo aninhados uns nos outros.
asdfghjkl
2

voltando e dando uma lista de usuários

com base na resposta do usuário1683793

Ao excluir os processos não-TTY, pulo o root como o iniciador do login. Não tenho certeza se isso pode significar muito em alguns casos

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

lognameou who am inão me dar a resposta desejada, especialmente não em listas mais longas de su user1, su user2, su user3,...

Sei que a pergunta original era de muito tempo atrás, mas as pessoas (como eu) ainda estão perguntando e este parecia um bom lugar para colocar a solução.

ULick
fonte
2

Alternativa para chamar ps várias vezes: faça uma chamada pstree

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

saída (quando conectado como par): (evan)

argumentos pstree:

  • -l: linhas longas (não encurtando)
  • -u: mostra quando o usuário muda como (userName)
  • -s $$: mostra os pais deste processo

Obtenha a primeira alteração do usuário (que é o login) com grep -oehead .

limitação: o comando não pode conter chaves ()(normalmente não contém )

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

Em sistemas em execução systemd-logind, a API systemd fornece essas informações . Se quiser acessar essas informações a partir de um script de shell, use algo como este:

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

Os comandos do sistema session-statuse têm comportamentos diferentes sem argumentos: usa a sessão atual, mas usa o gerenciador. No entanto, o uso é preferível para uso de script devido à sua saída legível por máquina. É por isso que duas invocações de são necessárias.show-ssessionloginctlsession-statusshow-ssessionshow-sessionloginctl

Florian Weimer
fonte