Aumento temporal del tiempo de espera de sudo durante la duración de un script de instalación

22

Estoy tratando de escribir un script que instale un montón de software y me gustaría no tener que ejecutar todo root, así que me gustaría poder solicitar una contraseña y luego realizar la instalación, usando sudoo supara obtener privilegios cuando los necesito.

Estaba haciendo una sudo -vsolicitud de contraseña al comienzo del script, y luego simplemente estaba usando sudo normalmente más adelante. Esto funciona muy bien hasta que llego a una sola instalación que toma el tiempo de espera.

Prefiero no tener que aumentar permanentemente el tiempo de espera. ¿Hay alguna manera de aumentar el tiempo de espera de sudo solo para la sesión actual?

Arelius
fuente

Respuestas:

8

Puede configurar un bucle que se ejecuta en segundo plano para ejecutar periódicamente "sudo -v", el truco, por supuesto, es hacer que el bucle finalice limpiamente cuando finalice su script. Entonces tiene que haber algún tipo de comunicación entre los dos procesos; Los archivos tmp están bien para esto, y también se pueden limpiar fácilmente después de que se ejecute el script. (Un script de instalación generalmente hace esto, de todos modos).

Por ejemplo (elimine las declaraciones 'echo' para usar esto; solo se muestra "funcionando"):

#!/bin/bash
log=running_setup.txt
sudo_stat=sudo_status.txt

echo "========= running script $$ ========"
echo $$ >> $sudo_stat
trap 'rm -f $sudo_stat >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 15

sudo_me() {
 while [ -f $sudo_stat ]; do
  echo "checking $$ ...$(date)"
  sudo -v
  sleep 5
 done &
}


echo "=setting up sudo heartbeat="
sudo -v
sudo_me

echo "=running setup=" | tee $log
while [ -f $log ]
do
 echo "running setup $$ ...$(date) ===" | tee -a $log
 sleep 2
done

# finish sudo loop
rm $sudo_stat

Entonces verá ... (nota: el pid se coloca en el archivo tmp, para que pueda matarlo fácilmente. Sin embargo, no es necesario):

$ ./do_it.sh
========= running script 6776 ========
=setting up sudo heartbeat=
[sudo] password for user: 
=running setup=
checking 6776 ...Wed May  4 16:31:47 PDT 2011
running setup 6776 ...Wed May  4 16:31:48 PDT 2011 ===
running setup 6776 ...Wed May  4 16:31:50 PDT 2011 ===
running setup 6776 ...Wed May  4 16:31:52 PDT 2011 ===
checking 6776 ...Wed May  4 16:31:53 PDT 2011
running setup 6776 ...Wed May  4 16:31:54 PDT 2011 ===
<ctrl-c>  (cleans up files, then exits)
Miguel
fuente
9

Me gustó la respuesta de michael_n, pero tenía el deseo más irracional de no usar un archivo temporal. Tal vez esto pueda proporcionar alguna perspectiva.

Mi solución fue:

#!/bin/bash
function sudo_ping() {
    if [[ ! -z $SUDO_PID ]]; then
        if [[ $1 -eq stop ]]; then
            echo "Stopping sudo ping in PID = $SUDO_PID"
            kill $SUDO_PID
            return
        else
            echo "Already sudo pinging in PID = $SUDO_PID"
            return
        fi
    fi

    echo "Starting background sudo ping..."
    sudo -v
    if [[ $? -eq 1 ]]; then
        echo "Oops, wrong password."
        return
    fi
    sudo echo "ok"

    while true; do
        echo 'Sudo ping!'
        sudo -v
        sleep 1
    done &
    SUDO_PID=$!
    sudo echo "Sudo pinging in PID = $SUDO_PID"

    # Make sure we don't orphan our pinger
    trap "sudo_ping stop" 0
    trap "exit 2" 1 2 3 15
}

sudo_ping
sleep 5
echo "Goodbye!"

De nuevo, los echoson extraños ...

$ ./sudoping.sh 
Starting background sudo ping...
Password:
ok  
Sudo ping!
Sudo pinging in PID = 47531
Sudo ping!
Sudo ping!
Sudo ping!
Sudo ping!
Goodbye!
Stopping sudo ping in PID = 47531

De nuevo, ctrl-c también funciona ...

$ ./sudoping.sh 
Starting background sudo ping...
ok  
Sudo ping!
Sudo pinging in PID = 47599
Sudo ping!
^CStopping sudo ping in PID = 47599
Gregory Perkins
fuente
66
Y una solución más sucinta: gist.github.com/3118588
Gregory Perkins
¿Cómo no tiene más de 1000 votos a favor? La versión sucinta es asombrosa. (Pero un mejor ejemplo ayudaría, creo.)
MountainX para Monica Cellio
3

Basado en esta esencia , hice una versión concisa y limpia:

# Prevent sudo timeout
sudo -v # ask for sudo password up-front
while true; do
  # Update user's timestamp without running a command
  sudo -nv; sleep 1m
  # Exit when the parent process is not running any more. In fact this loop
  # would be killed anyway after being an orphan(when the parent process
  # exits). But this ensures that and probably exit sooner.
  kill -0 $$ 2>/dev/null || exit
done &
Bohr
fuente
Creo que la versión básica sería mejor, porque si sudo -Kse invoca en otro lugar del script de shell, su versión le gritaría sudo: a password is requiredal stderr cada minuto.
Rockallite
@Rockallite ¿Te refieres a mi esencia vinculada? En realidad son lo mismo.
Bohr
0

Según la sudopágina del manual:

   -v          If given the -v (validate) option, sudo will update the user's time stamp,
               prompting for the user's password if necessary.  This extends the sudo timeout for
               another 15 minutes (or whatever the timeout is set to in sudoers) but does not run
               a command.

Entonces, supongo que si agrega algunos sudo -vpuntos más de su script de configuración para validar la sesión (y no solo al principio) obtendrá lo que desea, ya que cada vez aumentará el tiempo de espera (solo le pedirá la contraseña nuevamente si se alcanza el tiempo de espera). El único problema será si hay un comando en su script que tome más tiempo que el tiempo de espera (por lo tanto, incluso si valida justo después de él, el tiempo de espera expirará antes de completarse para otra validación), pero este es un caso muy específico.

Lo que sucede es que el solo uso sudono aumenta el tiempo de espera y sudo -vno ejecuta un comando, por lo que debe usar sudo -vmás veces para validar la sesión.

volcado de memoria
fuente
Si gracias. El problema es que mi tiempo de espera de sudo está más cerca de 5 minutos, y tengo comandos de instalación únicos que van mucho más allá de eso.
Arelius
Hmm Bien. No hay mucho que hacer aparte de aumentar el tiempo de espera entonces. No hay forma de configurarlo temporalmente.
coredump
0

Basándome en la esencia proporcionada por Gregory Perkins y mi experiencia, aquí está mi frase:

trap "exit" INT TERM; trap "kill 0" EXIT; sudo -v || exit $?; sleep 1; while true; do sleep 60; sudo -nv; done 2>/dev/null &

O

trap "exit" INT TERM
trap "kill 0" EXIT
sudo -v || exit $?
sleep 1
while true; do
    sleep 60
    sudo -nv
done 2>/dev/null &

Explicaciones

  • trap "exit" INT TERM; trap "kill 0" EXIT: Esto eliminará todo el árbol de procesos al salir o SIGINT / SIGTERM.

  • sudo -v || exit $?: Solicite la contraseña por adelantado y guarde en caché las credenciales de seguridad, pero no ejecute un comando. Si la contraseña no es correcta, salga con el código devuelto por sudo.

  • sleep 1: Demora un poco para que las credenciales de seguridad se guarden efectivamente. Si el siguiente sudo se ejecuta demasiado pronto, no lo sabrá porque las credenciales aún no se han guardado, por lo que le pedirá la contraseña nuevamente.

  • while true; do sleep 60; sudo -nv; done 2>/dev/null &: Actualice las credenciales de seguridad de sudo existentes repetidamente. Tenga en cuenta que esta versión difiere de la de la esencia vinculada: se ejecuta sleep 60primero y luego sudo -nv.

    • El &operador coloca todo el whilebucle en segundo plano y lo ejecuta como un proceso secundario.

    • La 2>/dev/nullredirigir la stderr del whilebucle para el vacío, por lo que los mensajes de error generados por cualquier comando dentro del bucle se descartarán.

    • La -nopción de sudoevita que solicite al usuario una contraseña, pero muestra un mensaje de error y sale si se requiere una contraseña.

    • No hay nada kill -0 "$$" || exitcomo en la esencia vinculada, porque los primeros dos traps harán el trabajo. ¡No tendrá que dormir durante 59 segundos antes de darse cuenta de que el proceso principal no se está ejecutando!

Rockallita
fuente