Книга: 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 Любое

Оглавление книги


Генерация: 1.738. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз