Tymczasowo zwiększa limit czasu sudo na czas trwania skryptu instalacyjnego

22

Próbuję napisać skrypt, który będzie zainstalować kilka programów i chciałbym, aby nie trzeba uruchamiać wszystko jako root, więc chciałbym, aby móc monit o hasło, a następnie przejść o instalacji, używając sudolub suaby uzyskać uprawnienia, kiedy ich potrzebuję.

Robiłem sudo -vmonit o podanie hasła na początku skryptu, a potem po prostu używałem sudo normalnie później. Działa to świetnie, dopóki nie przejdę do pojedynczej instalacji, która przejmuje limit czasu.

Wolałbym nie zmuszać do ciągłego zwiększania limitu czasu. Czy istnieje sposób na zwiększenie limitu czasu sudo tylko dla bieżącej sesji?

Arelius
źródło

Odpowiedzi:

8

Możesz skonfigurować pętlę, która działa w tle, aby okresowo uruchamiać „sudo -v”, sztuczka polega na tym, aby pętla zakończyła się po zakończeniu skryptu. Musi więc istnieć pewien rodzaj komunikacji między tymi dwoma procesami; Pliki tmp są do tego odpowiednie i można je łatwo wyczyścić po uruchomieniu skryptu. (Skrypt instalacyjny zwykle tak robi.)

Na przykład (usuń instrukcje „echo”, aby użyć tego; te po prostu pokazują, że „działa”):

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

Wtedy zobaczysz ... (uwaga: pid jest umieszczany w pliku tmp, abyś mógł go łatwo zabić. Nie jest to jednak konieczne):

$ ./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)
Michał
źródło
9

Podobało mi się odpowiedź Michaela, ale najbardziej irracjonalnie chciałem nie używać pliku tymczasowego. Może to może dać trochę perspektywy.

Moim rozwiązaniem było:

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

Ponownie, echosą obce ...

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

Ponownie, ctrl-c też działa ...

$ ./sudoping.sh 
Starting background sudo ping...
ok  
Sudo ping!
Sudo pinging in PID = 47599
Sudo ping!
^CStopping sudo ping in PID = 47599
Gregory Perkins
źródło
6
I bardziej zwięzłe rozwiązanie: gist.github.com/3118588
Gregory Perkins
Jak to nie ma ponad 1000 głosów pozytywnych ??? Zwięzła wersja jest niesamowita. (Ale myślę, że lepszy przykład mógłby pomóc.)
MountainX dla Moniki Cellio
3

Na podstawie tego GIST , zrobiłem zwięzły i czystą wersję:

# 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
źródło
Myślę, że wersja gist byłaby lepsza, ponieważ jeśli sudo -Kzostanie wywołana w innym miejscu skryptu powłoki, twoja wersja będzie krzyczeć sudo: a password is requireddo stderr co minutę.
Rockallite
@Rockallite Czy masz na myśli moją powiązaną treść? W rzeczywistości są takie same.
Bohr
0

Według strony podręcznika sudo:

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

Sądzę więc, że jeśli dodasz sudo -vwięcej punktów w skrypcie instalacyjnym, aby sprawdzić poprawność sesji (i to nie tylko na początku), dostaniesz to, czego chcesz, ponieważ za każdym razem zwiększa limit czasu (pyta tylko o hasło, jeśli limit czasu został osiągnięty). Jedynym problemem będzie, jeśli w skrypcie pojawi się polecenie, które zajmuje więcej czasu niż limit czasu (więc nawet jeśli sprawdzasz poprawność zaraz po tym, limit czasu upłynie przed zakończeniem kolejnej weryfikacji), ale jest to bardzo szczególny przypadek.

To, co się dzieje, polega na tym, że samo użycie sudonie zwiększa limitu czasu i sudo -vnie wykonuje polecenia, więc musisz użyć sudo -vwięcej razy, aby sprawdzić poprawność sesji.

rdzeń rdzeniowy
źródło
Tak dzieki. Problem polega na tym, że mój limit czasu sudo jest bliższy 5 minutom i mam pojedyncze polecenia instalacji, które już dawno minęły.
Arelius
Hmm Dobrze. Nie ma wtedy wiele do zrobienia poza zwiększaniem limitu czasu. Nie ma możliwości ustawienia go tymczasowo.
coredump
0

Baza na GIST dostarczonych przez Gregory Perkins i mojego doświadczenia, oto mój jeden-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 &

Lub

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

Objaśnienia

  • trap "exit" INT TERM; trap "kill 0" EXIT: Spowoduje to usunięcie całego drzewa procesów przy wyjściu lub SIGINT / SIGTERM.

  • sudo -v || exit $?: Poproś o hasło z góry i buforuj poświadczenia bezpieczeństwa, ale nie uruchamiaj polecenia. Jeśli hasło jest nieprawidłowe, wyjdź z kodem zwróconym przez sudo.

  • sleep 1: Opóźnij trochę, aby poświadczenia bezpieczeństwa zostały skutecznie zapisane. Jeśli następne sudo uruchomi się zbyt wcześnie, nie będzie o tym wiedział, ponieważ poświadczenia nie zostały jeszcze zapisane, dlatego poprosi o hasło ponownie.

  • while true; do sleep 60; sudo -nv; done 2>/dev/null &: Aktualizuj istniejące poświadczenia zabezpieczeń sudo wielokrotnie. Zauważ, że ta wersja różni się od jednej z powiązanych linków: sleep 60najpierw działa , a potem sudo -nv.

    • &Operator stawia całą whilepętlę w tle, uruchamiając go jako procesu potomnego.

    • 2>/dev/nullPrzekierować stderr z whilepętli do nieważna, więc komunikaty o błędach generowane przez jakiekolwiek polecenia wewnątrz pętli zostaną odrzucone.

    • -nOpcja sudouniemożliwia monitowania użytkownika o hasło, ale wyświetla komunikat o błędzie i wyjście, jeśli wymagane jest hasło.

    • Nie ma kill -0 "$$" || exitjak w połączonej treści, ponieważ pierwsze dwa traps wykonają zadanie. Nie będzie musiał spać przez 59 sekund, zanim zorientuje się, że proces nadrzędny nie jest uruchomiony!

Rockallite
źródło