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