#!/usr/bin/perl -w
# $Id: authProg.pl,v 1.5 2007/08/03 13:57:02 cbellot Exp $
#
# Module d'authentification externe pour courier-authdaemon
# en mode authpipe
#
# http://www.courier-mta.org/authlib/README_authlib.html
#

use Home;
use MIME::Base64;
use Digest::MD5 qw(md5 md5_hex);
use Digest::SHA1 qw(sha1 sha1_hex);

my %userinfo;

# Retrieve data via libhome
sub getuserinfo($$) {
    my $service = shift;
    my $user = shift;
    # Look up data for this account
    &Home::setpwtag($service);
    my ($name,$passwd,$uid,$gid, $quota,$comment,$gcos,$dir,$shell, $expire) = 
	&Home::getpwnam($user);
    %userinfo = (
	name	=> $name,
	passwd	=> $passwd,
	uid	=> $uid,
	gid	=> $gid,
	quota	=> $quota,
	dir	=> $dir );
}

sub printuserinfo() {
    # Return retrieved data
    if (!defined($userinfo{'name'}) || $userinfo{'name'} eq "") {
	print "FAIL\n";
	return;
    }
    #print "NAME=$userinfo{'name'}\n";
    #print "USERNAME=$userinfo{'name'}\n";
    print "ADDRESS=$userinfo{'name'}\n";
    print "PASSWD2=$userinfo{'passwd'}\n";
    print "UID=$userinfo{'uid'}\n";
    print "GID=$userinfo{'gid'}\n";
    print "HOME=$userinfo{'dir'}\n";
    #print "MAILDIR=$userinfo{'dir'}/Maildir\n";
    print "QUOTA=$userinfo{'quota'}S\n";
    print "OPTIONS=\n";
    print ".\n";
}


# MAIN

$|=1;

print STDERR "libhome compatible authProg module starting\n";

while (<>)
{
    if (/^PRE (\S+) (\S+) (.*)$/) {
	# Request type PRE
	# $1=. $2=service $3=uid
	&getuserinfo($2, $3);
	&printuserinfo();
    }
    elsif (/^AUTH (\d+)$/ && read(STDIN,$buf,$1) == $1) { 
	# Request type AUTH

	# AUTH method LOGIN
	if ($buf =~ /^(.*)\n(login)\n(.*)\n(.*)$/) {
	    # $1=service, $2=login, $3=user, $4=password
	    &getuserinfo($1,$3);
	    if ($userinfo{'passwd'} ne $4) {
		print "FAIL\n";
		next;
	    }
	    &printuserinfo();
	    next; 
	}
	# AUTH method CRAM-MD5
	if ($buf =~ /^(.*)\n(cram-md5)\n(.*)\n(.*)$/) {
	    # $1=service, $2=cram-md5, $3=challenge, $4=response
	    my $authservice = $1;
	    my $challenge = decode_base64($3);
	    my $response = decode_base64($4);
	    $response =~ /(.*) (.*)/;
	    my $username = $1;
	    my $digest = $2;
	    &getuserinfo($authservice,$username);
	    my $digest2 = md5_hex(($userinfo{'passwd'} ^ "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\").md5(($userinfo{'passwd'} ^ "6666666666666666666666666666666666666666666666666666666666666666").$challenge));
	    if ($digest ne $digest2) {
		print "FAIL\n";
		next;
	    }
	    &printuserinfo();
	    next; 
	}
	# AUTH method CRAM-SHA1
	if ($buf =~ /^(.*)\n(cram-sha1)\n(.*)\n(.*)$/) {
	    # $1=service, $2=cram-sha1, $3=challenge, $4=response
	    my $authservice = $1;
	    my $challenge = decode_base64($3);
	    my $response = decode_base64($4);
	    $response =~ /(.*) (.*)/;
	    my $username = $1;
	    my $digest = $2;
	    &getuserinfo($authservice,$username);
	    my $digest2 = sha1_hex(($userinfo{'passwd'} ^ "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\").sha1(($userinfo{'passwd'} ^ "6666666666666666666666666666666666666666666666666666666666666666").$challenge));
	    if ($digest ne $digest2) {
		print "FAIL\n";
		next;
	    }
	    &printuserinfo();
	    next; 
	}
	# AUTH method CRAM-SHA256

    }
    elsif (/^PASSWD (.*?)\t(.*?)\t(.*?)\t(.*?)$/) {
	# Request type PASSWD
	# Not implemented
	print "FAIL\n";
        next;
    }
    elsif (/^ENUMERATE$/) {
	# Request type ENUMERATE
	# Not implemented
	print ".\n";
	next;
    }
    else {
        print "FAIL\n";
    }
}
