mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-09 05:00:44 +00:00
fix(credentials): serve the passwd hash of a node's configured sudoer
getcredentials answered xcat_secure_pw only for root, so a postscript had no way to get the password of another node account from the passwd table. xcat_secure_pw:<user> now returns the password field of the passwd row key=system,username=<user> when <user> is root or a sudoer named in the postscripts or postbootscripts of the requesting node, its osimage, or xcatdefaults. A sudoer without a row or without a password gets the locked field "!", so the node applies the reply as is. Any other user, an invalid user name, or a failed hash answers with an error instead of an empty reply. The root request reads the same row as before and keeps the error reply for a missing row.
This commit is contained in:
@@ -328,12 +328,13 @@ sub process_request
|
||||
next;
|
||||
} elsif ($parm =~ /xcat_secure_pw:/) {
|
||||
xCAT::MsgUtils->trace(0, 'I', "credentials: sending $parm to $client");
|
||||
my @users=split(/:/,$parm);
|
||||
if (defined($users[1]) and $users[1] eq 'root') {
|
||||
my $pass = xCAT::PasswordUtils::crypt_system_password();
|
||||
if ($pass) {
|
||||
push @{$rsp->{'data'}}, { content => [ $pass ], desc => [ $parm ] };
|
||||
}
|
||||
my (undef, $user) = split(/:/, $parm);
|
||||
my ($hash, $error) = system_password_hash($client, $user);
|
||||
if ($hash) {
|
||||
push @{ $rsp->{'data'} }, { content => [$hash], desc => [$parm] };
|
||||
} else {
|
||||
push @{ $rsp->{'error'} }, "Unable to get the password hash for $parm: $error";
|
||||
xCAT::MsgUtils->trace(0, 'W', "credentials: Unable to get the password hash for $parm: $error");
|
||||
}
|
||||
next;
|
||||
} else {
|
||||
@@ -550,6 +551,63 @@ sub _sign_x509_certificate {
|
||||
return $certificate;
|
||||
}
|
||||
|
||||
# A sudoer without a passwd row gets the locked field so the node applies the reply as is.
|
||||
sub system_password_hash {
|
||||
my ($node, $user) = @_;
|
||||
unless (defined($user) and $user =~ /^[A-Za-z_][A-Za-z0-9_.-]{0,31}$/) {
|
||||
return (undef, 'invalid user name');
|
||||
}
|
||||
unless ($user eq 'root' or configured_sudoers($node)->{$user}) {
|
||||
return (undef, "$user is not a configured sudoer of $node");
|
||||
}
|
||||
|
||||
my %key = (key => 'system', username => $user);
|
||||
my $passwd = xCAT::Table->new('passwd', -create => 0);
|
||||
my $entry = $passwd ? $passwd->getAttribs(\%key, 'password') : undef;
|
||||
$passwd->close() if $passwd;
|
||||
unless ($entry and defined($entry->{password})) {
|
||||
return ('!', undef) unless $user eq 'root';
|
||||
return (undef, 'no password in the passwd table for root');
|
||||
}
|
||||
|
||||
my $hash = xCAT::PasswordUtils::crypt_system_password('passwd', \%key, [ 'password', 'cryptmethod' ]);
|
||||
return ($hash, $hash ? undef : "unable to hash the password of $user");
|
||||
}
|
||||
|
||||
# The sudoer postscript entries of a node, from the same three sources
|
||||
# Postage.pm uses: xcatdefaults, the osimage of provmethod, and the node.
|
||||
sub configured_sudoers {
|
||||
my $node = shift;
|
||||
my @lists;
|
||||
|
||||
my $posttab = xCAT::Table->new('postscripts', -create => 0);
|
||||
if ($posttab) {
|
||||
my $defaults = $posttab->getAttribs({ node => 'xcatdefaults' }, 'postscripts', 'postbootscripts');
|
||||
my $own = $posttab->getNodeAttribs($node, [ 'postscripts', 'postbootscripts' ]);
|
||||
push @lists, map { ($_->{postscripts}, $_->{postbootscripts}) } grep { $_ } ($defaults, $own);
|
||||
$posttab->close();
|
||||
}
|
||||
|
||||
my $typetab = xCAT::Table->new('nodetype', -create => 0);
|
||||
my $type = $typetab ? $typetab->getNodeAttribs($node, ['provmethod']) : undef;
|
||||
$typetab->close() if $typetab;
|
||||
if ($type and $type->{provmethod} and $type->{provmethod} !~ /^(?:install|netboot|statelite)$/) {
|
||||
my $imagetab = xCAT::Table->new('osimage', -create => 0);
|
||||
my $image = $imagetab ? $imagetab->getAttribs({ imagename => $type->{provmethod} }, 'postscripts', 'postbootscripts') : undef;
|
||||
$imagetab->close() if $imagetab;
|
||||
push @lists, ($image->{postscripts}, $image->{postbootscripts}) if $image;
|
||||
}
|
||||
|
||||
my %sudoers;
|
||||
foreach my $entry (map { split /,/, $_ } grep { defined } @lists) {
|
||||
next unless $entry =~ /^\s*sudoer(?:\s+(.*?))?\s*$/;
|
||||
my $args = defined $1 ? $1 : '';
|
||||
my $name = $args =~ /(?:^|\s)-u\s*(\S+)/ ? $1 : 'xcat';
|
||||
$sudoers{$name} = 1;
|
||||
}
|
||||
return \%sudoers;
|
||||
}
|
||||
|
||||
sub ok_with_node {
|
||||
my $node = shift;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user