Bump revision number to match CVS revision number. Replaced all signature
verification code with code that uses detached signatures. Signatures generated by GnuPG couldn't be verified using attached signatures without adding a Hash header, and this was the path of least resistance plus avoids munging problems in the future. Code taken from PGP::Sign.
This commit is contained in:
parent
46278eb3e3
commit
dea04e918e
1 changed files with 220 additions and 166 deletions
386
pgpverify
386
pgpverify
|
@ -1,16 +1,28 @@
|
||||||
#! /usr/bin/perl -ws
|
#! /usr/bin/perl -w
|
||||||
do '@LIBDIR@/innshellvars.pl';
|
# do '@LIBDIR@/innshellvars.pl';
|
||||||
# Remove the above line if not running as part of INN.
|
# If running inside INN, uncomment the above and point to innshellvars.pl.
|
||||||
#
|
#
|
||||||
# written April 1996, tale@isc.org (David C Lawrence)
|
# written April 1996, tale@isc.org (David C Lawrence)
|
||||||
# Currently maintained by Russ Allbery <rra@stanford.edu>
|
# Currently maintained by Russ Allbery <rra@stanford.edu>
|
||||||
# Version 1.15, 25 Nov 2002
|
# Version 1.22, 2003-07-06
|
||||||
#
|
#
|
||||||
# NOTICE TO INN MAINTAINERS: The version that is shipped with INN
|
# NOTICE TO INN MAINTAINERS: The version that is shipped with INN is the
|
||||||
# is the same as the version that I make available to the rest of the
|
# same as the version that I make available to the rest of the world
|
||||||
# world (including non-INN sites), so please make all changes through me.
|
# (including non-INN sites), so please make all changes through me.
|
||||||
#
|
#
|
||||||
# This program is intended to be compatible with Perl 4 and Perl 5.
|
# This program requires Perl 5, probably at least about Perl 5.003 since
|
||||||
|
# that's when FileHandle was introduced. If you want to use this program
|
||||||
|
# and your Perl is too old, please contact me (rra@stanford.edu) and tell
|
||||||
|
# me about it; I want to know what old versions of Perl are still used in
|
||||||
|
# practice.
|
||||||
|
#
|
||||||
|
# Changes from 1.15 -> 1.22
|
||||||
|
# -- Bump version number to match CVS revision number.
|
||||||
|
# -- Replaced all signature verification code with code that uses detached
|
||||||
|
# signatures. Signatures generated by GnuPG couldn't be verified using
|
||||||
|
# attached signatures without adding a Hash header, and this was the
|
||||||
|
# path of least resistance plus avoids munging problems in the future.
|
||||||
|
# Code taken from PGP::Sign.
|
||||||
#
|
#
|
||||||
# Changes from 1.14 -> 1.15
|
# Changes from 1.14 -> 1.15
|
||||||
# -- Added POD documentation.
|
# -- Added POD documentation.
|
||||||
|
@ -53,8 +65,8 @@ do '@LIBDIR@/innshellvars.pl';
|
||||||
# Changes from 1.9 -> 1.10
|
# Changes from 1.9 -> 1.10
|
||||||
# -- minor diddling for INN 2.0: use $inn'pathtmp if it exists, and
|
# -- minor diddling for INN 2.0: use $inn'pathtmp if it exists, and
|
||||||
# work with the new subst method to find innshellvars.pl
|
# work with the new subst method to find innshellvars.pl
|
||||||
# -- do not truncate the tmp file when opening, in case it is really linked
|
# -- do not truncate the tmp file when opening, in case it is really
|
||||||
# to another file
|
# linked to another file
|
||||||
#
|
#
|
||||||
# Changes from 1.8 -> 1.9
|
# Changes from 1.8 -> 1.9
|
||||||
# -- match 'Bad signature' pgp output to return exit status 3 by removing
|
# -- match 'Bad signature' pgp output to return exit status 3 by removing
|
||||||
|
@ -67,14 +79,17 @@ do '@LIBDIR@/innshellvars.pl';
|
||||||
# -- parse PGP 5.0 'good signature' lines.
|
# -- parse PGP 5.0 'good signature' lines.
|
||||||
# -- allow -test swtich; prints pgp input and output
|
# -- allow -test swtich; prints pgp input and output
|
||||||
# -- look for pgp in INN's innshellvars.pl
|
# -- look for pgp in INN's innshellvars.pl
|
||||||
# -- changed regexp delimiters for stripping $0 to be compatible with old perl
|
# -- changed regexp delimiters for stripping $0 to be compatible with old
|
||||||
|
# perl
|
||||||
#
|
#
|
||||||
# Changes from 1.5 -> 1.6
|
# Changes from 1.5 -> 1.6
|
||||||
# -- handle articles encoded in NNTP format ('.' starting line is doubled,
|
# -- handle articles encoded in NNTP format ('.' starting line is doubled,
|
||||||
# \r\n at line end) by stripping NNTP encoding.
|
# \r\n at line end) by stripping NNTP encoding.
|
||||||
# -- exit 255 with pointer to $HOME or $PGPPATH if pgp can't find key ring.
|
# -- exit 255 with pointer to $HOME or $PGPPATH if pgp can't find key
|
||||||
# (probably doesn't match the necessary error message with ViaCrypt PGP)
|
# ring. (probably doesn't match the necessary error message with
|
||||||
# -- failures also report message-id so the article can be looked up to retry.
|
# ViaCrypt PGP)
|
||||||
|
# -- failures also report message-id so the article can be looked up to
|
||||||
|
# retry.
|
||||||
#
|
#
|
||||||
# Changes from 1.4 -> 1.5
|
# Changes from 1.4 -> 1.5
|
||||||
# -- force English lanugage for 'Good signature from user' by passing
|
# -- force English lanugage for 'Good signature from user' by passing
|
||||||
|
@ -94,8 +109,8 @@ do '@LIBDIR@/innshellvars.pl';
|
||||||
# file, the value of $inn::gpgv will override this.
|
# file, the value of $inn::gpgv will override this.
|
||||||
# $gpgv = '/usr/local/bin/gpgv';
|
# $gpgv = '/usr/local/bin/gpgv';
|
||||||
|
|
||||||
# Path to pgp binary; for PGP 5.0, set the path to the pgpv binary.
|
# Path to pgp binary; for PGP 5.0, set the path to the pgpv binary. If
|
||||||
# If you have INN and the script is able to successfully include your
|
# you have INN and the script is able to successfully include your
|
||||||
# innshellvars.pl file, the value of $inn::pgp will override this.
|
# innshellvars.pl file, the value of $inn::pgp will override this.
|
||||||
$pgp = '/usr/local/bin/pgp';
|
$pgp = '/usr/local/bin/pgp';
|
||||||
|
|
||||||
|
@ -129,9 +144,9 @@ $lockdir = $tmpdir;
|
||||||
# the script will search some known directories for that program. If it
|
# the script will search some known directories for that program. If it
|
||||||
# can't be found & used, everything falls back on stderr logging.
|
# can't be found & used, everything falls back on stderr logging.
|
||||||
#
|
#
|
||||||
# You can test the script's syslogging by running "pgpverify < /some/text/file"
|
# You can test the script's syslogging by running "pgpverify <
|
||||||
# on a file that is not a valid news article. The "non-header at line #"
|
# /some/text/file" on a file that is not a valid news article. The
|
||||||
# error should be syslogged.
|
# "non-header at line #" error should be syslogged.
|
||||||
#
|
#
|
||||||
# $syslog_method = 'unix'; # Unix doman socket, perl5.004_03 or higher
|
# $syslog_method = 'unix'; # Unix doman socket, perl5.004_03 or higher
|
||||||
# $syslog_method = 'inet'; # UDP to port 514 of localhost
|
# $syslog_method = 'inet'; # UDP to port 514 of localhost
|
||||||
|
@ -148,8 +163,8 @@ $syslog_method = 'logger'; # search for the logger program
|
||||||
$syslog_facility = 'news';
|
$syslog_facility = 'news';
|
||||||
$syslog_level = 'err';
|
$syslog_level = 'err';
|
||||||
|
|
||||||
# Prepend the error message with a timestamp?
|
# Prepend the error message with a timestamp? This is only relevant if
|
||||||
# This is only relevant if not syslogging, when errors go to stderr.
|
# not syslogging, when errors go to stderr.
|
||||||
#
|
#
|
||||||
# $log_date = 0; # zero means don't do it.
|
# $log_date = 0; # zero means don't do it.
|
||||||
# $log_date = 1; # non-zero means do it.
|
# $log_date = 1; # non-zero means do it.
|
||||||
|
@ -164,6 +179,10 @@ use strict;
|
||||||
use vars qw($gpgv $pgp $keyring $tmp $tmpdir $lockdir $syslog_method
|
use vars qw($gpgv $pgp $keyring $tmp $tmpdir $lockdir $syslog_method
|
||||||
$syslog_facility $syslog_level $log_date $test $messageid);
|
$syslog_facility $syslog_level $log_date $test $messageid);
|
||||||
|
|
||||||
|
use Fcntl qw(O_WRONLY O_CREAT O_EXCL);
|
||||||
|
use FileHandle;
|
||||||
|
use IPC::Open3 qw(open3);
|
||||||
|
|
||||||
# Turn on test mode if the first argument is '-test'.
|
# Turn on test mode if the first argument is '-test'.
|
||||||
if ($1 && $1 eq '-test') {
|
if ($1 && $1 eq '-test') {
|
||||||
shift @ARGV;
|
shift @ARGV;
|
||||||
|
@ -200,17 +219,30 @@ if ($gpgv) {
|
||||||
# Parse the article headers and generate the PGP message.
|
# Parse the article headers and generate the PGP message.
|
||||||
my ($nntp_format, $header, $dup) = &parse_header();
|
my ($nntp_format, $header, $dup) = &parse_header();
|
||||||
exit 1 unless $$header{'X-PGP-Sig'};
|
exit 1 unless $$header{'X-PGP-Sig'};
|
||||||
my $message = &generate_message($nntp_format, $header, $dup);
|
my ($message, $signature, $version)
|
||||||
&write_message($message);
|
= &generate_message($nntp_format, $header, $dup);
|
||||||
|
|
||||||
|
# The call to pgp needs to be locked because it tries to both read and
|
||||||
|
# write a file named randseed.bin but doesn't do its own locking as it
|
||||||
|
# should, and the consequences of a multiprocess conflict is failure to
|
||||||
|
# verify.
|
||||||
|
my $lock;
|
||||||
|
unless ($gpgv) {
|
||||||
|
$lock = "$lockdir/LOCK.$0";
|
||||||
|
until (&shlock($lock) > 0) {
|
||||||
|
sleep(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Verify the message.
|
# Verify the message.
|
||||||
my ($ok, $signer);
|
my ($ok, $signer) = pgp_verify($signature, $version, $message);
|
||||||
if ($gpgv) {
|
unless ($gpgv) {
|
||||||
($ok, $signer) = &gpg_check($tmp, $keyring);
|
unlink ($lock) or &errmsg("$0: unlink $lock: $!\n");
|
||||||
} else {
|
|
||||||
($ok, $signer) = &pgp_check($tmp, $keyring);
|
|
||||||
}
|
}
|
||||||
print "$signer\n" if $signer;
|
print "$signer\n" if $signer;
|
||||||
|
unless ($ok == 0) {
|
||||||
|
&fail("$0: verification failed\n");
|
||||||
|
}
|
||||||
exit $ok;
|
exit $ok;
|
||||||
|
|
||||||
|
|
||||||
|
@ -245,15 +277,16 @@ sub parse_header {
|
||||||
return ($nntp_format, \%header, \%dup);
|
return ($nntp_format, \%header, \%dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Generate the PGP message to verify, undoing the same transformation as
|
# Generate the PGP message to verify. Takes a flag indicating wire
|
||||||
# is applied by signcontrol (along with other changes required to deal
|
# format, the hash of headers and header duplicates returned by
|
||||||
# with NNTP wire format and to quote the message properly for PGP). Takes
|
# parse_header and returns a list of three elements. The first is the
|
||||||
# the hash of headers and header duplicates returned by parse_header.
|
# message to verify, the second is the signature, and the third is the
|
||||||
|
# version number.
|
||||||
sub generate_message {
|
sub generate_message {
|
||||||
my ($nntp_format, $header, $dup) = @_;
|
my ($nntp_format, $header, $dup) = @_;
|
||||||
|
|
||||||
# The regexp below might be too strict about the structure of pgp sig
|
# The regexp below might be too strict about the structure of PGP
|
||||||
# lines.
|
# signature lines.
|
||||||
|
|
||||||
# The $sep value means the separator between the radix64 signature lines
|
# The $sep value means the separator between the radix64 signature lines
|
||||||
# can have any amount of spaces or tabs, but must have at least one
|
# can have any amount of spaces or tabs, but must have at least one
|
||||||
|
@ -271,9 +304,9 @@ sub generate_message {
|
||||||
|
|
||||||
my ($version, $signed_headers, $signature) = ($1, $3, $4);
|
my ($version, $signed_headers, $signature) = ($1, $3, $4);
|
||||||
$signature =~ s/$sep/\n/g;
|
$signature =~ s/$sep/\n/g;
|
||||||
|
$signature =~ s/^\s+//;
|
||||||
|
|
||||||
my $message = "-----BEGIN PGP SIGNED MESSAGE-----\n\n";
|
my $message = "X-Signed-Headers: $signed_headers\n";
|
||||||
$message .= "X-Signed-Headers: $signed_headers\n";
|
|
||||||
my $label;
|
my $label;
|
||||||
foreach $label (split(",", $signed_headers)) {
|
foreach $label (split(",", $signed_headers)) {
|
||||||
&fail("$0: duplicate signed $label header, can't verify\n")
|
&fail("$0: duplicate signed $label header, can't verify\n")
|
||||||
|
@ -295,146 +328,165 @@ sub generate_message {
|
||||||
s/^\.\./\./;
|
s/^\.\./\./;
|
||||||
s/\r\n$/\n/;
|
s/\r\n$/\n/;
|
||||||
}
|
}
|
||||||
|
$message .= $_;
|
||||||
s/^-/- -/; # pgp quote ("ASCII armor") dashes
|
|
||||||
$message .= $_; # append to output string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$message .= "\n-----BEGIN PGP SIGNATURE-----\n";
|
# Strip off all trailing whitespace for compatibility with the way that
|
||||||
$message .= "Version: $version\n";
|
# pgpverify used to work, using attached signatures.
|
||||||
$message .= $signature;
|
$message =~ s/[ \t]+\n/\n/g;
|
||||||
$message .= "\n-----END PGP SIGNATURE-----\n";
|
|
||||||
return $message;
|
return ($message, $signature, $version);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Write a PGP message to a file. Attempt to do so safely.
|
# Check a detatched signature for given data. Takes a signature block (in
|
||||||
sub write_message {
|
# the form of an ASCII-armored string with embedded newlines), a version
|
||||||
my ($message) = @_;
|
# number (which may be undef), and the message. We return an exit status
|
||||||
|
# and the key id if the signature verified. 0 means good signature, 1
|
||||||
|
# means bad data, 2 means an unknown signer, and 3 means a bad signature.
|
||||||
|
# In the event of an error, we report with errmsg.
|
||||||
|
#
|
||||||
|
# This code is taken almost verbatim from PGP::Sign except for the code to
|
||||||
|
# figure out the PGP style.
|
||||||
|
sub pgp_verify {
|
||||||
|
my ($signature, $version, $message) = @_;
|
||||||
|
chomp $signature;
|
||||||
|
|
||||||
open(TMP,">> $tmp") || &fail("$0: open > $tmp: $!\n");
|
# Ignore SIGPIPE, since we're going to be talking to PGP.
|
||||||
|
local $SIG{PIPE} = 'IGNORE';
|
||||||
|
|
||||||
-f TMP ||
|
# Set the PGP style based on whether $gpgv is set.
|
||||||
&fail("$0: $tmp not a plain file, possible security violation attempt\n");
|
my $pgpstyle = ($gpgv ? 'GPG' : 'PGP2');
|
||||||
(stat(_))[3] == 1 ||
|
|
||||||
&fail("$0: $tmp has hard links, possible security violation attempt\n");
|
|
||||||
|
|
||||||
seek(TMP, 0, 0); # make sure pointer is at beginning of file
|
# Because this is a detached signature, we actually need to save both
|
||||||
truncate(TMP, 0); # make sure file is zero length
|
# the signature and the data to files and then run PGP on the signature
|
||||||
|
# file to make it verify the signature. Because this is a detached
|
||||||
print TMP $message;
|
# signature, though, we don't have to do any data mangling, which makes
|
||||||
close(TMP) || &errmsg("$0: close > $tmp: $!\n");
|
# our lives much easier. It would be nice to do this without having to
|
||||||
&fail("$0: write error for message to check\n")
|
# use temporary files, but I don't see any way to do so without running
|
||||||
if -s $tmp != length($message);
|
# into mangling problems.
|
||||||
|
#
|
||||||
print $message if $test;
|
# PGP v5 *requires* there be some subheader or another. *sigh*. So we
|
||||||
}
|
# supply one if Version isn't given. :)
|
||||||
|
my $umask = umask 077;
|
||||||
# Check the signature using PGP (including 2.6.2, 5.0, and the pgpgpg
|
my $filename = $tmpdir . '/pgp' . time . '.' . $$;
|
||||||
# wrapper for GnuPG).
|
my $sigfile = new FileHandle "$filename.asc", O_WRONLY|O_EXCL|O_CREAT;
|
||||||
sub pgp_check {
|
unless ($sigfile) {
|
||||||
my ($file, $ring) = @_;
|
&errmsg ("Unable to open temp file $filename.asc: $!\n");
|
||||||
|
return (255, undef);
|
||||||
$ENV{'PGPPATH'} = $ring if $ring;
|
|
||||||
|
|
||||||
# The call to pgp needs to be locked because it tries to both read and
|
|
||||||
# write a file named randseed.bin but doesn't do its own locking as it
|
|
||||||
# should, and the consequences of a multiprocess conflict is failure to
|
|
||||||
# verify.
|
|
||||||
my $lock = "$lockdir/LOCK.$0";
|
|
||||||
|
|
||||||
until (&shlock($lock) > 0) {
|
|
||||||
sleep(2);
|
|
||||||
}
|
}
|
||||||
|
if ($pgpstyle eq 'PGP2') {
|
||||||
open(PGP,"$pgp -f +language=en < $file 2>&1 >/dev/null |") ||
|
print $sigfile "-----BEGIN PGP MESSAGE-----\n";
|
||||||
&fail("$0: failed to execute pgp: $!\n");
|
|
||||||
|
|
||||||
undef $/;
|
|
||||||
$_ = <PGP>;
|
|
||||||
|
|
||||||
unlink($lock) || &errmsg("$0: unlink $lock: $!\n");
|
|
||||||
unlink($file) || &errmsg("$0: unlink $file: $!\n");
|
|
||||||
|
|
||||||
unless (close(PGP)) {
|
|
||||||
if ($? >> 8) {
|
|
||||||
&errmsg("$0: pgp exited status " . ($? >> 8) . "\n");
|
|
||||||
} else {
|
|
||||||
&errmsg("$0: pgp died on signal " . ($? & 255) . "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
print if $test;
|
|
||||||
|
|
||||||
# MIT PGP 2.6.2:
|
|
||||||
# Good signature from user "Robert Braver <rbraver@ohww.norman.ok.us>".
|
|
||||||
# ViaCrypt PGP 4.0:
|
|
||||||
# Good signature from user: Robert Braver <rbraver@ohww.norman.ok.us>
|
|
||||||
# GnuPG (via pgpgpg)
|
|
||||||
# Good signature from "news.announce.newgroups"
|
|
||||||
# PGP 5.0i:
|
|
||||||
# Good signature made 1997-07-09 21:57 GMT by key:
|
|
||||||
# 1024 bits, Key ID B88DA9C1, Created 1996-04-10
|
|
||||||
# "news.announce.newgroups"
|
|
||||||
|
|
||||||
my $ok = 2; # unknown signature result is default
|
|
||||||
my $signer;
|
|
||||||
if (/B[Aa][Dd] signature /) {
|
|
||||||
$ok = 3;
|
|
||||||
} elsif (/Good signature from user(: (.*)| "(.*)"\.)/ ||
|
|
||||||
/Good signature from "(.*)"/ ||
|
|
||||||
/Good signature made .* by key:\n.+\n +"(.*)"/) {
|
|
||||||
$ok = 0;
|
|
||||||
$signer = $+;
|
|
||||||
} elsif (/Keyring file '(.*)' does not exist/) {
|
|
||||||
&fail("$0: couldn't access $1. Bad \$HOME or \$PGPPATH?\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ($ok, $signer);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check the signature using GnuPG.
|
|
||||||
sub gpg_check {
|
|
||||||
my ($file, $ring) = @_;
|
|
||||||
|
|
||||||
my $opts = '--quiet --status-fd=1 --logger-fd=1';
|
|
||||||
if ($ring) {
|
|
||||||
$opts .= " --keyring=$ring/pubring.gpg";
|
|
||||||
} else {
|
} else {
|
||||||
$opts .= ' --keyring=pubring.gpg';
|
print $sigfile "-----BEGIN PGP SIGNATURE-----\n";
|
||||||
|
}
|
||||||
|
if (defined $version) {
|
||||||
|
print $sigfile "Version: $version\n";
|
||||||
|
} elsif ($pgpstyle ne 'GPG') {
|
||||||
|
print $sigfile "Comment: Use GnuPG; it's better :)\n";
|
||||||
|
}
|
||||||
|
print $sigfile "\n", $signature;
|
||||||
|
if ($pgpstyle eq 'PGP2') {
|
||||||
|
print $sigfile "\n-----END PGP MESSAGE-----\n";
|
||||||
|
} else {
|
||||||
|
print $sigfile "\n-----END PGP SIGNATURE-----\n";
|
||||||
|
}
|
||||||
|
close $sigfile;
|
||||||
|
|
||||||
|
# Signature saved. Now save the actual message.
|
||||||
|
my $datafile = new FileHandle "$filename", O_WRONLY|O_EXCL|O_CREAT;
|
||||||
|
unless ($datafile) {
|
||||||
|
&errmsg ("Unable to open temp file $filename: $!\n");
|
||||||
|
unlink "$filename.asc";
|
||||||
|
return (255, undef);
|
||||||
|
}
|
||||||
|
print $datafile $message;
|
||||||
|
close $datafile;
|
||||||
|
|
||||||
|
# Figure out what command line we'll be using.
|
||||||
|
my @command;
|
||||||
|
if ($pgpstyle eq 'GPG') {
|
||||||
|
@command = ($gpgv, qw/--quiet --status-fd=1 --logger-fd=1/);
|
||||||
|
} else {
|
||||||
|
@command = ($pgp, '+batchmode');
|
||||||
}
|
}
|
||||||
|
|
||||||
open(PGP, "$gpgv $opts $file 2> /dev/null |") ||
|
# Now, call PGP to check the signature. Because we've written
|
||||||
&fail("$0: failed to execute $gpgv: $!\n");
|
# everything out to a file, this is actually fairly simple; all we need
|
||||||
|
# to do is grab stdout. PGP prints its banner information to stderr, so
|
||||||
|
# just ignore stderr. Set PGPPATH if desired.
|
||||||
|
local $ENV{PGPPATH} = $keyring if ($keyring && $pgpstyle ne 'GPG');
|
||||||
|
if ($keyring && $pgpstyle eq 'GPG') {
|
||||||
|
push (@command, "--keyring=$keyring/pubring.gpg");
|
||||||
|
}
|
||||||
|
push (@command, "$filename.asc");
|
||||||
|
push (@command, $filename);
|
||||||
|
my $input = new FileHandle;
|
||||||
|
my $output = new FileHandle;
|
||||||
|
my $pid = eval { open3 ($input, $output, $output, @command) };
|
||||||
|
if ($@) {
|
||||||
|
&errmsg ($@);
|
||||||
|
&errmsg ("Execution of $command[0] failed.\n");
|
||||||
|
unlink ($filename, "$filename.asc");
|
||||||
|
return (255, undef);
|
||||||
|
}
|
||||||
|
close $input;
|
||||||
|
|
||||||
undef $/;
|
# Check for the message that gives us the key status and return the
|
||||||
$_ = <PGP>;
|
# appropriate thing to our caller. This part is a zoo due to all of the
|
||||||
|
# different formats used. GPG has finally done the right thing and
|
||||||
unlink($file) || &errmsg("$0: unlink $file: $!\n");
|
# implemented a separate status stream with parseable data.
|
||||||
|
#
|
||||||
unless (close(PGP)) {
|
# MIT PGP 2.6.2 and PGP 6.5.2:
|
||||||
if ($? >> 8) {
|
# Good signature from user "Russ Allbery <rra@stanford.edu>".
|
||||||
&errmsg("$0: gpgv exited status " . ($? >> 8) . "\n");
|
# ViaCrypt PGP 4.0:
|
||||||
|
# Good signature from user: Russ Allbery <rra@stanford.edu>
|
||||||
|
# PGP 5.0:
|
||||||
|
# Good signature made 1999-02-10 03:29 GMT by key:
|
||||||
|
# 1024 bits, Key ID 0AFC7476, Created 1999-02-10
|
||||||
|
# "Russ Allbery <rra@stanford.edu>"
|
||||||
|
#
|
||||||
|
# Also, PGP v2 prints out "Bad signature" while PGP v5 uses "BAD
|
||||||
|
# signature", and PGP v6 reverts back to "Bad signature".
|
||||||
|
local $_;
|
||||||
|
local $/ = '';
|
||||||
|
my $signer;
|
||||||
|
my $ok = 255;
|
||||||
|
while (<$output>) {
|
||||||
|
if ($pgpstyle eq 'GPG') {
|
||||||
|
if (/\[GNUPG:\]\s+GOODSIG\s+\S+\s+(\S+)/) {
|
||||||
|
$ok = 0;
|
||||||
|
$signer = $1;
|
||||||
|
} elsif (/\[GNUPG:\]\s+NODATA/ || /\[GNUPG:\]\s+UNEXPECTED/) {
|
||||||
|
$ok = 1;
|
||||||
|
} elsif (/\[GNUPG:\]\s+NO_PUBKEY/) {
|
||||||
|
$ok = 2;
|
||||||
|
} elsif (/\[GNUPG:\]\s+BADSIG\s+/) {
|
||||||
|
$ok = 3;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
&errmsg("$0: gpgv died on signal " . ($? & 255) . "\n");
|
if (/^Good signature from user(?::\s+(.*)|\s+\"(.*)\"\.)$/m) {
|
||||||
|
$signer = $+;
|
||||||
|
$ok = 0;
|
||||||
|
last;
|
||||||
|
} elsif (/^Good signature made .* by key:\n.+\n\s+\"(.*)\"/m) {
|
||||||
|
$signer = $1;
|
||||||
|
$ok = 0;
|
||||||
|
last;
|
||||||
|
} elsif (/^\S+: Good signature from \"(.*)\"/m) {
|
||||||
|
$signer = $1;
|
||||||
|
$ok = 0;
|
||||||
|
last;
|
||||||
|
} elsif (/^(?:\S+: )?Bad signature /im) {
|
||||||
|
$ok = 3;
|
||||||
|
last;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
close $input;
|
||||||
print if $test;
|
waitpid ($pid, 0);
|
||||||
|
unlink ($filename, "$filename.asc");
|
||||||
my $ok = 255; # default exit status
|
umask $umask;
|
||||||
my $signer;
|
return ($ok, $signer || '');
|
||||||
if (/\[GNUPG:\]\s+GOODSIG\s+\S+\s+(\S+)/) {
|
|
||||||
$ok = 0;
|
|
||||||
$signer = $1;
|
|
||||||
} elsif (/\[GNUPG:\]\s+NODATA/ || /\[GNUPG:\]\s+UNEXPECTED/) {
|
|
||||||
$ok = 1;
|
|
||||||
} elsif (/\[GNUPG:\]\s+NO_PUBKEY/) {
|
|
||||||
$ok = 2;
|
|
||||||
} elsif (/\[GNUPG:\]\s+BADSIG\s+/) {
|
|
||||||
$ok = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ($ok, $signer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Log an error message, attempting syslog first based on $syslog_method
|
# Log an error message, attempting syslog first based on $syslog_method
|
||||||
|
@ -519,7 +571,6 @@ sub errmsg {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub fail {
|
sub fail {
|
||||||
unlink($tmp);
|
|
||||||
&errmsg($_[0]);
|
&errmsg($_[0]);
|
||||||
exit 255;
|
exit 255;
|
||||||
}
|
}
|
||||||
|
@ -574,9 +625,9 @@ sub shlock {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
# either this process unlinked the lockfile because it was bogus,
|
# either this process unlinked the lockfile because it was bogus, or
|
||||||
# or between this process's link() and open() the other process
|
# between this process's link() and open() the other process holding
|
||||||
# holding the lock unlinked it. This process can now try to aquire.
|
# the lock unlinked it. This process can now try to aquire.
|
||||||
if (! link($ltmp, $file)) {
|
if (! link($ltmp, $file)) {
|
||||||
unlink($ltmp);
|
unlink($ltmp);
|
||||||
return $! == &EEXIST ? 0 : -1; # maybe another proc grabbed the lock
|
return $! == &EEXIST ? 0 : -1; # maybe another proc grabbed the lock
|
||||||
|
@ -664,6 +715,8 @@ invoking the B<pgp> or B<gpgv> program. It is the responsibility of the
|
||||||
person who installs B<pgpverify> to ensure that when B<pgp> or B<gpgv>
|
person who installs B<pgpverify> to ensure that when B<pgp> or B<gpgv>
|
||||||
runs, it has the ability to locate and read a PGP key file that contains
|
runs, it has the ability to locate and read a PGP key file that contains
|
||||||
the PGP public keys for the appropriate Usenet hierarchy administrators.
|
the PGP public keys for the appropriate Usenet hierarchy administrators.
|
||||||
|
B<pgpverify> can be pointed to an appropriate key ring by editing
|
||||||
|
variables at the beginning of this script.
|
||||||
|
|
||||||
=head1 NOTES
|
=head1 NOTES
|
||||||
|
|
||||||
|
@ -716,7 +769,8 @@ hierarchy administration.
|
||||||
=head1 HISTORY
|
=head1 HISTORY
|
||||||
|
|
||||||
B<pgpverify> was written by David C Lawrence <tale@isc.org>. Manual page
|
B<pgpverify> was written by David C Lawrence <tale@isc.org>. Manual page
|
||||||
provided by James Ralston.
|
provided by James Ralston. It is currently maintained by Russ Allbery
|
||||||
|
<rra@stanford.edu>.
|
||||||
|
|
||||||
=head1 COPYRIGHT AND LICENSE
|
=head1 COPYRIGHT AND LICENSE
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue