Выбрать главу

2. Привилегированный процесс может установить идентификатор пользователя файловой системы на любое значение.

Реализация этих вызовов слегка не доработана. Для начала следует отметить отсутствие соответствующих системных вызовов, извлекающих текущее значение идентификаторов файловой системы. Кроме того, в системных вызовах отсутствует проверка на возникновение ошибки; если непривилегированный процесс предпринимает попытку установить для своего идентификатора файловой системы неприемлемое значение, она игнорируется. Возвращаемым значением для каждого из этих системных вызовов является предыдущее значение соответствующего идентификатора файловой системы, независимо от успешности выполнения системного вызова. Таким образом, у нас есть способ определения текущих значений идентификаторов файловой системы, но только с одновременной попыткой (либо успешной, либо нет) их изменения.

Использование системных вызовов setfsuid() и setfsgid() больше не имеет в Linux никакой практической необходимости, и его следует избегать в тех приложениях, которые разрабатываются с прицелом на портирование для работы в других реализациях UNIX.

9.7.3. Извлечение и изменение дополнительных групповых идентификаторов

Системный вызов getgroups() записывает в массив, указанный в аргументе grouplist, набор групп, в которые на данный момент входит вызывающий процесс.

#include <unistd.h>

int getgroups(int gidsetsize, gid_t grouplist[]);

Возвращает при успешном завершении количество групповых идентификаторов, помещенное в grouplist, а при ошибке —1

В Linux, как и в большинстве реализаций UNIX, getgroups() просто возвращает дополнительные групповые идентификаторы вызывающего процесса. Но SUSv3 также разрешает реализации включать в возвращаемый grouplist действующий групповой идентификатор вызывающего процесса.

Вызывающая программа должна выделить память под массив grouplist и указать его длину в аргументе gidsetsize. При успешном завершении getgroups() возвращает количество групповых идентификаторов, помещенных в grouplist.

Если количество групп, в который входит процесс, превышает значение, указанное в gidsetsize, системный вызов getgroups() возвращает ошибку (EINVAL). Во избежание этого можно задать для массива grouplist значение, большее на единицу (для разрешения портируемости при возможном включении действующего группового идентификатора), чем значение константы NGROUPS_MAX (определенной в заголовочном файле <limits.h>). Эта константа определяет максимальное количество дополнительных групп, в которые может входить процесс. Таким образом, grouplist можно объявить с помощью следующего выражения:

gid_t grouplist[NGROUPS_MAX + 1];

В ядрах Linux, предшествующих версии 2.6.4, у NGROUPS_MAX было значение 32. Начиная с версии 2.6.4, значение у NGROUPS_MAX стало равно 65536.

Приложение может также определить предельное значение NGROUPS_MAX в ходе своего выполнения следующими способами:

• вызвать sysconf(_SC_NGROUPS_MAX) (использование sysconf() рассматривается в разделе 11.2);

• считать ограничение из предназначенного только для чтения и характерного только для Linux файла /proc/sys/kernel/ngroups_max. Этот файл предоставляется ядрами, начиная с версии 2.6.4.

Кроме этого, приложение может выполнить вызов getgroups(), указав в качестве аргумента gidsetsize значение 0. В этом случае grouplist не изменяется, но возвращаемое вызовом значение содержит количество групп, в которые входит процесс.

Значение, полученное любым из этих способов, применяемых в ходе выполнения приложения, может затем использоваться для динамического выделения памяти под массив grouplist с целью последующего вызова getgroups().

Привилегированный процесс может изменить свой набор дополнительных групповых идентификаторов, выполнив setgroups() и initgroups().

#define _BSD_SOURCE

#include <grp.h>

int setgroups(size_t gidsetsize, const gid_t *grouplist);

int initgroups(const char *user, gid_t group);

Оба возвращают при успешном завершении 0, а при ошибке —1

Системный вызов setgroups() может заменить дополнительные групповые идентификаторы вызывающего процесса набором, заданным в массиве grouplist. Количество групповых идентификаторов в массиве аргумента grouplist указывается в аргументе gidsetsize.

Функция initgroups() инициализирует дополнительные групповые идентификаторы вызывающего процесса путем сканирования файла /etc/group и создания списка групп, в которые входит указанный пользователь. Кроме того, к набору дополнительных групповых идентификаторов процесса добавляется групповой идентификатор, указанный в аргументе group.