added rewrite of LDAP bind CN username@domain.com -> uid=username,dc=domain,dc=com
[virtual-ldap] / bin / ldap-rewrite.pl
index a6eff6e..cdc9534 100755 (executable)
@@ -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 <dpavlin@rot13.org> 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,13 +20,15 @@ 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 = 1;
+
 my $config = {
        yaml_dir => './yaml/',
-       listen => 'localhost:1389',
+       listen => shift @ARGV || 'localhost:1389',
        upstream_ldap => 'ldap.ffzg.hr',
        upstream_ssl => 1,
        overlay_prefix => 'ffzg-',
@@ -31,7 +39,10 @@ my $config = {
 my $log_fh;
 
 sub log {
-       open($log_fh, '>', $config->{log_file}) || die "can't open ", $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";
 }
@@ -53,9 +64,11 @@ sub handle {
 
        # read from client
        asn_read($clientsocket, my $reqpdu);
-       log_request($reqpdu);
-
-       return 1 unless $reqpdu;
+       if ( ! $reqpdu ) {
+               warn "WARNING no reqpdu\n";
+               return 1;
+       }
+       $reqpdu = log_request($reqpdu);
 
        # send to server
        print $serversocket $reqpdu or die "Could not send PDU to server\n ";
@@ -77,26 +90,40 @@ sub handle {
 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";
+#      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;
 
-       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;
 
@@ -133,7 +160,7 @@ sub log_response {
                $pdu = $LDAPResponse->encode($response);
        }
 
-       print dump($response);
+       warn "## response = ", dump($response);
 
        return $pdu;
 }
@@ -167,14 +194,12 @@ sub run_proxy {
 }
 
 
-$ENV{LANG} = 'C'; # so we don't double-encode utf-8 if LANG is utf-8
-
 my $listenersock = IO::Socket::INET->new(
        Listen => 5,
        Proto => 'tcp',
        Reuse => 1,
        LocalAddr => $config->{listen},
-);
+) || die "can't open listen socket: $!";
 
 
 my $targetsock = $config->{upstream_ssl}
@@ -184,7 +209,7 @@ my $targetsock = $config->{upstream_ssl}
                PeerPort => 389,
        )
        : IO::Socket::SSL->new( $config->{upstream_ldap} . ':ldaps')
-       ;
+       || die "can't open upstream socket: $!";
 
 run_proxy($listenersock,$targetsock);