File Coverage

blib/lib/Net/LDAP/Server.pm
Criterion Covered Total %
statement 24 85 28.2
branch 0 24 0.0
condition 0 6 0.0
subroutine 8 12 66.6
pod 2 2 100.0
total 34 129 26.3


line stmt bran cond sub pod time code
1             # ===========================================================================
2             # Net::LDAP::Server
3             #
4             # LDAP server side protocol handling
5             #
6             # Alessandro Ranellucci
7             # Hans Klunder
8             # Copyright (c) 2005-2007.
9             #
10             # See below for documentation.
11             #
12             package Net::LDAP::Server;
13 1     1   15294 use strict;
  1         2  
  1         37  
14 1     1   5 use warnings;
  1         2  
  1         30  
15              
16 1     1   2111 use Convert::ASN1 qw(asn_read);
  1         50365  
  1         103  
17 1     1   1357 use Net::LDAP::ASN qw(LDAPRequest LDAPResponse);
  1         75690  
  1         13  
18 1     1   1312 use Net::LDAP::Constant qw(LDAP_OPERATIONS_ERROR LDAP_UNWILLING_TO_PERFORM);
  1         7254  
  1         250  
19 1     1   1015 use Net::LDAP::Entry;
  1         2900  
  1         38  
20 1     1   1552 use Data::Dumper;
  1         11647  
  1         124  
21              
22             our $VERSION = '0.43';
23 1     1   1574304 use fields qw(in out);
  1         8975  
  1         9  
24              
25             our %respTypes=(
26             'bindRequest' => 'bindResponse',
27             'unbindRequest' => '',
28             'searchRequest' => 'searchResDone',
29             'modifyRequest' => 'modifyResponse',
30             'addRequest' => 'addResponse',
31             'delRequest' => 'delResponse',
32             'modDNRequest' => 'modDNResponse',
33             'compareRequest' => 'compareResponse',
34             'extendedReq' => 'extendedResp',
35             'abandonRequest' => ''
36             );
37             our %functions=(
38             'bindRequest' => 'bind',
39             'unbindRequest' => 'unbind',
40             'searchRequest' => 'search',
41             'modifyRequest' => 'modify',
42             'addRequest' => 'add',
43             'delRequest' => 'delete',
44             'modDNRequest' => 'modifyDN',
45             'compareRequest' => 'compare',
46             'extendedReq' => 'extended',
47             'abandonRequest' => 'abandon'
48             );
49             our @reqTypes = keys %respTypes;
50              
51             sub new {
52 0     0 1   my ($proto, $input, $output) = @_;
53 0   0       my $class = ref($proto) || $proto;
54 0           my $self = fields::new($class);
55              
56             #print STDERR Dumper($input);
57             #print STDERR Dumper($output);
58              
59 0           $self->{in} = $input;
60 0   0       $self->{out} = $output || $input;
61 0           return $self;
62             }
63              
64             sub handle {
65 0     0 1   my Net::LDAP::Server $self = shift;
66 0           my $in = $self->{in};
67 0           my $out = $self->{out};
68            
69             #print STDERR Dumper($in);
70             #print STDERR Dumper($out);
71              
72 0           asn_read($in, my $pdu);
73             #print '-' x 80,"\n";
74             #print "Received:\n";
75             #Convert::ASN1::asn_dump(\*STDOUT,$pdu);
76 0           my $request = $LDAPRequest->decode($pdu);
77 0 0         my $mid = $request->{'messageID'}
78             or return 1;
79              
80             #print "messageID: $mid\n";
81             #print Dumper($request);
82            
83 0           my $reqType;
84 0           foreach my $type (@reqTypes) {
85 0 0         if (defined $request->{$type}) {
86 0           $reqType = $type;
87 0           last;
88             }
89             }
90 0 0         return 1 if !exists $respTypes{$reqType}; # unknown request type: let's hangup
91 0           my $respType = $respTypes{$reqType};
92            
93             # here we can do something with the request of type $reqType
94 0           my $reqData = $request->{$reqType};
95 0           my $method = $functions{$reqType};
96 0           my $result;
97 0 0         if ($self->can($method)){
98 0 0         if ($method eq 'search') {
99 0           my @entries;
100 0           eval { ($result,@entries) = $self->search($reqData, $request) };
  0            
101            
102 0           foreach my $entry (@entries) {
103 0           my $data;
104             # default is to return a searchResEntry
105 0           my $sResType = 'searchResEntry';
106 0 0         if (ref $entry eq 'Net::LDAP::Entry') {
    0          
107 0           $data = $entry->{'asn'};
108             } elsif (ref $entry eq 'Net::LDAP::Reference') {
109 0           $data = $entry->{'asn'};
110 0           $sResType = 'searchResRef';
111             } else{
112 0           $data = $entry;
113             }
114            
115 0           my $response;
116             # is the full message specified?
117 0 0         if (defined $data->{'protocolOp'}) {
118 0           $response = $data;
119 0           $response->{'messageID'} = $mid;
120             } else {
121 0           $response = {
122             'messageID' => $mid,
123             'protocolOp' => {
124             $sResType => $data
125             }
126             };
127             }
128 0           my $pdu = $LDAPResponse->encode($response);
129 0 0         if ($pdu) {
130 0           print $out $pdu;
131             } else {
132 0           $result = undef;
133 0           last;
134             }
135             }
136             } else {
137 0           eval { $result = $self->$method($reqData, $request) };
  0            
138             }
139 0 0         $result = _operations_error() unless $result;
140             } else {
141 0           $result = {
142             'matchedDN' => '',
143             'errorMessage' => sprintf("%s operation is not supported by %s", $method, ref $self),
144             'resultCode' => LDAP_UNWILLING_TO_PERFORM
145             };
146             }
147            
148             # and now send the result to the client
149 0 0         print $out &_encode_result($mid, $respType, $result) if $respType;
150            
151 0           return 0;
152             }
153              
154             sub _encode_result {
155 0     0     my ($mid, $respType, $result) = @_;
156            
157 0           my $response = {
158             'messageID' => $mid,
159             'protocolOp' => {
160             $respType => $result
161             }
162             };
163 0           my $pdu = $LDAPResponse->encode($response);
164            
165             # if response encoding failed return the error
166 0 0         if (!$pdu) {
167 0           $response->{'protocolOp'}->{$respType} = _operations_error();
168 0           $pdu = $LDAPResponse->encode($response);
169             };
170            
171 0           return $pdu;
172             }
173              
174             sub _operations_error {
175 0     0     my $err = $@;
176 0           $err =~ s/ at .+$//;
177             return {
178 0           'matchedDN' => '',
179             'errorMessage' => $err,
180             'resultCode' => LDAP_OPERATIONS_ERROR
181             };
182             }
183              
184             1;
185              
186             __END__