#!/usr/bin/perl
#
# AUTHPROTOCOL: STDIN
#
use strict;
use Getopt::Std;
use lib qw(/usr/share/benno-auth-modules);
use Benno::LDAP::Config;
use Benno::LDAP;

our(%opts);
getopts('hvc:', \%opts);

my $noauth = 0;
if ($ENV{REQUEST_TYPE} eq 'metadata') {
    $noauth = 1;
}

if ($ENV{AUTHOK} &! $noauth) {
    print STDERR "[zimbra_ldapauth] Already authenticated, skip $0\n" if $ENV{DEBUG};
    exit 0;
}

print STDERR "[zimbra_ldapauth] Give <username> <password>:\n" if ! -p STDIN;

my $firstline  = <STDIN>;
my $secondline = <STDIN>;
chomp $firstline;
chomp $secondline;

my ($uid,$pass);
# AUTHPROTO: STDIN2
$uid = $firstline;
$pass = $secondline;
my ($userid,$domain) = split /\@/, $uid;
my $basedn = 'dc='.join(',dc=', split /\./, $domain);

$opts{'h'} && help_exit();
my $configfile  = $ENV{CONFIG}  || $opts{'c'} || '/etc/benno-auth-modules/ldapauth.conf';
my $verbose     = $ENV{VERBOSE} || $opts{'v'};
my $DEBUG       = $ENV{DEBUG};  # LDAP DEBUG LEVEL

if (!$pass &! $noauth) {
    print "ERROR ERR_NOPASS\n";
    print STDERR "[zimbra_ldapauth] Aufruf: $0 <username> <passwort>\n";
    exit 1;
}

print STDERR "[zimbra_ldapauth] Read config: $configfile\n" if $verbose;
my $Conf = new Benno::LDAP::Config($configfile);
$Conf->set('DEBUG',$DEBUG);
if (!$Conf->get('host')) { # early exit
    print "NOTE LDAP host not configured. Exit.\n";
    exit 0;
}

# attributes to fetch from ldap
$Conf->{attributes} = [ 'cn', 'whenCreated', 'memberOf',
                        $Conf->get_list('email'), $Conf->get_list('alias'),
                        $Conf->get('role'), $Conf->get_list('container'),
                      ];

if ($Conf->get('remove_domainsuffix')) {
    $uid =~ s/\@.+$//;
}

my $LDAP;
if ($Conf->get('usersuffix') and not $Conf->get('userfilter')) {
    # search not necessary, thus overwrite settings with current user data
    $Conf->set('basedn',$basedn);
    $Conf->set('binddn',$Conf->get('userattr').'='.$uid.','.$Conf->get('usersuffix').','.$basedn);
    $Conf->set('password',$pass);
}
if (!$Conf->get('binddn')) {
    print STDERR "[zimbra_ldapauth] Try anonymous bind to LDAP server.\n" if $verbose;
}
else {
    print STDERR 'Connect to '.$Conf->get('host').' with: '.$Conf->get('binddn')."\n" if $verbose;
}

eval {
    $LDAP = Benno::LDAP->new($Conf);
};
if ($@) {
    $@ =~ s/\R//g;
    $@ =~ s/at \/.+//g;
    print STDERR "[zimbra_ldapauth] ERROR $@";
    print "ERROR ERR_AUTH\n";
    exit;
}

my $ret;
my $UserEntry = $LDAP->get_user($uid,$Conf->get('userfilter'));
if ($UserEntry) {
    if ($noauth) {
        $ret = 'OK REQUEST_TYPE='.$ENV{REQUEST_TYPE};
    }
    else {
        my $dn = $UserEntry->dn();
        print STDERR "[zimbra_ldapauth] Bind LDAP as: $dn" if $DEBUG => 1;
        $ret = $LDAP->user_auth($dn,$pass);
    }
}
else {
    print "ERROR ERR_NOUSER\n";
    exit;
}

if ($ret !~ /^OK/) {
    print "ERROR ERR_AUTH\n";
    exit;
}
my @addresses;
foreach my $mailattr ($Conf->get_list('email')) {
    foreach my $addr ($UserEntry->get_value($mailattr)) {
        push @addresses, $addr;
    }
}
foreach my $aliasattr ($Conf->get_list('alias')) {
    foreach my $addr ($UserEntry->get_value($aliasattr)) {
        push @addresses, $addr;
    }
}
push @addresses, $Conf->get_list('addemail');

@addresses = Benno::LDAP::Config->format_addresslist(@addresses);

my $filter = Benno::LDAP::Config->get_before_created($Conf,$UserEntry);

my $role = uc $UserEntry->get_value($Conf->get('role')) || 'USER';

# overwrite role of admin user
foreach my $groupdn ($UserEntry->get_value('memberOf')) {
    if (lc($groupdn) eq lc($Conf->{admingroupdn})) {
        $role = 'ADMIN';
    }
}

# overwrite role of admin user
foreach my $adminid ($Conf->get_list('adminuser')) {
    if (lc($uid) eq lc($adminid)) {
        $role = 'ADMIN';
    }
}

if ($role eq 'ADMIN') {
    my @adminaddresses = ($Conf->get_list('adminaddress'));
    if (@adminaddresses) {
        foreach my $adminfilter (@adminaddresses) {
            next unless $adminfilter;
            push @addresses, $adminfilter;
        }
    }
    else {
        push @addresses, '*@*';
    }
    undef $filter;
}

# overwrite role of revisor user
foreach my $revisorid ($Conf->get_list('revisoruser')) {
    if (lc($uid) eq lc($revisorid)) {
        $role = 'REVISOR';
    }
}

if ($role eq 'REVISOR') {
    push @addresses, '*@*';
    undef $filter;
}

my @containers;
unless(@containers = $UserEntry->get_value($Conf->get('container'))) {
    @containers = $Conf->get_list('default_container');
}

print "ROLE $role\n";
print 'DISPLAYNAME '.$UserEntry->get_value('cn')."\n";

foreach my $address (@addresses) {
    print "MAIL $address\n";
}
foreach my $container (@containers) {
    print "ARCHIVE $container\n";
}
print "FILTER $filter\n" if $filter;
print "AUTH OK\n";


### SUBS #######################################################################
sub help_exit
{
    print "Usage: $0 [-h] [-v] [-c <configfile>]\n";
    print "\n";
    print "  -c <configfile>    Configfile (default /etc/benno-web/ldapauth.conf)\n";
    print "  -v                 Verbose output\n";
    print "  -h                 This help\n";

    exit;
}

### EOP ###
1;

