int setregid(gid_t rgid, gid_t egid)
Делает для действительных и эффективных ID групп то же, что
setreuid()
делает для действительных и эффективных ID пользователя. Используется то же разграничение между обычными пользователями и
root
.
Сохраненный set-user ID в модели BSD не существует, поэтому лежащей в основе
setreuid()
и
setregid()
идеей было упростить переключение между действительным и эффективным ID:
setreuid(geteuid(), getuid()); /* обмен действительным и эффективным */
Однако, с принятием POSIX модели сохранения set-user ID и функций
seteuid()
и
setegid()
функции BSD не следует использовать в новом коде. Даже документация BSD 4.4 помечает эти функции как устаревшие, рекомендуя вместо них
seteuid()
/
setuid()
и
setegid()
/
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 | Любое |