Модераторы: powerfox, ZeeLax
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Авторизация в ProFTPD по учетным записям форума. Нетривиальная задача. 
:(
    Опции темы
Imple
Дата 21.12.2009, 14:29 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1546
Регистрация: 14.9.2007
Где: Алма-Ата

Репутация: 18
Всего: 87



Авторизация пользователей в ProFTPD по учетным записям форума

Недавно появилась необходимость запретить вход кому попало на FTP сервер, то есть заблокировать вход под anonymous. Но содержать отдельную базу с FTP пользователями неудобно, а более того неэффективно. Думал-думал, и решил авторизировать пользователей по учетной записи форума, в моем случае SMF. Пользователи хранятся в MySQL таблице smf_members, имя пользователя в memberName, а пароль в passwd. У ProFTPD есть хорошо документированная возможность получать учетные данные с PostgreSQL / MySQL. Но вот беда, у форума пароли хранятся в хеше SHA1, да и в начало пароля добавляется имя пользователя в нижнем регистре. А ProFTPD ожидает, что ему из SQL-запроса к базе вернется пароль в форматах MySQL PASSWORD(), Crypt, либо Plaintext. Само собой, никакого SHA1 там нет, не говоря уже о том, что к паролю еще добавляется имя пользователя. Гуглил день, другой, все жалуются на подобное, а готового решения никто не предлагает.

Ну, наше дело не хитрое. Значит, что мы имеем? Есть параметр SQLAuthTypes, который указывает, каким методом криптован пароль. Нужного мне варианта нет, значит открываем исходники. С домашнего сайта ProFTPD был скачен последний RC-билд, на этот момент proftpd-1.3.3rc3. Беглый осмотр contrib/mod_sql.c и contrib/mod_sql.h, показал, что есть механизм добавления своих методов авторизации функцией:

Код
int sql_register_authtype(const char *name,  modret_t *(*callback)(cmd_rec *, const char *, const char *));


Интересно. Немного побегав по исходникам, найдя достаточно примеров вызова этой функции (что странно, ничего этого толком недокументированно, да и в интернетах по запросу "proftpd sql_register_authtype" 0 результатов), стало ясно, что все сводится к созданию callback функции, которая принимает в качестве параметров пароль в чистом виде, и хеш полученный из mysql, проверяет соответствует ли пароль хешу, и return’ом возвращает результат проверки. Ну, вроде бы звучит несложно. Создал кустарный модуль contrib/mod_sql_auth_smf.c следующего содержания:

Код
#include "conf.h"
#include "mod_sql.h"

#define MOD_SQL_AUTH_SMF_VERSION "mod_sql_smf/0.1"

#if defined(HAVE_OPENSSL) || defined(PR_USE_OPENSSL)

#include <openssl/evp.h>

static modret_t *auth_smf(cmd_rec *cmd, const char *c_clear, const char *c_hash) {
    const EVP_MD *md;
    EVP_MD_CTX md_ctxt;
    unsigned char mdval[EVP_MAX_MD_SIZE];
    char hash[EVP_MAX_MD_SIZE * 2];
    int mdlen, i;

    OpenSSL_add_all_digests();
    md = EVP_get_digestbyname("sha1");

    if (!md)
        return ERROR_INT(cmd, PR_AUTH_BADPWD);

    EVP_DigestInit(&md_ctxt, md);
    EVP_DigestUpdate(&md_ctxt, c_clear, strlen(c_clear));
    EVP_DigestFinal(&md_ctxt, mdval, &mdlen);

    for (i=0; i<mdlen; i++) {
        sprintf(hash+(i*2), "%02x", mdval[i]);
    }

    return strcmp(hash, c_hash) ? ERROR_INT(cmd, PR_AUTH_BADPWD) : HANDLED(cmd);
}

static int sql_auth_smf_init(void) {
  (void) sql_register_authtype("SMF", auth_smf);
  return 0;
}

#endif

module sql_auth_smf_module = {

  /* Always NULL */
  NULL, NULL,

  /* Module API version */
  0x20,

  /* Module name */
  "sql_auth_smf",

  /* Module configuration directive table */
  NULL,

  /* Module command handler table */
  NULL,

  /* Module auth handler table */
  NULL,

  /* Module initialization */
  sql_auth_smf_init,

  /* Session initialization */
  NULL,

  /* Module Version */
  MOD_SQL_AUTH_SMF_VERSION

};


В этом модуле я средствами OpenSSL реализовал хеширование SHA1 чистого пароля, сверку с полученным хешем, и возвратом результата проверки в mod_sql.c. Скомпилировал, не забыв добавить опцию к configure --with-shared=mod_sql_auth_smf, изменил параметр в proftpd.conf SQLAuthTypes на SMF и добавил строчку LoadModule mod_sql_mysql.c. Собралось, проверил, работает! Но только в том случае, если пользователь User1 с паролем PassWd22, укажет в качестве пароля user1PassWd22. Ну, это уже проще. Найдя вызов callback функции в mod_sql.c, изменил ее с такого вида:

Код
mr = sah->cb(cmd, plaintext, ciphertext);


На такой:

Код
if(strcmp(sah->name, "SMF")==0) {
  int i;
  char namepasswd[106];
  strncpy(namepasswd, cmd->argv[1], 25);
  for(i=0;namepasswd[i];i++) namepasswd[i]=tolower(namepasswd[i]);
  strncat(namepasswd, cmd->argv[2], 80);
  mr = sah->cb(cmd, namepasswd, ciphertext);
} else
  mr = sah->cb(cmd, plaintext, ciphertext);


Вот и все, цель достигнута. Если кого-то интересуют подробности настройки ProFTPD для работы с MySQL, тонкости компиляции, отвечу в комментариях. Цель данной статьи – не дать полное пошаговое руководство с нуля, а кратко показать как можно с небольшими знаниями C, заставить ProFTPD авторизировать пользователей по учетным данным любого форума, блога, и так далее.

Это сообщение отредактировал(а) Imple - 21.12.2009, 14:30


--------------------
Не шалю, никого не трогаю, починяю сервер.
PM WWW ICQ Skype GTalk Jabber   Вверх
SparF
Дата 27.12.2009, 20:39 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 387
Регистрация: 14.9.2006
Где: Санкт-Петербург/М осква

Репутация: 2
Всего: 18



Спасибо. решение и правда интересное.
Единственная просьба. Чтобы это решение не затерялось в интернете - отпишите его, пожалуйста, в официальную рассылку ProFTPD.
В случае, если его включат в релиз - это спасет множество пользователей от сборки (пересборки) вручную и необходимости отслеживать новостные рассылки на тему "а не появилась ли критичная дыра в proftpd - и не придется ли мне пересобирать его...".
Что, согласитесь, достаточно важно.


--------------------
Люди, не пользуйтесь пиратским программным обеспечением - переходите на Linux!
PM MAIL ICQ   Вверх
Imple
Дата 27.12.2009, 20:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1546
Регистрация: 14.9.2007
Где: Алма-Ата

Репутация: 18
Всего: 87



SparF, согласен, но нужно немного вылизать код. Будет свободная минутка, займусь, отправлю. Спасибо Вам за интерес к статье. smile


--------------------
Не шалю, никого не трогаю, починяю сервер.
PM WWW ICQ Skype GTalk Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Linux/UNIX: Администрирование"
ZeeLax
Imple
nerezus
Этот форум предназначен для решения вопросов по администрации *n?x-систем, в частности по настройке сложных сетей и обслуживанию серверного оборудования.

  • Вы должны соблюдать правила форума.
  • Помните: какой вопрос, такой и ответ. Прежде чем задать вопрос прочитайте вот эту статью на форуме CIT.
  • Оскорблять запрещается.
  • Религиозные войны в Религиозных войнах.
  • Общение "просто так" в Клубе юнуксоидов. В отличие от многих других разделов, здесь разрешается сдержанно оффтопить и юморить в тему.

За интересные статьи, находки, решения, программы и просто реальную помощь будут ставиться + в репу).


В данный момент этот раздел модерируют nerezus, nickless, powerfox, pythonwin, Imple и ZeeLax. Если вы хотите помочь нам, пишите в ПМ и мы обсудим.


Спасибо. И use UNIX or die; С уважением, nerezus, nickless, powerfox, pythonwin, Imple, ZeeLax.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Администрирование *NIX систем | Следующая тема »


 




[ Время генерации скрипта: 0.0963 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.