diff --git a/perl-xCAT/xCAT/zvmUtils.pm b/perl-xCAT/xCAT/zvmUtils.pm index ae6116add..0457fd5ed 100644 --- a/perl-xCAT/xCAT/zvmUtils.pm +++ b/perl-xCAT/xCAT/zvmUtils.pm @@ -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; } diff --git a/xCAT-test/unit/plugin_log_password_redaction.t b/xCAT-test/unit/plugin_log_password_redaction.t index 1a949a652..66f20edcf 100644 --- a/xCAT-test/unit/plugin_log_password_redaction.t +++ b/xCAT-test/unit/plugin_log_password_redaction.t @@ -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' );