2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-04 12:07:56 +00:00

Merge pull request #7812 from VersatusHPC/fix/zvm-command-continuation-redaction

fix(zvm): mask the whole continued COMMAND statement
This commit is contained in:
Daniel Hilst
2026-09-03 14:46:46 -03:00
committed by GitHub
2 changed files with 86 additions and 3 deletions
+43 -3
View File
@@ -337,8 +337,9 @@ sub printLn {
MDISK statement carries the read, write and multi
passwords after the access mode. The COMMAND statement
can start any CP command with an inline password, so
the whole statement masks. The keyword form carries
the passwords as PW assignments.
the whole statement masks, in either spelling and
through the last record of a continued statement. The
keyword form carries the passwords as PW assignments.
Arguments : Directory entry text
Returns : The text with each password masked
Example : my $safe = xCAT::zvmUtils->redact_directory_entry($entry);
@@ -349,11 +350,50 @@ sub printLn {
sub redact_directory_entry {
my ( $class, $entry ) = @_;
return $entry unless defined $entry;
# z/VM reads the statement in columns 1 to 71, so a sequence number
# after them cannot change the continuation. A comment record is
# ignored, so it neither ends an open statement nor starts one that
# reaches the records below. This pass runs before the rules below,
# which replace the end of a record and would drop a continuation
# comma.
my @records = split(/\n/, $entry, -1);
my $active = 0;
my $commented = 0;
foreach my $record (@records) {
my $statement = substr($record, 0, 71);
my $is_comment = ($statement =~ /^[ \t]*\*/) ? 1 : 0;
my $is_blank = ($statement =~ /^[ \t\r]*$/) ? 1 : 0;
my $continues = ($statement =~ /,[ \t\r]*$/) ? 1 : 0;
next if $is_blank;
if ($is_comment) {
if ($active or $commented) {
$record = 'xxxxxxxx';
next;
}
if ($record =~ /^[ \t]*(?:\*[ \t]*)*(?:COMMAND|CMD)\b/i) {
$record =~ s/^([ \t]*(?:\*[ \t]*)*(?:COMMAND|CMD)\b).*$/$1 xxxxxxxx/i;
$commented = $continues;
}
next;
}
$commented = 0;
if ($record =~ /^[ \t]*(?:COMMAND|CMD)\b/i) {
$record =~ s/^([ \t]*(?:COMMAND|CMD)\b).*$/$1 xxxxxxxx/i;
$active = $continues;
next;
}
next unless $active;
$active = $continues;
$record = 'xxxxxxxx';
}
$entry = join("\n", @records);
$entry =~ s/^([ \t]*(?:\*[ \t]*)*(?:USER|IDENTITY|IDENT)[ \t]+\S+[ \t]+)\S+/$1xxxxxxxx/img;
$entry =~ s/^([ \t]*(?:\*[ \t]*)*MDISK[ \t]+\S+[ \t]+\S+[ \t]+(?:DEVNO|V-DISK|T-DISK)[ \t]+\S+[ \t]+\S+)[ \t]+\S.*$/$1 xxxxxxxx/img;
$entry =~ s/^([ \t]*(?:\*[ \t]*)*MDISK[ \t]+(?:\S+[ \t]+){5}\S+)[ \t]+\S.*$/$1 xxxxxxxx/img;
$entry =~ s/^([ \t]*(?:\*[ \t]*)*APPCPASS\b).*$/$1 xxxxxxxx/img;
$entry =~ s/^([ \t]*(?:\*[ \t]*)*COMMAND\b).*$/$1 xxxxxxxx/img;
$entry =~ s/\b((?:READ|WRITE|MULTI)?(?:PASSWORD|PW)|APPCPASS)=\S+/$1=xxxxxxxx/ig;
return $entry;
}
@@ -120,6 +120,49 @@ subtest 'z/VM directory entries are redacted as data' => sub {
'COMMAND record is masked' );
unlike( directory_entry('* COMMAND XAUTOLOG VSEVM PW SENTCAUTO'), qr/SENTCAUTO/,
'commented COMMAND record is masked' );
is( directory_entry("COMMAND XAUTOLOG VSEVM PW ,\nSENTCONT"),
"COMMAND xxxxxxxx\nxxxxxxxx",
'a continued COMMAND record is masked through its last record' );
unlike( directory_entry("COMMAND DEFINE MDISK 0100 3390 1 100 EMC2C4 MR ,\nSENTCRPW SENTCWPW"),
qr/SENTCRPW|SENTCWPW/, 'continued COMMAND operands are masked' );
unlike( directory_entry("* COMMAND XAUTOLOG VSEVM PW ,\n* SENTCCONT"), qr/SENTCCONT/,
'a commented continuation record is masked' );
like( directory_entry("* COMMAND XAUTOLOG VSEVM PW ,\nNICDEF 0600 TYPE QDIO LAN SYSTEM VSW1"),
qr/NICDEF 0600 TYPE QDIO LAN SYSTEM VSW1/,
'a commented COMMAND record does not consume the record below it' );
unlike( directory_entry("COMMAND XAUTOLOG VSEVM PW ,\n* a note\nSENTAFTERNOTE"),
qr/SENTAFTERNOTE/, 'a comment record does not end the continuation' );
unlike( directory_entry("COMMAND XAUTOLOG VSEVM PW ,\n* one\n* two\n\nSENTDEEP"),
qr/SENTDEEP/, 'comment and blank records do not end the continuation' );
unlike( directory_entry("COMMAND XAUTOLOG VSEVM PW ,\n* COMMAND note\nSENTCOMNOTE"),
qr/SENTCOMNOTE/, 'a commented COMMAND record does not end the continuation' );
my $sequenced = 'COMMAND XAUTOLOG VSEVM PW' . ( ' ' x 45 ) . ',' . '00000010';
unlike( directory_entry("$sequenced\nSENTSEQPASS"), qr/SENTSEQPASS/,
'a sequence numbered record continues the statement' );
unlike( directory_entry('CMD XAUTOLOG VSEVM PW SENTCMD'), qr/SENTCMD/,
'CMD record is masked' );
unlike( directory_entry("CMD XAUTOLOG VSEVM PW ,\nSENTCMDCONT"), qr/SENTCMDCONT/,
'a continued CMD record is masked through its last record' );
unlike( directory_entry("COMMAND DEFINE ,\nMDISK 0100 3390 1 100 EMC2C4 MR ,\nSENTMIDMDISK"),
qr/SENTMIDMDISK/,
'a continuation record that reads as MDISK does not end the statement' );
unlike( directory_entry("COMMAND DEFINE ,\nAPPCPASS LUA LUB USERX PW ,\nSENTMIDAPPC"),
qr/SENTMIDAPPC/,
'a continuation record that reads as APPCPASS does not end the statement' );
unlike( directory_entry("COMMAND DEFINE ,\nUSER LNX1 SENTMIDLOGON 512M 1G G ,\nSENTMIDUSER"),
qr/SENTMIDLOGON|SENTMIDUSER/,
'a continuation record that reads as USER does not end the statement' );
my $spaced = ( ' ' x 71 ) . '00000020';
unlike( directory_entry("COMMAND XAUTOLOG VSEVM PW ,\n$spaced\nSENTSEQBLANK"),
qr/SENTSEQBLANK/,
'a sequence numbered blank record does not end the continuation' );
my $trailing = 'COMMAND SET RUN ON' . ( ' ' x 53 ) . '0000001,';
like( directory_entry("$trailing\nMDISK 0100 3390 0001 10016 EMC2C4 MR"),
qr/^MDISK 0100 3390 0001 10016 EMC2C4 MR$/m,
'a comma in the sequence number does not continue the statement' );
like( directory_entry("COMMAND XAUTOLOG VSEVM PW ,\nSENTCONT\nNICDEF 0600 TYPE QDIO LAN SYSTEM VSW1"),
qr/NICDEF 0600 TYPE QDIO LAN SYSTEM VSW1/,
'the record after a continuation is preserved' );
like( directory_entry("USER LNX1 SENTUSERPW 512M 1G G\nNICDEF 0600 TYPE QDIO LAN SYSTEM VSW1"),
qr/NICDEF 0600 TYPE QDIO LAN SYSTEM VSW1/,
'records beside credentials are preserved' );