gunnar: server/perl-kolab/lib/Kolab/LDAP/Backend ad.pm, NONE, 1.1 slurpd.pm, NONE, 1.1

cvs at kolab.org cvs at kolab.org
Wed Aug 1 16:57:44 CEST 2007


Author: gunnar

Update of /kolabrepository/server/perl-kolab/lib/Kolab/LDAP/Backend
In directory doto:/tmp/cvs-serv20643/lib/Kolab/LDAP/Backend

Added Files:
	ad.pm slurpd.pm 
Log Message:
Converted the perl-kolab package into a standard perl library.

--- NEW FILE: ad.pm ---
package Kolab::LDAP::Backend::ad;

##  COPYRIGHT
##  ---------
##
##  See AUTHORS file
##
##
##  LICENSE
##  -------
##
##  This  program is free  software; you can redistribute  it and/or
##  modify it  under the terms of the GNU  General Public License as
##  published by the  Free Software Foundation; either version 2, or
##  (at your option) any later version.
##
##  This program is  distributed in the hope that it will be useful,
##  but WITHOUT  ANY WARRANTY; without even the  implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
##  General Public License for more details.
##
##  You can view the  GNU General Public License, online, at the GNU
##  Project's homepage; see <http://www.gnu.org/licenses/gpl.html>.
##
##  $Revision: 1.1 $

use 5.008;
use strict;
use warnings;
use Kolab;
use Kolab::Util;
use Kolab::LDAP;
use Net::LDAP;
use Net::LDAP::Control;
use vars qw($ldap $cyrus);

require Exporter;

our @ISA = qw(Exporter);

our %EXPORT_TAGS = (
    'all' => [ qw(
    &startup
    &run
    ) ]
);

our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

our @EXPORT = qw(
    
);

our $VERSION = '0.9';

sub startup { 1; }

sub shutdown
{
    Kolab::log('AD', 'Shutting down');
    exit(0);
}

sub abort
{
    Kolab::log('AD', 'Aborting');
    exit(1);
}

sub changeCallback
{
    Kolab::log('AD', 'Change notification received', KOLAB_DEBUG);

    ###   $_[0]   isa     Net::LDAP::Message
    ###   $_[1]   shouldbea   Net::LDAP::Entry

    my $mesg = shift || 0;
    my $entry = shift || 0;

    my $issearch = $mesg->isa("Net::LDAP::Search");

    if (!$issearch) {
    Kolab::log('AD', 'mesg is not a search object, testing code...', KOLAB_DEBUG);
    if ($mesg->code == 88) {
        Kolab::log('AD', 'changeCallback() -> Exit code received, returning', KOLAB_DEBUG);
        return;
    } elsif ($mesg->code) {
        Kolab::log('AD', "mesg->code = `" . $mesg->code . "', mesg->msg = `" . $mesg->error . "'", KOLAB_DEBUG);
        &abort;
    }   
    } else {
    Kolab::log('AD', 'mesg is a search object, not testing code', KOLAB_DEBUG);
    }

    if (!$entry) {
    Kolab::log('AD', 'changeCallback() called with a null entry', KOLAB_DEBUG);
    return;
    } elsif (!$entry->isa("Net::LDAP::Entry")) {
    Kolab::log('AD', 'changeCallback() called with an invalid entry', KOLAB_DEBUG);
    return;
    }

    if (!Kolab::LDAP::isObject($entry, $Kolab::config{'user_object_class'})) {
    Kolab::log('AD', "Entry is not a `" . $Kolab::config{'user_object_class'} . "', returning", KOLAB_DEBUG);
    return;
    }

    my $deleted = $entry->get_value($Kolab::config{'user_field_deleted'}) || 0;
    if ($deleted) {
    Kolab::LDAP::deleteObject($ldap, $cyrus, $entry);
    return;
    }

    Kolab::LDAP::createObject($ldap, $cyrus, $entry);
}

sub run
{
    # This should be called from a separate thread, as we set our
    # own interrupt handlers here

    $SIG{'INT'} = \&shutdown;
    $SIG{'TERM'} = \&shutdown;

    END {
    alarm 0;
    Kolab::LDAP::destroy($ldap);
    }

    my $mesg;

    Kolab::log('AD', 'Listener starting up');

    $cyrus = Kolab::Cyrus::create;

    Kolab::log('AD', 'Cyrus connection established', KOLAB_DEBUG);

    while (1) {
    Kolab::log('AD', 'Creating LDAP connection to AD server', KOLAB_DEBUG);

    $ldap = Kolab::LDAP::create(
        $Kolab::config{'user_ldap_ip'},
        $Kolab::config{'user_ldap_port'},
        $Kolab::config{'user_bind_dn'},
        $Kolab::config{'user_bind_pw'},
        1
    );

    if (!$ldap) {
        Kolab::log('AD', 'Sleeping 5 seconds...');
        sleep 5;
        next;
    }

    Kolab::log('AD', 'LDAP connection established', KOLAB_DEBUG);

    Kolab::LDAP::ensureAsync($ldap);

    Kolab::log('AD', 'Async checked', KOLAB_DEBUG);

    my $ctrl = Net::LDAP::Control->new(
        type    => '1.2.840.113556.1.4.528',
        critical    => 'true'
    );

    Kolab::log('AD', 'Control created', KOLAB_DEBUG);

    my @userdns = split(/;/, $Kolab::config{'user_dn_list'});
    my $userdn;

    Kolab::log('AD', 'User DN list = ' . $Kolab::config{'user_dn_list'}, KOLAB_DEBUG);

    if (length(@userdns) == 0) {
    Kolab::log('AD', 'No user DNs specified, exiting', KOLAB_ERROR);
    exit(1);
    }

    foreach $userdn (@userdns) {
        Kolab::log('AD', "Registering change notification on DN `$userdn'");

        $mesg = $ldap->search (
        base    => $userdn,
        scope       => 'one',
        control     => [ $ctrl ],
        callback    => \&changeCallback,
        filter      => '(objectClass=*)',
        attrs   => [
            '*',
            $Kolab::config{'user_field_guid'},
            $Kolab::config{'user_field_modified'},
            $Kolab::config{'user_field_quota'},
            $Kolab::config{'user_field_deleted'},
        ],
        );

        Kolab::log('AD', "Change notification registered on `$userdn'");
    }

    eval {
        local $SIG{ALRM} = sub {
        alarm 0;
        Kolab::log('AD', 'Connection refresh period expired; tearing down connection');

        Kolab::LDAP::destroy($ldap);
        next;
        };

        Kolab::log('AD', 'Waiting for changes (refresh period = ' . $Kolab::config{'conn_refresh_period'} . ' minutes)...');
        alarm $Kolab::config{'conn_refresh_period'} * 60;
        $mesg->sync;
        alarm 0;
    };
    }

    1;
}

1;
__END__
# Below is stub documentation for your module. You'd better edit it!

=head1 NAME

Kolab::LDAP::Backend::ad - Perl extension for an Active Directory backend

=head1 ABSTRACT

  Kolab::LDAP::Backend::ad handles an Active Directory backend to the
  kolab daemon.

=head1 COPYRIGHT AND AUTHORS

Stuart Bingë and others (see AUTHORS file)

=head1 LICENSE

This  program is free  software; you can redistribute  it and/or
modify it  under the terms of the GNU  General Public License as
published by the  Free Software Foundation; either version 2, or
(at your option) any later version.

This program is  distributed in the hope that it will be useful,
but WITHOUT  ANY WARRANTY; without even the  implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You can view the  GNU General Public License, online, at the GNU
Project's homepage; see <http://www.gnu.org/licenses/gpl.html>.

=cut

--- NEW FILE: slurpd.pm ---
package Kolab::LDAP::Backend::slurpd;

##  COPYRIGHT
##  ---------
##
##  See AUTHORS file
##
##
##  LICENSE
##  -------
##
##  This  program is free  software; you can redistribute  it and/or
##  modify it  under the terms of the GNU  General Public License as
##  published by the  Free Software Foundation; either version 2, or
##  (at your option) any later version.
##
##  This program is  distributed in the hope that it will be useful,
##  but WITHOUT  ANY WARRANTY; without even the  implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
##  General Public License for more details.
##
##  You can view the  GNU General Public License, online, at the GNU
##  Project's homepage; see <http://www.gnu.org/licenses/gpl.html>.
##
##  $Revision: 1.1 $

use 5.008;
use strict;
use warnings;
use IO::Select;
use IO::Socket::INET;
use Convert::ASN1 qw(:io);
use Net::LDAP;
use Net::LDAP::Constant qw(LDAP_SUCCESS LDAP_PROTOCOL_ERROR);
use Net::LDAP::ASN qw(LDAPRequest LDAPResponse LDAPResult);
use Kolab;
use Kolab::Util;
use Kolab::LDAP;
use vars qw($conn $server);

require Exporter;

our @ISA = qw(Exporter);

our %EXPORT_TAGS = (
    'all' => [ qw(
        &startup
        &run
    ) ]
);

our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

our @EXPORT = qw(
    
);

our $VERSION = '0.9';

sub startup { 1; }

sub shutdown
{
    Kolab::log('SD', 'Shutting down');
    exit(0);
}

sub abort
{
    Kolab::log('SD', 'Aborting');
    exit(1);
}

sub PROTOCOLOP_BINDREQUEST      () { 0x00 }
sub PROTOCOLOP_BINDRESPONSE     () { 0x01 }
sub PROTOCOLOP_UNBINDREQUEST    () { 0x02 }
sub PROTOCOLOP_SEARCHREQUEST    () { 0x03 }
sub PROTOCOLOP_SEARCHRESENTRY   () { 0x04 }
sub PROTOCOLOP_SEARCHRESDONE    () { 0x05 }
sub PROTOCOLOP_SEARCHRESREF     () { 0x06 }
sub PROTOCOLOP_MODIFYREQUEST    () { 0x07 }
sub PROTOCOLOP_MODIFYRESPONSE   () { 0x08 }
sub PROTOCOLOP_ADDREQUEST       () { 0x09 }
sub PROTOCOLOP_ADDRESPONSE      () { 0x10 }
sub PROTOCOLOP_DELREQUEST       () { 0x11 }
sub PROTOCOLOP_DELRESPONSE      () { 0x12 }
sub PROTOCOLOP_MODDNREQUEST     () { 0x13 }
sub PROTOCOLOP_MODDNRESPONSE    () { 0x14 }
sub PROTOCOLOP_COMPAREREQUEST   () { 0x15 }
sub PROTOCOLOP_COMPARERESPONSE  () { 0x16 }
sub PROTOCOLOP_ABANDONREQUEST   () { 0x17 }
sub PROTOCOLOP_EXTENDEDREQ      () { 0x18 }
sub PROTOCOLOP_EXTENDEDRESP     () { 0x19 }

sub getRequestType
{
    my $op = shift;
    if ($op->{bindRequest})     { return "bindRequest"; }
    if ($op->{unbindRequest})   { return "unbindRequest"; }
    if ($op->{addRequest})      { return "addRequest"; }
    if ($op->{delRequest})      { return "delRequest"; }
    if ($op->{modifyRequest})   { return "modifyRequest"; }
    if ($op->{modDNRequest})    { return "modDNRequest"; }
    if ($op->{searchRequest})   { return "searchRequest"; }
    if ($op->{compareRequest})  { return "compareRequest"; }
    if ($op->{abandonRequest})  { return "abandonRequest"; }
    if ($op->{extendedRequest}) { return "extendedRequest"; }
    return "";
}

sub responseBind
{
    my $req = shift;
    my $pdu = $LDAPResponse->encode(
        messageID       => $req->{messageID},
        protocolOp      => {
            choiceID        => PROTOCOLOP_BINDRESPONSE,
            bindResponse    => {
                resultCode      => LDAP_SUCCESS,
                matchedDN       => $req->{bindRequest}{name},
                errorMessage    => "",
                serverSaslCreds => ""
            }
        }
    );
    if (!$pdu) {
        Kolab::log('SD', "LDAPResponse error `" .  $LDAPResponse->error . "'");
        &abort;
    }
    return $pdu;
}

sub responseAdd
{
    my $req = shift;
    my $pdu = $LDAPResponse->encode(
        messageID       => $req->{messageID},
        protocolOp      => {
            choiceID        => PROTOCOLOP_ADDRESPONSE,
            addResponse     => {
                resultCode      => LDAP_SUCCESS,
                matchedDN       => $req->{addRequest}{objectName},
                errorMessage    => ""
            }
        }
    );
    if (!$pdu) {
        Kolab::log('SD', "LDAPResponse error `" .  $LDAPResponse->error . "'");
        &abort;
    }
    return $pdu;
}

sub responseDel
{
    my $req = shift;
    my $pdu = $LDAPResponse->encode(
        messageID       => $req->{messageID},
        protocolOp      => {
            choiceID        => PROTOCOLOP_DELRESPONSE,
            addResponse     => {
                resultCode      => LDAP_SUCCESS,
                matchedDN       => $req->{delRequest},
                errorMessage    => ""
            }
        }
    );
    if (!$pdu) {
        Kolab::log('SD', "LDAPResponse error `" .  $LDAPResponse->error . "'");
        &abort;
    }
    return $pdu;
}

sub responseMod
{
    my $req = shift;
    my $pdu = $LDAPResponse->encode(
        messageID       => $req->{messageID},
        protocolOp      => {
            choiceID        => PROTOCOLOP_MODIFYRESPONSE,
            addResponse     => {
                resultCode      => LDAP_SUCCESS,
                matchedDN       => $req->{modifyRequest}{object},
                errorMessage    => ""
            }
        }
    );
    if (!$pdu) {
        Kolab::log('SD', "LDAPResponse error `" .  $LDAPResponse->error . "'");
        &abort;
    }
    return $pdu;
}

sub responseModDN
{
    my $req = shift;
    my $pdu = $LDAPResponse->encode(
        messageID       => $req->{messageID},
        protocolOp      => {
            choiceID        => PROTOCOLOP_MODDNRESPONSE,
            addResponse     => {
                resultCode      => LDAP_SUCCESS,
                matchedDN       => $req->{modDNRequest}{entry},
                errorMessage    => ""
            }
        }
    );
    if (!$pdu) {
        Kolab::log('SD', "LDAPResponse error `" .  $LDAPResponse->error . "'");
        &abort;
    }
    return $pdu;
}

sub run
{
    # This should be called from a separate thread, as we set our
    # own interrupt handlers here

    $SIG{'INT'} = \&shutdown;
    $SIG{'TERM'} = \&shutdown;

    END {
        if ($conn) { $conn->close; }
        if ($server) { $server->close; }
    }

    my $request;
    my $response;
    my $pdu;
    my $changes = 0;

    my $listenport = $Kolab::config{'slurpd_port'};
    my $listenaddr = $Kolab::config{'slurpd_addr'} || "127.0.0.1";
  TRYCONNECT:
    Kolab::log('SD', "Opening listen server on $listenaddr:$listenport");
    $server = IO::Socket::INET->new(
	LocalPort   => $listenport,
	Proto       => "tcp",
	ReuseAddr   => 1,
	Type        => SOCK_STREAM,
	LocalAddr   => $listenaddr,
	Listen      => 10
     );
    if (!$server) {
        Kolab::log('SD', "Unable to open TCP listen server on $listenaddr:$listenport, Error = $@", KOLAB_ERROR);
	sleep 1;
	goto TRYCONNECT;
    }

    Kolab::log('SD', 'Listen server opened, waiting for incoming connections');

    while ($conn = $server->accept()) {
      # PENDING: Only accept connections from localhost and
      # hosts listed in the kolabhost attribute

	my($peerport, $peeraddr) = sockaddr_in($conn->peername);
	$peeraddr = inet_ntoa( $peeraddr );
        Kolab::log('SD', "Incoming connection accepted, peer=$peeraddr");
	if( $Kolab::config{'slurpd_accept_addr'} && $peeraddr ne $Kolab::config{'slurpd_accept_addr'} ) {
	    Kolab::log('SD', "Unauthorized connection from $peeraddr, closing connection", KOLAB_WARN);
	    $conn->close;
	    undef $conn;
	    next;
	}

        my $select = IO::Select->new($conn);

        while ($conn) {
            undef $pdu;
            my $ready;
            my $offset = 0;

            if (!($select->can_read(0)) && $changes) {
	        Kolab::log('SD', 'Change detected w/ no pending LDAP messages; waiting a second...');
		if( !($select->can_read(1)) ) {
		  $changes = 0;
		  Kolab::log('SD', 'Change detected w/ no pending LDAP messages; reloading services if needed');
		  Kolab::LDAP::sync;
		  Kolab::log('SD', "Running $Kolab::config{'kolabconf_script'}");
		  system($Kolab::config{'kolabconf_script'}) == 0
		    or Kolab::log('SD', "Failed to run $Kolab::config{'kolabconf_script'}: $?", KOLAB_ERROR);
		  Kolab::log('SD', "$Kolab::config{'kolabconf_script'} complete");
		}
            }

            Kolab::log('SD', 'Waiting for LDAP updates');

            for ($ready = 1; $conn && $ready; $ready = $select->can_read(0)) {
                Kolab::log('SD', 'Reading ASN', KOLAB_DEBUG);
                my $newoffset = asn_read($conn, $pdu, $offset);
		if( !$conn->connected() or $offset == $newoffset ) {
		  Kolab::log('SD', 'Connection closed', KOLAB_DEBUG);
		  $conn->close;
		  undef $conn;
		}
		$offset = $newoffset;
                defined($offset) or $offset = 0;
            }

            if ($pdu) {
                $request = $LDAPRequest->decode($pdu);
                if (!$request) {
                    Kolab::log('SD', "Unable to decode slurpd request, Error = `" . $LDAPRequest->error . "'", KOLAB_ERROR);
		    $conn->close if $conn;
		    undef $conn;
		    undef $pdu;
                } else {
		    $_ = getRequestType($request);
		    Kolab::log('SD', "Request $_ received", KOLAB_DEBUG);
		    undef $pdu;

		    SWITCH: {
		      if (/^bindRequest/) { $pdu = responseBind($request); last SWITCH; }
                      if (/addRequest/) { $pdu = responseAdd($request); $changes = 1; last SWITCH; }
                      if (/delRequest/) { $pdu = responseDel($request); $changes = 1; last SWITCH; }
                      if (/modifyRequest/) { $pdu = responseMod($request); $changes = 1; last SWITCH; }
                      if (/modDNRequest/) { $pdu = responseModDN($request); $changes = 1; last SWITCH; }

                      if( $conn ) {
		        Kolab::log('SD', 'Unknown request, connection closed', KOLAB_DEBUG);
		        $conn->close;
		        undef $conn;
		      }
		    }
		}
	    }

            if ($pdu) {
                Kolab::log('SD', 'Writing response', KOLAB_DEBUG);
                syswrite($conn, $pdu, length($pdu));
                $response = $LDAPResponse->decode($pdu);
                if (!$response) {
                    Kolab::log('SD', "Unable to decode slurpd request, Error = `" . $LDAPRequest->error . "'");
		    $conn->close;
		    undef $conn;
                }
            }
        }
    }

    $server->close;

    1;
}

1;
__END__
# Below is stub documentation for your module. You'd better edit it!

=head1 NAME

Kolab::LDAP::Backend::slurpd - Perl extension for a slurpd backend

=head1 ABSTRACT

  Kolab::LDAP::Backend::slurpd handles a slurpd backend to the
  kolab daemon.

=head1 COPYRIGHT AND AUTHORS

Stuart Bingë and others (see AUTHORS file)

=head1 LICENSE

This  program is free  software; you can redistribute  it and/or
modify it  under the terms of the GNU  General Public License as
published by the  Free Software Foundation; either version 2, or
(at your option) any later version.

This program is  distributed in the hope that it will be useful,
but WITHOUT  ANY WARRANTY; without even the  implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You can view the  GNU General Public License, online, at the GNU
Project's homepage; see <http://www.gnu.org/licenses/gpl.html>.

=cut





More information about the commits mailing list