Files
proxmox-git-pve-access-control/src/PVE/Auth/PVE.pm
T
dualfroz 7676330a5c fix #8053: auth: accept "0" as password for pam and pve realms
Both plugins rejected the password with a plain boolean check, and in
Perl the string "0" is false. So a user whose password is "0" could
never log in, getting a generic authentication failure.

Only reject undefined or empty passwords.

Signed-off-by: Michal Fox <me@dualfroz.com>
2026-09-25 10:05:55 +02:00

115 lines
2.6 KiB
Perl

package PVE::Auth::PVE;
use strict;
use warnings;
use Encode;
use PVE::Tools;
use PVE::Auth::Plugin;
use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
use base qw(PVE::Auth::Plugin);
my $shadowconfigfile = "priv/shadow.cfg";
cfs_register_file($shadowconfigfile, \&parse_shadow_passwd, \&write_shadow_config);
sub parse_shadow_passwd {
my ($filename, $raw) = @_;
my $shadow = {};
return $shadow if !defined($raw);
while ($raw =~ /^\s*(.+?)\s*$/gm) {
my $line = $1;
if ($line !~ m/^\S+:\S+:$/) {
warn "pve shadow password: ignore invalid line $.\n";
next;
}
my ($userid, $crypt_pass) = split(/:/, $line);
$shadow->{users}->{$userid}->{shadow} = $crypt_pass;
}
return $shadow;
}
sub write_shadow_config {
my ($filename, $cfg) = @_;
my $data = '';
foreach my $userid (keys %{ $cfg->{users} }) {
my $crypt_pass = $cfg->{users}->{$userid}->{shadow};
$data .= "$userid:$crypt_pass:\n";
}
return $data;
}
sub lock_shadow_config {
my ($code, $errmsg) = @_;
cfs_lock_file($shadowconfigfile, undef, $code);
my $err = $@;
if ($err) {
$errmsg ? die "$errmsg: $err" : die $err;
}
}
sub type {
return 'pve';
}
sub options {
return {
default => { optional => 1 },
comment => { optional => 1 },
tfa => { optional => 1 },
};
}
sub authenticate_user {
my ($class, $config, $realm, $username, $password) = @_;
die "no password\n" if !defined($password) || $password eq '';
my $shadow_cfg = cfs_read_file($shadowconfigfile);
if ($shadow_cfg->{users}->{$username}) {
my $encpw =
crypt(Encode::encode('utf8', $password), $shadow_cfg->{users}->{$username}->{shadow});
die "invalid credentials\n" if ($encpw ne $shadow_cfg->{users}->{$username}->{shadow});
} else {
die "no password set\n";
}
return 1;
}
sub store_password {
my ($class, $config, $realm, $username, $password) = @_;
lock_shadow_config(sub {
my $shadow_cfg = cfs_read_file($shadowconfigfile);
my $epw = PVE::Tools::encrypt_pw($password);
$shadow_cfg->{users}->{$username}->{shadow} = $epw;
cfs_write_file($shadowconfigfile, $shadow_cfg);
});
}
sub delete_user {
my ($class, $config, $realm, $username) = @_;
lock_shadow_config(sub {
my $shadow_cfg = cfs_read_file($shadowconfigfile);
delete $shadow_cfg->{users}->{$username};
cfs_write_file($shadowconfigfile, $shadow_cfg);
});
}
1;