Опубликован: 15.06.2004 | Доступ: свободный | Студентов: 2557 / 712 | Оценка: 4.35 / 3.96 | Длительность: 27:47:00
ISBN: 978-5-9556-0011-6
Лекция 3:

Утилиты и функции, обслуживающие понятие "пользователь"

< Лекция 2 || Лекция 3: 12 || Лекция 4 >
Аннотация: Описываются утилиты и функции, предназначенные для получения информации о пользователях и их взаимодействия.

Данные, ассоциированные с пользователем

Операционная система, соответствующая стандарту 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 этот аспект считается зависящим от реализации. Более того, отмечается, что в базе данных групп нет удобных способов задания паролей, поэтому их использование в приложениях не приветствуется, а со временем пароли групп могут стать ненужными.

< Лекция 2 || Лекция 3: 12 || Лекция 4 >
Антон Коновалов
Антон Коновалов

В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13
Планируется ли актуализация материалов данного очень полезного курса?