Запросить привилегии root из скрипта

23

У меня есть скрипт, который может работать как sudo script.shилиpkexec script.sh

С точки зрения пользователя было бы намного лучше, если бы скрипт запрашивал пароль у пользователя при его запуске по имени script.sh.

Как я могу «встроить» запрос pkexecили sudoзапустить весь скрипт с привилегиями root?

Обратите внимание, что запуск всего с sudo sh -cне может быть лучшим решением, так как у меня есть функции в сценарии.

Сергей Колодяжный
источник

Ответы:

55

Это будет работать:

echo "$(whoami)"

[ "$UID" -eq 0 ] || exec sudo "$0" "$@"

пример:

./test.sh 
blade
[sudo] password for blade: 
root
blade19899
источник
3
Что хорошего в этом, так это рекурсия с exec- вызывайте саму себя, но в то же время заменяя процесс, поэтому мы не порождаем несколько экземпляров сценария
Сергей Колодяжный
1
Рекурс на помощь !!! Напомните мне, чтобы добавить награду к этому через несколько дней!
Fabby
6
При этом следует учитывать повышение привилегий; в основном, чем больше команд вы запускаете от имени root, тем больше у злоумышленника возможностей использовать что-то для получения доступа к учетной записи root. Я не говорю, что всегда неправильно запускать весь сценарий от имени root, но стоит подумать, прежде чем вы решите это сделать. Я думаю, что было бы неплохо (хотя и не обязательно), если бы ответ затронул это.
Дэвид З
Если в / etc / sudoers установлено приличное значение тайм-аута, то вы можете при желании поставить sudo перед каждой командой в скрипте, которая действительно нуждается в root-праве, и она спросит только один раз. Я часто путаюсь с тем, что вызов такого скрипта из графического интерфейса не будет работать, потому что sudo получает / dev / null для ввода пароля и завершается ошибкой. Это то, что gksudo и kdesudo были разработаны для обработки, потому что они будут использовать графический интерфейс для запроса пароля.
Джо
1
@ Coder256: Я не думаю, что ваше редактирование было правильным. "$@"расширится до нескольких слов, по одному для каждого параметра.
Jwodder
12

Если вы хотите красивый диалог, попробуйте что-то вроде этого. Я извлек это прямо из чего-то еще, что написал, так что у него есть дополнительные вещи, которые вам могут не понадобиться или не хотеть, но это показывает общую идею:

brand="My Software"

# Check that the script is running as root. If not, then prompt for the sudo
# password and re-execute this script with sudo.
if [ "$(id -nu)" != "root" ]; then
    sudo -k
    pass=$(whiptail --backtitle "$brand Installer" --title "Authentication required" --passwordbox "Installing $brand requires administrative privilege. Please authenticate to begin the installation.\n\n[sudo] Password for user $USER:" 12 50 3>&2 2>&1 1>&3-)
    exec sudo -S -p '' "$0" "$@" <<< "$pass"
    exit 1
fi

диалог sudo

Это использует whiptail, который вы можете установить, если у вас его еще нет:

sudo apt-get install whiptail
Майкл Хэмптон
источник
1
Почему вы сохраняете пароль в переменной?
Heemayl
10
Не звони exec echo [PASSWORD]! Это вызовет процесс с паролем в командной строке, который может увидеть любой пользователь. Либо используйте встроенную команду echo(принудительно builtin echoвключите встроенную версию ), либо bashism <<<(например, так :) sudo ... <<< "$pass"; Ш и другие снаряды имеют здесь документы на эти случаи. Также укажите пароль, если он содержит специальные символы.
Дэвид Фёрстер
В качестве альтернативы, поместите whiptailкоманду в отдельный скрипт и используйте что-то вроде того, SUDO_ASKPASS=/path/to/askpass-with-whiptail.sh sudo -A -p "My password prompt" -- "$0" "$@"чтобы иметь sudoдело с пользовательской подсказкой пароля.
Дэвид Фёрстер
@DavidFoerster Это может сработать, но тогда вам нужно либо два сценария, либо вы пишете сценарий askpass во временный файл, а затем передаете его в sudo.
Майкл Хэмптон
Хорошо, однако другие уже отметили, что нежелательно передавать пароль в переменную. Идентификационный подход заключается в том, чтобы передать вывод диалога в именованный канал, как я показал здесь askubuntu.com/a/704643/295286
Сергей Колодяжный
11

Ответ blade19899 - действительно путь, однако можно также вызвать sudo bashшебанг:

#!/usr/bin/sudo bash
# ...

Очевидное предостережение заключается в том, что это будет работать только до тех пор, пока вызывается сценарий, ./scriptи завершается ошибкой, как только вызывается сценарий bash script.

кос
источник
5
Это одна из причин, почему вы никогда не должны вводить bash scriptв командной строке, чтобы вызвать скрипт. Если сценарий определяет , что - нибудь другое , чем bashв #!линии, то применение его bash scriptбудет терпеть неудачу. Если бы я попытался вызвать скрипт Python, используя bash script.pyего, я бы тоже не смог.
Касперд
1
Вы можете запустить его perl script, хотя. Perl, стараясь быть действительно хорошим, проверяет строку shebang, и если он не вызывает perl, он запускает правильную программу.
tbodt
Это плохо, потому что он запускает каждую команду в сценарии с помощью sudo. Лучше выделить несколько команд, которые действительно нуждаются в sudo, и добавить их при необходимости. Не включайте оценку функций в эти вызовы sudo; они должны быть максимально четкими и минимальными.
Дуглас состоялся
@DouglasHeld Хотя я могу с этим согласиться, вопрос задается следующим образом: «Как я могу« встроить »запрос в pkexec или sudo для запуска всего скрипта с привилегиями root?». Уверен, что будут случаи использования, при которых возможность сделать это будет полезной.
Кос
6

Я предискажу команды внутри сценария, которым нужен root-доступ sudo- если пользователь еще не получил разрешения, сценарий запрашивает пароль в этой точке.

пример

#!/bin/sh 
mem=$(free  | awk '/Mem:/ {print $4}')
swap=$(free | awk '/Swap:/ {print $3}')

if [ $mem -lt $swap ]; then
    echo "ERROR: not enough RAM to write swap back, nothing done" >&2
    exit 1
fi

sudo swapoff -a && 
sudo swapon -a

Этот скрипт может быть запущен как sudo <scriptname>или как <scriptname>. В любом случае он будет запрашивать пароль только один раз.

Чарльз Грин
источник
2
Проблема здесь в том, что может быть несколько команд, которым нужен root-доступ, что означает вызов sudo25 различных команд с избыточностью - проще вызвать sudo один раз. Здесь, однако, причина, по которой ваш скрипт вызывает sudo только один раз, заключается в том, что у sudo есть время из 15 минут - команды, которые занимают больше времени, чем нужно, должны быть повторно обработаны. Твой путь работает просто. , , не так, как мне нужно, чтобы это работало.
Сергей Колодяжный,
@Serg Для маленького сценария мой способ был быстрым и легким - я действительно не элегантный программист!
Чарльз Грин
Вы лучший программист, размещающий на этой странице. Вы используете sudo точно так, как его следует использовать - только там, где это необходимо, и с очень четкими результатами.
Дуглас состоялся
4

Похоже, что никто другой не обратил внимание на очевидную проблему здесь. Помещение sudoв ваш скрипт, который вы затем распространяете, продвигает вредные привычки пользователя . (Я предполагаю, что вы распространяете его, потому что упоминаете «с точки зрения пользователя».)

Правда заключается в том, что в использовании приложений и сценариев существует руководство, аналогичное принципу безопасности в банковском деле: никогда не передавайте свою личную информацию тому, кто вам звонит и говорит, что он звонит «из вашего банка» , и который существует по тем же причинам.

Правило для приложений:

Никогда не вводите пароль при появлении запроса, если вы не уверены, что с ним делается. Это относится ко всем лицам, имеющим sudoдоступ.

Если вы вводите свой пароль, потому что вы запускаете sudoв командной строке, отлично. Если вы печатаете его, потому что вы запустили команду SSH, хорошо. Если вы набираете его при входе в свой компьютер, конечно, замечательно.

Если вы просто запускаете сторонний скрипт или исполняемый файл и при необходимости вводите свой пароль, вы не знаете, что скрипт делает с ним. Это может быть хранение его во временном файле в незашифрованном виде, насколько вы знаете, и может даже не очистить после себя.

Очевидно, что существуют отдельные и дополнительные проблемы с запуском неизвестного набора команд root, но я говорю здесь о поддержании безопасности самого пароля . Даже если предположить, что приложение / скрипт не является вредоносным, вы все равно хотите, чтобы ваш пароль обрабатывался надежно, чтобы другие приложения не могли его использовать и использовать его злонамеренно.

Итак, мой личный ответ на это, что лучше всего добавить в ваш скрипт, если ему нужны привилегии root, это:

#!/bin/bash
[ "$UID" -eq 0 ] || { echo "This script must be run as root."; exit 1;}

# do privileged stuff, etc.
Wildcard
источник
Хотя я полностью согласен с вами, пользователь, который запускает что-то, не зная, что он делает, так sudo script_nameже уязвим, но это то же самое. Может быть, эта идея продвигает вредные привычки - я ничего не скажу об этом. Но ключ в том, чтобы знать, что делает программа, и это ответственность пользователя. Вот и вся идея программного обеспечения с открытым исходным кодом. Что касается моего собственного сценария, хорошо. , , сценарий представляет собой простой текст - пользователи могут прочитать его, если они хотят знать, что он делает
Сергей Колодяжный
@SergiyKolodyazhnyy это похоже, но если вы введете свой пароль непосредственно в сценарий, это на самом деле хуже. Скрипт, запускаемый с помощью sudo, все еще не знает ваш пароль.
Wildcard
1

Я сделал это так:

echo -n "Enter password for sudo rights: "
read -s pass

echo $pass | sudo -S [your command here]
88weighed
источник
4
По крайней мере, укажите ваши переменные.
Муру
И цитирование ваших переменных может даже не помочь, если ваш пароль начинается с дефиса.
Wildcard