Read the source Luke – part 1

A fellow (and very competent) postmaster of an extremely high traffic ISP (by Greek standards) dropped me a note asking me whether I had seen the following error message:

Jan 25 11:07:43 XXXXXXXXXXX sm-mta[21622]: l0M7JEYx016921: SYSERR(root): Error in ldap_search using user@YYYYYYYYYYYY.gr in map ldapmra: Unknown error 325

Being the LDAP hater that I am, I had never encountered it. Googling arround did not result in anything meaningful. So the next step was to read the source code:

First I downloaded and uncpaked the latest sendmail (8.13.8) and openldap (2.3.32) sources. Now where do I start? The error message points where:

Inside the sendmail-8.13.8 directory:

$ grep -r "Error in ldap_search" .
./sendmail/map.c: syserr("Error in ldap_search using %s in map %s",
./sendmail/map.c: syserr("451 4.3.5 Error in ldap_search using %s in map %s",

syserr() is called when sm_ldap_search() fails and errno is set by calling sm_ldap_geterrno():

errno = sm_ldap_geterrno(lmap->ldap_ld) + E_LDAPBASE;

What is E_LDAPBASE? We find it defined in include/sm/errstring.h:

#define E_LDAPBASE (E_PSEUDOBASE + 70)

OK, now what is E_PSEUDOBASE? We find it defined again in include/sm/errstring.h:

#ifndef E_PSEUDOBASE
# define E_PSEUDOBASE 256
#endif /* ! E_PSEUDOBASE */

Hmm… the valuse of E_LDAPBASE is 256 + 70 = 326? Now does this not look familiar? So what makes sm_ldap_geterrno() return -1?

$ grep -r ^sm_ldap_geterrno .
./libsm/ldap.c:sm_ldap_geterrno(ld)

sm_ldap_geterrno() basically calls:

(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);

and returns the value of err.

Now we switch to the openldap-2.3.32 source directory:

$ grep -r ^ldap_get_option .
:
./libraries/libldap/options.c:ldap_get_option(

from which we find out that in our case it returns the following value:

* (int *) outvalue = ld->ld_errno;

So who sets the value of ld->ld_errno to -1? Back in the sendmail sources we see that we followed this branch of the code because of a call to sm_ldap_search():

$ grep -r ^sm_ldap_search() .
./libsm/ldap.c:sm_ldap_search(lmap, key)

sm_ldap_search returns the value of a call to ldap_search(). Switching back to openldap’s sources:

$ grep -r ^ldap_search .
:
./libraries/libldap/search.c:ldap_search(
:

ldap_search() returns the result of ldap_send_initial_request():

$ grep -r ^ldap_send_initial_request
./libraries/libldap/request.c:ldap_send_initial_request(

which in turns returns the result of ldap_server_request():

$ grep -r ^ldap_send_server_request .
./libraries/libldap/request.c:ldap_send_server_request(

It sets ld_errno to -1 in two cases. The first is when it sets it to LDAP_SERVER_DOWN (which is #defined as (-1) in ldap.h) and when ldap_int_flush_request() fails returning -1:

$ grep -r ^ldap_int_flush_request .
./libraries/libldap/request.c:ldap_int_flush_request(

ldap_int_flush_request() returns -1 when ber_flush() fails and sets ld_errno to LDAP_SERVER_DOWN.

So there:

Unknown error 325 means that your sendmail cannot talk to your LDAP server because sendmail thinks that slapd is down.

Or not?

(part2)

Ηλεκτρονικές Εκλογές ΤΕΕ – part 1

Σήμερα ξεκίνησαν οι εκλογές του ΤΕΕ. Το εκλογικό σώμα είναι περίπου το 1% του πληθυσμού της χώρας και με δώδεκα (12) κάλπες πρόκειται για την πιο πολύπλοκη εκλογική διαδικασία στη χώρα. Αν όλα πάνε καλά με το ηλεκτρονικό κομάτι των εκλογών θα έχουμε γράψει ιστορία.

Διευκρίνηση: Η καταμέτρηση είναι ηλεκτρονική, όχι η ψηφοφορία. Η ψηφοφορία γίνεται παραδοσιακά.

Πρέπει να ζητήσω συγνώμη από τη γυναίκα και το νεογέννητο γιό μου γιατί στο πρώτο του ΣΚ στο σπίτι μας εγώ είμαι μακριά του.

Update: Αποτελέσματα των εκλογών όπως κλείνουν τα διάφορα εκλογικά τμήματα

(part 2)

Migrating thousands of mailboxes to a new mailbox storage

Years ago we were faced with the following situation: We had thousands of mailboxes that were being served by a proprietary and unsupported version of email software. So we decided to move to a new architecture. While researching I selected a very good (IMHO) commercial product. But for reasons outside the scope of the post I opted for a F/OSS solution, and specifically the UW-IMAP toolkit. For those rushing to judge that price was the decisive factor I only have to reiterate Vladimir Butenko‘s words:

“Bottom line: you always pay. You need a simple thing – you pay a small amount, you need a big thing – you pay more.” (plain message and comp.mail.imap thread)

OK and now for the real question: How do you move thousands of mailboxes without your users noticing?

Since you do not know (and do not want to know) your users’ passwords the only thing you can do is to hack into the source code of your POP3 server (we do not offer IMAP yet). Whether it is the UW-IMAP toolkit, Cucipop, popa3d or any other server that you have access to its source, the server knows the correct password for your users when they authenticate. So when the authentication succeeds you fork(2) a program that logs into the old server and fetches the mailbox from the old server to the new one that runs the F/OSS software that you have selected. This can be fetchmail or any similar program. However I have found out that Net::POP3 is a better choice:

#!/usr/bin/perl
use Sys::Syslog;
use Net::POP3;
use DB_File;
$host = shift or die;
$user = shift or die;
$pass = shift or die;
tie %d, 'DB_File', "/etc/pop3.users.db", O_CREAT|O_RDWR, 0640, $DB_BTREE or die;
if ($d{$user}) {
        untie %d;
        exit 0;
}
$pop = Net::POP3->new($host) or die;
if ($pop->login($user, $pass) >= 0) {
        openlog("pop3cat-tmail", 'pid', 'mail') or die;
        syslog('info', 'fetching mail for user %s', $user);
        closelog();
        $msgnums = $pop->list or die;
        foreach $msgnum (keys %$msgnums) {
                $msg = $pop->get($msgnum);
                open T, "| /usr/bin/tmail $user" or die;
                print T @$msg;
                $pop->delete($msgnum);
                close T;
        }
        $d{$user} = "OK";
        untie %d;
}
$pop->quit;
exit 0;

Where exactly in the server code you fork(2), exec(3) and wait(2) for the script depends on the source code. You need to find where in the server code the authentication procedure succeeds and patch from there, before the server actually opens the user’s mailbox.

This script basically checks whether it has already moved a user’s mailbox from the old server. If it has, then the user is found in /etc/pop3.users.db and the script exits. If not, then the mailbox is moved and the user is inserted in /etc/pop3.users.db. Simply using Net::POP3 allows you to move the old mailbox to the Unix traditional mailbox format. That is why we fork tmail, since I have chosen the mbx mailbox format to store messages (I compile UW-IMAP with CREATEPROTO=mbxproto). If your server supports a format like Maildir, then you have to customize the above script accordingly, since it is written for mbx, which means that the user’s mailbox is a single file.

Όλα όσα θα χρειαστείτε για μια άνετη και επιτυχημένη θητεία

Ένας φίλος ξεκινάει τη στρατιωτική του θητεία σε λίγες μέρες και με την ευκαιρία του δείξαμε μια λίστα με πράγματα που πρέπει να έχει μαζί του. Με την άδεια του φίλου Γιώργου που την ανέπτυξε.

Καλή θητεία Κ.

[via]

smrsh and Debian sendmail

If you run sendmail from the Debian (Etch) packages and you use FEATURE(`smrsh’) then you must put the symlinks of the commands that you want smrsh to execute under /etc/mail/smrsh and not under /usr/lib/sm.bin . The Debian manpage is not particularly helpful on this.

From sendmail’s configuration README:

smrsh		Use the SendMail Restricted SHell (smrsh) provided
		with the distribution instead of /bin/sh for mailing
		to programs.  This improves the ability of the local
		system administrator to control what gets run via
		e-mail.  If an argument is provided it is used as the
		pathname to smrsh; otherwise, the path defined by
		confEBINDIR is used for the smrsh binary -- by default,
		/usr/libexec/smrsh is assumed.

Μονόζυγο

Αν ο εργασιακός σας χώρος το επιτρέπει (κοινώς δεν είναι ένας αχανής χώρος χωρισμένος σε cubicles) βάλτε κάπου ένα μονόζυγο (εμείς το βάλαμε στην πόρτα της τουαλέτας).

Απομακρύνει τα νεύρα1 και ισιώνει την πλάτη .

Επόμενο project: Ένας επιτοίχιος σάκος του μποξ.

(In-Reply-To:)

[1] Είχα πάρει από το Jumbo και ένα πιστολάκι με βεντούζες, αλλά δεν έφερε τα προσδοκώμενα αποτελέσματα.