X-Git-Url: http://git.rot13.org/?p=virtual-ldap;a=blobdiff_plain;f=bin%2Fldap-rewrite.pl;h=5994286521835c86b4ddb9790f5ce42d950fa9a2;hp=4e2d55e672cae29a74cb75594fa808ceede97578;hb=f5dba74d799ed8249be1ed2bfe1d61cec9221bc2;hpb=1372374f7304912d81029a3a3b3f0a935e9b9fa0 diff --git a/bin/ldap-rewrite.pl b/bin/ldap-rewrite.pl index 4e2d55e..5994286 100755 --- a/bin/ldap-rewrite.pl +++ b/bin/ldap-rewrite.pl @@ -3,6 +3,12 @@ # This program is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. +# It's modified by Dobrica Pavlinusic to include following: +# +# * rewrite LDAP bind request cn: username@domain.com -> uid=username,dc=domain,dc=com +# * rewrite search responses: +# ** expand key:value pairs from hrEduPersonUniqueNumber into hrEduPersonUniqueNumber_key +# ** augment response with yaml/dn.yaml data (for external data import) use strict; use warnings; @@ -14,19 +20,40 @@ use warnings; use Data::Dump qw/dump/; use Convert::ASN1 qw(asn_read); use Net::LDAP::ASN qw(LDAPRequest LDAPResponse); -our $VERSION = '0.2'; +our $VERSION = '0.3'; use fields qw(socket target); use YAML qw/LoadFile/; +my $debug = 0; + my $config = { yaml_dir => './yaml/', - listen => 'localhost:1389', + listen => shift @ARGV || 'localhost:1389', upstream_ldap => 'ldap.ffzg.hr', upstream_ssl => 1, overlay_prefix => 'ffzg-', +# log_file => 'log/ldap-rewrite.log', }; +my $log_fh; + +sub log { + return unless $config->{log_file}; + + if ( ! $log_fh ) { + open($log_fh, '>>', $config->{log_file}) || die "can't open ", $config->{log_file},": $!"; + print $log_fh "# " . time; + } + $log_fh->autoflush(1); + print $log_fh join("\n", @_),"\n"; +} + +BEGIN { + $SIG{'__WARN__'} = sub { warn @_; main::log(@_); } +} + + if ( ! -d $config->{yaml_dir} ) { warn "DISABLE ", $config->{yaml_dir}," data overlay"; } @@ -39,9 +66,11 @@ sub handle { # read from client asn_read($clientsocket, my $reqpdu); - log_request($reqpdu); - - return 1 unless $reqpdu; + if ( ! $reqpdu ) { + warn "client closed connection\n"; + return 0; + } + $reqpdu = log_request($reqpdu); # send to server print $serversocket $reqpdu or die "Could not send PDU to server\n "; @@ -50,39 +79,60 @@ sub handle { my $ready; my $sel = IO::Select->new($serversocket); for( $ready = 1 ; $ready ; $ready = $sel->can_read(0)) { - asn_read($serversocket, my $respdu) or return 1; + asn_read($serversocket, my $respdu); + if ( ! $respdu ) { + warn "server closed connection\n"; + return 0; + } $respdu = log_response($respdu); # and send the result to the client - print $clientsocket $respdu; + print $clientsocket $respdu || return 0; } - return 0; + return 1; } sub log_request { my $pdu=shift; - print '-' x 80,"\n"; - print "Request ASN 1:\n"; - Convert::ASN1::asn_hexdump(\*STDOUT,$pdu); - print "Request Perl:\n"; + die "empty pdu" unless $pdu; + +# print '-' x 80,"\n"; +# print "Request ASN 1:\n"; +# Convert::ASN1::asn_hexdump(\*STDOUT,$pdu); +# print "Request Perl:\n"; my $request = $LDAPRequest->decode($pdu); - print dump($request); + warn "## request = ",dump($request); + + if ( defined $request->{bindRequest} ) { + if ( $request->{bindRequest}->{name} =~ m{@} ) { + my $old = $request->{bindRequest}->{name}; + $request->{bindRequest}->{name} =~ s/[@\.]/,dc=/g; + $request->{bindRequest}->{name} =~ s/^/uid=/; + warn "rewrite bind cn $old -> ", $request->{bindRequest}->{name}; + Convert::ASN1::asn_hexdump(\*STDOUT,$pdu) if $debug; + $pdu = $LDAPRequest->encode($request); + Convert::ASN1::asn_hexdump(\*STDOUT,$pdu) if $debug; + } + } + + return $pdu; } sub log_response { my $pdu=shift; + die "empty pdu" unless $pdu; - print '-' x 80,"\n"; - print "Response ASN 1:\n"; - Convert::ASN1::asn_hexdump(\*STDOUT,$pdu); - print "Response Perl:\n"; +# print '-' x 80,"\n"; +# print "Response ASN 1:\n"; +# Convert::ASN1::asn_hexdump(\*STDOUT,$pdu); +# print "Response Perl:\n"; my $response = $LDAPResponse->decode($pdu); if ( defined $response->{protocolOp}->{searchResEntry} ) { my $uid = $response->{protocolOp}->{searchResEntry}->{objectName}; - warn "## SEARCH $uid"; + warn "## objectName $uid"; my @attrs; @@ -119,61 +169,58 @@ sub log_response { $pdu = $LDAPResponse->encode($response); } - print dump($response); + warn "## response = ", dump($response); return $pdu; } -sub run_proxy { - my $listenersock = shift; - my $targetsock=shift; - - die "Could not create listener socket: $!\n" unless $listenersock; - die "Could not create connection to server: $!\n" unless $targetsock; - - # mark sockets as binary - binmode( $listenersock ); - binmode( $targetsock ); - - my $sel = IO::Select->new($listenersock); - my %Handlers; - while (my @ready = $sel->can_read) { - foreach my $fh (@ready) { - if ($fh == $listenersock) { - # let's create a new socket - my $psock = $listenersock->accept; - $sel->add($psock); - } else { - my $result = handle($fh,$targetsock); - if ($result) { - # we have finished with the socket - $sel->remove($fh); - $fh->close; - delete $Handlers{*$fh}; - } - } - } - } -} - my $listenersock = IO::Socket::INET->new( Listen => 5, Proto => 'tcp', Reuse => 1, LocalAddr => $config->{listen}, -); - - -my $targetsock = $config->{upstream_ssl} - ? IO::Socket::INET->new( - Proto => 'tcp', - PeerAddr => $config->{upstream_ldap}, - PeerPort => 389, - ) - : IO::Socket::SSL->new( $config->{upstream_ldap} . ':ldaps') - ; +) || die "can't open listen socket: $!"; + +our $server_sock; + +sub connect_to_server { + my $sock; + if ( $config->{upstream_ssl} ) { + $sock = IO::Socket::SSL->new( $config->{upstream_ldap} . ':ldaps' ); + } else { + $sock = IO::Socket::INET->new( + Proto => 'tcp', + PeerAddr => $config->{upstream_ldap}, + PeerPort => 389, + ); + } + die "can't open ", $config->{upstream_ldap}, " $!\n" unless $sock; + warn "## connected to ", $sock->peerhost, ":", $sock->peerport, "\n"; + return $sock; +} -run_proxy($listenersock,$targetsock); +my $sel = IO::Select->new($listenersock); +while (my @ready = $sel->can_read) { + foreach my $fh (@ready) { + if ($fh == $listenersock) { + # let's create a new socket + my $psock = $listenersock->accept; + $sel->add($psock); + warn "## add $psock " . time; + } else { + $server_sock->{$fh} ||= connect_to_server; + if ( ! handle($fh,$server_sock->{$fh}) ) { + warn "## remove $fh " . time; + $sel->remove($server_sock->{$fh}); + $server_sock->{$fh}->close; + delete $server_sock->{$fh}; + # we have finished with the socket + $sel->remove($fh); + $fh->close; + } + } + } +} 1;