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 -.
Respostas:
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$
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á.
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.
lognameagora, o que parece funcionar, onde who am inão funciona.
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.
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.
Que tal usar logname (1) para obter o nome de login do usuário?
logname(1)não funciona, mas lognamefunciona - adicionando os resultados acima
$LOGNAMEmas não funcionou. Também adicionado aos resultados acima.
lognameainda necessitam de um tty? Com meus testes sempre passa. (Talvez eu tenha algo errado.) Estou executando o Linux com coreutils 8.26.
THIS_USER=`pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g'`
Essa é a única coisa que funcionou para mim.
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"
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.
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:
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 )
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
who | awk '{print $1}'