Книга: Linux программирование в примерах
11.6.3. Использование битов setuid и setgid
11.6.3. Использование битов setuid и setgid
Есть важные случаи, в которых действующая как root
программа должна безвозвратно изменить все три значения действительного, эффективного и сохраненного set-user ID на ID обычного пользователя. Наиболее очевидным случаем является программа login
, которую вы используете (либо непосредственно, либо удаленно) каждый раз при регистрации в системе GNU/Linux или Unix. Имеется иерархия программ, как очерчено на рис. 11.1.
Рис. 11.1. От init
через getty
через login
к shell
Код для login
слишком сложен, чтобы показать здесь, поскольку он имеет дело с рядом задач, не имеющих отношения к текущему обсуждению. Но мы можем очертить шаги, которые происходят во время регистрации, следующим образом:
1. init
является самым первым процессом. Его PID равен 1. Все другие процессы являются его потомками. Ядро вручную создает процесс 1 во время загрузки и запускает в нем init
. Он действует с действительным и эффективным UID, равными нулю, т.е. как root
.
2. init
читает /etc/inittab
, который, помимо прочих вещей, сообщает init
о том, на каких устройствах он должен запустить процесс getty
. Для каждого такого устройства (такого, как консоль, последовательные терминалы или виртуальные консоли в системе GNU/Linux) init
порождает новый процесс. Этот новый процесс использует затем exec()
для запуска getty
(от «get tty» («получить tty», т.е. терминал)). На многих системах GNU/Linux эта команда называется mingetty
. Программа открывает устройство, сбрасывает его состояние и выводит приглашение 'login:
'.
3. По получении регистрационного имени getty
выполняет login
. Программа login
ищет имя пользователя в файле паролей, запрашивает пароль и проверяет его. Если пароль подходит, процесс login
продолжается.
4. login
изменяет домашний каталог пользователя, устанавливает начальное окружение, а затем устанавливает начальный набор открытых файлов. Он закрывает дескрипторы файлов, открывает терминал и использует dup()
для копирования дескрипторов файла терминала в 0, 1 и 2. Вот откуда происходят дескрипторы уже открытых файлов стандартного ввода, стандартного вывода и стандартной ошибки.
5. Затем login
использует setgroups()
для установки дополнительного набора групп, setgid()
для установки значений действительного, эффективного и сохраненного set-group ID в соответствующее значение группы пользователя, и наконец, setuid()
для установки всех трех значений действительного, эффективного и сохраненного set-user ID в соответствующие значения для регистрирующегося пользователя. Обратите внимание, что вызов setuid()
должен быть последним для того, чтобы другие два вызова завершились успешно.
6. Наконец, login
вызывает зарегистрированную оболочку пользователя. Оболочки в стиле Борна после этого читают файлы /etc/profile
и $HOME/.profile
, если они существуют. Затем оболочка выводит приглашение.
Обратите внимание, как один процесс меняет свою сущность от системного процесса до процесса пользователя. Каждый потомок init
начинается как копия init
. Используя exec()
, тот же самый процесс выполняет различные задания. Вызвав setuid()
для перехода от root
к обычному пользователю, процесс в конечном счете поступает непосредственно для работы пользователя. Когда вы выходите из оболочки (посредством CTRL-D или exit
), процесс попросту завершается. Затем init
возобновляет цикл, порождая новый getty
, который выводит новое приглашение 'login:
'.
ЗАМЕЧАНИЕ. Открытые файлы остаются открытыми и доступными для использования, даже после изменения процессом своих UID или GID. Таким образом, программы с setuid должны заранее открыть все нужные файлы, изменить их ID на ID действительного пользователя и продолжить оставшуюся часть работы без дополнительных привилегий
В табл. 11.1 приведена сводка шести стандартных функций для манипулирования значениями UID и GID.
Таблица 11.1. Сводка API для установки действительных и эффективных ID[120]
Функция | Устанавливает | Постоянно | Обычный пользователь | Root |
---|---|---|---|---|
seteuid() |
E | Нет | Из R, E, S | Любое |
setegid() |
E | Нет | Из R, E, S | Любое |
setuid() |
Root: R,E,S Другие: E | Root: да Другие: нет | Из R, E | Любое |
setgid() |
Root: R,E,S Другие: E | Root: да Другие: нет | Из R, E | Любое |
setreuid() |
E, может установить R | Нет | Из R, E | Любое |
setregid() |
E, может установить R | Нет | Из R, E | Любое |
- Восстановление с использованием инструмента gbak
- Типы страниц и их использование
- Использование констант
- Использование переменной окружения ISC_PATH
- Использование сервера Yaffil внутри процесса
- Использование CAST() с типами дата
- Использование типов содержимого и столбцов
- Вызов хранимых процедур InterBase с использованием стандартного синтаксиса ODBC
- Использование кнопки Автосумма
- 24.7. Использование программы-твикера
- Использование отдельных процессоров XSLT
- 4. Использование подзапросов