File: //usr/share/webmin/virtual-server/sign-script-installers.pl
#!/usr/bin/perl
# Sign all script installer .pl files that are part of the Virtualmin core
# and upload them to some remote system.
package virtual_server;
if (!$module_name) {
$main::no_acl_check++;
$ENV{'WEBMIN_CONFIG'} ||= "/etc/webmin";
$ENV{'WEBMIN_VAR'} ||= "/var/webmin";
if ($0 =~ /^(.*)\/[^\/]+$/) {
chdir($pwd = $1);
}
else {
chop($pwd = `pwd`);
}
$0 = "$pwd/sign-script-installers.pl";
require './virtual-server-lib.pl';
$< == 0 || die "fetch-script-files.pl must be run as root";
}
@OLDARGV = @ARGV;
# Parse command-line args
$user = "root";
while(@ARGV) {
$a = shift(@ARGV);
if ($a eq "--dir") {
push(@dirs, shift(@ARGV));
}
elsif ($a eq "--key") {
$key = shift(@ARGV);
}
elsif ($a eq "--user") {
$user = shift(@ARGV);
}
elsif ($a eq "--ssh-user") {
$ssh_user = shift(@ARGV);
}
elsif ($a eq "--ssh-host") {
$ssh_host = shift(@ARGV);
}
elsif ($a eq "--ssh-dir") {
$ssh_dir = shift(@ARGV);
}
elsif ($a eq "--gpl-only") {
$gplonly = 1;
}
elsif ($a eq "--help") {
&usage();
}
else {
&usage("Unknown parameter $a");
}
}
# Check for needed args
@dirs || &usage("Missing --dir followed by Git directory");
$key || &usage("Missing --key followed by GPG key email");
$ssh_user || &usage("Missing --ssh-user followed by remote SSH user");
$ssh_host || &usage("Missing --ssh-user followed by SSH server hostname");
$ssh_dir || &usage("Missing --ssh-user followed by SSH server directory");
# Run an SVN update to get checked-in scripts
print "Updating scripts from Git ..\n";
foreach my $dir (@dirs) {
system("cd ".quotemeta($dir)." && su $user -c 'git pull'");
if ($?) {
print ".. Git failed!\n";
exit(1);
}
}
print ".. done\n";
# Build list of scripts and versions
print "Building list of scripts and versions ..\n";
@scripts_directories = ( @dirs );
@plugins = ( );
@snames = &list_scripts();
foreach $sname (@snames) {
$script = &get_script($sname);
next if (!$script);
$gfunc = $script->{'gpl_func'};
$gpl = $gfunc && defined(&$gfunc) && &$gfunc();
next if (!$gpl && $gplonly);
push(@scripts, $script);
push(@upload, $sname);
}
if (@scripts) {
print ".. found ",scalar(@scripts),"\n";
}
else {
print ".. none found!\n";
exit(2);
}
# Write out version file
print "Saving versions file ..\n";
$vfile = "$dirs[0]/scripts.txt";
&open_tempfile(VFILE, ">$vfile");
foreach $script (@scripts) {
&print_tempfile(VFILE, $script->{'name'}."\t".
join(" ", @{$script->{'versions'}})."\t".
$script->{'release'}."\n");
}
&close_tempfile(VFILE);
&set_ownership_permissions($user, undef, undef, $vfile);
# GPG sign version file
$sigvfile = $vfile."-sig.asc";
system("su $user -c 'rm -f $sigvfile ; gpg --armor --output $sigvfile --default-key $key --detach-sig $vfile'");
if ($?) {
print ".. GPG failed!\n";
exit(3);
}
print ".. done\n";
# GPG sign any new script files
foreach my $sfile (map { glob("$_/*.pl") } @dirs) {
$sigfile = $sfile."-sig.asc";
@st = stat($sfile);
@sigst = stat($sigfile);
if ($st[9] > $sigst[9]) {
# Needs re-signing
print "Signing script $sfile ..\n";
system("su $user -c 'rm -f $sigfile ; gpg --armor --output $sigfile --default-key $key --detach-sig $sfile'");
if ($?) {
print ".. GPG failed!\n";
exit(3);
}
print ".. done\n";
}
}
# Upload via SSH
print "Uploading via SCP to $ssh_host ..\n";
$snames = "{".join(",", @upload)."}.pl*";
system("su $user -c 'scp ".join(" ", map { "$_/$snames" } @dirs).
" $dirs[0]/scripts.txt* ${ssh_user}\@${ssh_host}:${ssh_dir}/'");
if ($?) {
print ".. SCP failed!\n";
exit(4);
}
print ".. done\n";
sub usage
{
print "$_[0]\n\n" if ($_[0]);
print "SVN update, sign and SCP all script installers.\n";
print "\n";
print "usage: sign-script-installers.pl --dir svn-dir\n";
print " [--user svn-username]\n";
print " --key gpg-key-name\n";
print " --ssh-user ssh-login-name\n";
print " --ssh-host ssh-server-name\n";
print " --ssh-dir ssh-directory\n";
exit(1);
}