Aumentando temporariamente o tempo limite do sudo pela duração de um script de instalação

22

Estou tentando escrever um script que instalará um monte de software e gostaria de não ter que executar tudo como root, portanto, gostaria de poder solicitar uma senha e depois prosseguir com a instalação, usando sudoou supara obter privilégios quando eu precisar deles.

Eu estava sudo -vsolicitando uma senha no início do script e depois usando o sudo normalmente mais tarde. Isso funciona muito bem até chegar a uma única instalação que demora o tempo limite.

Prefiro não ter que aumentar permanentemente o tempo limite. Existe uma maneira de aumentar o tempo limite do sudo apenas para a sessão atual?

Arelius
fonte

Respostas:

8

Você pode configurar um loop que é executado em segundo plano para executar periodicamente "sudo -v", o truque é fazer com que o loop termine de maneira limpa quando o script terminar. Portanto, deve haver algum tipo de comunicação entre os dois processos; Os arquivos tmp são bons para isso e também podem ser facilmente limpos após a execução do script. (Um script de instalação geralmente faz isso, de qualquer maneira.)

Por exemplo (remova as instruções 'echo' para usar isso; elas apenas mostram "trabalhando"):

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

Então você verá ... (nota: o pid é colocado no arquivo tmp, apenas para que você possa matá-lo facilmente. Porém, não é necessário):

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

Gostei da resposta de michael_n, mas tinha o desejo mais irracional de não usar um arquivo temporário. Talvez isso possa fornecer alguma perspectiva.

Minha solução foi:

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

Novamente, os echosão estranhos ...

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

Novamente, ctrl-c também 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
fonte
6
E uma solução mais sucinta: gist.github.com/3118588
Gregory Perkins
Como isso não tem mais de 1000 votos ??? A versão sucinta é incrível. (Mas um exemplo melhor ajudaria, eu acho.)
MountainX para Monica Cellio
3

Com base nessa essência , fiz uma versão concisa e limpa:

# 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
fonte
Eu acho que a versão principal seria melhor, porque se sudo -Kfor invocada em outro lugar do shell script, sua versão gritará sudo: a password is requiredcom o stderr a cada minuto.
Rockallite 16/02
@Rockallite Você quer dizer minha essência ligada? Eles são realmente os mesmos.
Bohr
0

De acordo com a sudopágina do 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.

Então, acho que se você adicionar mais alguns sudo -vpontos do seu script de configuração para validar a sessão (e não apenas no início), obterá o que deseja, pois cada vez que isso aumenta o tempo limite (ele só pede a senha novamente se o tempo limite é atingido). O único problema será se houver um comando no seu script que demore mais tempo do que o tempo limite (mesmo se você validar logo após o tempo limite expirar antes de concluir para outra validação), mas esse é um caso muito específico.

O que acontece é que apenas o uso sudonão aumenta o tempo limite e sudo -vnão executa um comando; portanto, você precisa usar sudo -vmais vezes para validar a sessão.

coredump
fonte
Sim obrigado. O problema é que o tempo limite do meu sudo está mais próximo de 5 minutos e eu tenho comandos make install únicos que ultrapassam isso.
Arelius
Hmm. Bem. Não há muito o que fazer além de aumentar o tempo limite. Não há como configurá-lo temporariamente.
Coredump
0

Baseando-nos na essência fornecida por Gregory Perkins e na minha experiência, aqui está o meu artigo:

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

Ou

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

Explicações

  • trap "exit" INT TERM; trap "kill 0" EXIT: Isso derrubará toda a árvore do processo na saída ou no SIGINT / SIGTERM.

  • sudo -v || exit $?: Solicite a senha antecipadamente e armazene em cache as credenciais de segurança, mas não execute um comando. Se a senha não estiver correta, saia com o código retornado pelo sudo.

  • sleep 1: Demore um pouco para que as credenciais de segurança sejam efetivamente salvas. Se o próximo sudo for executado muito cedo, ele não saberá, porque as credenciais ainda não foram salvas, portanto, solicitará a senha novamente.

  • while true; do sleep 60; sudo -nv; done 2>/dev/null &: Atualize as credenciais de segurança sudo existentes repetidamente. Observe que esta versão difere daquela da essência vinculada: é executada sleep 60primeiro e depois sudo -nv.

    • O &operador coloca todo o whileloop em segundo plano, executando-o como um processo filho.

    • O 2>/dev/nullredireciona o stderr do whileloop para o vazio, para que as mensagens de erro geradas por qualquer comando dentro do loop sejam descartadas.

    • A -nopção sudoimpede que ele solicite uma senha ao usuário, mas exiba uma mensagem de erro e saia se for necessária uma senha.

    • Não há kill -0 "$$" || exitcomo na essência vinculada, porque os dois primeiros traps farão o trabalho. Ele não precisará dormir por 59 segundos antes de descobrir que o processo pai não está sendo executado!

Rockallite
fonte