Этот вопрос задавался по-другому на других форумах. Но не было достойного объяснения, почему вы не можете сделать следующее в bash.
#!/bin/bash
command1
SWITCH_USER_TO rag
command2
command3
Обычно предлагаемый способ
#!/bin/bash
command1
sudo -u rag command2
sudo -u rag command3
но почему невозможно в bash
какой-то момент переключиться на другого пользователя во время выполнения сценария bash и выполнить остальные команды от имени другого пользователя?
Ответы:
Информация уже есть в моем другом ответе , но она там немного похоронена. Так что я подумал, я бы добавил это сюда.
bash
не предусматривает смену пользователей, ноzsh
имеет.В
zsh
, вы меняете пользователей, присваивая значения этим переменным:$EUID
: изменить эффективный идентификатор пользователя (и ничего больше). Обычно вы можете изменить свой euid между своим реальным идентификатором пользователя и сохраненным идентификатором пользователя (если он вызывается из исполняемого файла setuid) или изменить его на что угодно, если ваш euid равен 0.$UID
: измените эффективный идентификатор пользователя, реальный идентификатор пользователя и сохраненный набор идентификатора пользователя на новое значение. Если это новое значение не равно 0, возврата назад не будет, так как после того, как все 3 установлены на одно и то же значение, невозможно изменить его на что-либо еще.$EGID
и$GID
: то же самое, но для идентификаторов группы.$USERNAME
, Это похоже на использованиеsudo
илиsu
. Он устанавливает ваш euid, ruid, ssuid в uid этого пользователя. Он также устанавливает egid, rgid и ssgid и дополнительные группы на основе членства в группах, как определено в базе данных пользователей. Как и для$UID
, если вы установите$USERNAME
наroot
, нет возвращаться, но , как и для$UID
, вы можете изменить пользователь только для субоболочки.Если вы запускаете эти скрипты как «root»:
Теперь, чтобы изменить пользователя как в
sudo
илиsu
, мы можем сделать это только с помощью подоболочек, в противном случае мы можем сделать это только один раз:источник
Ядро предлагает
man 2 setuid
и друзья.Теперь, это работает над процессом вызова. Что еще более важно, вы не можете повысить свои привилегии. Вот почему
su
иsudo
установите бит SETUID, чтобы они всегда работали с самыми высокими привилегиями (root
) и соответственно переходили к нужному пользователю.Эта комбинация означает, что вы не можете изменить UID оболочки, запустив какую-либо другую программу для этого (поэтому вы не можете ожидать
sudo
, что это сделает любая другая программа), и вы не можете (как оболочка) сделать это самостоятельно, если вы не готовы работать от имени пользователя root или от того же пользователя, на которого вы хотите переключиться, что не имеет смысла. Более того, как только вы откажетесь от привилегий, пути назад нет.источник
Ну, вы всегда можете сделать:
(ʘ‿ʘ)
Это сначала началось как шутка, поскольку в нем реализовано то, что запрошено, хотя, вероятно, не совсем так, как ожидалось, и практически не полезно. Но так как он развился до чего-то, что работает в некоторой степени и включает в себя несколько хороших хаков, вот небольшое объяснение:
Как сказал Мирослав , если оставить в стороне Linux стиле возможностей (которые не очень помогают здесь ни в любом случае), единственный способ для непривилегированного процесса изменения UID является выполнение Setuid исполняемого файла.
Однако, как только вы получите привилегию суперпользователя (выполняя исполняемый файл setuid, владельцем которого является, например, root), вы можете переключать эффективный идентификатор пользователя назад и вперед между вашим исходным идентификатором пользователя, 0 и любым другим идентификатором, если только вы не откажетесь от сохраненного идентификатора установленного пользователя ( люблю такие вещи как
sudo
илиsu
обычно делаю).Например:
Теперь у меня есть
env
команда, которая позволяет мне выполнять любую команду с эффективным идентификатором пользователя и сохраненным установленным идентификатором пользователя 0 (мой реальный идентификатор пользователя все еще равен 1000):perl
имеет обертки кsetuid
/seteuid
(те$>
и$<
переменные).Так же как и Zsh:
Хотя выше эти
id
команды вызываются с реальным идентификатором пользователя и сохраненным установленным идентификатором пользователя, равным 0 (хотя, если бы я использовал мой./env
вместо этогоsudo
, был бы только сохраненный набор идентификаторов пользователей, в то время как реальный идентификатор пользователя остался бы 1000), что означает, что если бы они были ненадежными командами, они все равно могли бы нанести какой-то ущерб, так что вы бы хотели написать это так:(это устанавливает все uids (эффективный, реальный и сохраненный набор) только для выполнения этих команд.
bash
нет такого способа изменить идентификаторы пользователя. Таким образом, даже если у вас есть исполняемый файл setuid, с помощью которого можно вызватьbash
скрипт, это не поможет.С помощью
bash
вам остается выполнять исполняемый файл setuid каждый раз, когда вы хотите изменить uid.Идея в приведенном выше сценарии заключается в вызове SWITCH_TO_USER, чтобы выполнить новый экземпляр bash для выполнения оставшейся части сценария.
SWITCH_TO_USER someuser
более или менее функция, которая выполняет сценарий снова как другой пользователь (используяsudo
), но пропускает начало сценария доSWITCH_TO_USER someuser
.Сложность в том, что мы хотим сохранить состояние текущего bash после запуска нового bash от имени другого пользователя.
Давайте разберемся с этим:
Нам понадобятся псевдонимы. Один из трюков в этом скрипте - пропустить часть скрипта, пока что-
SWITCH_TO_USER someuser
то вроде:Эта форма похожа на
#if 0
используемую в C, это способ полностью закомментировать некоторый код.:
это неоперация, которая возвращает истину. Итак: || :
, второе:
никогда не выполняется. Тем не менее, он анализируется. И<< 'xxx'
это форма здесь-документа, где (потому чтоxxx
цитируется), не делается никакого расширения или интерпретации.Мы могли бы сделать:
Но это означало бы, что этот документ должен был быть написан и передан как stdin
:
.:||:
избегает этогоТеперь мы можем использовать тот факт, что мы
bash
очень рано расширяем псевдонимы в процессе анализа. Иметьskip
псевдоним для:||: << 'SWITCH_TO_USER someuther'
части закомментирующей конструкции.Давайте продолжим:
Вот определение функции SWITCH_TO_USER . Ниже мы увидим, что SWITCH_TO_USER в конечном итоге будет псевдонимом, обернутым вокруг этой функции.
Эта функция выполняет основную часть повторного выполнения сценария. В конце мы видим, что он повторно выполняется (в том же процессе из-за
exec
)bash
с_x
переменной в его среде (мы используемenv
здесь, потому чтоsudo
обычно дезинфицирует свою среду и не позволяет передавать произвольные переменные через). Этоbash
оценивает содержимое этой$_x
переменной как код bash и создает сам скрипт._x
определяется ранее как:Все из
declare
,alias
,shopt -p
set +o
выход составляет дамп внутреннего состояния оболочки. Таким образом, они сбрасывают определение всех переменных, функций, псевдонимов и опций как готовый к проверке код оболочки. Кроме того, мы добавляем настройку позиционных параметров ($1
,$2
...) на основе значения$_a
массива (см. Ниже), а некоторые очищают, чтобы огромная$_x
переменная не оставалась в environemnt для оставшихся сценария.Вы заметите, что первая часть до
set +x
обернута в группу команд, чей stderr перенаправлен в/dev/null
({...} 2> /dev/null
). Это потому, что если в какой-то момент сценарияset -x
(илиset -o xtrace
) выполняется, мы не хотим, чтобы эта преамбула генерировала трассировки, поскольку мы хотим сделать ее как можно менее навязчивой. Таким образом, мы запускаемset +x
(предварительно убедившись, что предварительно сбросили параметры (включаяxtrace
)), где трассировки отправляются в / dev / null.eval "$_X"
STDERR также перенаправлены / DEV / нуль по тем же причинам , но и избежать ошибок , о написании попытки специальных переменных только для чтения.Давайте продолжим со сценарием:
Это наш трюк, описанный выше. При первоначальном вызове сценария он будет отменен (см. Ниже).
Теперь обертка псевдонимов вокруг SWITCH_TO_USER. Основная причина в том, чтобы иметь возможность передавать позиционные параметры (
$1
,$2
...) в новый,bash
который будет интерпретировать остальную часть скрипта. Мы не могли сделать это вSWITCH_TO_USER
функции, потому что внутри функции"$@"
есть аргументы функций, а не скрипты. Перенаправление stderr в / dev / null снова позволяет скрыть xtraces, аeval
для устранения ошибкиbash
. Затем мы вызываемSWITCH_TO_USER
функцию .Эта часть отменяет
skip
псевдоним (заменяет его командой:
no-op), если$_u
переменная не установлена.Это наш
skip
псевдоним. При первом вызове это будет просто:
(без операции). На подпоследовательности повторных вызовов, то это будет что - то вроде::||: << 'SWITCH_TO_USER root'
.Итак, здесь, в качестве примера, в этот момент мы повторно вызываем скрипт как
root
пользователь, и скрипт восстанавливает сохраненное состояние, переходит к этойSWITCH_TO_USER root
строке и продолжает.Это означает, что она должна быть написана в точности как stat, с
SWITCH_TO_USER
началом строки и с одним пробелом между аргументами.Большая часть состояния, stdin, stdout и stderr будет сохранена, но не остальные файловые дескрипторы, потому что
sudo
обычно их закрывает, если явно не настроено. Так, например:как правило, не будет работать.
Также обратите внимание, что если вы делаете:
Это работает только в том случае, если у вас есть право на «
sudo
как»alice
иalice
«sudo
как»bob
и «bob
как»root
.Так что на практике это не очень полезно. Использование
su
вместоsudo
(илиsudo
конфигурации, гдеsudo
выполняется аутентификация целевого пользователя вместо вызывающего) может иметь немного больше смысла, но это все равно будет означать, что вам нужно знать пароли всех этих парней.источник
ioshcc
? Вы должны были ввести только одну строку.Команда "sudo -u ram sh" может быть использована для перехода к пользователю "ram" путем выполнения команды "sh" или shell. Команда «exit» вернет вас к первоначальному пользователю.
источник