Почему «sudo su» в сценарии оболочки не запускает остальную часть сценария от имени пользователя root?

36

Пример сценария может быть следующим:

#!/bin/bash
sudo su
ls /root

При использовании ./test.shв качестве обычного пользователя вместо запуска lsот имени суперпользователя и выхода, он переключается в режим root; и когда я выхожу, он выполняется ls /rootкак обычный пользователь.

Кто-нибудь может рассказать мне о механизме об этом?

Хунсю Чен
источник
13
sudo suзаставляет мои глаза болеть.
13
Он используется потому, что люди недостаточно хорошо знают sudo, и поэтому им нужен способ запуска su в системах, где root защищен намеренно поврежденным паролем. Но да, sudo «сокращает» использование su.
Йохан
1
Вы не можете просто использовать sudo -s, хотя?
Джо З.
@Johan, я часто использую, sudo suпотому что я более привык к опциям, suчем к тем, которые у меня есть sudo. Я знаю параметры sudo достаточно хорошо, но могу набрать su быстрее. Но да, я думаю, это значит, что я недостаточно хорошо знаю sudo.
user606723
1
Я только что проверил страницу руководства sudo. Похоже, sudo -iчто в su -то время как sudo -sработает как su(без черты)
Йохан

Ответы:

49

Команды в скрипте выполняются одна за другой, независимо. Сам скрипт, как родитель всех команд в скрипте, является другим независимым процессом, а команда su не изменяет и не может изменить его на root: команда su создает новый процесс с привилегиями root.

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

Что вы хотите сделать, это написать скрипт-обертку. Привилегированные команды входят в основной скрипт, например~/main.sh

#!/bin/sh
ls /root

Скрипт-обертка вызывает основной скрипт с правами root, как это

#!/bin/sh
su -c ~/main.sh root

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

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

$ 0 - это удобный способ заставить скрипт ссылаться на себя, а команда whoami может сказать нам, кто мы (мы root)?

Таким образом, основной скрипт со встроенной оберткой становится

#!/bin/sh
[ `whoami` = root ] || exec su -c $0 root
ls /root

Обратите внимание на использование exec. Это означает «заменить эту программу на», что фактически завершает ее выполнение и запускает новую программу, запускаемую su с root, для запуска сверху. Экземпляр замены - «root», поэтому он не выполняет правую часть ||

Johan
источник
1
Между прочим, добавление к этому пункту. Если бы я писал подобный скрипт, я бы просто сделал в начале оператор if, который проверяет $ EUID, и если он не равен нулю, sudo и завершается, в противном случае продолжите выполнение скрипта.
Братчли
Договорились, и я обновлю ответ, чтобы объяснить это.
Йохан
2
Возможно, это немного архаично, но мне нравятся абсолютные пути к каждому исполняемому файлу, поэтому кто-то не может изменить скрипт ~ / main.sh на что-то гнусное. Нападение на часть сценария пользователя USER
artifex,
2
Вы также можете перехватить переданные ему аргументы, включив ссылку на $ *
Братчли
@JoelDavis Я всегда сталкиваюсь со стеной «что, если в аргументах есть пробелы». Я никогда не находил удовлетворительного решения. Однажды я написал скрипт, который помещал его аргументы во временный файл, по одному аргументу на строку, а затем вызывал все, что ему нужно, и передавал этому финальному скрипту аргумент того файла, который нужно прочитать, чтобы найти исходные аргументы.
Йохан,
20

Используйте следующее в сценарии.

sudo su <<HERE
ls /root
HERE

Код между блоком HERE будет запущен от имени пользователя root.

Анкит
источник
6
sudo suвызывает две программы. Используйте sudo -s <<HEREDOCили su user <<HEREDOC... Глупый 5-минутный лимит.
Йохан
6

Без дальнейших аргументов suзапустим оболочку входа в систему для root. Вот что на самом деле делает первая строка вашего скрипта. При выходе, Замкнутая оболочки входа в систему , возвращается су и ваш скрипт продолжает выполнение, то есть во второй строке: ls /root. Я думаю, что вы можете просто sudo ls /rootделать то, что вы хотите.

Bananguin
источник
Да, я знаю, что могу сделать это ls, но это всего лишь пример. На самом деле мне нужно сделать намного больше вещей с привилегиями root :-) Поэтому я предпочитаю ответ @ Ankit.
Хунсю Чен
1

Как только вы запускаете sudo suновый процесс с userid (euid=EUID)использованием разветвленного суперпользователя, мы получаем новый bash с другим идентификатором процесса, (pid=PID)связанным с одним и тем же терминалом (tname=TTY).

объяснение

Предположим, что после выстрела у ps -A | grep bashвас есть 21460 pts/2 00:00:00 bashвыход. Теперь, когда вы выполните ./test.shобе команды sudo suи ls /rootбудете помещены в буфер PID 21460. После выполнения, когда вы снова rootнажмете в качестве активного пользователя ps -A | grep bash, вы увидите, что запущен новый bash PID say, 21570. Выход из root bashприведет к уничтожению вновь разветвленного bash, возвращающегося к нему, user's bashи, следовательно, к выполнению буферизованной команды ls /rootперед освобождением приглашения.

Sundeep
источник
Если использование su или sudo было «постоянным» в bash (или где-либо еще), это создаст намного больше проблем, чем решит. Вы должны сделать как можно меньше прав как root для обеспечения безопасности. Основной смысл наличия su и sudo (кроме безопасности!) Состоит в том, чтобы заставить вас тщательно продумать, что требует корневых привилегий.
Джо