Esta pregunta se ha formulado de manera diferente en otros foros. Pero no ha habido una explicación decente por la que no puedes hacer lo siguiente en bash.
#!/bin/bash
command1
SWITCH_USER_TO rag
command2
command3
Por lo general, la forma sugerida es
#!/bin/bash
command1
sudo -u rag command2
sudo -u rag command3
pero ¿por qué no es posible bash
cambiar a un usuario diferente en algún momento durante la ejecución del script bash y ejecutar el resto de los comandos como un usuario diferente?
Respuestas:
La información ya está en mi otra respuesta , pero está un poco enterrada allí. Entonces pensé, lo agregaría aquí.
bash
no tiene provisión para cambiar usuarios, perozsh
sí.En
zsh
, cambia usuarios asignando valores a esas variables:$EUID
: cambia la identificación de usuario efectiva (y nada más). Por lo general, puede cambiar su euid entre su ID de usuario real y el ID de usuario del conjunto guardado (si se llama desde un ejecutable setuid) o cambiar a cualquier cosa si su euid es 0.$UID
: cambia la identificación de usuario efectiva, la identificación de usuario real y la identificación de usuario establecida guardada al nuevo valor A menos que ese nuevo valor sea 0, no habrá regreso, ya que una vez que los 3 se hayan establecido en el mismo valor, no hay forma de cambiarlo a otra cosa.$EGID
y$GID
: lo mismo pero para identificadores de grupo.$USERNAME
. Eso es como usarsudo
osu
. Establece su euid, ruid, ssuid al uid de ese usuario. También establece los grupos egid, rgid y ssgid y suplementarios en función de las membresías de grupo como se define en la base de datos del usuario. Al igual que para$UID
, a menos que establezca$USERNAME
queroot
, no hay vuelta atrás, pero al igual que para el$UID
, puede cambiar el usuario sólo para un subnivel.Si ejecuta estos scripts como "root":
Ahora, para cambiar de usuario como en
sudo
osu
, solo podemos hacerlo usando subshells, de lo contrario solo podríamos hacerlo una vez:fuente
Ofertas de kernel
man 2 setuid
y amigos.Ahora, funciona en el proceso de llamadas. Más importante aún, no puede elevar sus privilegios. Es por eso
su
ysudo
tienen bit setuid de manera que corran siempre con privilegios más altos (root
) y caen a consecuencia de usuario deseado.Esa combinación significa que no puede cambiar el UID del shell ejecutando algún otro programa para hacer eso (es por eso que no puede esperar
sudo
ni ningún otro programa para hacerlo) y no puede hacerlo (como shell) a menos que están dispuestos a ejecutarse como root o el mismo usuario al que desea cambiar, lo que no tiene sentido. Además, una vez que abandonas los privilegios, no hay vuelta atrás.fuente
Bueno, siempre puedes hacer:
(ʘ‿ʘ)
Eso comenzó como una broma, ya que implementa lo solicitado, aunque probablemente no sea exactamente como se esperaba, y no es prácticamente útil. Pero a medida que evolucionó a algo que funciona hasta cierto punto e involucra algunos trucos agradables, aquí hay una pequeña explicación:
Como dijo Miroslav , si dejamos de lado las capacidades de estilo Linux (que de todos modos tampoco ayudaría aquí), la única forma de que un proceso sin privilegios cambie uid es ejecutando un setuid ejecutable.
Sin embargo, una vez que obtenga el privilegio de superusuario (al ejecutar un ejecutable setuid cuyo propietario es root, por ejemplo), puede cambiar la identificación de usuario efectiva de ida y vuelta entre su identificación de usuario original, 0 y cualquier otra identificación a menos que renuncie a su identificación de usuario establecida guardada ( cosas como
sudo
o quesu
suelen hacer).Por ejemplo:
Ahora tengo un
env
comando que me permite ejecutar cualquier comando con un ID de usuario efectivo y un ID de usuario guardado de 0 (mi ID de usuario real sigue siendo 1000):perl
tiene envoltorios parasetuid
/seteuid
(esos$>
y$<
variables).También lo hace zsh:
Aunque por encima de esos
id
comandos se invocan con un ID de usuario real y un ID de usuario del conjunto guardado de 0 (aunque si hubiera usado mi en./env
lugar desudo
eso, solo habría sido el ID de usuario del conjunto guardado, mientras que la ID de usuario real habría permanecido 1000), lo que significa que si fueran comandos no confiables, aún podrían causar algún daño, por lo que querrá escribirlo como:(es decir, establece todos los uids (conjunto efectivo, real y guardado) solo para la ejecución de esos comandos.
bash
no tiene tal forma de cambiar los identificadores de usuario. Entonces, incluso si tuviera un ejecutable setuid con el que llamar a subash
script, eso no ayudaría.Con
bash
, te queda ejecutar un setuid ejecutable cada vez que quieras cambiar uid.La idea en el script anterior es sobre una llamada a SWITCH_TO_USER, para ejecutar una nueva instancia de bash para ejecutar el resto del script.
SWITCH_TO_USER someuser
es más o menos una función que ejecuta el script nuevamente como un usuario diferente (usandosudo
) pero omitiendo el inicio del script hastaSWITCH_TO_USER someuser
.Donde se vuelve complicado es que queremos mantener el estado de la bash actual después de haber comenzado la nueva bash como un usuario diferente.
Vamos a desglosarlo:
Necesitaremos alias. Uno de los trucos en este script es omitir la parte del script hasta que
SWITCH_TO_USER someuser
, con algo como:Esa forma es similar a la
#if 0
utilizada en C, es una forma de comentar completamente algún código.:
es un no-op que devuelve verdadero. Entonces: || :
, el segundo:
nunca se ejecuta. Sin embargo, se analiza. Y<< 'xxx'
es una forma de documento aquí donde (porquexxx
se cita), no se realiza ninguna expansión o interpretación.Podríamos haber hecho:
Pero eso habría significado que el documento aquí habría tenido que escribirse y pasarse como estándar
:
.:||:
evita eso.Ahora, cuando se vuelve hacky es que usamos el hecho de que
bash
expande los alias muy temprano en su proceso de análisis. Tenerskip
un alias para la:||: << 'SWITCH_TO_USER someuther'
parte de la construcción de comentarios .Sigamos:
Aquí está la definición de la función SWITCH_TO_USER . Veremos a continuación que SWITCH_TO_USER eventualmente será un alias envuelto alrededor de esa función.
Esa función hace la mayor parte de volver a ejecutar el script. Al final, vemos que se vuelve a ejecutar (en el mismo proceso debido a
exec
)bash
con la_x
variable en su entorno (lo usamosenv
aquí porquesudo
generalmente desinfecta su entorno y no permite el paso de entornos arbitrarios). Esobash
evalúa el contenido de esa$_x
variable como código bash y genera el script en sí._x
se define anteriormente como:Todo el
declare
,alias
,shopt -p
set +o
salida forman un volcado del estado interno de la cáscara. Es decir, vuelcan la definición de todas las variables, funciones, alias y opciones como código shell listo para ser evaluado. Además de eso, agregamos la configuración de los parámetros posicionales ($1
,$2
...) en función del valor de la$_a
matriz (ver más abajo), y algunos limpian para que la gran$_x
variable no permanezca en el entorno durante el resto del guiónNotarás que la primera parte hasta
set +x
está envuelta en un grupo de comandos cuyo stderr se redirige a/dev/null
({...} 2> /dev/null
). Esto se debe a que, si en algún momento se ejecuta el scriptset -x
(oset -o xtrace
), no queremos que ese preámbulo genere rastros, ya que queremos que sea lo menos intrusivo posible. Entonces ejecutamos unset +x
(después de habernos asegurado de volcar laxtrace
configuración de la opción (incluida ) de antemano) donde se envían los seguimientos a / dev / null.El
eval "$_X"
stderr también se redirige a / dev / null por razones similares, pero también para evitar los errores sobre el intento de escritura en variables especiales de solo lectura.Continuemos con el guión:
Ese es nuestro truco descrito anteriormente. En la invocación inicial del script, se cancelará (ver más abajo).
Ahora el contenedor de alias alrededor de SWITCH_TO_USER. La razón principal es poder pasar los parámetros posicionales (
$1
,$2
...) a los nuevosbash
que interpretarán el resto del script. No pudimos hacerlo en laSWITCH_TO_USER
función porque dentro de la función"$@"
están los argumentos de las funciones, no los de los scripts. La redirección de stderr a / dev / null es nuevamente para ocultar xtraces, yeval
es evitar un errorbash
. Entonces llamamos a laSWITCH_TO_USER
función .Esa parte cancela el
skip
alias (lo reemplaza con el:
comando no-op) a menos que se establezca la$_u
variable.Ese es nuestro
skip
alias. En la primera invocación, solo será:
(el no-op). En subsecuencia re-invocaciones, será algo como::||: << 'SWITCH_TO_USER root'
.Así que aquí, como ejemplo, en ese punto, volvemos a invocar el script como
root
usuario, y el script restaurará el estado guardado, saltaremos a esaSWITCH_TO_USER root
línea y continuaremos.Lo que eso significa es que debe escribirse exactamente como stat, con
SWITCH_TO_USER
al principio de la línea y con exactamente un espacio entre argumentos.La mayor parte del estado, stdin, stdout y stderr se conservarán, pero no los otros descriptores de archivo porque
sudo
normalmente los cierra a menos que esté configurado explícitamente para no hacerlo. Entonces, por ejemplo:Normalmente no funcionará.
También tenga en cuenta que si lo hace:
Eso solo funciona si tiene derecho a
sudo
asalice
yalice
tiene derecho asudo
asbob
ybob
asroot
.Entonces, en la práctica, eso no es realmente útil. Usar en
su
lugar desudo
(o unasudo
configuración donde sesudo
autentique al usuario objetivo en lugar de la persona que llama) podría tener un poco más de sentido, pero eso aún significaría que necesitaría saber las contraseñas de todos esos tipos.fuente
ioshcc
? Deberías haber ingresado solo en una línea.El comando "sudo -u ram sh" se puede usar para cambiar al usuario "ram", ejecutando el comando "sh" o shell. El comando "salir" lo llevará de regreso al usuario original.
fuente