X-Git-Url: https://git.sthu.org/?a=blobdiff_plain;f=caff%2Fcaff;h=42e95f0696784f8d186805064818b8197acf63c9;hb=ca33169bf90bb6fa58307a91d2044cae0e83a663;hp=362ff95ff17fdc63ed1b7a15af2b07f621db4c00;hpb=b8faf2bc7b76f47e6cc494c81c0225ff1c4e8527;p=pgp-tools.git diff --git a/caff/caff b/caff/caff index 362ff95..42e95f0 100755 --- a/caff/caff +++ b/caff/caff @@ -90,6 +90,10 @@ configuration file. Import keys from file. Can be supplied more than once. +=item B<--keys-from-gnupg> + +Try to import keys from your standard GnuPG keyrings. + =back =head1 FILES @@ -305,7 +309,7 @@ http://pgp-tools.alioth.debian.org/ =head1 SEE ALSO -gpg(1), pgp-clean(1), /usr/share/doc/signing-party/caff/caffrc.sample. +gpg(1), pgp-clean(1), /usr/share/doc/signing-party/caff/ =cut @@ -325,8 +329,12 @@ use GnuPG::Interface; my %CONFIG; my $REVISION = '$Rev$'; my ($REVISION_NUMER) = $REVISION =~ /(\d+)/; +$REVISION_NUMER = 'unknown' unless defined $REVISION_NUMER; my $VERSION = "0.0.0.$REVISION_NUMER"; +# Global variables +my @KEYIDS; +my $params; ## # Display an error message on STDERR and then exit. @@ -367,7 +375,7 @@ sub trace2($) { sub generate_config() { - notice("Error: \$LOGNAME is not set.\n") unless defined $ENV{'LOGNAME'}; + notice("Error: \$LOGNAME is not set.") unless defined $ENV{'LOGNAME'}; my $gecos = defined $ENV{'LOGNAME'} ? (getpwnam($ENV{LOGNAME}))[6] : undef; my $email; my @keys; @@ -748,13 +756,13 @@ sub import_key($$) { ###### -# Send an email to $address. If $can_encrypt is true then the mail +# Create an email to $address. If $can_encrypt is true then the mail # will be PGP/MIME encrypted to $longkeyid. # # $longkeyid, $uid, and @attached will be used in the email and the template. ###### -#send_mail($address, $can_encrypt, $longkeyid, $uid, @attached); -sub send_mail($$$@) { +# create_mail($address, $can_encrypt, $longkeyid, $uid, @attached); +sub create_mail($$$@) { my ($address, $can_encrypt, $key_id, @keys) = @_; my $template = Text::Template->new(TYPE => 'STRING', SOURCE => $CONFIG{'mail-template'}) @@ -843,12 +851,25 @@ sub send_mail($$$@) { $message_entity->head->add("Subject", "Your signed PGP key 0x$key_id"); $message_entity->head->add("To", $address); $message_entity->head->add("From", '"'.Encode::encode('MIME-Q', $CONFIG{'owner'}).'" <'.$CONFIG{'email'}.'>'); + $message_entity->head->add("Sender", '"'.Encode::encode('MIME-Q', $CONFIG{'owner'}).'" <'.$CONFIG{'email'}.'>'); $message_entity->head->add("Reply-To", $CONFIG{'reply-to'}) if defined $CONFIG{'reply-to'}; $message_entity->head->add("Bcc", $CONFIG{'bcc'}) if defined $CONFIG{'bcc'}; $message_entity->head->add("User-Agent", $USER_AGENT); - mywarn("You have set arguments to pass to Mail::Mailer. Better fix your MTA. (Also, Mail::Mailer's error reporting is non existant, so it won't tell you when it doesn't work.)") if (scalar @{$CONFIG{'mailer-send'}} > 0); + return $message_entity; +}; + +###### +# send a mail message (MIME::Entity) +###### +my $warned_about_broken_mailer_send = 0; +sub send_message($) { + my ($message_entity) = @_; + + if ( (scalar @{$CONFIG{'mailer-send'}} > 0) && !$warned_about_broken_mailer_send) { + mywarn("You have set arguments to pass to Mail::Mailer. Better fix your MTA. (Also, Mail::Mailer's error reporting is non existant, so it won't tell you when it doesn't work.)"); + $warned_about_broken_mailer_send = 1; + }; $message_entity->send(@{$CONFIG{'mailer-send'}}); - $message_entity->stringify(); }; ###### @@ -906,15 +927,13 @@ sub delete_signatures($$$$$$) { # Check the local user keys. # # This function checks if the keyids defined through the --local-user -# command line option or set in .caffrc are valid and known to be one of the -# keyids listed in ./caffrc. The last check ensure we have those keyids -# available in the caff's gnupghome directory. +# command line option or set in ~/.caffrc are valid and known to be one of the +# keyids listed in ~/.caffrc. # # @return an array containing the local user keys\n -# (undef) if no key has been specified +# (undef) if no valid key has been found # -sub get_local_user_keys() -{ +sub get_local_user_keys() { my @local_user = (); my @key_list; @@ -944,7 +963,7 @@ sub get_local_user_keys() } unless (grep (/$user_key$/, @{$CONFIG{'keyid'}})) { - mywarn "Local-user $user_key is not defined as one of your keyid in ./caffrc (it will not be used)."; + mywarn "Local-user $user_key is not defined as one of your keyid in ~/.caffrc (it will not be used)."; next; } @@ -953,40 +972,130 @@ sub get_local_user_keys() # If no local-user key are valid, there is no need to go further unless (defined $local_user[0]) { - myerror (1, "None of the local-user keys seem to be known as a keyid listed in ./caffrc."); + myerror (1, "None of the local-user keys seem to be known as a keyid listed in ~/.caffrc."); } return @local_user; } +## +# Import a key from the user gnupghome into a specified gnupghome. +# +# @param asciikey ascii format of the gpg key to import +# @param dst_gnupghome gnupghome directory where to import the key +# +# @return 0 if successful\n +# 1 if the key could not be exported.\n +# 2 if the key could not be imported. +# +sub import_key_from_user_gnupghome($$) { + my $err; + my ($asciikey, $dst_gpghome) = @_; + + trace("Exporting key $asciikey from your normal GnuPGHOME."); + my $key = export_key(undef, $asciikey); + if (defined $key && $key ne '') { + trace("Importing key $asciikey into $GNUPGHOME."); + if (import_key($GNUPGHOME, $key)) { + $err = 0; + } else { + warn("Could not import $asciikey into caff's gnupghome."); + $err = 2; + } + } else { + $err = 1; + } + + return $err; +} + +## +# Import a key file into a specified gnupghome. +# +# @param keyfile file containing the keys to import +# @param dst_gnupghome gnupghome directory where to import the key +# +# @return 0 if successful\n +# 1 if an error occured. +# +sub import_key_files($$) { + my $err; + my ($keyfile, $dst_gpghome) = @_; + + my $gpg = GnuPG::Interface->new(); + $gpg->call( $CONFIG{'gpg'} ); + $gpg->options->hash_init( + 'homedir' => $dst_gpghome, + 'extra_args' => [ qw{ --no-auto-check-trustdb --trust-model=always } ] ); + $gpg->options->meta_interactive( 0 ); + my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds(); + my $pid = $gpg->import_keys(handles => $handles, command_args => $keyfile); + my ($stdout, $stderr, $status) = readwrite_gpg('', $inputfd, $stdoutfd, $stderrfd, $statusfd); + info("Importing keys from file $keyfile"); + waitpid $pid, 0; + + if ($status !~ /^\[GNUPG:\] IMPORT_OK/m) { + warn $stderr; + $err = 1; + } else { + $err = 0; + } + + return $err; +} + +## +# Import keys to be signed into caff gnupghome directory. +# +# This function imports the keys the user wants to sign into the caff gnupghome +# directory. We looks for the keys in the the user gnupghome directory first, +# and in the key files specified by the user if not all of the keys have been +# found. +# +sub import_keys_to_sign() { + # Check if we can find the gpg key from our normal gnupghome, and then + # try to import it into our working gnupghome directory + if ($CONFIG{'keys-from-gnupg'}) { + foreach my $keyid (@KEYIDS) { + if (!import_key_from_user_gnupghome($keyid, $GNUPGHOME)) { + info("Key $keyid imported from your normal GnuPGHOME."); + } + } + }; + + # Import user specified key files + foreach my $keyfile (@{$CONFIG{'key-files'}}) { + import_key_files($keyfile, $GNUPGHOME); + } + + return 0; +} ################### # argument handling ################### -my @KEYIDS; -my $params; - Getopt::Long::config('bundling'); if (!GetOptions ( - '-h' => \$params->{'help'}, - '--help' => \$params->{'help'}, - '--version' => \$params->{'version'}, - '-V' => \$params->{'version'}, - '-u=s' => \$params->{'local-user'}, - '--local-user=s' => \$params->{'local-user'}, - '-e' => \$params->{'export-old'}, - '--export-old' => \$params->{'export-old'}, - '-E' => \$params->{'no-export-old'}, - '--no-export-old' => \$params->{'no-export-old'}, + '-h' => \$params->{'help'}, + '--help' => \$params->{'help'}, + '--version' => \$params->{'version'}, + '-V' => \$params->{'version'}, + '-u=s' => \$params->{'local-user'}, + '--local-user=s' => \$params->{'local-user'}, + '-e' => \$params->{'export-old'}, + '--export-old' => \$params->{'export-old'}, + '-E' => \$params->{'no-export-old'}, + '--no-export-old' => \$params->{'no-export-old'}, '-m:s' => \$params->{'mail'}, '--mail:s' => \$params->{'mail'}, - '-M' => \$params->{'no-mail'}, - '--no-mail' => \$params->{'no-mail'}, - '-R' => \$params->{'no-download'}, - '--no-download' => \$params->{'no-download'}, - '-S' => \$params->{'no-sign'}, - '--no-sign' => \$params->{'no-sign'}, - '--key-file=s@' => \$params->{'key-files'}, + '-M' => \$params->{'no-mail'}, + '--no-mail' => \$params->{'no-mail'}, + '-R' => \$params->{'no-download'}, + '--no-download' => \$params->{'no-download'}, + '-S' => \$params->{'no-sign'}, + '--no-sign' => \$params->{'no-sign'}, + '--key-file=s@' => \$params->{'key-files'}, + '--keys-from-gnupg' => \$params->{'keys-from-gnupg'}, )) { usage(\*STDERR, 1); }; @@ -999,13 +1108,9 @@ if ($params->{'version'}) { }; usage(\*STDERR, 1) unless scalar @ARGV >= 1; -$CONFIG{'local-user'} = $params->{'local-user'} if defined $params->{'local-user'}; -$CONFIG{'no-download'} = $params->{'no-download'} if defined $params->{'no-download'}; -$CONFIG{'no-sign'} = $params->{'no-sign'} if defined $params->{'no-sign'}; - -$CONFIG{'no-mail'} = $params->{'no-mail'} if defined $params->{'no-mail'}; -$CONFIG{'mail'} = $params->{'mail'} if defined $params->{'mail'}; - +for my $hashkey (qw{local-user no-download no-sign no-mail mail keys-from-gnupg}) { + $CONFIG{$hashkey} = $params->{$hashkey} if defined $params->{$hashkey}; +}; # If old 'no-mail' parameter, or if the 'mail' parameter is set to 'no' if ( defined $CONFIG{'no-mail'} || ( defined $CONFIG{'mail'} && $CONFIG{'mail'} eq 'no' ) ) { @@ -1035,36 +1140,13 @@ for my $keyid (map { split /\n/ } @ARGV) { # caff "`cat txt`" is a single argume # import own keys ################# for my $keyid (@{$CONFIG{'keyid'}}) { - info("Importing key $keyid from your normal GnuPGHome."); - my $key = export_key(undef, $keyid); - if (!defined $key || $key eq '') { - warn ("Did not get key $keyid from your normal GnuPGHome\n"); - next; - }; - my $result = import_key($GNUPGHOME, $key); - unless ($result) { - warn ("Could not import $keyid into caff's gnupghome.\n"); - next; - }; + info("Importing key $keyid from your normal GnuPGHome."); + if (import_key_from_user_gnupghome($keyid, $GNUPGHOME)) { + mywarn("Key $keyid not found."); + } } -######################## -# import keys from files -######################## -foreach my $keyfile (@{$CONFIG{'key-files'}}) { - my $gpg = GnuPG::Interface->new(); - $gpg->call( $CONFIG{'gpg'} ); - $gpg->options->hash_init('homedir' => $GNUPGHOME); - $gpg->options->meta_interactive( 0 ); - my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds(); - my $pid = $gpg->import_keys(handles => $handles, command_args => $keyfile); - my ($stdout, $stderr, $status) = readwrite_gpg('', $inputfd, $stdoutfd, $stderrfd, $statusfd); - info ("Importing keys from $keyfile"); - waitpid $pid, 0; - if ($status !~ /^\[GNUPG:\] IMPORT_OK/m) { - warn $stderr; - } -} +&import_keys_to_sign(); ############################# # receive keys from keyserver @@ -1103,7 +1185,7 @@ if ($CONFIG{'no-download'}) { $speced_key = $spec if $local_keyids{$spec}; }; unless ($speced_key) { - notice ("Imported unexpected key; got: $imported_key\n"); + notice ("Imported unexpected key; got: $imported_key\nAre you trying to work on a subkey?"); next; }; debug ("Imported $imported_key for $speced_key"); @@ -1142,9 +1224,8 @@ if ($CONFIG{'ask-sign'} && ! $CONFIG{'no-sign'}) { $CONFIG{'no-sign'} = ! ask("Continue with signing?", 1); } -unless ($CONFIG{'no-sign'}) -{ - my @local_user = &get_local_user_keys(); +unless ($CONFIG{'no-sign'}) { + my @local_user = get_local_user_keys(); info("Sign the following keys according to your policy, then exit gpg with 'save' after signing each key"); for my $keyid (@keyids_ok) { @@ -1382,17 +1463,18 @@ for my $keyid (@keyids_ok) { if (!$uid->{'is_uat'} && ($uid->{'text'} =~ /@/)) { my $address = $uid->{'text'}; $address =~ s/.*<(.*)>.*/$1/; - if (ask("Mail signature for $uid->{'text'} to '$address'?", $CONFIG{'mail'} ne 'ask-no', $CONFIG{'mail'} eq 'yes')) { - my $mail = send_mail($address, $can_encrypt, $longkeyid, $uid, @attached); - if (defined $mail) { - my $keydir = "$KEYSBASE/$DATE_STRING"; - my $mailfile = "$keydir/$longkeyid.mail.".$uid->{'serial'}.".".sanitize_uid($uid->{'text'}); - open (KEY, ">$mailfile") or die ("Cannot open $mailfile: $!\n"); - print KEY $mail; - close KEY; - } else { - warn "Generating mail failed.\n"; - }; + my $mail = create_mail($address, $can_encrypt, $longkeyid, $uid, @attached); + if (defined $mail) { + my $should_send_mail = ask("Mail signature for $uid->{'text'} to '$address'?", $CONFIG{'mail'} ne 'ask-no', $CONFIG{'mail'} eq 'yes'); + send_message($mail) if $should_send_mail; + + my $keydir = "$KEYSBASE/$DATE_STRING"; + my $mailfile = "$keydir/$longkeyid.mail.".($should_send_mail ? '' : 'unsent.').$uid->{'serial'}.".".sanitize_uid($uid->{'text'}); + open (MAILFILE, ">$mailfile") or die ("Cannot open $mailfile: $!\n"); + print MAILFILE $mail->stringify(); + close MAILFILE; + } else { + warn "Generating mail failed.\n"; }; }; };