May 22, 2010

Установка и настройка jabberd-сервера на FreeBSD

UPD: в этом блоге также есть запись об установке ejabber-сервера (несколько более продвинутого), см. тег jabber.

Многим для поднятия Джаббера на своём домене может вполне хватить служб Яндекса или Google, но осмотрительные же предпочтут поднять Jabber-сервер на своём сервере (извините за каламбур).

Решил попробовать установить Jabberd. Устанавливал его я из портов:
cd /usr/ports/net-im/jabberd && make install clean

Выбрал MySQL, ответил утвердительно на поддержку IPv6.
Сообщение после установки выглядело следующим образом:
Added group "jabber".
Added user "jabber".
Creating "/var/jabberd".
Fixing ownerships and modes in "/usr/local/etc/jabberd".
Fixing ownerships and modes in "/var/jabberd".
===> Installing rc.d startup script(s)
===>   Compressing manual pages for jabberd-2.2.9
===>   Running ldconfig
/sbin/ldconfig -m /usr/local/lib/jabberd
===>   Installing ldconfig configuration file
===>   Registering installation for jabberd-2.2.9
===> SECURITY REPORT:
This port has installed the following files which may act as network
servers and may therefore pose a remote security risk to the system.
/usr/local/bin/sm
/usr/local/bin/c2s
/usr/local/bin/router
/usr/local/bin/s2s

This port has installed the following startup scripts which may cause
these network services to be started at boot time.
/usr/local/etc/rc.d/jabberd

If there are vulnerabilities in these programs there may be a security
risk to the system. FreeBSD makes no guarantee about the security of
ports included in the Ports Collection. Please type 'make deinstall'
to deinstall the port if this is a concern.

For more information, and contact details about the security
status of this software, see the following webpage:
http://jabberd2.xiaoka.com/
===>  Cleaning for libidn-1.15
===>  Cleaning for udns-0.0.9
===>  Cleaning for gsasl-1.4.0
===>  Cleaning for libntlm-1.1
===>  Cleaning for jabberd-2.2.9


Во-первых, необходимо настроить DNS. В то время пока мы будем заниматься дальнейшей настройкой, DNS уже начнёт обновляться. Подробнее об этом здесь.

Создаём базу данных MySQL для jabberd. Можно сделать это многократно упоминаемым способом из консоли, а можно и через ISPmanager: в соответствующем разделе создайте базу данных jabberd2, добавьте пользователя, и через phpMyAdmin выполните к ней запрос:
--
-- c2s authentication/registration table
--
CREATE TABLE `authreg` (
`username` TEXT, KEY `username` (`username`(255)),
`realm` TINYTEXT, KEY `realm` (`realm`(255)),
`password` TINYTEXT ) DEFAULT CHARSET=UTF8;

--
-- Session manager tables 
--

--
-- Active (seen) users
-- Used by: core
--
CREATE TABLE `active` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`time` INT ) DEFAULT CHARSET=UTF8;

--
-- Logout times
-- Used by: mod_iq_last
--
CREATE TABLE `logout` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`time` INT ) DEFAULT CHARSET=UTF8;

--
-- Roster items
-- Used by: mod_roster
--
CREATE TABLE `roster-items` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`jid` TEXT,
`name` TEXT,
`to` TINYINT,
`from` TINYINT,
`ask` INT ) DEFAULT CHARSET=UTF8;

--
-- Roster groups
-- Used by: mod_roster
--
CREATE TABLE `roster-groups` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`jid` TEXT,
`group` TEXT ) DEFAULT CHARSET=UTF8;

--
-- vCard (user profile information)
-- Used by: mod_iq_vcard
--
CREATE TABLE `vcard` (
`collection-owner` VARCHAR(255) NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`fn` VARCHAR(255),
`nickname` VARCHAR(255),
`url` VARCHAR(255),
`tel` VARCHAR(255),
`email` VARCHAR(255),
`jabberid` VARCHAR(3071),
`mailer` VARCHAR(1023),
`title` VARCHAR(255),
`role` VARCHAR(255),
`bday` VARCHAR(255),        # Shouldn't this be a DATE?
`tz` VARCHAR(7),
`n-family` VARCHAR(255),
`n-given` VARCHAR(255),
`n-middle` VARCHAR(255),
`n-prefix` VARCHAR(255),
`n-suffix` VARCHAR(255),
`adr-street` VARCHAR(255),
`adr-extadd` VARCHAR(255),
`adr-pobox` VARCHAR(15),
`adr-locality` VARCHAR(255),
`adr-region` VARCHAR(255),
`adr-pcode` VARCHAR(31),
`adr-country` VARCHAR(63),
`geo-lat` VARCHAR(255),
`geo-lon` VARCHAR(255),
`org-orgname` VARCHAR(255),
`org-orgunit` VARCHAR(255),
`agent-extval` VARCHAR(255),
`sort-string` VARCHAR(255),
`desc` TEXT,
`note` TEXT,
`uid` VARCHAR(255),

`photo-type` VARCHAR(127),
`photo-binval` TEXT,
`photo-extval` VARCHAR(255),

`logo-type` VARCHAR(127),
`logo-binval` TEXT,
`logo-extval` VARCHAR(255),

`sound-phonetic` VARCHAR(255),
`sound-binval` TEXT,
`sound-extval` VARCHAR(255),

`key-type` VARCHAR(127),
`key-cred` TEXT,

`rev` VARCHAR(255)
) DEFAULT CHARSET=UTF8;

--
-- Offline message queue
-- Used by: mod_offline
--
CREATE TABLE `queue` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`xml` MEDIUMTEXT ) DEFAULT CHARSET=UTF8;

--
-- Private XML storage
-- Used by: mod_iq_private
--
CREATE TABLE `private` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`ns` TEXT,
`xml` MEDIUMTEXT ) DEFAULT CHARSET=UTF8;

--
-- Message Of The Day (MOTD) messages (announcements)
-- Used by: mod_announce
--
CREATE TABLE `motd-message` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`xml` TEXT ) DEFAULT CHARSET=UTF8;

--
-- Times of last MOTD message for each user
-- Used by: mod_announce
--
CREATE TABLE `motd-times` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`time` INT ) DEFAULT CHARSET=UTF8;

--
-- User-published discovery items
-- Used by: mod_disco_publish
--
CREATE TABLE `disco-items` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`jid` TEXT,
`name` TEXT,
`node` TEXT ) DEFAULT CHARSET=UTF8;

--
-- Default privacy list
-- Used by: mod_privacy
--
CREATE TABLE `privacy-default` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`default` text ) DEFAULT CHARSET=UTF8;

--
-- Privacy lists
-- Used by: mod_privacy
--
CREATE TABLE `privacy-items` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`list` TEXT,
`type` TEXT,
`value` TEXT,
`deny` TINYINT,
`order` INT,
`block` INT ) DEFAULT CHARSET=UTF8;

--
-- Vacation settings
-- Used by: mod_vacation
--
CREATE TABLE `vacation-settings` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(`object-sequence`),
`start` INT,
`end` INT,
`message` TEXT ) DEFAULT CHARSET=UTF8;

--
-- Users statuses
-- Used by: mod_status
--
CREATE TABLE `status` (
`collection-owner` TEXT NOT NULL, KEY(`collection-owner`(255)),
`object-sequence` BIGINT NOT NULL AUTO_INCREMENT, KEY(`object-sequence`),
`status` TEXT NOT NULL,
`show` TEXT NOT NULL,
`last-login` INT DEFAULT '0',
`last-logout` INT DEFAULT '0',
`xml` TEXT ) DEFAULT CHARSET=UTF8;

Этот запрос указан в файле db-setup.mysql, который размещён в каталоге /usr/local/share/doc/jabberd.

Переходим к настройке jabberd. Все конфигурационные файлы (в системе FreeBSD) размещены в каталоге /usr/local/etc/jabberd.

Прописываем доступ к MySQL.
Подробнее об этом здесь (англ.).
Сначала в файле sm.xml необходимо указать:
  • Во-первых, MySQL в качестве БД по-умолчанию
    ...
    <!-- Storage database configuration -->
    <storage>
    <!-- Dynamic storage modules path -->
    <path>/usr/local/lib/jabberd</path>
    
    <!-- By default, we use the SQLite driver for all storage -->
    <driver>mysql</driver>
    ...
    
  • Во-вторых, доступ к подготовленной вышеуказанными шагами базе данных
    ...
    <!-- MySQL driver configuration -->
    <mysql>
    <!-- Database server host and port -->
    <host>localhost</host>
    <port>3306</port>
    
    <!-- Database name -->
    <dbname>jabberd2</dbname>
    
    <!-- Database username and password -->
    <user>jabberd2</user>
    <pass>secret</pass>
    ...
    

    (вместо secret указываем пароль для пользователя jabberd, или любого другого, которому разрешён доступ к одноимённой БД jabberd2)

Затем, в файле sm.xml необходимо указать:
  • Во-первых, MySQL для авторизации
    ...
    <!-- Authentication/registration database configuration -->
    <authreg>
    ...
    <!-- Backend module to use -->
    <module>mysql</module>
    ...
    
  • Во-вторых, доступ к базе данных
    ...
    <!-- MySQL module configuration -->
    <mysql>
    <!-- Database server host and port -->
    <host>localhost</host>
    <port>3306</port>
    
    <!-- Database name -->
    <dbname>jabberd2</dbname>
    
    <!-- Database username and password -->
    <user>jabberd2</user>
    <pass>secret</pass>
    ...
    

    (вместо secret указываем пароль для пользователя jabberd, или любого другого, которому разрешён доступ к одноимённой БД jabberd2)
Теперь укажем имя домена для сервера, для этого в файле sm.xml правим:
<!-- Session manager configuration -->
<sm>
<!-- Our ID on the network (default: sm) -->
<id>какой-либо_домен.com</id>
Также отредактируйте секцию <local><id> в том же файле, иначе выдаст следующую ошибку:
[error] request to create user for non-serviced domain: jid=user@domain.tld
В нескольких мануалах рекомендуется подобные действия проделать и в файле c2s.xml, однако не уточняется в какой именно секции. Если указать также как и здесь, в <id>, это вызывает следующую ошибку в /var/log/messages:
jabberd/router[19890]: [127.0.0.1, port=18194] tried to bind 'какой-либо_домен.com', but it's already bound
jabberd/sm[19891]: router refused bind request (409)
jabberd/router[19890]: [localhost.localdomain] online (bound to 127.0.0.1, port 18194)
jabberd/router[19890]: [127.0.0.1, port=18194] disconnect
jabberd/router[19890]: [localhost.localdomain] offline
Как было сказано здесь (в ответ на этот вопрос), в главной секции <id> доменное имя должно быть указано только у sm, причём это должен быть адрес сервера где работает jabberd (может не совпадать с доменом из правой части JIDпользователей). В c2s домен нужно указать в секции <local>, об этом ниже.

Редактируем c2s.xml:
  • В секции <mechanisms><sasl> следует закомментировать <digest-md5/>:
    <!-- SASL authentication mechanisms. Comment out any that you
    don't want to be offered to clients. Again, if the auth/reg
    module does not support one of these mechanisms, then it will
    not be offered. -->
    <sasl>
    <plain/>
    <!--
    <digest-md5/>
    <anonymous/>
    <gssapi/>
    <external/>
    -->
    </sasl>
  • В секции <mechanisms><traditional> следует закомментировать <digest/>:
    <!-- These are the traditional Jabber authentication mechanisms.
    Comment out any that you don't want to be offered to clients.
    Note that if the auth/reg module does not support one of
    these mechanisms, then it will not be offered regardless of
    whether or not it is enabled here. -->
    <traditional>
    <plain/>
    <!--digest/-->
    </traditional>
    
  • В секции <local>:
    <!-- Local network configuration -->
    <local>
    <id realm='доменное_из_правой_части_JID'
    register-enable='true'
    instructions='Enter a username and password to register with this server.'
    register-oob='http://example.org/register'
    password-change='true'
    >адрес_сервера_где_работает_jabberd</id>
    Здесь, поле <c2s><local><id> равно полю <sm><id> в файле sm.xml.
В противном случае могут возникать следующие проблемы при подключении:
jabberd/c2s[70000]: [8] [xxx.xxx.xxx.xxx, port=2243] connect
jabberd/c2s[70000]: [8] [xxx.xxx.xxx.xxx, port=2243] disconnect jid=unbound, packets: 0
Генерируем сертификат (Внимание! В «Common Name» вводите имя домена, в прочих полях можно поставить точку):
openssl req -new -x509 -newkey rsa:1024 -days 3650 -keyout privkey.pem -out server.pem
openssl rsa -in privkey.pem -out privkey.pem
cat privkey.pem >> server.pem
rm privkey.pem
mv server.pem /usr/local/etc/jabberd/server.pem
chown root:jabber /usr/local/etc/jabberd/server.pem
chmod 640 /usr/local/etc/jabberd/server.pem
В c2s.xml впишите (или раскомментируйте строку если уже вписан) путь к сертификату (в нашем случае это /usr/local/etc/jabberd/server.pem) в секциях <local><id> (атрибут pemfile) и <local><pemfile> (для старых видов подключения).

При желании можно настроить вывод информации не в общий системный лог-файл, а в конкретный для каждого модуля. На примере sm.xml:
<log type='file'>
<!-- If logging to syslog, this is the log ident -->
<ident>jabberd/sm</ident>

<!-- If logging to syslog, this is the log facility
(local0 - local7)                        [default: local3] -->
<facility>local3</facility>

<!-- If logging to file, this is the filename of the logfile -->
<file>/var/jabberd/log/sm.log</file>
</log>
Создадим эти файлы:
cd /var/jabberd/logs && touch c2s.log sm.log s2s.log router.log && chown -R jabber:jabber
Убедитесь что пути в конфигах прописаны правильно, т.к. по умолчанию там указана (закомментирована) директория log, а jabberd2 создаёт logs.

Разрешаем запуск:
echo "jabberd_enable=YES">>/etc/rc.conf
Запускаем jabberd:
/usr/local/etc/rc.d/jabberd start
P.S.: Возможные ошибки:
There was an error communicating with the server . Details: Authentication Error: No appropriate mechanism available for given security settings (e.g. SASL library too weak, or plaintext authentication not enabled)
С данной ошибкой я столкнулся в клиенте PSI, для её разрешения потребовалось выставить параметр Allow plaintext authentication (Account Setup → Modify → Connection → Allow plaintext authentication) в положение Always (при этом задумываясь о настройке сертификатов).

No comments: