#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.
Некоторые приложения требуют, чтобы пользователи прошли аутентификацию. Обычно требуется ввести имя пользователя (имя для входа в систему) и пароль. Приложение для этих целей может работать с собственной базой данных пользовательских имен и паролей. Но иногда необходимо или удобно позволять пользователям вводить их стандартные имена пользователей и пароли, определенные в файлах /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 представляет собой сложный тип функции хеширования. Результат в обоих случаях получается один и тот же: не поддающееся расшифровке и необратимое преобразование входного пароля.