#!/usr/bin/perl # # Quick hack to make SHA256 files and create gpg detached signatures # for all packages and SHA256 files. use warnings; use File::Find; use Digest::MD5; use Digest::SHA; umask(022); die "usage: $0 start_dir\n" unless @ARGV; $| = 1; # unbuffered stdout # gpg (via pinentry) will read the passphrase from the terminal $ENV{'GPG_TTY'} = `tty`; if ($ENV{'GPG_TTY'} =~ /not a tty/) { die "$0: a tty is required\n"; } # Also used by wanted() my @signfiles; my %filelist; foreach my $startdir (@ARGV) { undef @signfiles; undef %filelist; print "Checking signatures for $startdir"; find(\&wanted, $startdir); print "\n"; # Sign any files without a signature (detached or embedded) foreach (@signfiles) { if (/\.rpm$/) { $cmd = "rpm --addsign $_"; } elsif (/\.deb$/) { $cmd = "debsigs --sign=origin --gpgopts=--batch $_"; } else { $cmd = "gpg --yes --batch -b $_"; } system($cmd); } print "Computing md5 and sha256 digests for $startdir\n"; foreach my $file (keys %filelist) { write_md5($file, @{$filelist{$file}}); write_sha($file, @{$filelist{$file}}); } } exit(0); # XXX - return an error if warranted sub wanted { my $dir = $_; if (-d && opendir(DIR, $dir)) { my @files = (); while (defined(my $file = readdir(DIR))) { next unless $file =~ /\.(gz|deb|rpm|pkg)$/; push(@files, $file); } if (int(@files)) { print "."; $filelist{$File::Find::name} = \@files; foreach (@files) { # Only need to sign if no valid existing signature my $file = "$dir/$_"; my $sign_it = 1; if (/\.rpm$/) { my $output = `rpm --checksig $file`; if ($output =~ / gpg .*OK$/) { $sign_it = 0; } } elsif (/\.deb$/) { # Old way: just check for presence of signature #my @out = `debsigs --list --gpgopts=--batch,--no-tty,--pinentry-mode=loopback $file`; #$sign_it = 0 if grep(": signed by ", @out); # Note: requires local changes to debsigs system("debsigs --verify --gpgopts=--batch,--no-tty,--pinentry-mode=loopback $file >/dev/null 2>&1"); $sign_it = $? >> 8; } elsif (-f "$file.sig") { system("gpg --quiet --batch --no-tty --verify $file.sig $file >/dev/null 2>&1"); $sign_it = $? >> 8; } push(@signfiles, $File::Find::name . "/$_") if $sign_it; } } closedir(DIR); } } sub write_md5 { my ($dir, @files) = @_; # Calculate MD5 digest of all the files in the dir my $md5 = Digest::MD5->new; my %digests; foreach my $file (@files) { if (open(FILE, '<', "$dir/$file")) { $md5->addfile(*FILE); $digests{$file} = $md5->hexdigest; close(FILE); $md5->reset; } else { warn "$dir/$file: $!\n"; } } if (scalar(keys %digests)) { my $modified = 1; if (open(MD5, '<', "$dir/MD5")) { my %old_digests; while () { chomp; my ($digest, $file) = split; $old_digests{$file} = $digest; } close(MD5); # Check existing digest file for modifications if (scalar(keys %old_digests) == scalar(keys %digests)) { $modified = 0; foreach my $file (sort keys %digests) { if ($old_digests{$file} ne $digests{$file}) { $modified = 1; last; } } } } if ($modified) { if (open(MD5, '>', "$dir/MD5")) { # Digest file missing or changed, write a new one foreach my $file (sort keys %digests) { print MD5 "$digests{$file} $file\n"; } close(MD5); } else { warn "$dir/MD5: $!\n"; } system("gpg --yes --batch -b $dir/MD5"); } } } sub write_sha { my ($dir, @files) = @_; # Calculate SHA256 digest of all the files in the dir my $sha = Digest::SHA->new(256); my %digests; foreach my $file (@files) { if (open(FILE, '<', "$dir/$file")) { $sha->addfile(*FILE); $digests{$file} = $sha->hexdigest; close(FILE); $sha->reset; } else { warn "$dir/$file: $!\n"; } } if (scalar(keys %digests)) { my $modified = 1; if (open(SHA256, '<', "$dir/SHA256")) { my %old_digests; while () { chomp; my ($digest, $file) = split; $old_digests{$file} = $digest; } close(SHA256); # Check existing digest file for modifications if (scalar(keys %old_digests) == scalar(keys %digests)) { $modified = 0; foreach my $file (sort keys %digests) { if ($old_digests{$file} ne $digests{$file}) { $modified = 1; last; } } } } if ($modified) { if (open(SHA256, '>', "$dir/SHA256")) { # Digest file missing or changed, write a new one foreach my $file (sort keys %digests) { print SHA256 "$digests{$file} $file\n"; } close(SHA256); } else { warn "$dir/SHA256: $!\n"; } system("gpg --yes --batch -b $dir/SHA256"); } } }