Основы программирования в Linux - Нейл Мэтью
Шрифт:
Интервал:
Закладка:
else perror("tmpfile");
exit(0);
}
Когда вы откомпилируете и выполните программу tmpnam.с, то увидите уникальное имя файла, сгенерированное функцией tmpnam:
$ ./tmpnam
Temporary file name is: /tmp/file2S64zc
Opened a temporary file OK
Как это работает
Программа вызывает функцию tmpnam для генерации уникального имени временного файла. Если вы хотите его использовать, нужно быстро его открыть, чтобы минимизировать риск того, что другая программа откроет файл с тем же именем. Вызов функции tmpfile одновременно создает и открывает временный файл, тем самым устраняя этот риск. При компиляции программы, использующей функцию tmpnam, компилятор GNU С может вывести предупреждение о применении этой функции.
В некоторых версиях UNIX предлагается другой способ генерации имен временных файлов — с помощью функций mktemp и mkstemp. Они поддерживаются и ОС Linux и аналогичны функции tmpnam за исключением того, что вы должны задать шаблон имени временного файла, который предоставляет некоторые дополнительные возможности управления местом хранения и именем файла.
#include <stdlib.h>
char *mktemp(char *template);
int mkstemp(char *template);
Функция mktemp создает уникальное имя файла на основе заданного шаблона template. Аргумент template должен быть строкой с шестью завершающими символами Х. mktemp заменяет эти символы Х уникальной комбинацией символов, допустимых в именах файлов. Она возвращает указатель на сгенерированную строку или NULL при невозможности сформировать уникальное имя.
Функция mkstemp аналогична функции tmpfile: она создает и открывает временный файл. Имя файла генерируется так же, как в функции mktemp, но возвращенный результат — открытый низкоуровневый дескриптор файла.
ПримечаниеВ ваших собственных программах следует всегда применять функции "создать и открыть" tmpfile и mkstemp вместо функций tmpnam и mktemp.
Информация о пользователе
Все программы в ОС Linux за исключением программы init, запускаются другими программами или пользователями. В главе 11 вы узнаете больше о взаимодействии выполняющихся программ или процессов. Пользователи чаще всего запускают программы из командной оболочки, реагирующей на их команды. Вы видели, что в программе можно определить собственное окружение, просматривая переменные окружения и читая системные часы. Программа может также выяснить данные о пользователе, применяющем ее.
Когда пользователь регистрируется в системе Linux, у него или у нее есть имя пользователя и пароль. После того как эти данные проверены, пользователю предоставляется командная оболочка. В системе у пользователя также есть уникальный идентификатор пользователя, называемый UID (user identifier). Каждая программа, выполняемая Linux, запускается от имени пользователя и имеет связанный с ней UID.
Вы можете настроить выполнение программ так, как будто они запускаются другим пользователем. Если у программы есть свой набор прав доступа для UID, она будет выполняться от имени владельца исполняемого файла. Когда выполнена команда su, программа действует так, как будто она запущена суперпользователем. Затем она проверяет право доступа пользователя, изменяет UID на идентификатор назначенной учетной записи и запускает регистрационную командную оболочку данной учетной записи. Этот прием позволяет программе выполняться от имени другого пользователя и часто используется системными администраторами для выполнения задач технического обслуживания системы.
Поскольку UID — это ключевой параметр для идентификации пользователя, начнем с него.
У UID есть свои тип uid_t, определенный в файле sys/types.h. Обычно это короткое целое (small integer). Одни идентификаторы пользователя заранее определены системой, другие создаются системным администратором, когда новые пользователи становятся известны системе. Как правило, идентификаторы пользователей имеют значения, большие 100.
#include <sys/types.h>
#include <unistd.h>
uid_t getuid (void);
char *getlogin(void);
Функция getuid возвращает UID, с которым связана программа. Обычно это UID пользователя, запустившего программу.
Функция getlogin возвращает регистрационное имя, ассоциированное с текущим пользователем.
Системный файл /etc/passwd содержит базу данных, имеющую дело с учетными записями пользователей. Он состоит из строк по одной на каждого пользователя, в каждую строку включены имя пользователя, зашифрованный пароль, идентификатор пользователя (UID), идентификатор группы (GID), полное имя, исходный каталог и командная оболочка, запускаемая по умолчанию. Далее приведен пример такой строки:
neil:zBqxfqedfpk:500:100:Neil Matthew:/home/neil:/bin/bash
Если вы пишете программу, которая определяет UID пользователя, запустившего ее, то можете расширить ее возможности и заглянуть в файл passwd для выяснения регистрационного имени пользователя и его полного имени. Мы не рекомендуем делать это, потому что современные UNIX-подобные системы уходят от применения файлов учетных записей пользователей для повышения безопасности системы. Многие системы, включая Linux, имеют возможность использовать файлы теневых паролей (shadow password), совсем не содержащие пригодной информации о зашифрованных паролях (она часто хранится в файле /etc/shadow, которые обычные пользователи не могут читать). По этой причине определен ряд функций для предоставления эффективного программного интерфейса, позволяющего получать эту пользовательскую информацию.
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
Структура базы данных учетных записей пользователей passwd определена в файле pwd.h и включает элементы, перечисленные в табл. 4.4.
Таблица 4.4
Элемент passwd Описание char *pw_name Регистрационное имя пользователя uid_t pw_uid Номер UID gid_t pw_gid Номер GID char *pw_dir Исходный каталог пользователя char *pw_gecos Полное имя пользователя char *pw_shell Командная оболочка пользователя, запускаемая по умолчаниюВ некоторых системах UNIX может использоваться другое имя для поля с полным именем пользователя: в одних системах это pw_gecos, как в ОС Linux, в других — pw_comment. Это означает, что мы не можем рекомендовать его использование. Обе функции (и getpwuid, и getpwnam) возвращают указатель на структуру passwd, соответствующую пользователю. Пользователь идентифицируется по UID в функции getpwuid и по регистрационному имени в функции getpwnam. В случае ошибки обе функции вернут пустой указатель и установят переменную errno.
Выполните упражнение 4.11.
Упражнение 4.11. Информации о пользователеВ этом упражнении показана программа user.c, извлекающая некоторую информацию о пользователе из базы данных учетных записей.
#include <sys/types.h>
#include <pwd.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
uid_t uid;
gid_t gid;
struct passwd *pw;
uid = getuid();
gid = getgid();
printf("User is %sn", getlogin());
printf("User IDs: uid=%d, gid=%dn", uid, gid);
pw = getpwuid(uid);
printf(
"UID passwd entry:n name=%s, uid=%d, gid=%d, home=%s, shell=%sn",
pw->pw_name, pw->pw_uid, pw->pw_gid, pw->pw_dir, pw->pw_shell);
pw = getpwnam("root");
printf("root passwd entry:n");
printf("name=%s, uid=%d, gid=%d, home=%s, shell=%sn",
pw->pw_name, pw->pw_uid, pw->pw_gid, pw->pw_dir, pw->pw_shell);
exit(0);
}
Программа предоставит следующий вывод, который может слегка отличаться в разных версиях Linux и UNIX:
$ ./user
User is neil
User IDs: uid=1000, gid=100
UID passwd entry:
name=neil, uid=1000, gid=100, home=/home/neil, shell=/bin/bash
root passwd entry:
name=root, uid=0, gid=0, home=/root, shell=/bin/bash
Как это работает
Эта программа вызывает функцию getuid для получения UID текущего пользователя, Этот UID применяется в функции getpwuid для получения подробной информации из файла учетных записей пользователей. В качестве альтернативы мы показываем, как для извлечения информации о пользователе можно задать в функции getpwnam имя пользователя root.