Как повысить привилегии пользователя root в bash
? А как тогда вернуться обратно в точно предыдущее состояние? У меня вопрос о повышении / уменьшении привилегий и возможных проблемах с некоторыми приложениями, особенно приложениями с графическим интерфейсом (и «средой»).
Скажем, некоторые приложения поддерживают отдельный профиль для каждого пользователя и пользователя root. GUI & amp; профили могут быть не единственной проблемой «среды», если я запускаю приложение от имени пользователя root, независимо от того, является ли это ошибкой их или ОС, или функцией.
Скажем, мне нужно запустить скрипт от имени пользователя root или уже запустить скрипт от имени пользователя root (как в rc.local), поэтому вам может потребоваться уменьшить привилегии или «полностью» переключиться обратно на обычного пользователя ([ 115] не всегда работает). Запустить сначала скрипт с sudo -H
, а затем переключиться на другого пользователя? Это не всегда работает должным образом, особенно с приложениями с графическим интерфейсом. Я полагаю, что проблема в «окружающей среде», и DISPLAY=:0 ...
или DISPLAY=:0 gtk-launch ...
(gtk-launch
, вероятно, прослушивается) могут быть все же бесполезными.
Скажем, у меня есть gedit
с открытым документом. Если я работаю как обычный пользователь gedit /doc2
, он открывается с видимым меню и в уже существующем окне в еще одна вкладка . Если я запускаю его как root, он открывается в отдельном окне и без видимого меню. Если я запускаю скрипт через sudo -H
или su
и пытаюсь запустить там gedit /doc2
от имени этого обычного пользователя (снова с sudo (-H) или su), то он работает так, как будто я сделал это как root, а не как обычный пользователь. Я попробовал также sudo
варианты -l, -s, -i
. С другими приложениями GUI, которые вызвали гораздо более серьезные проблемы. Некоторые приложения с графическим интерфейсом имеют другой графический интерфейс или вообще не запускаются. Иногда runuser
помогал мне, но не всегда. И формат heredoc (sudo -H /bin/bash <<EOF <lines with commands> EOF
) не работает должным образом.
И полный пример на всякий случай (запустите как sudo ./script.sh
или с -H
):
cd /somedir
some_commands # using the current directory, root privileges and setting some variables, and writing to somefile (better as normal user)
sudo -u normaluser /bin/bash -c 'gedit --encoding someencoding /somefile'`
Если я запускаю следующий скрипт bash как просто [ 1121]
gedit --encoding someencoding /somefile
, затем gedit
работает как надо.
На всякий случай: речь идет об Ubunu 16.04 xenial, версия bash 4.3.48.
Обновление :
Я знаю, что могу запускать такие команды, как
sudo sh -c ‘command1 $somevariable; command2’
или (я обнаружил, что это может быть несколько строк)
[ 113] или, может быть, что-то похожее с bash
. Это может быть не вариант для большого набора команд и не решает всех проблем. И мне абсолютно не нужно вводить команды в интерактивном режиме. Смотрите также мой ответ.
P.S. Я думаю, что Linux должен быть удобным и простым в использовании.
Мой ответ. Тем не менее, необходимо решить, как просто повысить и уменьшить привилегии (фактически, концептуально, даже без переноса, существующие отдельно) или полностью переключиться на root и обратно.
Основываясь на моих предложениях, LeonidMew и WinEunuuchs2Unix, вот обходной путь. Параметр -H
обычно является хорошим выбором, поэтому я его включаю.
Существует два обходных пути (bash
можно заменить на sh
):
1) sudo -H /bin/bash -c ‘commands’
и
2) sudo -H /bin/bash -c “commands”
(а также формат heredoc sudo -H /bin/bash <<EOF <lines with commands> EOF
).
1) Переменные снаружи не видны внутри автоматически. Они должны быть перемещены внутрь, иметь двойное определение или передаваться в качестве аргументов. Я не мог сделать или передать короткое (пере) объявление внешней функции, такой как $(declare -f functionname)
внутри (возможно, это еще возможно), но это сработало, если я просто переместил ее внутрь.
2) Внутри передаются только копии переменных извне. Вы должны будете уйти с \
конструкциями $(...)
, $PWD
или другими локально определенными переменными, И комментирование с #
может не работать (как с #$(declare -f ...)
). Аргументы типа $1
являются аргументами всего скрипта и не могут быть переданы внутрь как локальные переменные. Внешне определенные функции не видны внутри, но могут быть повторно объявлены внутри, как $(declare -f functionname)
.
В обоих случаях вы можете получить вывод через файлы или быстрый вывод строки из stdout (или нескольких разделенных пробелами переменных) через перенос res=$(...)
. Вы можете увидеть пример здесь: https://stackoverflow.com/a/23567255 . Хотя после упаковки все EOLs конвертируются в пробелы. Может быть, export
, предназначенный для передачи переменных в подпроцессы, поможет избежать такого переноса или использования файлов, но почему-то это не сработало для меня.
Случай 1) представляется наилучшим выбором по умолчанию и, скорее всего, потребует меньшего количества модификаций существующего кода, в отличие от случая 2), когда обычно требуется тщательная модификация существующего кода. Может быть, вы найдете оба случая полезными одновременно.
Это мой простой пример:
tmpdir=/tmp/
tmpfile=/tmp/tmpfile
res=$(sudo -H bash -c 'tmpdir=$1; tmpfile=$2
echo "$tmpdir;"
cd $ tmpdir
echo $(pwd)
echo "A string from file" > $tmpfile
' - $tmpdir $tmpfile)
echo $res
arr=($res)
echo ${arr[0]} # Hellooo
echo ${arr[1]} # world;
echo ${arr[*]} # whole array
echo ${#arr[*]} # number of items
n=0
echo ${#arr[$n]} # length of the n-th element
cat $tmpfile
sudo sh -c 'rm -f $2' - - $tmpfile
У меня не так много сценариев, которые повышают привилегии пользователя до полномочий sudo
(суперпользователя). По иронии судьбы, из-за того, что ваш вопрос касается gedit
одного из моих сценариев, он называется sgedit
. Он был создан из-за того, что gksu gedit
больше не поддерживается и из-за того, что пользователь root не может устанавливать настройки вкладок, настройки шрифтов и т. Д.
#!/bin/bash
# NAME: sgedit
# PATH: /mnt/e/bin
# DESC: Run gedit as sudo using $USER preferences
# DATE: June 17, 2018.
# Must not prefix with sudo when calling script
if [[ $(id -u) == 0 ]]; then
zenity --error --text "You cannot call this script using sudo. Aborting."
exit 99
fi
# Get user preferences before elevating to sudo
gsettings list-recursively | grep -i gedit | grep -v history | \
grep -v docinfo | \
grep -v virtual-root | grep -v state.window > /tmp/gedit.gsettings
sudoFunc () {
# Must be running as sudo
if [[ $(id -u) != 0 ]]; then
zenity --error --text "Sudo password authentication failed. Aborting."
exit 99
fi
# Get sudo's gedit preferences
gsettings list-recursively | grep -i gedit | grep -v history | \
grep -v docinfo | \
grep -v virtual-root | grep -v state.window > /tmp/gedit.gsettings.root
diff /tmp/gedit.gsettings.root /tmp/gedit.gsettings | grep '>' > /tmp/gedit.gsettings.diff
sed -i 's/>/gsettings set/g; s/uint32 //g' /tmp/gedit.gsettings.diff
chmod +x /tmp/gedit.gsettings.diff
bash -x /tmp/gedit.gsettings.diff # Display override setting to terminal
# nohup gedit $@ &>/dev/null &
nohup gedit -g 1300x840+1+1220 $@ &>/dev/null &
# Set the X geometry window size (WIDTHxHEIGHT+X+Y).
}
FUNC=$(declare -f sudoFunc)
sudo -H bash -c "$FUNC; sudoFunc $*;"
exit 0
Сценарий должен вызываться в обычном пользовательском режиме. Копирует gsettings
для gedit
из профиля пользователя в /tmp
. Важные настройки, такие как размер шрифта, перенос строки, настройки вкладок, преобразование вкладок в пробелы и плагины, копируются.
Затем запрашивается sudo
пароль и статус повышается до root.
sudo -H
используется для эквивалентной gksu
защиты, чтобы не дать root
полномочиям забивать файлы конфигурации пользователя.
Следующие корневые параметры конфигурации для gedit
наследуются от профиля вызывающего пользователя, который был скопирован в /tmp
.
gedit
загружается как фоновая задача, и пользователю предоставляется sudo
версия открытого файла. Например, /etc/default/grub
.
Полномочия sudo
немедленно сбрасываются, и приглашение командной строки возвращается. Однако gedit
все еще работает в отдельном окне с файлом, открытым для редактирования.
-H
для sudo
делала все, что делает ваш скрипт, но для всех приложений. И все же это будет не все. Потребовалось бы уменьшить привилегии, скажем, для запуска с crontab
или rc.local
, потому что sudo -u normaluser ...
не всегда работает должным образом.
– kynan
02.05.2019, 16:40
Чтобы повысить привилегии для нескольких команд в скрипте, используйте sudo с синтаксисом heredoc:
possiblevariable=something
sudo /bin/bash <<EOF
cd /somedir
pwd
commandasroot1 "$possiblevariable"
commandasroot2
EOF
nonrootcommand (and not in /somedir)
Тестирование cd: (рабочий каталог изменен внутри heredoc, но восстанавливается, как это было раньше в конце heredoc)
leonid@DevSSD:~$ sudo bash <<EOF
> cd /tmp
> pwd
> EOF
[sudo] password for leonid:
/tmp
leonid@DevSSD:~$
Еще один пример, показывающий, как подстановка переменных работает в heredoc:
leonid@DevSSD:~$ sudo bash <<EOF
cd /tmp
echo $PWD; echo \$PWD
EOF
[sudo] password for leonid:
/home/leonid
/tmp
leonid@DevSSD:~$
Обновление: пример того, как вы можете получить вывод в переменную
leonid@DevSSD:~$ variable=$(sudo bash <<EOF
cd /tmp
echo $PWD; echo \$PWD
EOF
)
[sudo] password for leonid:
leonid@DevSSD:~$ echo $variable
/home/leonid /tmp
cd
там не работает, и я получаю $PWD
неизменным даже при жестко закодированном пути. Смотрите мое обновление выше.
– Dave Donahue
01.05.2019, 17:27
pwd
вместо 'echo $ PWD'
– MichaelBlume
01.05.2019, 17:36
sh
требует меньшей модификации существующего кода, потому что, например, echo $PWD
или echo $(pwd)
работает. Может быть, есть аналогичный режим с bash
. Мне больше нравится мой обходной путь. Пока что решение не найдено. Я думал, что есть решение для такой вещи.
– Kristoffer Sall-Storgaard
01.05.2019, 20:59
tmphost=$(mktemp)
и перехватите при выходе:trap 'rm "$tmphost"' EXIT
– Trevor Burnham 01.05.2019, 22:13mktemp
, потому что он генерирует больше строк ... И он не позволяет выбрать местоположение временного файла, скажем, на каком диске, на случай, если я решу сохранить его постоянно. – Trevor Burnham 01.05.2019, 22:22