Upstream proxmox-git/pve-common state of the touched files before b40f26a995
This commit is contained in:
1 parent
1f627a1a14
commit
eafdc1c6ac
1 file changed
+276
+276
@@ -0,0 +1,276 @@
|
|||||||
|
package PVE::LDAP;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Net::IP;
|
||||||
|
use Net::LDAP;
|
||||||
|
use Net::LDAP::Control::Paged;
|
||||||
|
use Net::LDAP::Constant qw(LDAP_CONTROL_PAGED);
|
||||||
|
use Net::LDAP::Util qw(escape_filter_value);
|
||||||
|
|
||||||
|
sub ldap_connect {
|
||||||
|
my ($servers, $scheme, $port, $opts) = @_;
|
||||||
|
|
||||||
|
my $start_tls = 0;
|
||||||
|
|
||||||
|
if ($scheme eq 'ldap+starttls') {
|
||||||
|
$scheme = 'ldap';
|
||||||
|
$start_tls = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
my %ldap_opts = (
|
||||||
|
scheme => $scheme,
|
||||||
|
port => $port,
|
||||||
|
timeout => 10,
|
||||||
|
);
|
||||||
|
|
||||||
|
my $hosts = [];
|
||||||
|
for my $host (@$servers) {
|
||||||
|
if (Net::IP::ip_is_ipv6($host)) {
|
||||||
|
push @$hosts, "[$host]";
|
||||||
|
} else {
|
||||||
|
push @$hosts, $host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for my $opt (qw(clientcert clientkey capath cafile sslversion verify)) {
|
||||||
|
$ldap_opts{$opt} = $opts->{$opt} if $opts->{$opt};
|
||||||
|
}
|
||||||
|
|
||||||
|
my $ldap = Net::LDAP->new($hosts, %ldap_opts) || die "$@\n";
|
||||||
|
|
||||||
|
if ($start_tls) {
|
||||||
|
my $res = $ldap->start_tls(%$opts);
|
||||||
|
die $res->error . "\n" if $res->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ldap;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub ldap_bind {
|
||||||
|
my ($ldap, $dn, $pw) = @_;
|
||||||
|
|
||||||
|
my $res;
|
||||||
|
if (defined($dn) && defined($pw)) {
|
||||||
|
$res = $ldap->bind($dn, password => $pw);
|
||||||
|
} else { # anonymous bind
|
||||||
|
$res = $ldap->bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
my $code = $res->code;
|
||||||
|
my $err = $res->error;
|
||||||
|
|
||||||
|
die "ldap bind failed: $err\n" if $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_user_dn {
|
||||||
|
my ($ldap, $name, $attr, $base_dn) = @_;
|
||||||
|
|
||||||
|
my $escaped_name = escape_filter_value($name);
|
||||||
|
# search for dn
|
||||||
|
my $result = $ldap->search(
|
||||||
|
base => $base_dn // "",
|
||||||
|
scope => "sub",
|
||||||
|
filter => "$attr=$escaped_name",
|
||||||
|
attrs => ['dn'],
|
||||||
|
);
|
||||||
|
die $result->error . "\n" if $result->code;
|
||||||
|
return undef if !$result->entries;
|
||||||
|
my @entries = $result->entries;
|
||||||
|
return $entries[0]->dn;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub auth_user_dn {
|
||||||
|
my ($ldap, $dn, $pw, $noerr) = @_;
|
||||||
|
|
||||||
|
if (!$dn) {
|
||||||
|
return undef if $noerr;
|
||||||
|
die "user dn is empty\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $res = $ldap->bind($dn, password => $pw);
|
||||||
|
|
||||||
|
my $code = $res->code;
|
||||||
|
my $err = $res->error;
|
||||||
|
|
||||||
|
if ($code) {
|
||||||
|
return undef if $noerr;
|
||||||
|
die "$err\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub query_users {
|
||||||
|
my ($ldap, $filter, $attributes, $base_dn, $classes) = @_;
|
||||||
|
|
||||||
|
# build filter from given filter and attribute list
|
||||||
|
my $tmp = "(|";
|
||||||
|
foreach my $att (@$attributes) {
|
||||||
|
$tmp .= "($att=*)";
|
||||||
|
}
|
||||||
|
$tmp .= ")";
|
||||||
|
|
||||||
|
if ($classes) {
|
||||||
|
$tmp = "(&$tmp(|";
|
||||||
|
for my $class (@$classes) {
|
||||||
|
$tmp .= "(objectclass=$class)";
|
||||||
|
}
|
||||||
|
$tmp .= "))";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($filter) {
|
||||||
|
$filter = "($filter)" if $filter !~ m/^\(.*\)$/;
|
||||||
|
$filter = "(&${filter}${tmp})";
|
||||||
|
} else {
|
||||||
|
$filter = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $page = Net::LDAP::Control::Paged->new(size => 900);
|
||||||
|
|
||||||
|
my @args = (
|
||||||
|
base => $base_dn // "",
|
||||||
|
scope => "subtree",
|
||||||
|
filter => $filter,
|
||||||
|
control => [$page],
|
||||||
|
attrs => [@$attributes, 'memberOf'],
|
||||||
|
);
|
||||||
|
|
||||||
|
my $cookie;
|
||||||
|
my $err;
|
||||||
|
my $users = [];
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
my $mesg = $ldap->search(@args);
|
||||||
|
|
||||||
|
# stop on error
|
||||||
|
if ($mesg->code) {
|
||||||
|
$err = "ldap user search error: " . $mesg->error;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
#foreach my $entry ($mesg->entries) { $entry->dump; }
|
||||||
|
foreach my $entry ($mesg->entries) {
|
||||||
|
my $user = {
|
||||||
|
dn => $entry->dn,
|
||||||
|
attributes => {},
|
||||||
|
groups => [$entry->get_value('memberOf')],
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach my $attr (@$attributes) {
|
||||||
|
my $vals = [$entry->get_value($attr)];
|
||||||
|
if (scalar(@$vals)) {
|
||||||
|
$user->{attributes}->{$attr} = $vals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push @$users, $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
$err = "LDAP user query unsuccessful" if !$err;
|
||||||
|
}
|
||||||
|
|
||||||
|
die "$err\n" if $err;
|
||||||
|
|
||||||
|
return $users;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub query_groups {
|
||||||
|
my ($ldap, $base_dn, $classes, $filter, $group_name_attr) = @_;
|
||||||
|
|
||||||
|
my $tmp = "(|";
|
||||||
|
for my $class (@$classes) {
|
||||||
|
$tmp .= "(objectclass=$class)";
|
||||||
|
}
|
||||||
|
$tmp .= ")";
|
||||||
|
|
||||||
|
if ($filter) {
|
||||||
|
$filter = "($filter)" if $filter !~ m/^\(.*\)$/;
|
||||||
|
$filter = "(&${filter}${tmp})";
|
||||||
|
} else {
|
||||||
|
$filter = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $page = Net::LDAP::Control::Paged->new(size => 100);
|
||||||
|
|
||||||
|
my $attrs = ['member', 'uniqueMember'];
|
||||||
|
push @$attrs, $group_name_attr if $group_name_attr;
|
||||||
|
my @args = (
|
||||||
|
base => $base_dn,
|
||||||
|
scope => "subtree",
|
||||||
|
filter => $filter,
|
||||||
|
control => [$page],
|
||||||
|
attrs => $attrs,
|
||||||
|
);
|
||||||
|
|
||||||
|
my $cookie;
|
||||||
|
my $err;
|
||||||
|
my $groups = [];
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
my $mesg = $ldap->search(@args);
|
||||||
|
|
||||||
|
# stop on error
|
||||||
|
if ($mesg->code) {
|
||||||
|
$err = "ldap group search error: " . $mesg->error;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $entry ($mesg->entries) {
|
||||||
|
my $group = {
|
||||||
|
dn => $entry->dn,
|
||||||
|
members => [],
|
||||||
|
};
|
||||||
|
my $members = [$entry->get_value('member')];
|
||||||
|
if (!scalar(@$members)) {
|
||||||
|
$members = [$entry->get_value('uniqueMember')];
|
||||||
|
}
|
||||||
|
$group->{members} = $members;
|
||||||
|
if ($group_name_attr && (my $name = $entry->get_value($group_name_attr))) {
|
||||||
|
$group->{name} = $name;
|
||||||
|
}
|
||||||
|
push @$groups, $group;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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 ($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);
|
||||||
|
$err = "LDAP group query unsuccessful" if !$err;
|
||||||
|
}
|
||||||
|
|
||||||
|
die "$err\n" if $err;
|
||||||
|
|
||||||
|
return $groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
Reference in new issue
Block a user