X-Git-Url: http://git.rot13.org/?p=virtual-ldap;a=blobdiff_plain;f=bin%2Fldap-rewrite.pl;h=cdc9534b1e0b2e2121e8fba030fec40ebed39c5c;hp=58c8222814fc3b738c0ed7c9e6d7af530622385d;hb=cdf5334694219b628813a512b37f3115535907a1;hpb=5b765848229835ff58a53095b7e494047f69a6fb diff --git a/bin/ldap-rewrite.pl b/bin/ldap-rewrite.pl index 58c8222..cdc9534 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,55 @@ 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 => shift @ARGV || 'localhost:1389', + upstream_ldap => 'ldap.ffzg.hr', + upstream_ssl => 1, + overlay_prefix => 'ffzg-', + log_file => 'log', + +}; + +my $log_fh; + +sub log { + 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"; +} + +warn "# config = ",dump( $config ); + sub handle { my $clientsocket=shift; my $serversocket=shift; # 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 "; @@ -48,36 +90,58 @@ 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; -if(0) { map { - if ( $_->{type} eq 'postalAddress' ) { - $_->{vals} = [ 'foobar' ]; + if ( $_->{type} eq 'hrEduPersonUniqueNumber' ) { + foreach my $val ( @{ $_->{vals} } ) { + next if $val !~ m{.+:.+}; + my ( $n, $v ) = split(/\s*:\s*/, $val ); + push @attrs, { type => $_->{type} . '_' . $n, vals => [ $v ] }; + } } } @{ $response->{protocolOp}->{searchResEntry}->{attributes} }; -} - my $path = "yaml/$uid.yaml"; + warn "# ++ attrs ",dump( @attrs ); + + push @{ $response->{protocolOp}->{searchResEntry}->{attributes} }, $_ foreach @attrs; + + my $path = $config->{yaml_dir} . "$uid.yaml"; if ( -e $path ) { my $data = LoadFile($path); warn "# yaml = ",dump($data); @@ -85,19 +149,18 @@ if(0) { foreach my $type ( keys %$data ) { my $vals = $data->{$type}; - $vals =~ s{#\s*$}{}; - - my @vals = split(/\s*#\s*/, $vals); - push @{ $response->{protocolOp}->{searchResEntry}->{attributes} }, - { type => "ffzg-$type", vals => [ @vals ] }; + push @{ $response->{protocolOp}->{searchResEntry}->{attributes} }, { + type => $config->{overlay_prefix} . $type, + vals => ref($vals) eq 'ARRAY' ? $vals : [ $vals ], + }; } } $pdu = $LDAPResponse->encode($response); } - print dump($response); + warn "## response = ", dump($response); return $pdu; } @@ -135,17 +198,18 @@ my $listenersock = IO::Socket::INET->new( Listen => 5, Proto => 'tcp', Reuse => 1, - LocalPort => 1389 -); - - -my $targetsock = new IO::Socket::INET ( - Proto => 'tcp', - PeerAddr => 'ldap.ffzg.hr', - PeerPort => 389, -); - -$targetsock = IO::Socket::SSL->new("ldap.ffzg.hr:ldaps"); + LocalAddr => $config->{listen}, +) || die "can't open listen socket: $!"; + + +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 upstream socket: $!"; run_proxy($listenersock,$targetsock);