В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13 |
Процессы
Переустановить действующий идентификатор пользователя вызывающего процесса позволяют функции setuid() и seteuid() (см. листинг 7.11). Операция разрешена, если реальный или сохраненный ПДП-идентификатор пользователя совпадает со значением аргумента uid. Помимо этого, обладающие соответствующими привилегиями процессы с помощью функции setuid() могут установить по значению uid все три идентификатора пользователя процесса – реальный, действующий и сохраненный.
#include <unistd.h> int setuid (uid_t uid); #include <unistd.h> int seteuid (uid_t uid);Листинг 7.11. Описание функций setuid() и seteuid().
Для непривилегированных процессов по соображениям мобильности рекомендуется использование функции seteuid().
Аналогичные функции для переустановки идентификаторов группы процесса показаны в листинге 7.12.
#include <unistd.h> int setgid (gid_t gid); #include <unistd.h> int setegid (gid_t gid);Листинг 7.12. Описание функций setgid() и setegid().
Отметим, что функция для изменения списка дополнительных групп setgroups() относится к числу привилегированных и, следовательно, остается за рамками стандарта POSIX.
Проиллюстрируем использование описанных функций с помощью программы, показанной в листинге 7.13.
#include <unistd.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> int main (void) { uid_t uid; int nsupgroups; gid_t *supgroupslist; int i; /* Отменим буферизацию стандартного вывода */ setbuf (stdout, NULL); printf ("Идентификаторы пользователя текущего процесса:\n" " реальный: %d, действующий: %d\n", uid = getuid (), geteuid ()); printf ("Идентификаторы группы текущего процесса:\n" " реальный: %d, действующий: %d\n", getgid (), getegid ()); printf ("Количество дополнительных групп текущего процесса: %d\n", nsupgroups = getgroups (0, supgroupslist)); if (nsupgroups > 0) { if ((supgroupslist = (gid_t *) malloc (nsupgroups * sizeof (gid_t))) == NULL) { perror ("MALLOC"); } else if (getgroups (nsupgroups, supgroupslist) == (-1)) { perror ("GETGROUPS"); } else { /* Выдадим идентификаторы дополнительных */ /* групп процесса */ printf ("Идентификаторы дополнительных групп текущего процесса:\n"); for (i = 0; i < nsupgroups; i++) { printf (" %d", supgroupslist [i]); } printf ("\n"); } } /* Попробуем переустановить идентификатор */ /* пользователя процесса */ if (setuid ((uid_t) 1) != 0) { perror ("setuid (1)"); } printf ("Идентификаторы пользователя текущего процесса после первой смены:\n" " реальный: %d, действующий: %d\n", getuid (), geteuid ()); /* Попробуем вернуть прежний идентификатор */ /* пользователя процесса */ if (setuid (uid) != 0) { perror ("setuid (uid)"); } printf ("Идентификаторы пользователя текущего процесса после второй смены:\n" " реальный: %d, действующий: %d\n", getuid (), geteuid ()); /* Попробуем сменить действующий идентификатор */ /* с помощью функции seteuid() */ if (seteuid ((uid_t) 1) != 0) { perror ("seteuid (1)"); } printf ("Идентификаторы пользователя текущего процесса после третьей смены:\n" " реальный: %d, действующий: %d\n", getuid (), geteuid ()); return (0); }Листинг 7.13. Пример использования функций опроса и изменения идентификаторов пользователя процесса.
Если эту программу запустить от имени обычного пользователя, результат может выглядеть так, как показано в листинге 7.14.
Идентификаторы пользователя текущего процесса: реальный: 108, действующий: 108 Идентификаторы группы текущего процесса: реальный: 3, действующий: 3 Количество дополнительных групп текущего процесса: 1 Идентификаторы дополнительных групп текущего процесса: 3 setuid (1): Operation not permitted Идентификаторы пользователя текущего процесса после первой смены: реальный: 108, действующий: 108 Идентификаторы пользователя текущего процесса после второй смены: реальный: 108, действующий: 108 seteuid (1): Operation not permitted Идентификаторы пользователя текущего процесса после третьей смены: реальный: 108, действующий: 108Листинг 7.14. Возможный результат работы программы, показанной в листинге 7.13 и запущенной от имени обычного пользователя.
После запуска той же программы от имени суперпользователя может получиться результат, показанный в листинге 7.15.
Идентификаторы пользователя текущего процесса: реальный: 0, действующий: 0 Идентификаторы группы текущего процесса: реальный: 0, действующий: 0 Количество дополнительных групп текущего процесса: 7 Идентификаторы дополнительных групп текущего процесса: 0 1 2 3 4 6 10 Идентификаторы пользователя текущего процесса после первой смены: реальный: 1, действующий: 1 setuid (uid): Operation not permitted Идентификаторы пользователя текущего процесса после второй смены: реальный: 1, действующий: 1 Идентификаторы пользователя текущего процесса после третьей смены: реальный: 1, действующий: 1Листинг 7.15. Возможный результат работы программы, показанной в листинге 7.13 и запущенной от имени суперпользователя.
Утерять статус суперпользователя легко, а вернуть трудно...
Наконец, сделаем владельцем выполнимого файла рассматриваемой программы пользователя с идентификатором 1, то же проделаем с владеющей группой, взведем в режиме этого файла биты ПДИП и ПДИГ(на ОС Linux можно воспользоваться командой chmod ug+s ) и вновь запустим его от имени обычного пользователя (см. листинг 7.16).
Идентификаторы пользователя текущего процесса: реальный: 108, действующий: 1 Идентификаторы группы текущего процесса: реальный: 3, действующий: 1 Количество дополнительных групп текущего процесса: 1 Идентификаторы дополнительных групп текущего процесса: 3 Идентификаторы пользователя текущего процесса после первой смены: реальный: 108, действующий: 1 Идентификаторы пользователя текущего процесса после второй смены: реальный: 108, действующий: 108 Идентификаторы пользователя текущего процесса после третьей смены: реальный: 108, действующий: 1Листинг 7.16. Возможный результат работы программы, показанной в листинге 7.13 и запущенной от имени обычного пользователя после взведения в режиме выполнимого файла бита ПДИП.
Видно, что сохраненный ПДП-идентификатор помогает непривилегированному процессу переустанавливать действующий идентификатор пользователя.
Отметим, что если функция getgroups() применяется в программе несколько раз, то память под массив supgroupslist лучше отвести по максимуму, воспользовавшись выражением вида nsupgroups = sysconf (_SC_NGROUPS_MAX) + 1;.
Для опроса и/или изменения маски режима создания файлов вызывающего процесса предназначены служебная программа umask:
umask [-S] [маска]
и одноименная функция (см. листинг 7.17).
#include <sys/stat.h>> mode_t umask (mode_t cmask);Листинг 7.17. Описание функции umask().
Согласно стандарту, в маске могут фигурировать только биты режима доступа к файлам; трактовка прочих бит зависит от реализации.
Для служебной программы umask маска может задаваться и выводиться в символьной и восьмеричной формах. Маска в символьной форме является "позитивной" в том смысле, что заданные в ней биты режима доступа будут сохранены при создании файла. Восьмеричная форма – "негативная", заданные в ней биты будут "вычитаться" (очищаться) из режима доступа, заданного при создании. Синтаксис маски в umask аналогичен утилите chmod.
Опция -S предписывает выдавать маску в символьной форме.
Функция umask() устанавливает новую ("негативную") маску и возвращает старую.
Пример. Последовательность команд, показанная в листинге 7.18, выдаст результат, воспроизведенный в листинге 7.19.
umask 0 umask -S umask -- -x umaskЛистинг 7.18. Пример использования служебной программы umask.
u=rwx,g=rwx,o=rwx 01117.19. Листинг 7.19. Возможный результат использования служебной программы umask.
Обратим внимание на употребление признака конца опций --. Он позволяет задавать аргументы, начинающиеся с минуса. Отметим также, что результаты, выдаваемые umask, могут в дальнейшем использоваться как аргументы данной утилиты (и в символьной, и в восьмеричных формах).