Skip to content

fix(xcat-core): getpostscript serves no node when the client reverse lookup is empty - #7993

Merged
dhilst merged 5 commits into
xcat2:masterfrom
VersatusHPC:fix/getpostscript-client-identity-v2
Oct 30, 2026
Merged

dhilst merged 5 commits into
xcat2:masterfrom
VersatusHPC:fix/getpostscript-client-identity-v2

Conversation

@dhilst

@dhilst dhilst commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

getpostscript identifies the requesting node from _xcat_clienthost, and rejects the request as malformed when that is empty. The peer host and fqdn are a reverse lookup of the client socket, so both are empty whenever that lookup fails, however good the client credentials are. Every postscript request from such a node is dropped.

xCAT::DiscoveryUtils::request_client_names returns the candidate names for a request: the peer host, the fqdn, and the certificate name. It drops empty names, de-duplicates, and deliberately excludes the request's own node attribute, which the client sends and has not proved.

xCAT-test/unit/getpostscript_client_identity.t drives the routine. Removing the empty-name guard fails one assertion; removing the de-duplication fails two.

Two notes for the reviewer. The test covers the routine, not the plugin's candidate loop. And with nodeauthentication off, falling back to the certificate name shifts identity from network position to the client certificate; a client can only offer its own CN, but that is the change worth checking.

…erse lookup fails

xcatd fills _xcat_clienthost and _xcat_clientfqdn from a reverse lookup of the
client socket, so both are empty when that lookup fails, however good the
client credentials are. A plugin that asks only for the peer host therefore
cannot identify a node whose certificate names it correctly.

xCAT::DiscoveryUtils::request_client_names returns the names a request offers,
most trustworthy first: the peer host, its fully qualified form, then
_xcat_authname, which is the name in the validated client certificate and does
not depend on name resolution. The request's own node attribute is excluded on
purpose -- a client sends it, so it states what the client wants to be rather
than what it proved it is, and postscripts carry the cluster root ssh key.

xCAT-test/unit/getpostscript_client_identity.t drives the routine directly: the
request hash is its only input and a list of names its only output. It fails on
five mutants of the routine, each naming the assertion it breaks -- the
certificate name dropped (2 checks), the empty-name guard dropped (1), the
client-supplied node offered (3), the de-duplication dropped (2), and the
array-ref guard dropped (1).

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
… cannot reverse-resolve it

A diskless openEuler 22.03sp4 node netbooted, took a lease, reached a login
prompt and answered ping, and then every xdsh and ssh answered
"root@xcat59-cn: Permission denied (publickey)" while the node never reported
"booted". reg_linux_diskless_installation_flat failed after 7072 s.

xcatd on that management node logged "xCAT: Allowing getpostscript xcat59-cn"
with no "from <peerhost>", then "Received malformed getpostscript requesting,
ignore it." -- 100 times, with 0 "Sending scripts data" in the whole log. The
green openEuler 24.03sp4 cell beside it logged 3 sends and 0 malformed. The
client certificate named the node correctly; only the reverse lookup of the
peer socket failed.

getpostscript read _xcat_clienthost and nothing else, so it dropped every
request. No postscript ran: remoteshell never installed root's
authorized_keys, which is the ssh failure, and nothing updated node status,
which is the stuck "powering-on". One cause, both symptoms.

process_request now tries each name xCAT::DiscoveryUtils::request_client_names
offers and takes the first that correlates to a node. A request that offers no
name at all, and one whose names correlate to nothing, are now reported as what
they are; the old message said the request was malformed, which sent two
investigations into DNS and the netboot image.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
…measured

Ninety xCAT modules carry
BEGIN { $::XCATROOT = $ENV{XCATROOT} || '/opt/xcat' } use lib "$::XCATROOT/lib/perl";
so the first xCAT module a test loads can put an installed product in front of
the checkout in @inc. A build host has one: xcat-master carries
/opt/xcat/lib/perl/xCAT/DiscoveryUtils.pm. A run that loaded that copy would
pass while measuring a product built weeks ago, and nothing in the test said
otherwise.

The test now reports the file that answered, refuses one under /opt/xcat, and
asserts the routine exists. A stale copy winning @inc lacks it, so the file
goes red instead of passing on three assertions that never ran against this
change.

Measured both ways: on a host with no xCAT the module resolves to
perl-xCAT/xCAT/DiscoveryUtils.pm, and on xcat-master, which has an installed
copy, it still resolves to the checkout -- so the use lib does win today and
this holds that down rather than fixing a live fault.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
The comment carried a date, a node, and the request counts from one run. The code
standard keeps bug history out of source comments: the fact a reader needs is that
the peer host is a reverse lookup and can be empty, which the remaining two sentences
state.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
@dhilst
dhilst marked this pull request as ready for review October 26, 2026 17:58
@dhilst dhilst self-assigned this Oct 26, 2026
@dhilst
dhilst requested a review from viniciusferrao October 26, 2026 17:59
@dhilst dhilst added this to the 2.20 milestone Oct 26, 2026

@viniciusferrao viniciusferrao left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @dhilst, this fallback can send a node’s postscripts to a user account. _xcat_authname can contain a password or token username.

With nodeauthentication off and no resolved peer name, a user named compute reaches the candidate loop. If compute is a node group, noderange selects its first member. The default policy permits this request. I reproduced the head serving node01; the base rejects the same request.

Keep login/token identities out of this fallback. Use a verified node-certificate identity, require an exact node match without group or range expansion, and add a regression test through the plugin.

Thanks.

…rd or token login

With nodeauthentication off and no peer name, getpostscript used
_xcat_authname as the client identity and expanded it with noderange.
becomeuser and tokens set _xcat_authname to an account name, so a user
named after a node group received the postscripts of the first node in
that group.

xcatd now records the CN of the validated client certificate as
_xcat_certname, and only while no becomeuser or token replaced it. It
deletes any _xcat_certname the client sent. getpostscript uses that
name only when it names exactly one node, with no group or range
expansion. _xcat_authname is no longer a candidate.

getpostscript_client_identity.t drives the plugin with these requests.
On the previous head the group and node login checks fail, and
dropping the exact match fails the group and range checks.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
@viniciusferrao
viniciusferrao self-requested a review October 29, 2026 17:50

@viniciusferrao viniciusferrao left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@dhilst
dhilst merged commit 10c30c8 into xcat2:master Oct 30, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants