¿Cómo encuentras al usuario original a través de múltiples comandos sudo y su?

93

Al ejecutar un script a través de sudo o su, quiero obtener el usuario original. Esto debería suceder independientemente de que se ejecuten múltiples sudoo suuno dentro del otro y específicamente sudo su -.

evan
fuente

Respuestas:

136

Resultados:

Utilice who am i | awk '{print $1}'OR lognameya que no se garantizan otros métodos.

Iniciar sesión como yo:

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
fuente
1
En ese caso, sólo puede utilizarwho | awk '{print $1}'
SiegeX
2
... si eres el único que ha iniciado sesión (y es solo una vez).
Pausado hasta nuevo aviso.
9
todo lo que necesitas son 2 argumentos: who am ies lo mismo que who smells bad. Además, solo funciona si STDINestá asociado con un TTY. Entonces, si lo ejecuta echo "hello" | who am i, simplemente no funcionará.
tylerl
1
No se ejecutaría echo "hello" | who am inormalmente, a menos que su script se esté ejecutando en un entorno donde no hay una terminal. Luego, es posible que vea el error que who am ino funciona porque hay algún tipo de problema con el stdin no legible, en cuyo caso puede intentar canalizar los datos who am ipor desesperación para satisfacer su requisito de stdin. tylerl solo está notando que ya ha recorrido ese camino, y la tubería no funcionará porque stdin debe ser legible y estar asociado con un TTY.
Edwin Buck
4
@even True, aunque me gustaría que requiera la menor configuración posible, así que estoy usando lognameahora, que resulta que funciona, donde who am ino.
Bart van Heukelom
18

No hay una respuesta perfecta . Cuando cambia las ID de usuario, la ID de usuario original no suele conservarse, por lo que se pierde la información. Algunos programas, como lognamee who -mimplementan un truco en el que verifican a qué terminal está conectado stdiny luego verifican qué usuario ha iniciado sesión en ese terminal.

Esta solución a menudo funciona, pero no es infalible y ciertamente no debe considerarse segura. Por ejemplo, imagina si whogenera lo siguiente:

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

tomutilizado supara llegar a la raíz y ejecuta su programa. Si STDINno se redirige, se lognamegenerará un programa como tom. Si ES redirigido (por ejemplo, desde un archivo) así:

logname < /some/file

Entonces el resultado es " no login name", ya que la entrada no es el terminal. Más interesante aún, sin embargo, es el hecho de que el usuario podría hacerse pasar por un usuario que inició sesión diferente. Dado que Joe está conectado en pts / 1, Tom podría fingir ser él corriendo

logname < /dev/pts1

Ahora, dice joea pesar de que Tom es quien ejecutó el comando. En otras palabras, si utiliza este mecanismo en cualquier tipo de función de seguridad, está loco.

Tylerl
fuente
2
Si está ejecutando el script usted mismo (como lo demuestran los comandos utilizados), la seguridad no es el problema. Si es así, tienes un problema mucho mayor, ya que también tienen acceso sudo. La persona puede simplemente copiar el guión y modificarlo de la forma que desee. Esta es simplemente una forma de obtener el nombre de inicio de sesión para usarlo en un script. ¿O me estoy perdiendo algo de lo que estás diciendo?
evan
1
@evan: Tener acceso a sudo no implica la capacidad de sobrescribir archivos.
Flimzy
@Flimzy ¿En qué caso root no tiene la capacidad de sobrescribir archivos?
evan
1
@evan: Cada vez que su acceso a sudo no le da acceso a un shell, o cualquier otro comando que pueda sobrescribir archivos, obviamente.
Flimzy
El acceso de @evan sudo no es siempre (no debería serlo en la mayoría de los casos de administración) el acceso root total. Es un conjunto de contextos de ejecución restringidos configurables.
DylanYoung
8

Esta es una kshfunción que escribí en HP-UX. No sé cómo funcionará Bashen Linux. La idea es que el sudoproceso se esté ejecutando como el usuario original y los procesos secundarios sean el usuario objetivo. Al retroceder por los procesos principales, podemos encontrar al usuario del proceso 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
}

Sé que la pregunta original era de hace mucho tiempo, pero la gente (como yo) todavía está preguntando y este parecía un buen lugar para poner la solución.

user1683793
fuente
5

¿Qué tal usar logname (1) para obtener el nombre de inicio de sesión del usuario?

sam
fuente
logname(1)no funciona pero lognamesí - agregando los resultados anteriores
evan
originalmente lo había intentado $LOGNAMEpero no funcionó. También se agregó a los resultados anteriores.
evan
¿ lognameTodavía requiere un tty? Con mis pruebas siempre pasa. (Tal vez me haya equivocado de algo.) Estoy ejecutando linux con coreutils 8.26.
simohe
Mi nombre de registro (GNU coreutils) 8.28 en siempre devuelve "nombre de registro: sin nombre de inicio de sesión" (Ubuntu 18.04.2)
sondra.kinsey
5
THIS_USER=`pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g'`

Eso es lo único que funcionó para mí.

Christoforo gris
fuente
1
Sin explicación y solo mínimamente mejorada a partir de una respuesta existente
sondra.kinsey
2

La función findUser () de user1683793 se transfirió bashy extendió para que también devuelva los nombres de usuario almacenados en las 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
fuente
FYI: esta función (y en la que se basó) no retrocederá a través de múltiples shells generados por sudo anidados entre sí.
asdfghjkl
2

retroceder y dar una lista de usuarios

basado en la respuesta del usuario1683793

Al excluir los procesos que no son TTY, omito root como iniciador del inicio de sesión. No estoy seguro de si eso puede excluir demasiado en algún caso

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

lognameo who am ino me dio la respuesta deseada, especialmente no en listas más largas de su user1, su user2, su user3,...

Sé que la pregunta original era de hace mucho tiempo, pero la gente (como yo) todavía está preguntando y este parecía un buen lugar para poner la solución.

ULick
fuente
2

Alternativa a llamar a ps varias veces: haga una llamada pstree

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

salida (cuando se inicia sesión como par): (evan)

pstree argumentos:

  • -l: colas largas (sin acortar)
  • -u: muestra cuando el usuario cambia como (nombre de usuario)
  • -s $$: muestra a los padres de este proceso

Obtenga el primer cambio de usuario (que es inicio de sesión) con grep -oy head.

limitación: el comando no puede contener llaves ()(normalmente no lo hace)

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

En los sistemas en ejecución systemd-logind, la API systemd proporciona esta información . Si desea acceder a esta información desde un script de shell, debe usar algo como esto:

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

Los comandos del sistema session-statusy tienen un comportamiento diferente sin argumentos: usa la sesión actual, pero usa el administrador. Sin embargo, es preferible utilizar scripts debido a su salida legible por máquina. Es por eso que se necesitan dos invocaciones de .show-ssessionloginctlsession-statusshow-ssessionshow-sessionloginctl

Florian Weimer
fuente