В один прекрасный или не очень момент на работе я ощутил нехватку местного IM-сервера.

И тут возникла идея, что такой сервачок было бы не дурственно взять и запилить. Сказано-сделано, благо я и есть администратор, соответственно, мне и карты в руки. Запинка возникла в том моменте, где происходит процесс авторизации пользователя. А именно, сопоставление указанного им логина и пароля тому, что есть в некоей базе, мне хотелось, чтобы такой базой была база почтовика, а именно - dovecot'а.

На данный момент логин-пароли хранятся в отдельно стоящей MySQL базе данных. Изначально идея была авторизовываться через сокет dovecot, но протокол общения по этому сокету документирован... да никак он не документирован - типа смотри исходники dovecot, благо они есть. Разбираться в чужом коде - занятие, как вы понимаете, мягко скажем, не сильно благодарное, да и выхлопа от этого будет не очень-то много.

Во втором подходе я думал организовать процесс авторизации по почтовому протоколу, например POP3 или IMAP. С почтовиками взаимодействовать нам не впервой, были скрипты для мониторинга прохождения почты через релэй головной организации (там стояли безопасники, чьё оборудование регулярно начинало вести себя нагло и резало даже исходящую почту, что недопустимо, нам надо было оперативно это обнаруживать и пинать их). Решил, что на сей раз можно жизнь разнообразить и попытать IMAP. Это удалось на славу. Благо задача сводилась к попытке авторизации и закрытию соединения.

Однако на пути возникло другое препятствие - extauth-скрипт должен возвращать 1 или 0 в каком-то бинарном формате. Такой подставы я конечно же не ожидал, ибо в подавляющем большинстве случаев подобные программы возвращают данные в human-readable формате-то, а тут какая-то бинарная херня, которую неудобно дебажить. Хотя сам ejabberd вообще работает по принципу обмена xml-сообщениями. Все примеры скриптов, которые мне попадались это и с родного сайта и например отсюда <a title="http://habrahabr.ru/post/99803/" href="http://habrahabr.ru/post/99803/" target="_blank">http://habrahabr.ru/post/99803/</a> или <a title="http://allgnu.com/xmpp/ejabberd-authenticate-against-imap-with-perl/" href="http://allgnu.com/xmpp/ejabberd-authenticate-against-imap-with-perl/" target="_blank">http://allgnu.com/xmpp/ejabberd-authenticate-against-imap-with-perl/</a> и тд - это всё наглый реврайт и копи-паста оригинальных скриптов, которые содержат ошибки.

Отвлекусь немного от темы и скажу, что довольно давно заметил, что на популярном ресурсе habrahabr.ru очень много статей-реврайтов чего-то англоязычного с бездумной копи-пастой содержащей порой довольно глупые ляпы. Но благодаря активному "продвижению" хабр пользуется незаслуженным авторитетом. В данном случае очень чётко прослеживается работа цитаты: "Ложь, повторенная тысячу раз, становится правдой." тов. Пауля Йозефа Геббельса, чей глубокий вклад в вопросы про-германской пропаганды во время 2-й Мировой Войны вряд ли подлежит сомнению, учитывая тот факт, что отголоски его противо-советской деятельнсти сегодня в нежно лелеятся в российских СМИ.

Итак время для опытов в какой-то момент кончилось и я подзабыл об этом сервисе, но не прошло и года, как я обнаружил раскуроченные скрипты и конфиг на сервере и решил таки добить этот вопрос раз и навсегда. Результатом стали очередные выкапывания реликтов в интернете, но таки нашёлся скрипт на гитхабе, который тупо говорил, что "да это валидный юзер" - то есть отвечал этому самому Ejabberd в правильном формате, что мне и требовалось.

Далее на его основе был запилен уже полноценный скрпит скрипт авторизации, но на сей раз я решил не заморачиваться с обращением к imap-серверу а напрямую стучаться в mysql-бд, в которой хранятся логины и хэши паролей. Алгоритм генерации пароля я знал как воспроизвести, так что итоговый скрипт получился на редкость простым.

Ниже приведён скрипт авторизации, всю логигку, обрабатывающую сравнение логин-паролей в с правильными значениями, я умышленно опустил, здесь свобода действий, что и подразумевает такой метод авторизации.

 

#!/usr/bin/perl

use Unix::Syslog qw(:macros :subs);

my $domain = $ARGV[0] || "eltechs.com";

while(1)
  {
   # my $rin = '',$rout;
   # vec($rin,fileno(STDIN),1) = 1;
   # $ein = $rin;
   # my $nfound = select($rout=$rin,undef,undef,undef);

    my $buf = "";
    syslog LOG_INFO,"waiting for packet";
    my $nread = sysread STDIN,$buf,2;
    do { syslog LOG_INFO,"port closed"; exit; } unless $nread == 2;
    my $len = unpack "n",$buf;
    my $nread = sysread STDIN,$buf,$len;

    my ($op,$user,$host,$password) = split /:/,$buf;
    #$user =~ s/\./\//og;
    my $jid = "$user\@$domain";
    my $result;

    syslog(LOG_INFO,"request (%s)", $op);

  SWITCH:
      {
        $op eq 'auth' and do
         {
             $result = 1;
         },last SWITCH;

        $op eq 'setpass' and do
         {
             $result = 1;
         },last SWITCH;

        $op eq 'isuser' and do
          {
             # password is null. Return 1 if the user $user\@$domain exitst.
             $result = 1;
          },last SWITCH;

        $op eq 'tryregister' and do
          {
             $result = 1;
          },last SWITCH;

        $op eq 'removeuser' and do
          {
             # password is null. Return 1 if the user $user\@$domain exitst.
             $result = 1;
          },last SWITCH;

        $op eq 'removeuser3' and do
          {
             $result = 1;
          },last SWITCH;
      };
    my $out = pack "nn",2,$result ? 1 : 0;
    syswrite STDOUT,$out;
  }

closelog;

Спешу заметить, что сервер, при использовании внешнего скрипта авторизации работает в несколько неполном режиме. - в shared roster он не может отобразить список ВСЕХ пользователей, только тех, что в текущий момент онлайн, а, например, в случае использования LDAP, внутреннего мех-ма, или sql-базы Ejabbrd таккой список изобразить может.

Next Post