Что вижу - о том пою (aragont) wrote,
Что вижу - о том пою
aragont

Category:

pam_mysql

На днях переносил почтовый сервер с Linux CentOS 5 на CentOS 7. Автоматическое обновление версий невозможно, по-этому пришлось руками переносить все настройки на новый сервер. Получился скрипт на полторы тысячи строк (из них половина во встроенных документах).

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

Цепочка проверки паролей выглядит так:

Почтовый сервер cyrus-imapd -> сервер авторизации saslauthd -> модуль pam_mysql -> БД mariadb.

Поиск в интернете по сообщениям ядра ничего не дал:

$> dmesg
[530037.792817] saslauthd[52890]: segfault at 0 ip 00007fdc51eda70a sp 00007fff8e3a2e08 error 4 in libc-2.17.so[7fdc51d9c000+1c3000]

Пришлось включить сброс дампа памяти saslauthd. В файле /lib/systemd/system/saslauthd.service добавили:

[Service]
...
LimitCORE=infinity
...

и для красоты (чтобы дамп создавался в известном месте с разумным именем) в /proc/sys/kernel/core_pattern :

/tmp/core.%e.%t.%p

После очередного падения подключились к дампу отладчиком и получили место ошибки:

$> gdb /usr/sbin/saslauthd /tmp/core.saslauthd.1528199730.8293
(gdb) bt
#0 __strcmp_sse42 () at ../sysdeps/x86_64/multiarch/strcmp-sse42.S:165
#1 0x00007fe5bbc64b27 in pam_mysql_check_passwd (ctx=0x557c843c3730, user=, passwd=0x557c843dee50 "b@$Cpw",
null_inhibited=null_inhibited@entry=1) at pam_mysql.c:2648
#2 0x00007fe5bbc65060 in pam_sm_authenticate (pamh=0x557c843be630, flags=32768, argc=, argv=) at pam_mysql.c:3478

Теперь осталось посмотреть pam_mysql.c:2648. Проверка пароля выглядит так (row[0] - строка из БД):

vresult = strcmp(row[0], crypt(passwd, row[0]));

Про функцию crypt в man странице написано: "В случае ошибки возвращает NULL", правда явно не написано, что приводит к ошибке. Маленький эксперимент показал, что ошибка происходит в двух случаях - второй аргумент (salt) это строка короче двух символов или один из первых двух символов - спецсимвол (оба условия описаны в man).

Удивительно, но на старой системе функция crypt работала не так. Вместо указателя NULL она возвращала указатель на пустую строку и всё шло без проблем. Вторая особенность crypt, приведшая к проблеме, - это то, как crypt реализован в php. В веб-интерфейсе администратора не проводилась проверка на формат второго аргумента, а функция crypt в php не считала спецсимволы ошибкой. В результате в БД оказалось несколько записей со спецсимволами в первых двух позициях - они и ломали сервер авторизации.

Всё хорошо, что хорошо кончается. Заодно нашёлся патч для исправления утечки памяти в pam_mysql, который приводил к редким зависаниям saslauthd на старой системе.

Правильные исходные коды pam_mysql - https://github.com/NigelCunningham/pam-MySQL
А правильные скрипты для сборки RPM пакета лучше взять здесь - https://src.fedoraproject.org/rpms/pam_mysql
Tags: #0, #1, #2, программы
Subscribe

  • Летнее стерео

    Режевской район Свердловской области Меловые скалы на берегу реки Другие форматы Отвалы никелевого рудника Другие форматы Другие…

  • Нижний Тагил - стерео

    Нижнетагильский Металлургический-завод музей, о котором я уже писал, оказался чрезвычайно фотогеничным с точки зрения стереофотографии. Из полутора…

  • Реж/Таватуй/Шемаха

    До сих пор я рассказывал про познавательную часть нашей поездки по среднему Уралу, а теперь несколько заключительных слов про отдыхательную часть.…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments