Ignacio de Cordoba <[EMAIL PROTECTED]> writes:
> 
> Anybody has any ideas on how to modify qmail-getpw and make it check
> users on a different way other than /etc/passwd ? (PostgreSQL)

It is easy to write a checkpassword replacement that does
whatever authentification you can imagine. We also have
our customer data in a PostgreSQL database, but we deliberately
chose not to checkpassword() directly against the SQL database
because if you do that then the database server becomes a
potential single point of failure (PostgreSQL machine goes
down -> Users can't get mail via POP3 -> Hotline jumps
straight into panic! mode -> you lose)
Because of that we generate a per-customer-domain CDB
database from the data that is stored in the SQL database
once per hour. With that scheme even if the PostgreSQL server
goes down existing users still can get at their mail (you
just can't update/add users for as long as the SQL server
is down, but that's more acceptable).

Attached below is our checkpassword replacement that works
like explained above. It expects to find a passwd.cdb for
each customer domain in /MailSpool/$customer_domain/
and clients need to use username%domain as their POP3
login id.



#!/usr/bin/perl -wT

#
# $Id$
#

use strict;


sub read_parms {
    my $buf = 512 x 0;
    local *INP;
    open(INP, "<&=3") || die "can't open fd 3: $!\n";
    sysread(INP,$buf,512) || die "sysread failed: $!\n";
    close(INP);
    $buf =~ /([^\0]+)\0([^\0]+)\0([^\0]+)\0/;
}


sub checkpass {
    my($u,$p,$s) = @_;
    if (defined($u) && defined($p) && defined($s)) {
        if ($u =~ /(\S+)[@%](\S+)/) {
            my($usr,$dom) = ($1,$2);
            chdir "/MailSpool/$dom" || exit 111;
            if (-d $usr && -d "$usr/Maildir" && -f 'passwd.cdb') {
                use CDB_File;

                my %db;
                tie %db, 'CDB_File', 'passwd.cdb' || exit 111;
                my $dbpass = $db{$usr};
                untie(%db);

                # prepare environment in case we succeed below
                $ENV{'PATH'} = '/admin/qmail/bin:/bin:/usr/bin';
                $ENV{'HOME'} = "/MailSpool/$dom/$usr";
                $ENV{'USER'} = $usr;
                $ENV{'SHELL'} = '/bin/true';

                my $ok;
                $ok = defined($dbpass) && $dbpass eq $p && chdir($usr);
                use IO::File;
                my $logf = new IO::File ">&5";
                if (defined($logf)) {
                        $logf->print(!$ok ? "FAILED: " : "", "User='$u' Pass='$p' 
Stamp='$s'\n");
                        $logf->close;
                }
                return $ok;
            }
        }
    }
    return 0;
}

exec @ARGV if checkpass(read_parms());
exit 111;

Reply via email to