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

#include <shadow.h>

struct spwd *getspnam(const char *name);

Возвращает при успешном завершении указатель или NULL, если запись не найдена либо произошла ошибка

struct spwd *getspent(void);

Возвращает указатель при успешном завершении или NULL в случае конца потока либо при ошибке

void setspent(void);

void endspent(void);

Мы не станем рассматривать эти функции во всех подробностях, поскольку их работа похожа на работу соответствующих функций, относящихся к файлу паролей. (Эти функции не указаны в SUSv3 и представлены не во всех реализациях UNIX.)

Функции getspnam() и getspent() возвращают указатели на структуру типа spwd. Она имеет следующую форму:

struct spwd {

char *sp_namp; /* Имя для входа в систему (имя пользователя) */

char *sp_pwdp; /* Зашифрованный пароль */

/* Остальные поля поддерживают «устаревание пароля», дополнительное средство,

заставляющее пользователей регулярно менять свои пароли, чтобы, даже если

злоумышленник сумел получить пароль, тот со временем стал для него

бесполезным. */

long sp_lstchg; /* Время последнего изменения пароля (количество

дней, прошедших с 1 января 1970 года) */

long sp_min; /* Минимальное количество дней между сменами пароля */

long sp_max; /* Максимальное количество дней до требуемой смены пароля */

long sp_warn; /* Количество дней, за которое пользователь

заранее получает предупреждение о скором

истечении срока действия пароля */

long sp_inact; /* Количество дней после истечения срока действия пароля

до признания учетной записи неактивнойи заблокированной */

long sp_expire; /* Дата, когда истекает срок действия учетной

записи (количество дней, прошедших с 1 января 1970 года) */

unsigned long sp_flag; /* Зарезервировано для будущего использования */

};

Применение функции getspnam() будет показано в листинге 8.2.

8.5. Шифрование пароля и аутентификация пользователя

Некоторые приложения требуют, чтобы пользователи прошли аутентификацию. Обычно требуется ввести имя пользователя (имя для входа в систему) и пароль. Приложение для этих целей может работать с собственной базой данных пользовательских имен и паролей. Но иногда необходимо или удобно позволять пользователям вводить их стандартные имена пользователей и пароли, определенные в файлах /etc/passwd и /etc/shadow. (В остальной части раздела будет считаться, что в системе включен режим использования теневых паролей и что эти зашифрованные пароли хранятся в файле /etc/shadow.) Наглядными примерами таких программ могут послужить сетевые приложения, предоставляющие какие-либо формы для входа в удаленную систему, например ssh и ftp. Они должны проверить допустимость имени пользователя и пароля точно так же, как это делают программы стандартного входа в систему.

Из соображений безопасности системы UNIX шифруют пароли, используя алгоритм одностороннего шифрования. Он гарантирует невозможность воссоздания исходного пароля из его зашифрованной формы. Поэтому единственный способ проверить верность проверяемого пароля — его шифрование с использованием того же метода, что позволит увидеть, соответствует ли зашифрованный результат значению, сохраненному в файле /etc/shadow. Алгоритм шифрования заключен в функции crypt().

#define _XOPEN_SOURCE

#include <unistd.h>

char *crypt(const char *key, const char *salt);

Возвращает указатель на статично выделенную строку, содержащую при успешном завершении зашифрованный пароль, или NULL при ошибке

Работа функции crypt() предусматривает получение ключа key (то есть пароля) длиной до восьми символов и применение к нему разновидности алгоритма Data Encryption Standard (DES). Аргумент salt является строкой из двух символов, чье значение используется для внесения помех в алгоритм (его изменения), то есть для применения технологии, затрудняющей взлом зашифрованного пароля. Функция возвращает указатель на статически выделенную 13-символьную строку, являющуюся зашифрованным паролем.

Подробности, касающиеся алгоритма DES, можно найти по адресу http://www.itl.nist.gov/fipspubs/fip46-2.htm. Как уже ранее упоминалось, вместо DES могут использоваться другие алгоритмы. Например, применение алгоритма MD5 приводит к созданию 34-символьной строки, начинающейся с символа доллара ($), который позволяет функции crypt() отличать пароли, зашифрованные с помощью DES, от паролей, зашифрованных с помощью MD5.

При рассмотрении вопроса шифрования паролей здесь употребляется слово «шифрование», что не совсем верно отражает действительность. Если выражаться точнее, то DES использует заданную строку пароля в качестве ключа шифрования для зашифровки фиксированной строки битов, а MD5 представляет собой сложный тип функции хеширования. Результат в обоих случаях получается один и тот же: не поддающееся расшифровке и необратимое преобразование входного пароля.