Server IP : 85.214.239.14 / Your IP : 18.226.187.232 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /proc/2/root/usr/share/perl5/Amavis/LDAP/ |
Upload File : |
# SPDX-License-Identifier: GPL-2.0-or-later package Amavis::LDAP::Connection; use strict; use re 'taint'; use warnings; use warnings FATAL => qw(utf8 void); no warnings 'uninitialized'; # use warnings 'extra'; no warnings 'experimental::re_strict'; use re 'strict'; use Net::LDAP; use Net::LDAP::Util; BEGIN { require Exporter; use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION $have_sasl $ldap_sys_default); $VERSION = '2.412'; @ISA = qw(Exporter); $have_sasl = eval { require Authen::SASL }; } use Amavis::Conf qw(:platform :confvars c cr ca); use Amavis::Timing qw(section_time); use Amavis::Util qw(ll do_log do_log_safe); BEGIN { # must be in a separate BEGIN block to be able to see imported symbols $ldap_sys_default = { hostname => 'localhost', localaddr => undef, port => undef, # 389 or 636, default provided by Net::LDAP scheme => undef, # 'ldaps' or 'ldap', depending on hostname version => 3, timeout => 120, deref => 'find', bind_dn => undef, bind_password => undef, tls => 0, verify => 'none', sslversion => 'tlsv1', clientcert => undef, clientkey => undef, cafile => undef, capath => undef, sasl => 0, sasl_mech => undef, # space-separated list of mech names sasl_auth_id => undef, }; 1; } sub new { my($class,$default) = @_; my $self = bless { ldap => undef }, $class; $self->{incarnation} = 1; for (qw(hostname localaddr port scheme inet6 version timeout base scope deref bind_dn bind_password tls verify sslversion clientcert clientkey cafile capath sasl sasl_mech sasl_auth_id)) { # replace undefined attributes with user values or defaults $self->{$_} = $default->{$_} if !defined($self->{$_}); $self->{$_} = $ldap_sys_default->{$_} if !defined($self->{$_}); } if (!defined $self->{scheme}) { $self->{scheme} = $self->{hostname} =~ /^ldaps/i ? 'ldaps' : 'ldap'; } $self; } sub ldap { # get/set ldap handle my $self = shift; !@_ ? $self->{ldap} : ($self->{ldap}=shift); } sub DESTROY { my $self = $_[0]; local($@,$!,$_); do_log_safe(5,"Amavis::LDAP::Connection DESTROY called"); # ignore failure, make perlcritic happy eval { $self->disconnect_from_ldap } or 1; } sub incarnation { my $self = $_[0]; $self->{incarnation} } sub in_transaction { 0 } sub begin_work { my $self = $_[0]; do_log(5,"ldap begin_work"); $self->ldap or $self->connect_to_ldap; } sub connect_to_ldap { my $self = $_[0]; my($bind_err,$start_tls_err); do_log(3,"Connecting to LDAP server"); my $hostlist = ref $self->{hostname} eq 'ARRAY' ? join(", ",@{$self->{hostname}}) : $self->{hostname}; do_log(4,"connect_to_ldap: trying %s", $hostlist); my $ldap = Net::LDAP->new($self->{hostname}, localaddr => $self->{localaddr}, port => $self->{port}, scheme => $self->{scheme}, version => $self->{version}, timeout => $self->{timeout}, keepalive => 1, # since Net::LDAP 0.53 # remaining keepalive* options need Socket::Linux and a # patch at [rt.cpan.org #83039], otherwise are ignored keepalive_idle => 240, keepalive_interval => 30, keepalive_probe => 10, ); if (!$ldap) { # connect failed do_log(-1,"connect_to_ldap: unable to connect to host %s", $hostlist); } else { do_log(3,"connect_to_ldap: connected to %s", $hostlist); # $ldap->debug(12); # debug output goes to STDERR if ($self->{tls}) { # TLS required my $mesg = $ldap->start_tls(verify => $self->{verify}, sslversion => $self->{sslversion}, clientcert => $self->{clientcert}, clientkey => $self->{clientkey}, cafile => $self->{cafile}, capath => $self->{capath}); if ($mesg->code) { # start TLS failed my $err = $mesg->error_name; do_log(-1,"connect_to_ldap: start TLS failed: %s", $err); $self->ldap(undef); $start_tls_err = 1; } else { # started TLS do_log(3,"connect_to_ldap: TLS version %s enabled", $mesg); } } if ($self->{bind_dn} || $self->{sasl}) { # bind required my $sasl; my $passw = $self->{bind_password}; if ($self->{sasl}) { # using SASL to authenticate? $have_sasl or die "connect_to_ldap: SASL requested but no Authen::SASL"; $sasl = Authen::SASL->new(mechanism => $self->{sasl_mech}, callback => { user => $self->{sasl_auth_id}, pass => $passw } ); } my $mesg = $ldap->bind($self->{bind_dn}, $sasl ? (sasl => $sasl) : defined $passw ? (password => $passw) : ()); $passw = 'X' x length($passw) if defined $passw; # can't hurt if ($mesg->code) { # bind failed my $err = $mesg->error_name; do_log(-1,"connect_to_ldap: bind failed: %s", $err); $self->ldap(undef); $bind_err = 1; } else { # bind succeeded do_log(3,"connect_to_ldap: bind %s succeeded", $self->{bind_dn}); } } } $self->ldap($ldap); $self->{incarnation}++; $ldap or die "connect_to_ldap: unable to connect"; if ($start_tls_err) { die "connect_to_ldap: start TLS failed" } if ($bind_err) { die "connect_to_ldap: bind failed" } section_time('ldap-connect'); $self; } sub disconnect_from_ldap { my $self = $_[0]; return if !$self->ldap; do_log(4,"disconnecting from LDAP"); $self->ldap->disconnect; $self->ldap(undef); 1; } sub do_search { my($self,$base,$scope,$filter) = @_; my($result,$error_name); $self->ldap or die "do_search: ldap not available"; do_log(5,'lookup_ldap: searching base="%s", scope="%s", filter="%s"', $base, $scope, $filter); eval { $result = $self->{ldap}->search(base => $base, scope => $scope, filter => $filter, deref => $self->{deref}, ); if ($result->code) { $error_name = $result->error_name; if ($error_name eq 'LDAP_NO_SUCH_OBJECT') { # probably alright, e.g. a foreign %d do_log(4, 'do_search failed in "%s": %s', $base, $error_name); } else { die $error_name."\n"; } } 1; } or do { my $err = $@ ne '' ? $@ : "errno=$!"; chomp $err; die $err if $err =~ /^timed out\b/; # resignal timeout if ($err !~ /^LDAP_/) { die "do_search: $err"; } elsif ($error_name !~ /^LDAP_(?:BUSY|UNAVAILABLE|UNWILLING_TO_PERFORM| TIMEOUT|SERVER_DOWN|CONNECT_ERROR|OTHER| LOCAL_ERROR|OPERATIONS_ERROR)\z/x) { die "do_search: failed: $error_name\n"; } else { # LDAP related error, worth retrying do_log(0, "NOTICE: do_search: trying again: %s", $error_name); $self->disconnect_from_ldap; $self->connect_to_ldap; $self->ldap or die "do_search: reconnect failed"; do_log(5, 'lookup_ldap: searching (again) base="%s", scope="%s", filter="%s"', $base, $scope, $filter); eval { $result = $self->{ldap}->search(base => $base, scope => $scope, filter => $filter, deref => $self->{deref}, ); if ($result->code) { die $result->error_name, "\n"; } 1; } or do { my $err = $@ ne '' ? $@ : "errno=$!"; chomp $err; $self->disconnect_from_ldap; die $err if $err =~ /^timed out\b/; # resignal timeout die "do_search: failed again, $err"; }; }; }; $result; } 1;