Untuk sementara waktu meningkatkan batas waktu sudo selama skrip instalasi

22

Saya mencoba menulis skrip yang akan menginstal banyak perangkat lunak dan saya ingin tidak harus menjalankan semuanya root, jadi saya ingin dapat meminta kata sandi dan kemudian menginstal, menggunakan sudoatau suuntuk mendapatkan hak istimewa saat saya membutuhkannya.

Saya melakukan sudo -vuntuk meminta kata sandi di awal skrip, dan kemudian hanya menggunakan sudo secara normal nanti. Ini berfungsi dengan baik sampai saya mendapatkan satu instalasi yang membutuhkan waktu habis.

Saya lebih suka tidak perlu menambah waktu tunggu secara permanen. Apakah ada cara saya dapat menambah waktu tunggu sudo hanya untuk sesi saat ini?

Arelius
sumber

Jawaban:

8

Anda dapat mengatur loop yang berjalan di latar belakang untuk secara berkala mengeksekusi "sudo -v", triknya tentu saja adalah mendapatkan loop untuk mengakhiri dengan bersih ketika skrip Anda berakhir. Jadi harus ada beberapa jenis komunikasi antara kedua proses; File tmp baik untuk ini, dan mereka dapat dengan mudah dibersihkan setelah skrip berjalan juga. (Lagi pula, skrip instal biasanya melakukan ini.)

Misalnya (hapus pernyataan 'gema' untuk menggunakan ini; ini hanya menunjukkan itu "berfungsi"):

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

Maka Anda akan melihat ... (catatan: pid dimasukkan ke dalam file tmp, supaya Anda dapat dengan mudah membunuhnya. Namun, tidak perlu):

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

Saya menyukai jawaban michael_n, tetapi memiliki keinginan paling irasional untuk tidak menggunakan file temp. Mungkin ini bisa memberikan beberapa perspektif.

Solusi saya adalah:

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

Sekali lagi, echoitu adalah ...

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

Sekali lagi, ctrl-c berfungsi juga ...

$ ./sudoping.sh 
Starting background sudo ping...
ok  
Sudo ping!
Sudo pinging in PID = 47599
Sudo ping!
^CStopping sudo ping in PID = 47599
Gregory Perkins
sumber
6
Dan solusi yang lebih ringkas: gist.github.com/3118588
Gregory Perkins
Bagaimana ini tidak memiliki 1000+ upvotes ??? Versi ringkasnya mengagumkan. (Tapi saya rasa contoh yang lebih baik akan membantu.)
MountainX untuk Monica Cellio
3

Berdasarkan intisari ini , saya telah membuat versi yang ringkas dan bersih:

# 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
sumber
Saya pikir versi inti akan lebih baik, karena jika sudo -Kdipanggil di tempat lain dari skrip shell, versi Anda akan berteriak sudo: a password is requiredke stderr setiap menit.
Rockallite
@Rockallite Maksud Anda inti tertaut saya? Mereka sebenarnya sama.
Bohr
0

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

Jadi saya kira jika Anda menambahkan beberapa sudo -vpoin skrip pengaturan Anda untuk memvalidasi sesi (dan tidak hanya di awal), Anda akan mendapatkan apa yang Anda inginkan, karena setiap kali akan menambah batas waktu (hanya meminta kata sandi lagi jika batas waktu tercapai). Satu-satunya masalah adalah jika ada perintah pada skrip Anda yang membutuhkan lebih banyak waktu daripada batas waktu (jadi meskipun Anda memvalidasi tepat setelah itu, batas waktu akan berakhir sebelum menyelesaikan untuk validasi lain), tetapi ini adalah kasus yang sangat spesifik.

Apa yang terjadi adalah bahwa menggunakan sudosaja tidak menambah batas waktu, dan sudo -vtidak menjalankan perintah, jadi Anda harus menggunakan sudo -vlebih banyak waktu untuk memvalidasi sesi.

coredump
sumber
Ya terima kasih. Masalahnya adalah batas waktu sudo saya lebih dekat ke 5 menit, dan saya punya perintah install make tunggal yang melewati itu.
Arelius
Hmm. Baik. Tidak banyak yang bisa dilakukan selain meningkatkan batas waktu itu. Tidak ada cara untuk mengaturnya sementara.
coredump
0

Berdasarkan intisari yang disediakan oleh Gregory Perkins dan pengalaman saya, inilah one-liner saya:

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

Atau

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

Penjelasan

  • trap "exit" INT TERM; trap "kill 0" EXIT: Ini akan mencatat seluruh pohon proses saat keluar atau SIGINT / SIGTERM.

  • sudo -v || exit $?: Minta kata sandi di muka dan tembolok kredensial keamanan, tetapi jangan jalankan perintah. Jika kata sandi salah, keluar dengan kode yang dikembalikan oleh sudo.

  • sleep 1: Menunda sedikit agar kredensial keamanan disimpan secara efektif. Jika sudo berikutnya berjalan terlalu cepat, ia tidak akan mengetahuinya karena kredensial belum disimpan, sehingga akan meminta kata sandi lagi.

  • while true; do sleep 60; sudo -nv; done 2>/dev/null &: Perbarui kredensial keamanan sudo yang ada berulang kali. Perhatikan bahwa versi ini berbeda dari salah satu intisari tertaut: berjalan sleep 60pertama, dan kemudian sudo -nv.

    • The &Operator menempatkan seluruh whilelingkaran ke latar belakang, menjalankannya sebagai proses anak.

    • The 2>/dev/nullmengarahkan stderr dari whileloop untuk kekosongan, sehingga pesan error yang dihasilkan oleh setiap perintah dalam loop akan dibuang.

    • The -npilihan untuk sudomencegah dari mendorong pengguna untuk password, tetapi menampilkan pesan kesalahan dan keluar jika diperlukan password.

    • Tidak ada kill -0 "$$" || exitdi intisari tertaut, karena dua yang pertama trapakan melakukan pekerjaan. Tidak perlu tidur selama 59 detik sebelum mengetahui proses induknya tidak berjalan!

Rockallite
sumber