долгожданный пример, демонстрирующий использование механизма
Вот, наконец, долгожданный пример, демонстрирующий использование механизма поддержки теневых паролей программой, которая нуждается в этом механизме, но изначально его не обслуживает. Пример использует сервер протокола Point-to-Point (pppd-1.2.1d), который имеет режим аутентификации пользователей PAP, с использованием записей из файла /etc/passwd вместо PAP и CHAP файлов.
Этот режим используется не слишком часто, но если вы установите Shadow Suite то он просто не будет работать вообще, поскольку пароли более не хранятся в файле /etc/passwd.
Программы аутентификации пользователей pppd-1.2.1d вы можете найти в файле /usr/src/pppd-1.2.1d/pppd/auth.c.
Вначале вам придется добавить в начало этого файла несколько директив, включающих заголовочные файлы. Обратите вниамание на директивы условной компиляции.
#ifdef HAS_SHADOW
#include <shadow.h>
#include <shadow/pwauth.h>
#endif
Следующий шаг — модификация исходного кода. Мы продолжаем модифицировать файл auth.c.
Вот функция auth.c до модификации:
/*
* login - Проверка имени пользователя и его пароля по
* данным из базы /etc/passwd.
*
* Возвращает:
* UPAP_AUTHNAK: Регистрация неудачна.
* UPAP_AUTHACK: Регистрация прошла успешно.
* В любом случае msg указывает на соответствующее сообщение.
*/
static int
login(user, passwd, msg, msglen)
char *user;
char *passwd;
char **msg;
int *msglen;
{
struct passwd *pw;
char *epasswd;
char *tty;
if ((pw = getpwnam(user)) == NULL) {
return (UPAP_AUTHNAK);
}
/*
* XXX Если пароля нет, регистрируемся без него.
*/
if (pw->pw_passwd == '\0') {
return (UPAP_AUTHACK);
}
epasswd = crypt(passwd, pw->pw_passwd);
if (strcmp(epasswd, pw->pw_passwd)) {
return (UPAP_AUTHNAK);
}
syslog(LOG_INFO, "user %s logged in", user);
/*
* Заполняем запись wtmp для этого пользователя.
*/
tty = strrchr(devname, '/');
if (tty == NULL)
tty = devname;
else
tty++;
logwtmp(tty, user, ""); /* Добавляем запись wtmp */
logged_in = TRUE;
return (UPAP_AUTHACK);
}
Пароль пользователя помещается в поле pw->pw_passwd, поэтому нам придется воспользоваться функцией getspnam, которая запишет пароль в spwd->sp_pwdp.
Для выполнения реальной аутентификации мы добавим функцию pwauth, которая будет автоматически выполнять вторичную проверку, если это указано в настройках теневых паролей.
Вот код функции auth.c после модификации, обеспечивающей работу с теневыми паролями:
/*
* login - Проверка имени пользователя и его пароля по
* данным из базы /etc/passwd.
*
*
* Функция модифицирована для работы со средствами поддержки
* Linux Shadow Password Suite если установлен режим USE_SHADOW
*
* Возвращает:
* UPAP_AUTHNAK: Регистрация неудачна.
* UPAP_AUTHACK: Регистрация прошла успешно.
* В любом случае msg указывает на соответствующее сообщение.
*/
static int
login(user, passwd, msg, msglen)
char *user;
char *passwd;
char **msg;
int *msglen;
{
struct passwd *pw;
char *epasswd;
char *tty;
#ifdef USE_SHADOW
struct spwd *spwd;
struct spwd *getspnam();
#endif
if ((pw = getpwnam(user)) == NULL) {
return (UPAP_AUTHNAK);
}
#ifdef USE_SHADOW
spwd = getspnam(user);
if (spwd)
pw->pw_passwd = spwd->sp-pwdp;
#endif
/*
* XXX Если пароля нет, НЕ ПОЗВОЛЯЕМ регистрироваться!
*/
if (pw->pw_passwd == '\0') {
return (UPAP_AUTHNAK);
}
#ifdef HAS_SHADOW
if ((pw->pw_passwd && pw->pw_passwd[0] == '@'
&& pw_auth (pw->pw_passwd+1, pw->pw_name, PW_LOGIN, NULL))
|| !valid (passwd, pw)) {
return (UPAP_AUTHNAK);
}
#else
epasswd = crypt(passwd, pw->pw_passwd);
if (strcmp(epasswd, pw->pw_passwd)) {
return (UPAP_AUTHNAK);
}
#endif
syslog(LOG_INFO, "user %s logged in", user);
/*
* Формируем запись wtmp.
*/
tty = strrchr(devname, '/');
if (tty == NULL) tty = devname;
else tty++;
logwtmp(tty, user, ""); /* Добавляем запись wtmp */
logged_in = TRUE;
return (UPAP_AUTHACK);
}
Тщательный анализ кода позволяет заметить еще одно важное изменение. Если в первоначальной версии программы разрешался доступ к системе пользователю, для которого не был введен пароль в файле /etc/passwd, то теперь такой безответственный пользователь в систему просто допущен не будет.
Теперь нам необходимо модифицировать сборочный файл Makefile, таким образом, чтобы учитывались следующие два фактора:
·
наличие условной переменной USE_SHADOW;
·
подключение библиотеки libshadow.a на этапе компоновки.
Для этого при редактировании Makefile вы должны добавить:
LIBS = -lshadow
а затем найти строку:
COMPILE_FLAGS = -I.. -D_linux_=1 -DGIDSET_TYPE=gid_t
и изменнить ее на:
COMPILE_FLAGS=-I.. -D_linux_=1 -DGIDSET_TYPE=gid_t -DUSE_SHADOW
Все, теперь для запуска примера достаточно запустить make install.