В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13 |
Утилиты и функции, обслуживающие понятие "пользователь"
Данные, ассоциированные с пользователем
Операционная система, соответствующая стандарту POSIX, должна поддерживать базу данных пользователей, в которой о каждом из них хранится по крайней мере следующая информация:
- имя пользователя ;
- числовой идентификатор пользователя ;
- числовой идентификатор начальной группы ;
- начальный рабочий каталог ;
- начальная программа пользователя.
Поясним смысл перечисленных элементов данных.
Каждый зарегистрированный пользователь ОС имеет имя, которое он указывает для целей идентификации при входе в систему. После проведения идентификации и, как правило, аутентификации пользователя, с ним ассоциируются (неотрицательные) числовые идентификаторы пользователя и начальной группы. В отличие от имен, ОС оперирует ими во всех случаях, кроме первоначальной идентификации. Затем запускается начальная программа пользователя (например, командный интерпретатор shell) с указанным начальным рабочим каталогом.
Поля начального рабочего каталога и начальной программы пользователя могут быть пустыми; в таком случае их трактовка зависит от реализации. Обычно в системе определена подразумеваемая начальная программа, в качестве которой обычно используется /bin/sh.
Пользователи объединяются в группы ; каждый пользователь является членом хотя бы одной из них. Для групп также существует база данных, ее записи содержат по крайней мере следующие поля:
- имя группы ;
- числовой идентификатор группы ;
- список пользователей, которым разрешено становиться членами данной группы.
В базе данных пользователей указывается идентификатор начальной группы, в нее пользователь попадает сразу после входа в систему. В процессе работы возможен переход в другую группу (см. далее описание утилиты newgrp ), однако на эти переходы наложены ограничения в виде списка возможных членов группы.
С объектно-ориентированной точки зрения можно считать, что класс "пользователь" предоставляет один метод - начальную программу. Его можно применить для программирования определенных услуг. Например, если нужно дать возможность любому человеку (не обязательно зарегистрированному пользователю), оказавшемуся рядом со свободным терминалом, узнать текущие дату и время, заводят пользователя date с начальной программой /bin/date.
Опросить ассоциированные с пользователем данные (точнее, идентификаторы и имена пользователя и начальной группы, а также всех групп, членами которых ему разрешено быть, - так называемых дополнительных групп ) позволяет служебная программа
id [имя_пользователя]
Если имя_пользователя опущено, выдается информация о текущем пользователе и его текущей группе.
Пример использования служебной программы id. Команда
id root
может выдать на стандартный вывод следующий результат:
uid=0(root) gid=0(root) groups=0(root), 1(bin),2(daemon),3(sys),4(adm),6(disk), 10(wheel)
Числовой идентификатор 0 характеризует суперпользователя, который в большинстве Unix-систем не подвержен контролю прав доступа.
Входное имя текущего пользователя можно узнать также с помощью утилиты
logname
и функции getlogin():
#include <unistd.h> char *getlogin (void);
Отметим, что одному идентификатору пользователя может соответствовать несколько записей в базе данных пользователей, различающихся входными именами и, возможно, другими атрибутами; logname и getlogin() выдают имя, под которым начат текущий сеанс работы с ОС.
Над базой данных пользователей определены операции поиска по идентификатору или имени пользователя, реализуемые, соответственно, функциями getpwuid() и getpwnam() (см. листинг 3.1):
#include <pwd.h> struct passwd *getpwuid (uid_t uid); #include <pwd.h> struct passwd *getpwnam (const char *name);Листинг 3.1. Описание функций getpwuid() и getpwnam().
По стандарту структура passwd должна содержать по крайней мере следующие поля, соответствующие описанным выше обязательным элементам базы данных пользователей:
char *pw_name; /* Имя пользователя */ uid_t pw_uid; /* Числовой идентификатор пользователя */ gid_t pw_gid; /* Числовой идентификатор начальной группы */ char *pw_dir; /* Начальный рабочий каталог */ char *pw_shell; /* Начальная программа пользователя */
Типы uid_t и gid_t определяются в заголовочном файле <sys/types.h>.
Приведем пример выдачи информации о текущем пользователе и пользователе root с идентификатором 0 (см. листинг 3.2).
#include <unistd.h> #include <sys/types.h> #include <pwd.h> #include <stdio.h> /* Печать элемента базы данных пользователей */ static void print_pwent (const struct passwd *pw) { printf ("Имя пользователя: %s\n", pw->pw_name); printf ("Идентификатор пользователя: %d\n", pw->pw_uid); printf ("Идентификатор группы: %d\n", pw->pw_gid); printf ("Начальный каталог: %s\n", pw->pw_dir); printf ("Начальная программа: %s\n", pw->pw_shell); } int main (void) { char *lgnm; /* Имя текущего пользователя */ struct passwd *pw; /* Данные о текущем пользователе */ /* Поиск и печать информации о текущем пользователе */ if ((lgnm = getlogin ()) == NULL || (pw = getpwnam (lgnm)) == NULL) { fprintf (stderr, "\nНе удалось найти информацию о текущем пользователе\n"); return 1; } printf ("\nИнформация о текущем пользователе\n"); print_pwent (pw); /* То же для пользователя root */ if ((pw = getpwuid ((uid_t) 0)) == NULL) { fprintf (stderr, "\nНе удалось найти информацию о пользователе root\n"); return 1; } printf ("\nИнформация о пользователе root\n"); print_pwent (pw); return 0; }Листинг 3.2. Пример работы с базой данных пользователей.
По окончании работы этой программы может быть получен следующий результат (см. листинг 3.3):
Информация о текущем пользователе Имя пользователя: galat Идентификатор пользователя: 108 Идентификатор группы: 3 Начальный каталог: /home/galat Начальная программа: /bin/sh Информация о пользователе root Имя пользователя: root Идентификатор пользователя: 0 Идентификатор группы: 0 Начальный каталог: /root Начальная программа: /bin/bashЛистинг 3.3. Возможный результат работы с базой данных пользователей.
Аналогичные функции имеются для поиска в базе данных групп - getgrgid() и getgrnam() (см. листинг 3.4):
#include <grp.h> struct group *getgrgid (gid_t gid); #include <grp.h> struct group *getgrnam (const char *name);Листинг 3.4. Описание функций getgrgid() и getgrnam().
Структура group обязана содержать поля
char *gr_name;/* Имя группы */ gid_t gr_gid; /* Числовой идентификатор группы */ char **gr_mem; /* Указатель на ограниченный пустым указателем массив символьных указателей на имена пользователей, которым разрешено становиться членами данной группы */
Применение функции getgrgid() отражено в листинге 3.5.
#include <sys/types.h> #include <grp.h> #include <stdio.h> /* Печать списка пользователей, включенных в группу с заданным идентификатором */ static int print_gr_mem (const gid_t gid) { struct group *grp; /* Данные о группе */ char **c_gr_mem; /* Текущий указатель на имя члена группы */ char *c_gr_mem_name; /* Текущее имя члена группы */ if ((grp = getgrgid (gid)) == NULL) { fprintf (stderr, "\nНе удалось найти информацию о группе с идентификатором %d\n", gid); return 1; } printf ("\nПользователи, включенные в группу с идентификатором %d:\n", gid); c_gr_mem = grp->gr_mem; while ((c_gr_mem_name = *c_gr_mem++) != NULL) { printf(" %-8.8s", c_gr_mem_name); } printf ("\n"); return 0; } int main (void) { return print_gr_mem (1); }Листинг 3.5. Пример работы с базой данных групп.
Приведенная в качестве примера программа может привести к результату, показанному в листинге 3.6:
Пользователи, включенные в группу с идентификатором 1: root bin daemonЛистинг 3.6. Возможный результат работы с базой данных групп.
Для смены текущей группы пользователя предназначена служебная программа newgrp (стандарт POSIX-2001 относит ее к числу необязательных, входящих в расширение "Мобильность пользователей", UP):
newgrp [-l] [группа]
Группа, в которую осуществляется переход, задается именем или числовым идентификатором. Будучи вызванной без аргументов, утилита newgrp возвращает пользователя в его начальную группу, заданную в базе данных пользователей.
При смене группы порождается новый процесс, в рамках которого запускается новый экземпляр командного интерпретатора, наследующий у своего предшественника текущий каталог и значения переменных окружения. При указании опции -l окружение формируется так, будто пользователь заново вошел в систему.
Если пользователь не входит в список возможных членов новой группы, при переходе в нее может запрашиваться пароль, однако в стандарте POSIX-2001 этот аспект считается зависящим от реализации. Более того, отмечается, что в базе данных групп нет удобных способов задания паролей, поэтому их использование в приложениях не приветствуется, а со временем пароли групп могут стать ненужными.