[pve-devel] [PATCH pmg-api 1/2] use new PVE::LDAP instead of Net::LDAP directly
Dominik Csapak
d.csapak at proxmox.com
Fri Mar 6 11:05:46 CET 2020
for things like connecting/binding/etc.
Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
src/PMG/LDAPCache.pm | 299 ++++++++++++++-----------------------------
1 file changed, 93 insertions(+), 206 deletions(-)
diff --git a/src/PMG/LDAPCache.pm b/src/PMG/LDAPCache.pm
index ca18ad6..987f8bc 100755
--- a/src/PMG/LDAPCache.pm
+++ b/src/PMG/LDAPCache.pm
@@ -5,13 +5,11 @@ use warnings;
use File::Path;
use LockFile::Simple;
use Data::Dumper;
-use Net::LDAP;
-use Net::LDAP::Control::Paged;
-use Net::LDAP::Constant qw (LDAP_CONTROL_PAGED);
use DB_File;
use PVE::SafeSyslog;
use PVE::Tools qw(split_list);
+use PVE::LDAP;
use PMG::Utils;
use PMG::LDAPConfig;
@@ -140,124 +138,78 @@ sub update {
sub queryusers {
my ($self, $ldap) = @_;
- my $filter = '(|';
- foreach my $attr (@{$self->{mailattr}}) {
- $filter .= "($attr=*)";
- }
- $filter .= ')';
-
- if ($self->{filter}) {
- my $tmp = $self->{filter};
- $tmp = "($tmp)" if $tmp !~ m/^\(.*\)$/;
-
- $filter = "(&${filter}${tmp})";
- }
-
- my $page = Net::LDAP::Control::Paged->new(size => 900);
- my @args = (
- base => $self->{basedn},
- scope => "subtree",
- filter => $filter,
- control => [ $page ],
- attrs => [ @{$self->{mailattr}}, @{$self->{accountattr}}, 'memberOf' ]
- );
+ my $attrs = [ @{$self->{mailattr}}, @{$self->{accountattr}}, 'memberOf' ];
- my $cookie;
- while(1) {
-
- my $mesg = $ldap->search(@args);
-
- # stop on error
- if ($mesg->code) {
- my $err = "ldap user search error: " . $mesg->error;
- $self->{errors} .= "$err\n";
- syslog('err', $err);
- last;
- }
+ my $users = eval { PVE::LDAP::query_users($ldap, $self->{filter}, $attrs, $self->{basedn}) };
+ if (my $err = $@) {
+ $self->{errors} .= "$err\n";
+ syslog('err', $err);
+ return;
+ }
- #foreach my $entry ($mesg->entries) { $entry->dump; }
- foreach my $entry ($mesg->entries) {
- my $dn = $entry->dn;
+ foreach my $user (@$users) {
+ my $dn = $user->{dn};
- my $umails = {};
- my $pmail;
+ my $umails = {};
+ my $pmail;
- foreach my $attr (@{$self->{mailattr}}) {
- foreach my $mail ($entry->get_value($attr)) {
- $mail = lc($mail);
- # Test if the Line starts with one of the following lines:
- # proxyAddresses: [smtp|SMTP]:
- # and also discard this starting string, so that $mail is only the
- # address without any other characters...
+ foreach my $attr (@{$self->{mailattr}}) {
+ next if !$user->{attributes}->{$attr};
+ foreach my $mail (@{$user->{attributes}->{$attr}}) {
+ $mail = lc($mail);
+ # Test if the Line starts with one of the following lines:
+ # proxyAddresses: [smtp|SMTP]:
+ # and also discard this starting string, so that $mail is only the
+ # address without any other characters...
- $mail =~ s/^(smtp|SMTP)[\:\$]//gs;
+ $mail =~ s/^(smtp|SMTP)[\:\$]//gs;
- if ($mail !~ m/[\{\}\\\/]/ && $mail =~ m/^\S+\@\S+$/) {
- $umails->{$mail} = 1;
- $pmail = $mail if !$pmail;
- }
+ if ($mail !~ m/[\{\}\\\/]/ && $mail =~ m/^\S+\@\S+$/) {
+ $umails->{$mail} = 1;
+ $pmail = $mail if !$pmail;
}
}
- my $addresses = [ keys %$umails ];
+ }
+ my $addresses = [ keys %$umails ];
- next if !$pmail; # account has no email addresses
+ next if !$pmail; # account has no email addresses
- my $cuid;
- $self->{dbstat}->{dnames}->{dbh}->get($dn, $cuid);
- if (!$cuid) {
- $cuid = ++$self->{dbstat}->{dnames}->{idcount};
- $self->{dbstat}->{dnames}->{dbh}->put($dn, $cuid);
- }
+ my $cuid;
+ $self->{dbstat}->{dnames}->{dbh}->get($dn, $cuid);
+ if (!$cuid) {
+ $cuid = ++$self->{dbstat}->{dnames}->{idcount};
+ $self->{dbstat}->{dnames}->{dbh}->put($dn, $cuid);
+ }
- foreach my $attr (@{$self->{accountattr}}) {
- my $account = $entry->get_value($attr);
- if ($account && ($account =~ m/^\S+$/s)) {
- $account = lc($account);
- $self->{dbstat}->{accounts}->{dbh}->put($account, $cuid);
- my $data = pack('n/a* n/a* n/a*', $pmail, $account, $dn);
- $self->{dbstat}->{users}->{dbh}->put($cuid, $data);
- }
- }
+ foreach my $attr (@{$self->{accountattr}}) {
+ next if !$user->{attributes}->{$attr};
+ foreach my $account (@{$user->{attributes}->{$attr}}) {
+ next if !defined($account) || !length($account);
- foreach my $mail (@$addresses) {
- $self->{dbstat}->{mails}->{dbh}->put($mail, $cuid);
+ $account = lc($account);
+ $self->{dbstat}->{accounts}->{dbh}->put($account, $cuid);
+ my $data = pack('n/a* n/a* n/a*', $pmail, $account, $dn);
+ $self->{dbstat}->{users}->{dbh}->put($cuid, $data);
}
+ }
+
+ foreach my $mail (@$addresses) {
+ $self->{dbstat}->{mails}->{dbh}->put($mail, $cuid);
+ }
- if (!$self->{groupbasedn}) {
- my @groups = $entry->get_value('memberOf');
- foreach my $group (@groups) {
- my $cgid;
- $self->{dbstat}->{groups}->{dbh}->get($group, $cgid);
- if (!$cgid) {
- $cgid = ++$self->{dbstat}->{groups}->{idcount};
- $self->{dbstat}->{groups}->{dbh}->put($group, $cgid);
- }
- $self->{dbstat}->{memberof}->{dbh}->put($cuid, $cgid);
+ if (!$self->{groupbasedn}) {
+ foreach my $group (@{$user->{groups}}) {
+ my $cgid;
+ $self->{dbstat}->{groups}->{dbh}->get($group, $cgid);
+ if (!$cgid) {
+ $cgid = ++$self->{dbstat}->{groups}->{idcount};
+ $self->{dbstat}->{groups}->{dbh}->put($group, $cgid);
}
+ $self->{dbstat}->{memberof}->{dbh}->put($cuid, $cgid);
}
}
-
- # Get cookie from paged control
- my ($resp) = $mesg->control(LDAP_CONTROL_PAGED) or last;
- $cookie = $resp->cookie;
-
- last if (!defined($cookie) || !length($cookie));
-
- # Set cookie in paged control
- $page->cookie($cookie);
- }
-
-
- if (defined($cookie) && length($cookie)) {
- # We had an abnormal exit, so let the server know we do not want any more
- $page->cookie($cookie);
- $page->size(0);
- $ldap->search(@args);
- my $err = "LDAP user query unsuccessful";
- $self->{errors} .= "$err\n";
- syslog('err', $err);
}
}
@@ -266,135 +218,70 @@ sub querygroups {
return undef if !$self->{groupbasedn};
- my $filter = "(|";
-
- for my $class (@{$self->{groupclass}}) {
- $filter .= "(objectclass=$class)";
- }
-
- $filter .= ")";
-
- my $page = Net::LDAP::Control::Paged->new(size => 100);
-
- my @args = ( base => $self->{groupbasedn},
- scope => "subtree",
- filter => $filter,
- control => [ $page ],
- attrs => [ 'member', 'uniqueMember' ],
- );
-
- my $cookie;
- while(1) {
-
- my $mesg = $ldap->search(@args);
-
- # stop on error
- if ($mesg->code) {
- my $err = "ldap group search error: " . $mesg->error;
- $self->{errors} .= "$err\n";
- syslog('err', $err);
- last;
- }
-
- foreach my $entry ( $mesg->entries ) {
- my $group = $entry->dn;
- my @members = $entry->get_value('member');
- if (!scalar(@members)) {
- @members = $entry->get_value('uniqueMember');
- }
- my $cgid;
- $self->{dbstat}->{groups}->{dbh}->get($group, $cgid);
- if (!$cgid) {
- $cgid = ++$self->{dbstat}->{groups}->{idcount};
- $self->{dbstat}->{groups}->{dbh}->put($group, $cgid);
- }
-
- foreach my $m (@members) {
-
- my $cuid;
- $self->{dbstat}->{dnames}->{dbh}->get($m, $cuid);
- if (!$cuid) {
- $cuid = ++$self->{dbstat}->{dnames}->{idcount};
- $self->{dbstat}->{dnames}->{dbh}->put($m, $cuid);
- }
-
- $self->{dbstat}->{memberof}->{dbh}->put($cuid, $cgid);
- }
- }
-
- # Get cookie from paged control
- my ($resp) = $mesg->control(LDAP_CONTROL_PAGED) or last;
- $cookie = $resp->cookie or last;
-
- # Set cookie in paged control
- $page->cookie($cookie);
- }
-
- if ($cookie) {
- # We had an abnormal exit, so let the server know we do not want any more
- $page->cookie($cookie);
- $page->size(0);
- $ldap->search(@args);
- my $err = "LDAP group query unsuccessful";
+ my $groups = eval { PVE::LDAP::query_groups($ldap, $self->{groupbasedn}, $self->{groupclass}) };
+ if (my $err = $@) {
$self->{errors} .= "$err\n";
syslog('err', $err);
+ return;
}
-}
-sub ldap_connect {
- my ($self) = @_;
+ foreach my $group (@$groups) {
+ my $dn = $group->{dn};
- my $hosts = [ $self->{server1} ];
-
- push @$hosts, $self->{server2} if $self->{server2};
+ my $cgid;
+ $self->{dbstat}->{groups}->{dbh}->get($dn, $cgid);
+ if (!$cgid) {
+ $cgid = ++$self->{dbstat}->{groups}->{idcount};
+ $self->{dbstat}->{groups}->{dbh}->put($dn, $cgid);
+ }
- my $opts = { timeout => 10, onerror => 'die' };
+ foreach my $m (@{$group->{members}}) {
+ my $cuid;
+ $self->{dbstat}->{dnames}->{dbh}->get($m, $cuid);
+ if (!$cuid) {
+ $cuid = ++$self->{dbstat}->{dnames}->{idcount};
+ $self->{dbstat}->{dnames}->{dbh}->put($m, $cuid);
+ }
- $opts->{port} = $self->{port} if $self->{port};
- if ($self->{mode} eq 'ldaps') {
- $opts->{scheme} = 'ldaps';
- $opts->{verify} = 'require' if $self->{verify};
- if ($self->{cafile}) {
- $opts->{cafile} = $self->{cafile};
- } else {
- $opts->{capath} = '/etc/ssl/certs/';
+ $self->{dbstat}->{memberof}->{dbh}->put($cuid, $cgid);
}
- } else {
- $opts->{scheme} = 'ldap';
}
-
- return Net::LDAP->new($hosts, %$opts);
}
sub ldap_connect_and_bind {
my ($self) = @_;
- my $ldap = $self->ldap_connect() ||
- die "Can't bind to ldap server '$self->{id}': " . ($@ // "unknown error") . "\n";
-
- my $mesg;
+ my $hosts = [ $self->{server1} ];
+ push @$hosts, $self->{server2} if $self->{server2};
- if ($self->{mode} eq 'ldap+starttls') {
- my $opts = {
- verify => $self->{verify} ? 'require' : 'none',
- };
+ my $opts = {};
+ my $scheme = $self->{mode};
+ if ($scheme eq 'ldaps') {
+ $opts->{verify} = 'require' if $self->{verify};
if ($self->{cafile}) {
$opts->{cafile} = $self->{cafile};
} else {
$opts->{capath} = '/etc/ssl/certs/';
}
+ } elsif ($self->{mode} eq 'ldap+starttls') {
+ $opts->{verify} = $self->{verify} ? 'require' : 'none';
- $ldap->start_tls(%$opts);
+ if ($self->{cafile}) {
+ $opts->{cafile} = $self->{cafile};
+ } else {
+ $opts->{capath} = '/etc/ssl/certs/';
+ }
}
- if ($self->{binddn}) {
- $mesg = $ldap->bind($self->{binddn}, password => $self->{bindpw});
- } else {
- $mesg = $ldap->bind(); # anonymous bind
- }
+ my $ldap = eval { PVE::LDAP::ldap_connect($hosts, $scheme, $self->{port}, $opts) };
+ die "Can't bind to ldap server '$self->{id}': " . ($@) . "\n" if $@;
- die "ldap bind failed: " . $mesg->error . "\n" if $mesg->code;
+ my $dn;
+ my $pw;
+ $dn = $self->{binddn} if $self->{binddn};
+ $pw = $self->{bindpw} if $self->{bindpw};
+ PVE::LDAP::ldap_bind($ldap, $dn, $pw);
if (!$self->{basedn}) {
my $root = $ldap->root_dse(attrs => [ 'defaultNamingContext' ]);
--
2.20.1
More information about the pve-devel
mailing list