Временное увеличение времени ожидания sudo на время установки скрипта

22

Я пытаюсь написать сценарий, который установит кучу программного обеспечения, и я бы не хотел запускать все как root, поэтому я хотел бы иметь возможность запросить пароль и затем выполнить установку, используя sudoили suчтобы получить привилегии, когда они мне нужны.

Я делал sudo -vзапрос на ввод пароля в начале скрипта, а затем просто использовал sudo, как правило, позже. Это прекрасно работает, пока я не доберусь до одной установки, которая займет тайм-аут.

Я бы не хотел постоянно увеличивать время ожидания. Есть ли способ увеличить время ожидания sudo только для текущего сеанса?

Arelius
источник

Ответы:

8

Вы можете настроить цикл, который запускается в фоновом режиме, чтобы периодически выполнять «sudo -v», трюк, конечно, заключается в том, чтобы заставить цикл завершаться полностью, когда завершается ваш скрипт. Таким образом, должен быть какой-то тип связи между двумя процессами; Файлы tmp подходят для этого, и их легко можно очистить и после запуска скрипта. (В любом случае скрипт установки обычно делает это.)

Например (удалите операторы 'echo', чтобы использовать это; они просто показывают, что он "работает"):

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

Тогда вы увидите ... (примечание: pid помещен в файл tmp, просто чтобы вы могли легко его убить. Хотя это и не обязательно):

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

Мне понравился ответ michael_n, но у меня было иррациональное желание не использовать временный файл. Может быть, это может обеспечить некоторую перспективу.

Мое решение было:

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

Опять же, echoпосторонние ...

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

Опять же, Ctrl-C тоже работает ...

$ ./sudoping.sh 
Starting background sudo ping...
ok  
Sudo ping!
Sudo pinging in PID = 47599
Sudo ping!
^CStopping sudo ping in PID = 47599
Грегори Перкинс
источник
6
И более краткое решение: gist.github.com/3118588
Грегори Перкинс,
Как это не имеет 1000+ upvotes ??? Сжатая версия потрясающая. (Думаю, что поможет лучший пример.)
MountainX для Моники Челлио
3

На основании этой сущности , я сделал краткий и чистую версию:

# 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 &
Бор
источник
Я думаю, что gist-версия была бы лучше, потому что, если sudo -Kона вызывается в другом месте сценария оболочки, ваша версия будет кричать sudo: a password is requiredна stderr каждую минуту.
Rockallite
@Rockallite Вы имеете в виду мой связанный суть? Они на самом деле одинаковы.
Бор
0

Согласно 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.

Поэтому я полагаю, что если вы добавите некоторые sudo -vдополнительные пункты вашего сценария установки для проверки сеанса (и не только в начале), вы получите то, что хотите, так как каждый раз это увеличивает время ожидания (оно только запрашивает пароль снова, если тайм-аут достигнут). Единственная проблема будет в том случае, если в вашем скрипте есть команда, которая занимает больше времени, чем время ожидания (так что даже если вы выполняете проверку сразу после нее, время ожидания истечет до его завершения для другой проверки), но это очень специфический случай.

Что происходит, так это то, что простое использование sudoне увеличивает время ожидания и sudo -vне выполняет команду, поэтому вам нужно использовать sudo -vбольше раз для проверки сеанса.

CoreDump
источник
Да спасибо. Проблема в том, что мой тайм-аут sudo ближе к 5 минутам, и у меня есть отдельные команды make install, которые давно прошли.
Арелиус
Хм. Что ж. Тогда не нужно делать ничего, кроме увеличения времени ожидания. Там нет способа установить его временно.
coredump
0

Основываясь на сути, предоставленной Григорием Перкинсом, и моим опытом, вот моя строка:

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

Или

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

Пояснения

  • trap "exit" INT TERM; trap "kill 0" EXIT: Это приведет к удалению всего дерева процессов при выходе или SIGINT / SIGTERM.

  • sudo -v || exit $?: Запрашивать пароль заранее и кэшировать учетные данные безопасности, но не запускать команду. Если пароль неверный, выйдите с кодом, возвращенным sudo.

  • sleep 1: Задержка немного, чтобы учетные данные безопасности были эффективно сохранены. Если следующий sudo запускается слишком рано, он не узнает об этом, поскольку учетные данные еще не сохранены, поэтому запросит пароль еще раз.

  • while true; do sleep 60; sudo -nv; done 2>/dev/null &: Неоднократно обновлять существующие учетные данные безопасности sudo. Обратите внимание, что эта версия отличается от одной из связанных суть: sleep 60сначала она запускается , а затем sudo -nv.

    • &Оператор помещает весь whileцикл в фоновом режиме, запустив его в качестве дочернего процесса.

    • 2>/dev/nullПеренаправить поток ошибок в whileцикле до пустоты, так что сообщения об ошибках , генерируемых с помощью любых команд внутри цикла будет отброшены.

    • -nВариант sudoпредотвращает его запрашивая пользователя для пароля, но вывести сообщение об ошибке и выход , если требуется пароль.

    • Там нет, kill -0 "$$" || exitкак в связанной сущности, потому что первые два trapс будут делать эту работу. Ему не придется спать в течение 59 секунд, пока он не обнаружит, что родительский процесс не запущен!

Rockallite
источник