[Pgp-tools-commit] r773 - in trunk: caff debian

Guilhem Moulin guilhem-guest at moszumanska.debian.org
Fri Feb 20 19:35:41 UTC 2015


Author: guilhem-guest
Date: 2015-02-20 19:35:41 +0000 (Fri, 20 Feb 2015)
New Revision: 773

Modified:
   trunk/caff/caff
   trunk/debian/changelog
Log:
caff: Fix compatibility with GnuPG 2.1.

Note: Caff is broken with GnuPG <= 2.1.2 due to the standard output not
being flushed properly before status prompts in the pruning. But it
should work in the later version.  See

http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=commit;h=d2a70fd8348d6c11d1960caf2afe0701833dad6a

Modified: trunk/caff/caff
===================================================================
--- trunk/caff/caff	2015-02-20 19:35:32 UTC (rev 772)
+++ trunk/caff/caff	2015-02-20 19:35:41 UTC (rev 773)
@@ -205,6 +205,14 @@
 needed while the upstream GnuPG was not fixed.  Default: what B<gpg>
 is set to.
 
+=item B<secret-keyring> [string]
+
+Path to your secret keyring (GnuPG < 2.1), or to the GnuPGHOME
+of the agent managing the secret key material (GnuPG >= 2.1).
+Default: B<$HOME/.gnupg/secring.gpg>.
+If the value is not a directory with GnuPG >= 2.1, the parent directory
+(i.e., B<$HOME/.gnupg> by default) is considered instead.
+
 =item B<also-encrypt-to> [keyid, or list of keyids]
 
 Additional keyids to encrypt messages to. Default: none.
@@ -416,11 +424,18 @@
 $REVISION_NUMER //= 'unknown';
 my $VERSION = "0.0.0.$REVISION_NUMER";
 my $LOCALE = Encode::find_encoding(langinfo(I18N::Langinfo::CODESET()));
+my $USER_AGENT = "caff $VERSION - http://pgp-tools.alioth.debian.org/";
 
 # Global variables
 my @KEYIDS;
+my @LOCAL_USER;
 my $params;
 
+my $GNUPG_VERSION;
+my $KEYSBASE;
+my $GNUPGHOME;
+
+
 ##
 # Display an error message on STDERR and then exit.
 #
@@ -579,6 +594,14 @@
 	};
 
 	$CONFIG{'caffhome'} //= $ENV{'HOME'}.'/.caff';
+	$KEYSBASE  = $CONFIG{'caffhome'}.'/keys';
+	$GNUPGHOME = $CONFIG{'caffhome'}.'/gnupghome';
+	foreach ($KEYSBASE, $GNUPGHOME) {
+		next if -d $_;
+		info("Creating $_");
+		mkdir $_, 0700 or myerror(1, "Cannot mkdir $_: $!");
+	}
+
 	die ("$PROGRAM_NAME: owner is not defined in $config.\n") unless defined $CONFIG{'owner'};
 	die ("$PROGRAM_NAME: email is not defined in $config.\n") unless defined $CONFIG{'email'};
 	die ("$PROGRAM_NAME: keyid is not defined in $config.\n") unless defined $CONFIG{'keyid'};
@@ -593,23 +616,7 @@
 	$CONFIG{'gpg-sign'} //= $CONFIG{'gpg'};
 	$CONFIG{'gpg-delsig'} //= $CONFIG{'gpg'};
 	check_executable($_, $CONFIG{$_}) for qw/gpg gpg-sign gpg-delsig/;
-	if (defined $CONFIG{'secret-keyring'}) {
-		die ("\$CONFIG{'secret-keyring'} is deprecated and will be removed in a future release. "
-			."Create a symlink to $CONFIG{'secret-keyring'} in $CONFIG{'caffhome'}/gnupghome instead.\n");
-		delete $CONFIG{'secret-keyring'};
-	} else {
-		unless (-d $CONFIG{'caffhome'}.'/gnupghome') {
-			mkdir $CONFIG{'caffhome'}.'/gnupghome', 0700 or die "Cannot mkdir: $!\n";
-		}
-		foreach my $sec (qw/secring.gpg private-keys-v1.d/) {
-			my $osec = ($ENV{'GNUPGHOME'} || "$ENV{'HOME'}/.gnupg") .'/'. $sec;
-			my $nsec = $CONFIG{'caffhome'}.'/gnupghome/'.$sec;
-			unless (-e $nsec or -l $nsec) {
-				info ("Creating symlink $nsec to $osec.");
-				symlink $osec, $nsec or die "Cannot create symlink: $!\n";
-			}
-		}
-	}
+	$CONFIG{'secret-keyring'} //= ($ENV{'GNUPGHOME'} || "$ENV{'HOME'}/.gnupg") . '/secring.gpg';
 	$CONFIG{'no-download'} //= 0;
 	$CONFIG{'no-sign'} //= 0;
 	$CONFIG{'key-files'} //= [];
@@ -634,11 +641,6 @@
 	$CONFIG{'also-lsign-in-gnupghome'} = 'no' if $CONFIG{'no-sign'};
 	die "$PROGRAM_NAME: invalid value for 'also-lsign-in-gnupghome': $CONFIG{'also-lsign-in-gnupghome'}.\n"
 		unless grep { $_ eq $CONFIG{'also-lsign-in-gnupghome'} } qw/auto ask no/;
-	# ensure there is a working gpg-agent if $CONFIG{'also-lsign-in-gnupghome'} is 'auto'
-	$CONFIG{'also-lsign-in-gnupghome'} = 'ask'
-		if $CONFIG{'also-lsign-in-gnupghome'} eq 'auto' and
-		   $CONFIG{'gpg-sign-type'} !~ /l/ and
-		   system (qw/gpg-agent -q/) == 0;
 	$CONFIG{'show-photos'} //= 0;
 };
 
@@ -799,15 +801,8 @@
 my $KEYEDIT_SIGNUID_CLASS_PROMPT = qr/GET_LINE sign_uid\.class/;
 my $KEYEDIT_SIGNUID_PROMPT = qr/GET_BOOL sign_uid\.okay/;
 
-load_config;
-my $USER_AGENT = "caff $VERSION - http://pgp-tools.alioth.debian.org/";
+load_config();
 
-my $KEYSBASE =  $CONFIG{'caffhome'}.'/keys';
-my $GNUPGHOME = $CONFIG{'caffhome'}.'/gnupghome';
-
--d $KEYSBASE  || make_path($KEYSBASE , {mode => 0700}) or die ("Cannot create $KEYSBASE: $!\n");
--d $GNUPGHOME || make_path($GNUPGHOME, {mode => 0700}) or die ("Cannot create $GNUPGHOME: $!\n");
-
 my $NOW = time;
 my  ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($NOW);
 my $DATE_STRING = sprintf("%04d-%02d-%02d", $year+1900, $mon+1, $mday);
@@ -1365,6 +1360,53 @@
 	push @KEYIDS, uc($keyid);
 };
 
+
+$GNUPG_VERSION = `$CONFIG{'gpg'} --with-colons --list-config version`;
+chomp $GNUPG_VERSION;
+$GNUPG_VERSION =~ s/^cfg:version:(\d+\.\d+).*/$1/;
+debug "gpg (GnuPG) $GNUPG_VERSION";
+
+if ($GNUPG_VERSION >= 2.1) {
+	my @sockets;
+	unless ($CONFIG{'no-sign'}) {
+		# Ensure we have a working agent for our secret key material
+		my $secdir = $CONFIG{'secret-keyring'};
+		$secdir =~ s#/[^/]+$## unless -d $secdir;
+		mysystem('gpg-connect-agent', '--homedir', $secdir, '/bye');
+		push @sockets, "$secdir/S.gpg-agent";
+	}
+	unless ($CONFIG{'no-download'}) {
+		# Ensure we have a working agent for the downloads
+		my $homedir = ($ENV{'GNUPGHOME'} || "$ENV{'HOME'}/.gnupg");
+		mysystem('gpg-connect-agent', '--homedir', $homedir, '--dirmngr', '/bye');
+		push @sockets, "$homedir/S.dirmngr";
+	}
+
+	foreach my $socket (@sockets) {
+		my $l = $socket =~ s#.*/(S\.[^/]+)$#$GNUPGHOME/$1#r;
+		if (-l $l) {
+			unlink $l
+		}
+		elsif (-S $l) {
+			# don't run agents in caff's homedir
+			myerror(1, "$l: socket exists; runaway gpg-agent?");
+		}
+		elsif (! -S $socket) {
+			myerror(1, "Missing socket $socket");
+		}
+		debug "Creating symlink $l to $socket";
+		symlink $socket, $l or myerror(1, "Cannot symlink: $!");
+	}
+}
+elsif ($CONFIG{'also-lsign-in-gnupghome'} eq 'auto' and $CONFIG{'gpg-sign-type'} !~ /l/) {
+	# Ensure there is a working gpg-agent if $CONFIG{'also-lsign-in-gnupghome'} is 'auto'
+	system qw/gpg-agent -q/;
+	unless ($? == 0) {
+		mywarn("No gpg-agent running: set \$CONFIG{'also-lsign-in-gnupghome'} = 'ask'");
+		$CONFIG{'also-lsign-in-gnupghome'} = 'ask';
+	}
+}
+
 #################
 # import own keys
 #################
@@ -1455,38 +1497,8 @@
 	$CONFIG{'no-sign'} = ! ask("Continue with signing?", 1);
 }
 
-my @LOCAL_USER;
-unless ($CONFIG{'no-sign'}) {
-	@LOCAL_USER = get_local_user_keys();
+ at LOCAL_USER = get_local_user_keys() unless $CONFIG{'no-sign'};
 
-	# If a local user doesn't have a secret key, gpg --edit-key prints "gpg:
-	# error reading key: No secret key" and returns with status 2.  We're
-	# trying to display a more helpful message here.
-	my $gpg = GnuPG::Interface->new();
-	$gpg->call( $CONFIG{'gpg'} );
-	$gpg->options->hash_init(
-		'homedir' => $GNUPGHOME,
-		'meta_interactive' => 0,
-		'always_trust' => 1,
-		'extra_args' => [ qw{ --no-auto-check-trustdb --fingerprint --with-colons --fixed-list-mode } ] );
-	my $handles = make_gpg_fds( stdin => $NULL, stdout => undef, stderr => \*STDERR );
-	my $pid = $gpg->list_secret_keys( handles => $handles, command_args => \@LOCAL_USER );
-
-	my $stdout = $handles->{stdout};
-	my %failed = map {$_ => 1} @LOCAL_USER;
-	while (<$stdout>) {
-		next unless /^fpr:(?:[^:]*:){8}([0-9A-F]{40})(?::.*)?$/;
-		delete @failed{ grep { $1 =~ /\Q$_\E$/ } @LOCAL_USER };
-	}
-	waitpid $pid, 0;
-	close $stdout;
-
-	die "Error: No secret key for ".join(',',keys %failed).".\n".
-		"If an empty secret keyring 'secring.gpg' ('private-keys-v1.d' for GnuPG 2.1 and latter) ".
-		"was automatically created by gpg(1) in $CONFIG{'caffhome'}/gnupghome, you may want to remove it and restart caff to ".
-		"use the secret keyring from your default GnuPGHOME instead.\n" if %failed;
-}
-
 my %KEYS;
 for my $keyid (@keyids_ok) {
 	# get key listing (and ensure there is no collision)
@@ -1570,6 +1582,7 @@
 			my @command = ($CONFIG{'gpg-sign'});
 			push @command, '--local-user', $local_user;
 			push @command, "--homedir=$GNUPGHOME";
+			push @command, '--secret-keyring', $CONFIG{'secret-keyring'};
 			push @command, qw/--no-auto-check-trustdb --trust-model=always/;
 			push @command, '--edit-key', $keyid;
 			push @command, 'showphoto' if $CONFIG{'show-photos'};
@@ -1710,6 +1723,7 @@
 			foreach my $local_user (@LOCAL_USER) {
 				my @command = ($CONFIG{'gpg-sign'});
 				push @command, '--local-user', $local_user;
+				push @command, '--secret-keyring', $CONFIG{'secret-keyring'};
 				push @command, qw/--no-auto-check-trustdb --trust-model=always/;
 				push @command, '--edit-key', $keyid;
 				push @command, 'showphoto' if $CONFIG{'show-photos'};

Modified: trunk/debian/changelog
===================================================================
--- trunk/debian/changelog	2015-02-20 19:35:32 UTC (rev 772)
+++ trunk/debian/changelog	2015-02-20 19:35:41 UTC (rev 773)
@@ -1,11 +1,12 @@
 signing-party (1.1.13-1) UNRELEASED; urgency=low
 
   * caff:
-    + Deprecate $CONFIG{'secret-keyring'}.  Instead, the secret keyring
-      (secring.gpg for GnuPG < 2.1, private-keys-v1.d for GnuPG 2.1 or latter)
-      is to be symlinked into ~/.caff/gnupghome.  Symlinks are automatically
-      created if ~/.caff/gnupghome doesn't contain a secret keyring or
-      directory.  (Closes: #771857)
+    + Fix broken compatibility with GnuPG 2.1, due to --secret-keyring being
+      ignored by the most recent gpg(1).  On those we automaticalyl symlink
+      the S.gpg-agent (unless 'no-sign') and S.dirmngr (unless 'no-download')
+      sockets to avoid spawning new agents in caff's GNUPGHOME.  This require
+      an extra call to gpg(1) at the begining to determine the version.
+      (Closes: #771857)
     + Don't redirect gpg's STDERR when listing the keys, as it makes gpg
       croak on OSX when GPG_TTY is not set.  Patch from Ewen McNeill.
       (Closes: #775702)




More information about the Pgp-tools-commit mailing list