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 | Любое |
11.7. Работа со всеми тремя ID: getresuid() и setresuid() (Linux)
Linux предоставляет дополнительные системные вызовы, посредством которых вы можете непосредственно работать с действительными, эффективными и сохраненными ID пользователя и группы:
#include
#include
int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
int setresuid(uid_t ruid, uid_t euid, uid_t suid);
int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
Функции следующие:
int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)