Рис. 2.10. Наследование пользовательских идентификаторов
Для получения значений идентификаторов процесса используются следующие системные вызовы:
#include
#include
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
Эти функции возвращают для сделавшего вызов процесса соответственно реальный и эффективный идентификаторы пользователя и реальный и эффективный идентификаторы группы.
Процесс также может изменить значения этих идентификаторов с помощью системных вызовов:
#include
#include
int setuid(uid_t uid);
int setegid(gid_t egid);
int seteuid(uid_t euid);
int setgid(gid_t gid);
Системные вызовы
Ниже приведен фрагмент программы passwd
, определенной в файле
Таблица 2.17. Поля структуры passwd
Поле | Значение |
---|---|
char *pw_name | Имя пользователя |
char *pw_passwd | Строка, содержащая пароль в зашифрованном виде; из соображения безопасности в большинстве систем пароль хранится в файле /etc/shadow, а это поле не используется |
uid_t pw_uid | Идентификатор пользователя |
gid_t pw_gid | Идентификатор группы |
char *pw_gecos | Комментарий (поле GECOS), обычно реальное имя пользователя и дополнительная информация |
char *pw_dir | Домашний каталог пользователя |
char *pw_shell | Командный интерпретатор |
Функция, которая потребуется для нашего примера, позволяет получить запись файла паролей по имени пользователя. Она имеет следующий вид:
#include
struct passwd *getpwnam(const char *name);
Итак, перейдем к фрагменту программы:
...
struct passwd *pw;
char logname[MAXNAME];
/* Массив аргументов при запуске
командного интерпретатора */
char *arg[MAXARG];
/* Окружение командного интерпретатора */
char *envir[MAXENV];
...
/* Проведем поиск записи пользователя с именем logname,
которое было введено на приглашение "login:" */
pw = getpwnam(logname);
/* Если пользователь с таким именем не найден, повторить
приглашение */
if (pw == 0)
retry();
/* В противном случае установим идентификаторы процесса
равными значениям, полученным из файла паролей и запустим
командный интерпретатор */
else {
setuid(pw->pw_uid);
setgid(pw->pw_gid);
execve(pw->pw_shell, arg, envir);
}
...
Вызов
Выделение памяти
При обсуждении формата исполняемых файлов и образа программы в памяти мы отметили, что сегменты данных и стека могут изменять свои размеры. Если для стека операцию выделения памяти операционная система производит автоматически, то приложение имеет возможность управлять ростом сегмента данных, выделяя дополнительную память из хипа (heap — куча). Рассмотрим этот программный интерфейс.
Память, которая используется сегментами данных и стека, может быть выделена несколькими различными способами как во время создания процесса, так и динамически во время его выполнения. Существует четыре способа выделения памяти:
1. Переменная объявлена как глобальная, и ей присвоено начальное значение в исходном тексте программы, например:
char ptype = "Unknown file type";
Строка ptype
размещается в сегменте инициализированных данных исполняемого файла, и для нее выделяется соответствующая память при создании процесса.
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии