From 2f798c20eac0eb2e6e38fe044b3eb6ef7bb25fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Sun, 30 Aug 2026 17:22:51 -0300 Subject: [PATCH] feat(policy): allow Unix group rules Co-authored-by: Samveen --- perl-xCAT/xCAT/Utils.pm | 44 ++++++++++++++++++++++ xCAT-server/lib/perl/xCAT/xcatd.pm | 9 ++++- xCAT-server/lib/xcat/plugins/rollupdate.pm | 8 +++- 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/perl-xCAT/xCAT/Utils.pm b/perl-xCAT/xCAT/Utils.pm index 4b08e226b..65c253a7d 100644 --- a/perl-xCAT/xCAT/Utils.pm +++ b/perl-xCAT/xCAT/Utils.pm @@ -1606,6 +1606,50 @@ sub getHomeDir } +#-------------------------------------------------------------------------------- + +=head3 user_matches_policy_name + + Match an authenticated username against a policy name. Bare names + match usernames exactly; names prefixed with '%' match Unix groups. + + Arguments: + username, policy name + Returns: + 1 - match + 0 - no match + +=cut + +#-------------------------------------------------------------------------------- + +sub user_matches_policy_name +{ + my ($class, $username, $policy_name) = @_; + + return 0 unless defined($username) && length($username); + return 0 unless defined($policy_name) && length($policy_name); + return $username eq $policy_name unless $policy_name =~ /\A%(.*)\z/x; + + my $group_name = $1; + return 0 unless length($group_name); + + my @user = getpwnam($username); + return 0 unless @user; + + my @group = getgrnam($group_name); + return 0 unless @group; + + return 1 if defined($user[3]) && defined($group[2]) && $user[3] == $group[2]; + return 0 unless defined($group[3]) && length($group[3]); + + foreach my $member (split(/\s+/x, $group[3])) { + return 1 if $member eq $username; + } + return 0; +} + + #------------------------------------------------------------------------------- diff --git a/xCAT-server/lib/perl/xCAT/xcatd.pm b/xCAT-server/lib/perl/xCAT/xcatd.pm index 4de9fbcf2..3514bd280 100644 --- a/xCAT-server/lib/perl/xCAT/xcatd.pm +++ b/xCAT-server/lib/perl/xCAT/xcatd.pm @@ -90,7 +90,7 @@ sub validate { # check to see if peerhost is trusted foreach $rule (@sortedpolicies) { - if (($rule->{name} and $rule->{name} eq $peername) && ($rule->{rule} =~ /trusted/i)) { + if (($rule->{name} and $rule->{name} !~ /\A%/x and $rule->{name} eq $peername) && ($rule->{rule} =~ /trusted/i)) { $peerstatus = "Trusted"; last; } @@ -108,11 +108,16 @@ sub validate { } } + my %principal_matches; + RULE: foreach $rule (@sortedpolicies) { if ($rule->{name} and $rule->{name} ne '*') { #TODO: more complex matching (lists, wildcards) - next unless ($peername and $peername eq $rule->{name}); + $principal_matches{ $rule->{name} } = + xCAT::Utils->user_matches_policy_name($peername, $rule->{name}) + unless exists($principal_matches{ $rule->{name} }); + next unless $principal_matches{ $rule->{name} }; } if ($rule->{name} and $rule->{name} eq '*') { #a name is required, but can be any name whatsoever.... next unless ($peername); diff --git a/xCAT-server/lib/xcat/plugins/rollupdate.pm b/xCAT-server/lib/xcat/plugins/rollupdate.pm index 88fc48bbd..afd2acf27 100644 --- a/xCAT-server/lib/xcat/plugins/rollupdate.pm +++ b/xCAT-server/lib/xcat/plugins/rollupdate.pm @@ -1277,9 +1277,13 @@ sub check_policy { my $policies = $policytable->getAllEntries; $policytable->close; + my %principal_matches; foreach my $rule (@$policies) { - if ($rule->{name} && - (($rule->{name} eq "*") || ($rule->{name} eq $userid))) { + if ($rule->{name}) { + $principal_matches{ $rule->{name} } = + xCAT::Utils->user_matches_policy_name($userid, $rule->{name}) + unless exists($principal_matches{ $rule->{name} }); + next unless ($rule->{name} eq "*" || $principal_matches{ $rule->{name} }); if ($rule->{commands}) { if (($rule->{commands} eq "") || ($rule->{commands} eq "*") || ($rule->{commands} =~ /$xcatcmd/)) { return 0; # match found