Ao executar um script via sudo ou su, desejo obter o usuário original. Isso deve acontecer independentemente de múltiplas sudo
ou su
execuções dentro umas das outras e especificamente sudo su -
.
Respostas:
Resultados:
Use who am i | awk '{print $1}'
OR, logname
pois 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 STDIN
estiver associado a um TTY. Portanto, se você executá- echo "hello" | who am i
lo, simplesmente não funcionará.
echo "hello" | who am i
normalmente, 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 i
nã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.
logname
agora, o que parece funcionar, onde who am i
nã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 logname
e who -m
implementam 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 who
saí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)
tom
usado su
para fazer root e executa seu programa. Se STDIN
não for redirecionado, um programa semelhante logname
será 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 joe
mesmo 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 ksh
função que escrevi no HP-UX. Não sei como vai funcionar Bash
no Linux. A ideia é que o sudo
processo 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 logname
funciona - adicionando os resultados acima
$LOGNAME
mas não funcionou. Também adicionado aos resultados acima.
logname
ainda 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 bash
e 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
}
logname
ou who am i
nã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 -o
ehead
.
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-status
e 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-ssession
loginctl
session-status
show-ssession
show-session
loginctl
who | awk '{print $1}'