-#!/usr/bin/perl -Tw
+#!/usr/bin/perl -w
# (c) 2000, 2002 Christian Kurz <shorty@debian.org>,
# Peter Palfrader <peter@palfrader.org>
my $version = '2.1 ($Id$)';
-# The port to use for keyservers unless given otherwise.
-my $PORT=11371;
-# The default proxy port which is used unless the port is explicitly given
-# in the http_proxy environment variable.
-my $PROXY_PORT=3128;
-
-# Name of the GnuPG binary. The executeable must the in the PATH. This may
-# be overriden using the --gnupg= switch.
-my $GnuPG='gpg';
# Where to find GnuPG's options file.
-my $GNUPGOPTIONS=(defined $ENV{GNUPGHOME} ? $ENV{GNUPGHOME} : $ENV{'HOME'}.'/.gnupg' ) . '/options';
# Full path to the dialog and whiptail executeable.
my $Dialog = '/usr/bin/dialog';
my $Whiptail = '/usr/bin/whiptail';
my $keyserverWasSetOnCmdLine = 0;
-# Queries a remote keyserver (using a proxy if requested) and returns
-# the keyservers anser. No module is used deliberatly to make this
-# script run on as many systems as possible.
-
-sub fetchIt($$$$) {
- my $server = shift;
- my $port = shift;
- my $requestURL = shift;
- my $honorproxy = shift;
-
- my $result;
- my $remote;
-
- if ($honorproxy && defined $ENV{'http_proxy'}) {
- my $proxyserver;
- my $proxyport;
-
- if ( $ENV{'http_proxy'} =~ m#^http://(\S+):(\d+)/?$# ) {
- $proxyserver = $1;
- $proxyport = $2;
- } elsif ( $ENV{'http_proxy'} =~ m#^http://(\S+)/?$# ) {
- $proxyserver = $1;
- $proxyport = $PROXY_PORT;
- } else {
- die ("Unkown http_proxy format");
- };
-
- $remote = IO::Socket::INET->new(
- Proto => 'tcp',
- PeerAddr => $proxyserver,
- PeerPort => $proxyport
- ) || die ("Cannot connect to prox: $!");
-
- my $URL=sprintf("http://%s:%s%s/", $server, $port, $requestURL);
- printf $remote "GET %s HTTP/1.1\n\n", $URL;
- } else {
- $remote = IO::Socket::INET->new(
- Proto => 'tcp',
- PeerAddr => $server,
- PeerPort => $port
- ) || die ("Cannot connect to keysever: $!");
-
- printf $remote "GET %s HTTP/1.1\nHost: %s\n\n\n", $requestURL, $server;
- };
-
-
- {
- local $/;
- $/=undef;
- $result = <$remote>;
- };
- return $result;
-};
+# Maps algorithm numbers to algorithm types as defined in RFC 2400.
+my %ALGOS = (
+ 1 => 'R', # RSA
+ 2 => 'r', # RSA encrypt only (deprecated)
+ 3 => 's', # RSA sign only (deprecated)
+ 16 => 'g', # ElGamal encrypt only
+ 20 => 'g', # ElGamal sign and encrypt (all OpenPGP implementations cryptographically broken, do not use. no longer part of OpenPGP)
+ 17 => 'D' # DSA
+ );
# getHits receives all options as a parameter, calls fetchIT to
sub getHits($) {
my $options = shift;
- die ("$0: No keyserver given!\n") unless (defined $options->{'keyserver'});
-
- my $result = fetchIt(
- $options->{'keyserver'},
- $options->{'port'},
- sprintf("/pks/lookup?op=index&search=%s", $options->{'search'}),
- $options->{'honor-http-proxy'}
- );
-
- $result =~ s/<.*?>//g;
- $result =~ s/>/>/g;
- $result =~ s/</</g;
- $result =~ s/"/"/g;
- $result =~ s/&/&/g;
-
- my @lines = split (/\r?\n/, $result);
-
- shift @lines;
- shift @lines;
- shift @lines;
- shift @lines;
+ my $pid = open(KID, '-|');
+ defined ($pid) or die ("Cannot fork: $!\n");
+ unless ($pid) {
+ close (STDIN);
+ open (STDIN, "/dev/null") || die ("Cannot open /dev/null as stdin: $!\n");
+ # child
+ my @ops = ('gpg');
+ if ($options->{'keyserver'}) {
+ push @ops, '--keyserver='.$options->{'keyserver'};
+ };
+ push @ops, '--command-fd=0';
+ push @ops, '--batch';
+ push @ops, '--no-tty';
+ push @ops, '--with-colons';
+ push @ops, '--fixed-list-mode';
+ push @ops, '--search';
+ push @ops, $options->{'search'};
+ exec(@ops);
+ die ("Cannot exec GnuPG: $!\n");
+ };
my %keys;
my $currentKey;
- for (@lines) {
- if (/^pub /) {
- m, ^pub # pub at the start of the line
- \s+ # whitespace
- (\d+) # bits 1024
- ([A-Za-z]*) # optional type (R or D usually) D
- / # a slash
- ([0-9A-Za-z]+) # keyid 94C09C7F
- \s+ # whitespace
- (\d+)/(\d+)/(\d+) # date 1999/11/10
- \s+ # whitespace
- (.*) # primary user id Peter Palfrader
- ,x or
- warn ("Unexpected format: $_\n"), next;
-
- $currentKey = { 'bits' => $1,
- 'type' => $2,
- 'keyid' => $3,
- 'year' => $4,
- 'month' => $5,
- 'day' => $6,
- 'uid' => [ $7 ]
+ while (<KID>) {
+ chomp;
+ my ($type, undef) = split /:/;
+ if ($type eq 'pub') {
+ my ($type, $keyid, $algo, $bits, $created, undef, $revoked) = split /:/;
+ my (undef,undef,undef,$mday,$mon,$year,undef,undef,undef) = localtime ($created);
+ $currentKey = { 'bits' => $bits,
+ 'type' => (defined $ALGOS{$algo} ? $ALGOS{$algo} : '#'.$algo),
+ 'keyid' => $keyid,
+ 'year' => $year+1900,
+ 'month' => $mon+1,
+ 'day' => $mday,
+ 'revoked' => $revoked,
+ 'uid' => []
};
- $keys{ $3 } = $currentKey;
- } elsif (defined $currentKey) {
- s/^\s+//;
- push @{ $currentKey->{'uid'} }, $_;
+ $keys{ $keyid } = $currentKey;
+ } elsif (defined $currentKey && $type eq 'uid') {
+ my ($type, $name) = split /:/;
+ if ($currentKey->{'revoked'} eq 'r') {
+ $name .= ' [REVOKED]';
+ };
+ push @{ $currentKey->{'uid'} }, $name;
};
};
+ close KID;
+ waitpid $pid, 0;
return \%keys;
};
my $keyids = shift;
my $options = shift;
- my @args = ( $options->{'gnupg'},
- '--keyserver',
- $options->{'keyserver'},
- '--recv-keys');
+ my @args = ('gpg');
+ if ($options->{'keyserver'}) {
+ push @args, '--keyserver='.$options->{'keyserver'};
+ };
+ push @args, '--recv-keys';
for my $keyid (@$keyids) {
# untaint keyids
my ($cleanid) = $keyid =~ /^([a-zA-Z0-9]{8})$/;
unless defined $cleanid;
push @args, $cleanid;
}
-
+
print "Calling GnuPG...\n";
exec (@args) || die "can't exec gnupg: $!\n"; # won't return
};
Options:
--keyserver=<keyserver> Select keyserver
- --port=<port> Use a non standard port
--frontend=<frontend> One of whiptail, dialog or plain
--importall Import all matched keys
- --gnupg=<gnupg> use this gnupg binary
- --honor-http-proxy honor the http_proxy environment varibale
--help print this message
EOF
my %options;
GetOptions( \%options,
'keyserver=s',
- 'port=i',
'frontend=s',
'importall',
- 'gnupg=s',
- 'honor-http-proxy',
'version',
'help') or
&usage(1);
&version(0) if ($options{'version'});
&usage(0) if ($options{'help'} || ( scalar(@ARGV) == 0));
- ## If the keyserver was not given on the command line, lurk into
- ## GnuPG's config file, it might be defined there.
- $keyserverWasSetOnCmdLine = defined $options{'keyserver'};
- unless (defined $options{'keyserver'} &&
- defined $options{'honor-http-proxy'} ) {
- if ( open(GNUPGOPTIONS, $GNUPGOPTIONS) ) {
- my $keyserver = $options{'keyserver'};
- while (<GNUPGOPTIONS>) {
- $options{'keyserver'} = $1 if (/^\s*keyserver\s+(\S+?)[#\s]/i && ! defined $keyserver);
- $options{'honor-http-proxy'} = 1 if /^\s*(keyserver-options\s+)honor-http-proxy\s/i;
- };
- close(GNUPGOPTIONS) || warn("Cannot close $GNUPGOPTIONS: $!\n");
- } else {
- warn ("Cannot open $GNUPGOPTIONS: $!\n");
- };
- };
- $options{'port'} = $PORT unless (defined $options{'port'});
- $options{'gnupg'} = $GnuPG unless (defined $options{'gnupg'});
-
- # Untaint it
- $options{'keyserver'} =~ /(.*)/;
- $options{'keyserver'} = $1;
-
## Take all additional arguments to the program as a search target,
## escape the string for use in URLs.
$options{'search'} = join ' ', @ARGV;