Как повысить привилегии root в bash и вернуть обратно?

Как повысить привилегии пользователя 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) не работает должным образом.

1131 Это много неприятностей. Больше года я не мог найти хорошего универсального решения. Так есть ли что-нибудь для повышения привилегий и возвращения обратно? Или другие хорошие обходные пути?

И полный пример на всякий случай (запустите как 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 должен быть удобным и простым в использовании.

-2
задан 13.05.2019, 04:54

3 ответа

Мой ответ. Тем не менее, необходимо решить, как просто повысить и уменьшить привилегии (фактически, концептуально, даже без переноса, существующие отдельно) или полностью переключиться на 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

-1
ответ дан 25.10.2019, 12:47
  • 1
    Да, вы можете передать var при экспорте. Передача вывода в файл tmp считается вредной – Koen. 01.05.2019, 21:52
  • 2
    Как-то не смог в моем случае. В вашем случае это было не нужно и не позволяло мне изменять переменную изнутри. Да, файл tmp может вызвать проблемы с безопасностью. А также передача аргументов или особенно всех аргументов недоверенным командам. – Luiz Freneda 01.05.2019, 21:59
  • 3
    Создайте временный файл с помощью tmphost=$(mktemp) и перехватите при выходе: trap 'rm "$tmphost"' EXIT – Trevor Burnham 01.05.2019, 22:13
  • 4
    Мне не нравится mktemp, потому что он генерирует больше строк ... И он не позволяет выбрать местоположение временного файла, скажем, на каком диске, на случай, если я решу сохранить его постоянно. – Trevor Burnham 01.05.2019, 22:22

У меня не так много сценариев, которые повышают привилегии пользователя до полномочий 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 все еще работает в отдельном окне с файлом, открытым для редактирования.

1
ответ дан 25.10.2019, 12:47
  • 1
    Спасибо! Я улучшил свой ответ и уточнил свой вопрос. После модификации ваш сценарий может стать обходным решением только для одного приложения. Хорошее решение выглядело бы как изменение 1-2 параметров в Ubuntu или лучше, если бы опция -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
2
ответ дан 25.10.2019, 12:47
  • 1
    Может быть, этот heredoc поможет, но пока он не работает. А именно, cd там не работает, и я получаю $PWD неизменным даже при жестко закодированном пути. Смотрите мое обновление выше. – Dave Donahue 01.05.2019, 17:27
  • 2
    CD работает. Вы получите неправильный вывод, потому что $ PWD разрешается до того, как sudo выполнит heredoc. Попробуйте pwd вместо 'echo $ PWD' – MichaelBlume 01.05.2019, 17:36
  • 3
    Я запускаю cd /tmp/ echo $(pwd) и получаю путь без изменений. – floriankrueger 01.05.2019, 17:43
  • 4
    Обновлено снова. В последнем примере вы можете увидеть, как следует избегать переменных, чтобы получить то, что вам нужно. – Jon Stevens 01.05.2019, 18:29
  • 5
    Спасибо! Таким образом, это работает. Но все же это не совсем то, что мне было нужно. Смотрите также мой ответ. Вариант с sh требует меньшей модификации существующего кода, потому что, например, echo $PWD или echo $(pwd) работает. Может быть, есть аналогичный режим с bash. Мне больше нравится мой обходной путь. Пока что решение не найдено. Я думал, что есть решение для такой вещи. – Kristoffer Sall-Storgaard 01.05.2019, 20:59

Теги

Похожие вопросы