11 |
); |
); |
12 |
use Net::LDAP::Server; |
use Net::LDAP::Server; |
13 |
use Net::LDAP::Filter; |
use Net::LDAP::Filter; |
14 |
use base 'Net::LDAP::Server'; |
use base qw(Net::LDAP::Server); |
15 |
use fields qw(upstream); |
use fields qw(upstream); |
16 |
|
|
17 |
use A3C::LDAP; |
use A3C::LDAP; |
18 |
|
use A3C::Cache; |
19 |
|
|
20 |
|
#use A3C::Cache; |
21 |
|
use URI::Escape; # uri_escape |
22 |
|
|
23 |
use Data::Dump qw/dump/; |
use Data::Dump qw/dump/; |
24 |
|
|
25 |
=head1 NAME |
=head1 NAME |
32 |
|
|
33 |
Provide LDAP server functionality for L<A3C> somewhat similar to C<slapo-rwm> |
Provide LDAP server functionality for L<A3C> somewhat similar to C<slapo-rwm> |
34 |
|
|
35 |
|
=head1 METHODS |
36 |
|
|
37 |
|
=head2 run |
38 |
|
|
39 |
|
my $pid = A3C::LDAP::Server->run({ port => 1389, fork => 0 }); |
40 |
|
|
41 |
=cut |
=cut |
42 |
|
|
43 |
|
our $pids; |
44 |
|
our $cache; |
45 |
|
|
46 |
|
sub cache { |
47 |
|
return $cache if $cache; |
48 |
|
$cache = new A3C::Cache->new({ instance => '', dir => 'ldap' }); |
49 |
|
} |
50 |
|
|
51 |
|
sub run { |
52 |
|
my $self = shift; |
53 |
|
|
54 |
|
my $args = shift; |
55 |
|
# default LDAP port |
56 |
|
my $port = $args->{port} ||= 1389; |
57 |
|
|
58 |
|
if ( $args->{fork} ) { |
59 |
|
defined(my $pid = fork()) or die "Can't fork: $!"; |
60 |
|
if ( $pid ) { |
61 |
|
$pids->{ $port } = $pid; |
62 |
|
warn "# pids = ",dump( $pids ); |
63 |
|
sleep 1; |
64 |
|
return $pid; |
65 |
|
} |
66 |
|
} |
67 |
|
|
68 |
|
my $sock = IO::Socket::INET->new( |
69 |
|
Listen => 5, |
70 |
|
Proto => 'tcp', |
71 |
|
Reuse => 1, |
72 |
|
LocalPort => $port, |
73 |
|
) or die "can't listen on port $port: $!\n"; |
74 |
|
|
75 |
|
warn "LDAP server listening on port $port\n"; |
76 |
|
|
77 |
|
my $sel = IO::Select->new($sock) or die "can't select socket: $!\n"; |
78 |
|
my %Handlers; |
79 |
|
while (my @ready = $sel->can_read) { |
80 |
|
foreach my $fh (@ready) { |
81 |
|
if ($fh == $sock) { |
82 |
|
# let's create a new socket |
83 |
|
my $psock = $sock->accept; |
84 |
|
$sel->add($psock); |
85 |
|
$Handlers{*$psock} = A3C::LDAP::Server->new($psock); |
86 |
|
} else { |
87 |
|
my $result = $Handlers{*$fh}->handle; |
88 |
|
if ($result) { |
89 |
|
# we have finished with the socket |
90 |
|
$sel->remove($fh); |
91 |
|
$fh->close; |
92 |
|
delete $Handlers{*$fh}; |
93 |
|
} |
94 |
|
} |
95 |
|
} |
96 |
|
} |
97 |
|
} |
98 |
|
|
99 |
|
=head2 stop |
100 |
|
|
101 |
|
my $stopped_pids = A3C::LDAP::Server->stop; |
102 |
|
|
103 |
|
=cut |
104 |
|
|
105 |
|
sub stop { |
106 |
|
warn "## stop pids = ",dump( $pids ); |
107 |
|
return unless $pids; |
108 |
|
my $stopped = 0; |
109 |
|
foreach my $port ( keys %$pids ) { |
110 |
|
my $pid = delete($pids->{$port}) or die "no pid?"; |
111 |
|
warn "# Shutdown LDAP server at port $port pid $pid\n"; |
112 |
|
kill(9,$pid) or die "can't kill $pid: $!"; |
113 |
|
waitpid($pid,0) or die "waitpid $pid: $!"; |
114 |
|
$stopped++; |
115 |
|
} |
116 |
|
warn "## stopped $stopped processes\n"; |
117 |
|
return $stopped; |
118 |
|
} |
119 |
|
|
120 |
use constant RESULT_OK => { |
use constant RESULT_OK => { |
121 |
'matchedDN' => '', |
'matchedDN' => '', |
122 |
'errorMessage' => '', |
'errorMessage' => '', |
163 |
password => $req->{authentication}->{simple} |
password => $req->{authentication}->{simple} |
164 |
); |
); |
165 |
|
|
166 |
warn "# bind msg = ",dump( $msg ); |
#warn "# bind msg = ",dump( $msg ); |
167 |
if ( $msg->code != LDAP_SUCCESS ) { |
if ( $msg->code != LDAP_SUCCESS ) { |
168 |
warn "ERROR: ", $msg->code, ": ", $msg->server_error, "\n"; |
warn "ERROR: ", $msg->code, ": ", $msg->server_error, "\n"; |
169 |
return { |
return { |
239 |
} |
} |
240 |
|
|
241 |
warn "## entries = ",dump( @entries ); |
warn "## entries = ",dump( @entries ); |
242 |
|
|
243 |
|
$self->cache->write_cache( \@entries, uri_escape( $filter )); |
244 |
|
|
245 |
return RESULT_OK, @entries; |
return RESULT_OK, @entries; |
246 |
} |
} |
247 |
|
|