Valid HTML 4.01 Transitional

Setting Up DJabberd

James F. Carter <jimc@math.ucla.edu>, 2013-00-00

Prosody is a nice XMPP/Jabber server, but after unknown events connected with migrating to the new home server machine, it broke. Specifically, when the client connects, the server is supposed to propose SASL authentication mechanisms, which it does, but the number in the list is zero.

I put a fair amount of work into debugging this, with no solution. A big problem with Prosody is that it is stuck with Lua5.1 (back version), although the package on the SuSE Build Service seems to be kind of a hybrid of 5.1 and 5.2. I would not be at all surprised if version skew is causing my SASL problems. So I've decided to attempt installing DJabberd. The operative word here is attempt.

The biggest problem with DJabberd is its skimpy documentation. Basically you have to read each Perl module. Fortunately the modules have embedded PODs. Here is what I did to install DJabberd.

Installation

Installation dependencies. All of this group are either in the main distro, or I had already obtained them from the SuSE Build Service, or I did so for this purpose.

Additional material was needed:

/etc/djabberd/log.conf has logging configurations. I omitted this file, assuming I'll get default logging. This puts messages on stderr, in color.

/etc/djabberd/djabberd.conf is the main configuration file. It is described in Config.pod. I put together an initial attempt, but the final file is shown later.

Running the Sample Server

Starting the sample server by hand:

Configuring all the plugins:

Oh, crap, yesterday I was starting the server when $PWD = the CPAN sources. When I start it with $PWD = another directory, it behaves differently, because it *is* different. New strategy: toss the SuSE packages and use the CPAN stuff directly. Starting over…

On the first connection it eventually reads /usr/lib/perl5/vendor_perl/5.16.2/Authen/SASL/Perl/PLAIN.pm gets the UID and GID, sends nothing to the client (which it needs to do to start the SASL negotiation), then waits forever (epoll) on a file descriptor opened at global level, before the connection was made. This is the FD returned by epoll_create. The program adds FD 3 and 4 to the set using epoll_ctl; these FDs are sockets bound and listening to ports 5222 and 5269 resp. Later the client connection FD is added.

I'm not going to debug this. Conclusion: DJabberd is too poorly documented and too fragile, so I will not be able to get it to work in the time allowed.

DJabberd Redux

Having had some problems with Tigase, possibly fixable, and having learned some things while installing it, I decided to give DJabberd another try. This time I put the CPAN package in /m1/DJabberd-0.85 with a symlink to there from /usr/local/DJabberd, and a script in /usr/local/sbin that says basically cd /usr/local/DJabberd; ./djabberd $*. I did compile the program but the compilation steps were basically cp -p lib/file.pl blib/lib/file.pl. And I ran the tests (successfully).

A proper LSB startup script will come later.

Starting the server by hand. It makes a TLS connection. It reports the requested cert, jfcarter.net. It commits to PLAIN auth, the client asks for a password, and everyone sits there without closing the connection. This user is in LDAP but perhaps is not known to SASL. Something I learned: the SASL module's purpose is to deal with the wire protocol; this may not be a backend client-type module.

Let's turn LDAP back on. Can't find DJabberd/Authen/LDAP.pm. It's on CPAN. It even has a spec file, which looks functional. Just drop it into the DJabberd directory. It depends on Net::LDAP which we have installed.

So which storage backend is turned on by default and where do the files go? InMemoryOnly.pm, how lameass! SQLite is available; see DJabberd::RosterStorage::SQLite. One config option: Database $filename. There's a warning that database access happens on the main thread, which has to be shared with message passing. For a big site, i.e. thousands of users active at once, the other backends, e.g. PostgreSQL, MySQL, etc., are smarter about not blocking the main thread.

Now it makes the TLS connection (jfcarter.net), commits to PLAIN auth. Authen.pm calls DJabberd/Authen/LDAP.pm which calls undef->vhost(). This is a bug in DJabberd::SASL::Manager::AuthenSASL.pm and apparently most Authen modules do not trigger it, but LDAP.pm does. Fixed. If your version hasn't received the patch yet, in line 50 where it sets args, append , conn => $conn within the brackets (comma separated list).

OK, I'm on. DJabberd lacks a plugin to respond to ping. It's on CPAN, DJabberd::Plugin::Ping

Jimc and Alice are both on but each shows the other as offline. Requesting buddy authorization, jimc goes first. And we get presence updates. Now both of us log off and the server is restarted. We're still buddies, and receive the appropriate presence updates. This is a very positive development; this is the step where Tigase failed to remember the buddy relation.

Here is /etc/djabberd/djabberd.conf that gave this successful outcome:

# /etc/djabberd/djabberd.conf
# Created for CouchNet by jimc.  Revision history:
#   2013-08-01 jimc	Trying again to make DJabberd work.
#   2013-07-24 jimc	Initial setup

# According to the docs the SSL parameters belong in the global section,
# and they refer to the hostname of the server that clients (in all 
# domains/VHosts) connect to.  However, when Pidgin does TLSv3 it sends over
# the domain as the cert it wants to see.  These are the domain's credentials.
SSLCertificateKeyFile	/etc/ssl/private/jfcarter.key
SSLCertificateFile	/etc/ssl/hostcerts/jfcarter.crt
# There is some ambiguity about what should be in the chain file.  The
# one specified starts with the private key, then the host cert, then
# the intermediate cert, then the root cert.  Docs say that you must also
# specify SSLCertificateFile and SSLCertificateKeyFile even though they are
# in the chain file also.  
SSLCertificateChainFile	/etc/ssl/private/jfcarter.pem

# ClientPort 5222 and ServerPort 5269 are the defaults. 
PidFile /var/run/djabberd.pid

<VHost jfcarter.net>
    # Allows new users to register
    InBandReg on
    # Server to server communication, default is off
    S2S off
    # Require SSL before passwords are sent from the client
    RequireSSL true

    # How to get the client to give us a credential.  Uses Authen::SASL::Perl
    <Plugin DJabberd::SASL::AuthenSASL>
	Optional   yes
	# DIGEST-MD5 is also available
	Mechanisms PLAIN LOGIN 
    </Plugin>

    # Backend auth: what to do with the Jabber ID and password?  Uses Net::LDAP
    <Plugin DJabberd::Authen::LDAP>
	LDAPURI             ldap://jacinth.cft.ca.us/
	LDAPBaseDN          ou=people,dc=cft,dc=ca,dc=us
	LDAPFilter	    (uid=%u)
    </Plugin>

    # Roster (buddy list) storage
    <Plugin DJabberd::RosterStorage::SQLite>
	Database /var/lib/xmpp/djabberd.sqlite
    </Plugin>

    # Handles Ping packets (XEP 0199)
    <Plugin DJabberd::Plugin::Ping />

    # Private XML Storage (XEP 0049), often used by clients for settings
    # and buddy lists.
    <Plugin DJabberd::Plugin::PrivateStorage::DBI>
	Datasource	  SQLite:dbname=/var/lib/xmpp/private-0049.sqlite
    </Plugin>

</VHost>

Operational Cleanup

Now I'm going to housebreak DJabberd for production operation.

Future Development

Here are some issues I want to investigate. But later.