From 401dc0e3df53586c81f108fabaa864d3946bee6e Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 4 Nov 2025 18:04:55 -0500 Subject: [PATCH 1/2] Add verify-packages subcommand --- lib/LUCCDC/Jiujitsu/Commands/file.pm | 81 +++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/lib/LUCCDC/Jiujitsu/Commands/file.pm b/lib/LUCCDC/Jiujitsu/Commands/file.pm index 9db1a23..a39b7ed 100644 --- a/lib/LUCCDC/Jiujitsu/Commands/file.pm +++ b/lib/LUCCDC/Jiujitsu/Commands/file.pm @@ -2,6 +2,8 @@ package LUCCDC::Jiujitsu::Commands::file; use strictures 2; use LUCCDC::Jiujitsu::Util::Logging qw(error warning %CR); use LUCCDC::Jiujitsu::Util::Arguments qw(&parser :patterns); +use LUCCDC::Jiujitsu::Util::Linux::Files qw(dirmap); +use LUCCDC::Jiujitsu::Util::Linux::PerDistro qw(platform); use Digest::SHA; use Cwd 'abs_path'; use POSIX; @@ -47,11 +49,13 @@ my @options = ( ); my %subcommands = ( - 'store-hashes' => \&store, - 's' => \&store, - 'verify-hashes' => \&verify, - 'v' => \&verify, - '--help' => \&help, + 'store-hashes' => \&store, + 's' => \&store, + 'verify-hashes' => \&verify, + 'v' => \&verify, + 'verify-packages' => \&verify_pkgs, + 'vp' => \&verify_pkgs, + '--help' => \&help, ); my $toplevel_parser = parser( \@options, \%subcommands ); @@ -189,6 +193,68 @@ sub retrieve_hashes { return; } +sub verify_pkgs { + my @options = @_; + my %arg = $subcmd_parser->(@options); + my @target_dirs = ('/usr/bin', '/usr/sbin'); + push @target_dirs, ('/bin', '/sbin') unless ( -l "/bin" ); + my @all_files; + for my $dir (@target_dirs) { + print "Scanning $dir...\n"; + my @files_in_dir = dirmap( $dir, sub { return 1 } ); + push @all_files, @files_in_dir; + } + + print "Verifying " . scalar(@all_files) . " files against package manager database...\n"; + + my $platform = platform(); + + if ($platform eq "rhel") { + for my $file (@all_files) { + my $output = `rpm -Vf "$file" 2>&1`; + if ($output) { + chomp $output; + if ( $output =~ /is not owned by any package/ ) { + print "[$CR{yellow}!$CR{nocolor}]: $file (UNOWNED)\n"; + } + else { + print "[$CR{red}✗$CR{nocolor}]: $output\n"; + } + } + #else { + # print "[$CR{green}✓$CR{nocolor}]: $file\n"; + #} + } + } + else { + my %packages_to_check; + for my $file (@all_files) { + my $owner_line = `dpkg -S "$file" 2>/dev/null`; + if ($owner_line) { + chomp $owner_line; + if ($owner_line =~ /^([a-z0-9][a-z0-9.+-]+):/) { + my $pkg_name = $1; + $packages_to_check{$pkg_name} = 1; + } + } + else { + print "[$CR{yellow}!$CR{nocolor}]: $file (UNOWNED)\n"; + } + } + + my @unique_packages = keys %packages_to_check; + print "Verifying " . scalar(@unique_packages) . " unique packages...\n"; + + for my $pkg (@unique_packages) { + my $output = `dpkg -V "$pkg" 2>&1`; + if ($output) { + print $output; + } + } + } + exit; +} + sub help { print <<"END_HELP"; @@ -198,8 +264,9 @@ Usage: jj file Subcommands: - s, store-hashes: Stores current hashes - v, verify-hashes: Verifies stored hashes + s, store-hashes: Stores current hashes + v, verify-hashes: Verifies stored hashes + vp, verify-packages: Verifies installed packages Verification Status: [$CR{green}✓$CR{nocolor}]: Good hash From 5287840b49abfeb373b347cca26678ac3f2dc50d Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 8 Nov 2025 12:32:29 -0500 Subject: [PATCH 2/2] Improved RHEL package verification logic --- lib/LUCCDC/Jiujitsu/Commands/file.pm | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/LUCCDC/Jiujitsu/Commands/file.pm b/lib/LUCCDC/Jiujitsu/Commands/file.pm index a39b7ed..026dbcd 100644 --- a/lib/LUCCDC/Jiujitsu/Commands/file.pm +++ b/lib/LUCCDC/Jiujitsu/Commands/file.pm @@ -210,22 +210,21 @@ sub verify_pkgs { my $platform = platform(); if ($platform eq "rhel") { + my $verify_output = `rpm -Va 2>&1`; + if ($verify_output) { + print "rpm -Va output: \n"; + print $verify_output; + } + for my $file (@all_files) { - my $output = `rpm -Vf "$file" 2>&1`; - if ($output) { - chomp $output; - if ( $output =~ /is not owned by any package/ ) { - print "[$CR{yellow}!$CR{nocolor}]: $file (UNOWNED)\n"; - } - else { - print "[$CR{red}✗$CR{nocolor}]: $output\n"; - } + system("rpm -qf \"$file\" >/dev/null 2>&1"); + if ($? != 0) + { + print "[$CR{yellow}!$CR{nocolor}]: $file (UNOWNED)\n"; } - #else { - # print "[$CR{green}✓$CR{nocolor}]: $file\n"; - #} } } + else { my %packages_to_check; for my $file (@all_files) {