Aumentando temporaneamente il timeout di sudo per la durata di uno script di installazione


22

Sto cercando di scrivere uno script che installerà un sacco di software e mi piacerebbe non dover eseguire tutto come root, quindi mi piacerebbe essere in grado di richiedere una password e quindi procedere con l'installazione, utilizzando sudoo super ottenere privilegi quando ne ho bisogno.

Stavo facendo una sudo -vrichiesta di password all'inizio dello script, e poi semplicemente usando sudo normalmente più tardi. Funziona benissimo fino a quando non arrivo a una singola installazione che prende il timeout.

Preferirei non dover aumentare permanentemente il timeout. È possibile aumentare il timeout di sudo solo per la sessione corrente?

Risposte:


8

È possibile impostare un ciclo che viene eseguito in background per eseguire periodicamente "sudo -v", il trucco ovviamente consiste nel far terminare il ciclo in modo pulito quando termina lo script. Quindi deve esserci un qualche tipo di comunicazione tra i due processi; I file tmp vanno bene per questo, e possono essere facilmente ripuliti anche dopo l'esecuzione dello script. (Uno script di installazione di solito fa questo, comunque.)

Ad esempio (rimuovi le istruzioni 'echo' per usarlo; queste mostrano semplicemente che "funziona"):

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

Quindi vedrai ... (nota: il pid viene inserito nel file tmp, solo per poterlo facilmente uccidere. Non è necessario, però):

$ ./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)

9

Mi è piaciuta la risposta di michael_n, ma avevo il desiderio più irrazionale di non usare un file temporaneo. Forse questo può fornire qualche prospettiva.

La mia soluzione era:

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

Ancora una volta, echosono estranei ...

$ ./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

Anche in questo caso, ctrl-c funziona anche ...

$ ./sudoping.sh 
Starting background sudo ping...
ok  
Sudo ping!
Sudo pinging in PID = 47599
Sudo ping!
^CStopping sudo ping in PID = 47599

6
E una soluzione più concisa
Gregory Perkins,

In che modo questo non ha 1000+ voti ??? La versione succinta è fantastica. (Ma un esempio migliore sarebbe di aiuto, credo.)
MountainX per Monica Cellio il

3

Sulla base di questa sintesi , ho realizzato una versione concisa e pulita:

# 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 &

Penso che la versione gist sarebbe migliore, perché se sudo -Kinvocata in un altro posto dello script della shell, la tua versione urlerebbe sudo: a password is requiredallo standard ogni minuto.
Rockallite,

@Rockallite Intendi la mia sostanza collegata? In realtà sono gli stessi.
Bohr,

0

Secondo la sudopagina man:

   -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.

Quindi immagino che se ne aggiungi alcuni sudo -vin più punti dello script di installazione per convalidare la sessione (e non solo all'inizio) otterrai ciò che desideri, poiché ogni volta aumenterà il timeout (chiederà di nuovo la password solo se il timeout è raggiunto). L'unico problema sarà se sul tuo script è presente un comando che richiede più tempo del timeout (quindi anche se lo convalidi subito dopo il timeout scadrà prima che venga completato per un'altra convalida), ma questo è un caso molto specifico.

Quello che succede è che il solo utilizzo sudonon aumenta il timeout e sudo -vnon esegue un comando, quindi è necessario utilizzare sudo -vpiù volte per convalidare la sessione.


Si, grazie. Il problema è che il mio timeout sudo è più vicino ai 5 minuti e ho comandi di installazione singola che vanno oltre.
Arelius,

Hmm. Bene. Allora non c'è molto da fare oltre ad aumentare il timeout. Non c'è modo di impostarlo temporaneamente.
coredump,

0

Base sul Gist fornito da Gregory Perkins e la mia esperienza, ecco il mio one-liner:

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 &

spiegazioni

  • trap "exit" INT TERM; trap "kill 0" EXIT: Questo eliminerà l'intero albero di processo all'uscita o SIGINT / SIGTERM.

  • sudo -v || exit $?: Chiedi la password in anticipo e memorizza nella cache le credenziali di sicurezza, ma non esegui un comando. Se la password non è corretta, uscire con il codice restituito da sudo.

  • sleep 1: Ritarda un po 'in modo che le credenziali di sicurezza vengano effettivamente salvate. Se il prossimo sudo viene eseguito troppo presto, non lo saprà perché le credenziali non sono ancora state salvate, quindi chiederà di nuovo la password.

  • while true; do sleep 60; sudo -nv; done 2>/dev/null &: Aggiorna ripetutamente le credenziali di sicurezza sudo esistenti. Si noti che questa versione differisce da quella dell'essenza collegata: viene eseguita sleep 60prima e quindi sudo -nv.

    • L' &operatore mette l'intero whileciclo in background, eseguendolo come un processo figlio.

    • Il 2>/dev/nullreindirizzamento dello stderr del whileloop verso il vuoto, quindi i messaggi di errore generati da qualsiasi comando all'interno del loop verranno eliminati.

    • L' -nopzione sudoimpedisce che richieda all'utente una password, ma visualizza un messaggio di errore ed esce se è richiesta una password.

    • Non c'è kill -0 "$$" || exitcome nell'essenza collegata, perché i primi due trapfaranno il lavoro. Non dovrà dormire per 59 secondi prima di capire che il processo genitore non è in esecuzione!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.