[git] Pinentry - branch, master, updated. pinentry-0.9.1-18-g3a8daef

by Neal H. Walfield cvs at cvs.gnupg.org
Thu May 7 14:44:59 CEST 2015


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The standard pinentry collection".

The branch, master has been updated
       via  3a8daef81c49dc3c04b6703a0384381cb43eb91b (commit)
       via  c6eaa7bf8300f524de41956a339ca0ed3af4656e (commit)
      from  aa98f25ddcc3c36035f18249443cec15d16e8fa5 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 3a8daef81c49dc3c04b6703a0384381cb43eb91b
Author: Neal H. Walfield <neal at gnu.org>
Date:   Thu May 7 14:44:37 2015 +0200

    Minor documentation cleanups.

diff --git a/doc/pinentry.texi b/doc/pinentry.texi
index c2df479..2c8aae1 100644
--- a/doc/pinentry.texi
+++ b/doc/pinentry.texi
@@ -105,7 +105,7 @@ passphrases. It is usually invoked by @sc{gpg-agent}
 @pinentry{} comes in several flavors to fit the look and feel of the
 used GUI toolkit: A @sc{GTK+} based one named @code{pinentry-gtk}; a
 @sc{Qt} based one named @code{pinentry-qt}; and, two non-graphical
-ones @code{pinentry-curses}, which uses curses and
+ones @code{pinentry-curses}, which uses curses, and
 @code{pinentry-tty}, which doesn't require anything more than a simple
 terminal.  Not all of them are necessarily available on your
 installation.  If curses is supported on your system, the GUI-based
@@ -212,10 +212,10 @@ options using Assuan protocol options.
 @c  Assuan Protocol
 @c
 @node Protocol
- at chapter pinentry's Assuan Protocol
+ at chapter @pinentry{}'s Assuan Protocol
 
 The @pinentry{} should never service more than one connection at once.
-It is reasonable to exec the PIN-Entry prior to a request.
+It is reasonable to exec the @pinentry{} prior to a request.
 
 The @pinentry{} does not need to stay in memory because the
 @sc{gpg-agent} has the ability to cache passphrases.  The usual way to
@@ -224,10 +224,10 @@ fork/exec the @pinentry{}.  The communication is then done by means of
 the protocol described here until the client is satisfied with the
 result.
 
-Although it is called a @pinentry{}, it allow entering reasonably long
-strings (strings that are up to 2048 characters long are supported by
-every pinentry).  The client using the PIN-Entry has to check for
-correctness.
+Although it is called a @pinentry{}, it allows entering reasonably
+long strings (strings that are up to 2048 characters long are
+supported by every pinentry).  The client using the @pinentry{} has to
+check for correctness.
 
 Note that all strings are expected to be encoded as UTF-8; @pinentry{}
 takes care of converting it to the locally used codeset.  To include

commit c6eaa7bf8300f524de41956a339ca0ed3af4656e
Author: Neal H. Walfield <neal at gnu.org>
Date:   Thu May 7 14:43:48 2015 +0200

    Add support for saving the passphrase with libsecret.
    
    * configure.ac (COMMON_CFLAGS): New variable.  AC_SUBST it.
    (COMMON_LIBS): Likewise.  AC_SUBST it.
    (LIBSECRET_CFLAGS): Likewise.
    (LIBSECRET_LIBS): Likewise.
    (--enable-libsecret): Add option to enable support for libsecret.  If
    enabled, check for its presense.
    * pinentry/password-cache.h: New field.
    * pinentry/password-cache.c: New field.
    * pinentry/pinentry.h (struct pinentry): Add fields pin_from_cache,
    allow_external_password_cache, tried_password_cache, keyinfo, and
    may_cache_password.
    * pinentry/pinentry.c: Include "password-cache.h".
    (pinentry): Initialize new fields.
    (option_handler): Handle the "allow-external-password-cache" option.
    (cmd_setkeyinfo): Implement it.
    (cmd_getpin): Read the password from the cache, if appropriate.  Save
    it to the cache, if appropriate.
    * pinentry/Makefile.am (AM_CPPFLAGS): Add $(COMMON_CFLAGS).
    (LDADD): Add $(COMMON_LIBS).
    (libpinentry_a_SOURCES): Add password-cache.h
    password-cache.c.
    * gtk+-2/pinentry-gtk-2.c (may_save_passphrase_toggled): New function.
    (create_window): Take additional parameter, the pinentry's context.
    Update callers.
    [HAVE_LIBSECRET]: Show a checkbox asking whether the passphrase should
    be saved.
    * gtk+-2/Makefile.am (AM_CPPFLAGS): Add $(COMMON_CFLAGS).
    (LDADD): Add $(COMMON_LIBS).
    * curses/Makefile.am (AM_CPPFLAGS): Add $(COMMON_CFLAGS).
    (LDADD): Add $(COMMON_LIBS).
    * tty/Makefile.am (AM_CPPFLAGS): Add $(COMMON_CFLAGS).
    (LDADD): Add $(COMMON_LIBS).
    * doc/pinentry.texi (Protocol): Update documentation.  Describe the
    protocol and provide some justification.

diff --git a/configure.ac b/configure.ac
index 271234f..ec7bbfd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
 # configure.ac
 # Copyright (C) 1999 Robert Bihlmeyer <robbe at orcus.priv.at>
-# Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
+# Copyright (C) 2001, 2002, 2003, 2004, 2007, 2015 g10 Code GmbH
 #
 # This file is part of PINENTRY.
 #
@@ -167,6 +167,12 @@ dnl Checks for library functions.
 AC_CHECK_FUNCS(seteuid stpcpy mmap)
 GNUPG_CHECK_MLOCK
 
+# Common libraries and cflags.
+COMMON_CFLAGS=
+COMMON_LIBS=
+AC_SUBST(COMMON_CFLAGS)
+AC_SUBST(COMMON_LIBS)
+
 dnl Checks for libassuan.
 dnl -> None required because we use a stripped down version of libassuan.
 
@@ -310,6 +316,45 @@ if test "$pinentry_gtk_2" != "no"; then
 fi
 AM_CONDITIONAL(BUILD_PINENTRY_GTK_2, test "$pinentry_gtk_2" = "yes")
 
+dnl
+dnl Check for libsecret.
+dnl
+AC_ARG_ENABLE(libsecret,
+            AC_HELP_STRING([--enable-libsecret],
+	    [optionally cache passphrases using libsecret]),
+            libsecret=$enableval, libsecret=maybe)
+
+dnl check for pkg-config
+if test "$libsecret" != "no"; then
+        AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+	if test x"${PKG_CONFIG}" = xno ; then
+		libsecret=no
+	fi
+fi
+
+dnl check if the module libsecret exists
+if test "$libsecret" != "no"; then
+	AC_MSG_CHECKING([for libsecret])
+	"${PKG_CONFIG}" --exists 'libsecret-1'
+	if test $? -ne 0 ; then
+		AC_MSG_RESULT([no])
+		AC_MSG_WARN([pkg-config could not find the modules libsecret-1])
+		libsecret=no
+	else
+		AC_MSG_RESULT([yes])
+		LIBSECRET_CFLAGS=`"${PKG_CONFIG}" --cflags 'libsecret-1'`
+		LIBSECRET_LIBS=`"${PKG_CONFIG}" --libs 'libsecret-1'`
+		libsecret=yes
+	fi
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBSECRET, test "$libsecret" = "yes")
+if test "$libsecret" = "yes"; then
+  AC_DEFINE(HAVE_LIBSECRET, 1,
+    [The pinentries should optionally cache the passphrase using libsecret.])
+
+  COMMON_CFLAGS="$COMMON_CFLAGS $LIBSECRET_CFLAGS"
+  COMMON_LIBS="$COMMON_LIBS $LIBSECRET_LIBS"
+fi
 
 dnl
 dnl Check for Qt4 pinentry program.
@@ -453,5 +498,7 @@ AC_MSG_NOTICE([
 
 	Fallback to Curses: $fallback_curses
 
+	libsecret ........: $libsecret
+
 	Default Pinentry .: $PINENTRY_DEFAULT
 ])
diff --git a/curses/Makefile.am b/curses/Makefile.am
index 404a8ed..e8ea031 100644
--- a/curses/Makefile.am
+++ b/curses/Makefile.am
@@ -1,5 +1,5 @@
 # Makefile.am - PIN entry curses frontend.
-# Copyright (C) 2002 g10 Code GmbH
+# Copyright (C) 2002, 2015 g10 Code GmbH
 #
 # This file is part of PINENTRY.
 #
@@ -21,8 +21,9 @@
 
 bin_PROGRAMS = pinentry-curses
 
-AM_CPPFLAGS = $(NCURSES_INCLUDE) -I$(top_srcdir)/pinentry
-LDADD = ../pinentry/libpinentry.a ../pinentry/libpinentry-curses.a \
+AM_CPPFLAGS = $(COMMON_CFLAGS) $(NCURSES_INCLUDE) -I$(top_srcdir)/pinentry
+LDADD = $(COMMON_LIBS) \
+	../pinentry/libpinentry.a ../pinentry/libpinentry-curses.a \
 	../assuan/libassuan.a ../secmem/libsecmem.a \
 	$(LIBCAP) $(LIBCURSES) $(LIBICONV)
 
diff --git a/doc/pinentry.texi b/doc/pinentry.texi
index fb4017e..c2df479 100644
--- a/doc/pinentry.texi
+++ b/doc/pinentry.texi
@@ -414,6 +414,51 @@ strings.
 The strings are subject to accelerator marking, see SETPROMPT for
 details.
 
+ at item Passphrase caching
+
+Some environments, such as GNOME, cache passwords and passphrases.
+The @pinentry{} should only use an external cache if the
+ at code{allow-external-password-cache} option was set and a stable key
+identifier (using SETKEYINFO) was provided.  In this case, if the
+passphrase was read from the cache, the @pinentry{} should send the
+ at code{PASSWORD_FROM_CACHE} status message before returning the
+passphrase.  This indicates to GPG Agent that it should not increment
+the passphrase retry counter.
+
+ at example
+  C: OPTION allow-external-password-cache
+  S: OK
+  C: SETKEYINFO key-grip
+  S: OK
+  C: getpin
+  S: S PASSWORD_FROM_CACHE
+  S: D 1234
+  C: OK
+ at end example
+
+Note: if @code{allow-external-password-cache} is not specified, an
+external password cache must not be used: this can lead to subtle
+bugs.  In particular, if this option is not specified, then GPG Agent
+does not recognize the @code{PASSWORD_FROM_CACHE} status message and
+will count trying a cached password against the password retry count.
+If the password retry count is 1, then the user will never have the
+opportunity to correct the cached password.
+
+Note: it is strongly recommended that a pinentry supporting this
+feature provide the user an option to enable it manually.  That is,
+saving a passphrase in an external password manager should be opt-in.
+
+The key identifier provided by SETKEYINFO is the key grip, which is
+not the OpenPGP Key ID.  To map the key grip to a key, you can use the
+following:
+
+ at example
+  # gpg2 --with-keygrip --list-secret-keys
+ at end example
+
+ at noindent
+and search for the key grip.
+
 @end table
 
 @c ---------------------------------------------------------------------
diff --git a/gtk+-2/Makefile.am b/gtk+-2/Makefile.am
index 94346c0..c98139f 100644
--- a/gtk+-2/Makefile.am
+++ b/gtk+-2/Makefile.am
@@ -1,5 +1,5 @@
 # Makefile.am - PIN entry GTK+ frontend.
-# Copyright (C) 2002 g10 Code GmbH
+# Copyright (C) 2002, 2015 g10 Code GmbH
 #
 # This file is part of PINENTRY.
 #
@@ -29,9 +29,10 @@ ncurses_include =
 libcurses =
 endif
 
-AM_CPPFLAGS = $(GTK2CFLAGS) $(ncurses_include) \
+AM_CPPFLAGS = $(COMMON_CFLAGS) $(GTK2CFLAGS) $(ncurses_include) \
 	-I$(top_srcdir)/secmem -I$(top_srcdir)/pinentry
-LDADD = ../pinentry/libpinentry.a ../assuan/libassuan.a ../secmem/libsecmem.a \
+LDADD = $(COMMON_LIBS) \
+	../pinentry/libpinentry.a ../assuan/libassuan.a ../secmem/libsecmem.a \
 	$(LIBCAP) $(GTK2LIBS) $(libcurses)
 
 pinentry_gtk_2_SOURCES = pinentry-gtk-2.c \
diff --git a/gtk+-2/pinentry-gtk-2.c b/gtk+-2/pinentry-gtk-2.c
index b3698c0..b154831 100644
--- a/gtk+-2/pinentry-gtk-2.c
+++ b/gtk+-2/pinentry-gtk-2.c
@@ -1,6 +1,6 @@
 /* pinentry-gtk-2.c
    Copyright (C) 1999 Robert Bihlmeyer <robbe at orcus.priv.at>
-   Copyright (C) 2001, 2002, 2007 g10 Code GmbH
+   Copyright (C) 2001, 2002, 2007, 2015 g10 Code GmbH
    Copyright (C) 2004 by Albrecht Dreß <albrecht.dress at arcor.de>
 
    pinentry-gtk-2 is a pinentry application for the Gtk+-2 widget set.
@@ -328,6 +328,18 @@ changed_text_handler (GtkWidget *widget)
 }
 
 
+#ifdef HAVE_LIBSECRET
+static void
+may_save_passphrase_toggled (GtkWidget *widget, gpointer data)
+{
+  GtkToggleButton *button = GTK_TOGGLE_BUTTON (widget);
+  pinentry_t ctx = (pinentry_t) data;
+
+  ctx->may_cache_password = gtk_toggle_button_get_active (button);
+}
+#endif
+
+
 static gboolean
 timeout_cb (gpointer data)
 {
@@ -339,7 +351,7 @@ timeout_cb (gpointer data)
 
 
 static GtkWidget *
-create_window (int confirm_mode)
+create_window (pinentry_t ctx, int confirm_mode)
 {
   GtkWidget *w;
   GtkWidget *win, *box;
@@ -552,6 +564,21 @@ create_window (int confirm_mode)
   gtk_box_set_spacing (GTK_BOX (bbox), 6);
   gtk_box_pack_start (GTK_BOX (wvbox), bbox, TRUE, FALSE, 0);
 
+#ifdef HAVE_LIBSECRET
+  if (ctx->allow_external_password_cache && ctx->keyinfo)
+    /* Only show this if we can cache passwords and we have a stable
+       key identifier.  */
+    {
+      w = gtk_check_button_new_with_label ("Save passphrase using libsecret");
+      gtk_box_pack_start (GTK_BOX (box), w, TRUE, FALSE, 0);
+      gtk_widget_show (w);
+
+      g_signal_connect (G_OBJECT (w), "toggled",
+                        G_CALLBACK (may_save_passphrase_toggled),
+			(gpointer) ctx);
+    }
+#endif
+
   if (!pinentry->one_button)
     {
       if (pinentry->cancel)
@@ -661,7 +688,7 @@ gtk_cmd_handler (pinentry_t pe)
   pinentry = pe;
   confirm_value = CONFIRM_CANCEL;
   passphrase_ok = 0;
-  w = create_window (want_pass ? 0 : 1);
+  w = create_window (pe, want_pass ? 0 : 1);
   gtk_main ();
   gtk_widget_destroy (w);
   while (gtk_events_pending ())
diff --git a/pinentry/Makefile.am b/pinentry/Makefile.am
index c3926b2..7fbbab6 100644
--- a/pinentry/Makefile.am
+++ b/pinentry/Makefile.am
@@ -1,5 +1,5 @@
 # Pinentry support library Makefile
-# Copyright (C) 2002 g10 Code GmbH
+# Copyright (C) 2002, 2015 g10 Code GmbH
 #
 # This file is part of PINENTRY.
 #
@@ -29,7 +29,9 @@ endif
 
 noinst_LIBRARIES = libpinentry.a $(pinentry_curses)
 
-AM_CPPFLAGS = -I$(top_srcdir)/assuan -I$(top_srcdir)/secmem
+LDADD = $(COMMON_LIBS)
+AM_CPPFLAGS = $(COMMON_CFLAGS) -I$(top_srcdir)/assuan -I$(top_srcdir)/secmem
 
-libpinentry_a_SOURCES = pinentry.h pinentry.c argparse.c argparse.h
+libpinentry_a_SOURCES = pinentry.h pinentry.c argparse.c argparse.h \
+	password-cache.h password-cache.c
 libpinentry_curses_a_SOURCES = pinentry-curses.h pinentry-curses.c
diff --git a/pinentry/password-cache.c b/pinentry/password-cache.c
new file mode 100644
index 0000000..53bb39f
--- /dev/null
+++ b/pinentry/password-cache.c
@@ -0,0 +1,131 @@
+/* password-cache.c - Password cache support.
+   Copyright (C) 2015 g10 Code GmbH
+
+   This file is part of PINENTRY.
+
+   PINENTRY is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   PINENTRY is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_LIBSECRET
+# include <libsecret/secret.h>
+#endif
+
+#include "password-cache.h"
+#include "memory.h"
+
+#ifdef HAVE_LIBSECRET
+static const SecretSchema *
+gpg_schema (void)
+{
+    static const SecretSchema the_schema = {
+        "org.gnupg.Passphrase", SECRET_SCHEMA_NONE,
+        {
+	  { "stored-by", SECRET_SCHEMA_ATTRIBUTE_STRING },
+	  { "key-grip", SECRET_SCHEMA_ATTRIBUTE_STRING },
+	  { "NULL", 0 },
+	}
+    };
+    return &the_schema;
+}
+
+static char *
+key_grip_to_label (const char *key_grip)
+{
+  char *label = NULL;
+  if (asprintf(&label, "GnuPG: %s", key_grip) < 0)
+    return NULL;
+  return label;
+}
+#endif
+
+void
+password_cache_save (const char *key_grip, const char *password)
+{
+#ifdef HAVE_LIBSECRET
+  char *label;
+  GError *error = NULL;
+
+  if (! *key_grip)
+    return;
+
+  label = key_grip_to_label (key_grip);
+  if (! label)
+    return;
+
+  if (! secret_password_store_sync (gpg_schema (),
+				    SECRET_COLLECTION_DEFAULT,
+				    label, password, NULL, &error,
+				    "stored-by", "GnuPG Pinentry",
+				    "key-grip", key_grip, NULL))
+    {
+      printf("Failed to cache password for key %s with secret service: %s\n",
+	     key_grip, error->message);
+
+      g_error_free (error);
+    }
+
+  free (label);
+#else
+  return;
+#endif
+}
+
+char *
+password_cache_lookup (const char *key_grip)
+{
+#ifdef HAVE_LIBSECRET
+  GError *error = NULL;
+  char *password;
+  char *password2;
+
+  if (! *key_grip)
+    return NULL;
+
+  password = secret_password_lookup_nonpageable_sync
+    (gpg_schema (), NULL, &error,
+     "key-grip", key_grip, NULL);
+
+  if (error != NULL)
+    {
+      printf("Failed to lookup password for key %s with secret service: %s\n",
+	     key_grip, error->message);
+      g_error_free (error);
+      return NULL;
+    }
+  if (! password)
+    /* The password for this key is not cached.  Just return NULL.  */
+    return NULL;
+
+  /* The password needs to be returned in secmem allocated memory.  */
+  password2 = secmem_malloc (strlen (password) + 1);
+  if (password2)
+    strcpy(password2, password);
+  else
+    printf("secmem_malloc failed: can't copy password!\n");
+
+  secret_password_free (password);
+
+  return password2;
+#else
+  return NULL;
+#endif
+}
diff --git a/pinentry/password-cache.h b/pinentry/password-cache.h
new file mode 100644
index 0000000..7c6cd5a
--- /dev/null
+++ b/pinentry/password-cache.h
@@ -0,0 +1,27 @@
+/* password-cache.h - Password cache support interfaces.
+   Copyright (C) 2015 g10 Code GmbH
+
+   This file is part of PINENTRY.
+
+   PINENTRY is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   PINENTRY is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PASSWORD_CACHE_H
+#define PASSWORD_CACHE_H
+
+void password_cache_save (const char *key_grip, const char *password);
+
+char *password_cache_lookup (const char *key_grip);
+
+#endif
diff --git a/pinentry/pinentry.c b/pinentry/pinentry.c
index 04de1aa..7b3fde5 100644
--- a/pinentry/pinentry.c
+++ b/pinentry/pinentry.c
@@ -47,6 +47,7 @@
 #include "secmem-util.h"
 #include "argparse.h"
 #include "pinentry.h"
+#include "password-cache.h"
 
 #ifdef HAVE_W32CE_SYSTEM
 #define getpid() GetCurrentProcessId ()
@@ -67,6 +68,7 @@ struct pinentry pinentry =
     NULL,	/* Cancel button.  */
     NULL,	/* PIN.  */
     2048,	/* PIN length.  */
+    0,          /* pin_from_cache.  */
     0,		/* Display.  */
     0,		/* TTY name.  */
     0,		/* TTY type.  */
@@ -98,6 +100,10 @@ struct pinentry pinentry =
     NULL,        /* default_ok  */
     NULL,        /* default_cancel  */
     NULL,        /* default_prompt  */
+    0,           /* allow_external_password_cache.  */
+    0,           /* tried_password_cached.  */
+    NULL,        /* keyinfo  */
+    0,           /* may_cache_password. */
     NULL         /* Assuan context.  */
   };
 
@@ -711,6 +717,11 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
       if (!pinentry.default_prompt)
 	return ASSUAN_Out_Of_Core;
     }
+  else if (!strcmp (key, "allow-external-password-cache") && !*value)
+    {
+      pinentry.allow_external_password_cache = 1;
+      pinentry.tried_password_cache = 0;
+    }
   else
     return ASSUAN_Invalid_Option;
   return 0;
@@ -772,13 +783,20 @@ cmd_setprompt (ASSUAN_CONTEXT ctx, char *line)
 
 
 /* The data provided at LINE may be used by pinentry implementations
-   to identify a key for caching strategies of its own.  As of now
-   this is here only for documentation purposes.  */
+   to identify a key for caching strategies of its own.  The empty
+   string and --clear mean that the key does not have a stable
+   identifier.  */
 static int
 cmd_setkeyinfo (ASSUAN_CONTEXT ctx, char *line)
 {
-  (void)ctx;
-  (void)line;
+  if (pinentry.keyinfo)
+    free (pinentry.keyinfo);
+
+  if (*line && strcmp(line, "--clear") != 0)
+    pinentry.keyinfo = strdup (line);
+  else
+    pinentry.keyinfo = NULL;
+
   return 0;
 }
 
@@ -955,10 +973,57 @@ cmd_getpin (ASSUAN_CONTEXT ctx, char *line)
 {
   int result;
   int set_prompt = 0;
+  int just_read_password_from_cache = 0;
 
   pinentry.pin = secmem_malloc (pinentry.pin_len);
   if (!pinentry.pin)
     return ASSUAN_Out_Of_Core;
+
+  /* Try reading from the password cache.  */
+  if (/* If repeat passphrase is set, then we don't want to read from
+	 the cache.  */
+      ! pinentry.repeat_passphrase
+      /* Are we allowed to read from the cache?  */
+      && pinentry.allow_external_password_cache
+      && pinentry.keyinfo
+      /* Only read from the cache if we haven't already tried it.  */
+      && ! pinentry.tried_password_cache)
+    {
+      char *password;
+
+      pinentry.tried_password_cache = 1;
+
+      password = password_cache_lookup (pinentry.keyinfo);
+      if (password)
+	/* There is a cached password.  Try it.  */
+	{
+	  int len = strlen(password) + 1;
+	  if (len > pinentry.pin_len)
+	    len = pinentry.pin_len;
+
+	  memcpy (pinentry.pin, password, len);
+	  pinentry.pin[len] = '\0';
+
+	  secmem_free (password);
+
+	  pinentry.pin_from_cache = 1;
+
+	  assuan_write_status (ctx, "PASSWORD_FROM_CACHE", "");
+
+	  /* Result is the length of the password not including the
+	     NUL terminator.  */
+	  result = len - 1;
+
+	  just_read_password_from_cache = 1;
+
+	  goto out;
+	}
+    }
+
+  /* The password was not cached (or we are not allowed to / cannot
+     use the cache).  Prompt the user.  */
+  pinentry.pin_from_cache = 0;
+
   if (!pinentry.prompt)
     {
       pinentry.prompt = pinentry.default_prompt?pinentry.default_prompt:"PIN:";
@@ -999,6 +1064,7 @@ cmd_getpin (ASSUAN_CONTEXT ctx, char *line)
       return pinentry.locale_err? ASSUAN_Locale_Problem: ASSUAN_Canceled;
     }
 
+ out:
   if (result)
     {
       if (pinentry.repeat_okay)
@@ -1006,6 +1072,15 @@ cmd_getpin (ASSUAN_CONTEXT ctx, char *line)
       result = assuan_send_data (ctx, pinentry.pin, result);
       if (!result)
 	result = assuan_send_data (ctx, NULL, 0);
+
+      if (/* GPG Agent says it's okay.  */
+	  pinentry.allow_external_password_cache && pinentry.keyinfo
+	  /* We didn't just read it from the cache.  */
+	  && ! just_read_password_from_cache
+	  /* And the user said it's okay.  */
+	  && pinentry.may_cache_password)
+	/* Cache the password.  */
+	password_cache_save (pinentry.keyinfo, pinentry.pin);
     }
 
   if (pinentry.pin)
diff --git a/pinentry/pinentry.h b/pinentry/pinentry.h
index 6787130..02f76a3 100644
--- a/pinentry/pinentry.h
+++ b/pinentry/pinentry.h
@@ -1,5 +1,5 @@
 /* pinentry.h - The interface for the PIN entry support library.
-   Copyright (C) 2002, 2003, 2010 g10 Code GmbH
+   Copyright (C) 2002, 2003, 2010, 2015 g10 Code GmbH
 
    This file is part of PINENTRY.
 
@@ -57,6 +57,9 @@ struct pinentry
   char *pin;
   /* The length of the buffer.  */
   int pin_len;
+  /* Whether the pin was read from an external cache (1) or entered by
+     the user (0). */
+  int pin_from_cache;
 
   /* The name of the X display to use if X is available and supported.  */
   char *display;
@@ -111,7 +114,7 @@ struct pinentry
      dismiss button is required. */
   int one_button;
 
-  /* If true a second prompt for the passphrase is show and the user
+  /* If true a second prompt for the passphrase is shown and the user
      is expected to enter the same passphrase again.  Pinentry checks
      that both match.  */
   char *repeat_passphrase;
@@ -146,6 +149,22 @@ struct pinentry
   char *default_cancel;
   char *default_prompt;
 
+  /* Whether we are allowed to read the password from an external
+     cache.  */
+  int allow_external_password_cache;
+
+  /* We only try the cache once.  */
+  int tried_password_cache;
+
+  /* A stable identifier for the key.  */
+  char *keyinfo;
+
+  /* Whether we may cache the password (according to the user).  */
+  int may_cache_password;
+
+  /* NOTE: If you add any additional fields to this structure, be sure
+     to update the initializer in pinentry/pinentry.c!!!  */
+
   /* For the quality indicator we need to do an inquiry.  Thus we need
      to save the assuan ctx.  */
   void *ctx_assuan;
@@ -158,7 +177,8 @@ typedef struct pinentry *pinentry_t;
    PIN.  If PIN->pin is zero, request a confirmation, otherwise a PIN
    entry.  On confirmation, the function should return TRUE if
    confirmed, and FALSE otherwise.  On PIN entry, the function should
-   return -1 if cancelled and the length of the secret otherwise.  */
+   return -1 if an error occured or the user cancelled the operation
+   and the length of the secret otherwise.  */
 typedef int (*pinentry_cmd_handler_t) (pinentry_t pin);
 
 /* Start the pinentry event loop.  The program will start to process
diff --git a/qt4/Makefile.am b/qt4/Makefile.am
index e52169c..31274bb 100644
--- a/qt4/Makefile.am
+++ b/qt4/Makefile.am
@@ -1,6 +1,6 @@
 # Makefile.am
 # Copyright (C) 2002 g10 Code GmbH, Klarälvdalens Datakonsult AB
-# Copyright (C) 2008 g10 Code GmbH
+# Copyright (C) 2008, 2015 g10 Code GmbH
 #
 # This file is part of PINENTRY.
 #
@@ -34,10 +34,12 @@ libcurses =
 endif
 
 
-AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/assuan -I$(top_srcdir)/secmem \
+AM_CPPFLAGS = $(COMMON_CFLAGS) \
+	-I$(top_srcdir) -I$(top_srcdir)/assuan -I$(top_srcdir)/secmem \
 	$(ncurses_include) -I$(top_srcdir)/pinentry
 AM_CXXFLAGS = $(QT4_CORE_CFLAGS) $(QT4_GUI_CFLAGS)
-pinentry_qt4_LDADD = $(QT4_CORE_LIBS) $(QT4_GUI_LIBS) $(libcurses) \
+pinentry_qt4_LDADD = $(COMMON_LIBS) \
+	$(QT4_CORE_LIBS) $(QT4_GUI_LIBS) $(libcurses) \
 	../pinentry/libpinentry.a $(top_builddir)/assuan/libassuan.a \
 	$(top_builddir)/secmem/libsecmem.a $(LIBCAP)
 
diff --git a/tty/Makefile.am b/tty/Makefile.am
index d872fcc..798c08f 100644
--- a/tty/Makefile.am
+++ b/tty/Makefile.am
@@ -1,5 +1,5 @@
 # Makefile.am - PIN entry curses frontend.
-# Copyright (C) 2002 g10 Code GmbH
+# Copyright (C) 2002, 2015 g10 Code GmbH
 #
 # This file is part of PINENTRY.
 #
@@ -20,8 +20,8 @@
 
 bin_PROGRAMS = pinentry-tty
 
-AM_CPPFLAGS = -I$(top_srcdir)/pinentry
-LDADD = ../pinentry/libpinentry.a \
+AM_CPPFLAGS = $(COMMON_CFLAGS) -I$(top_srcdir)/pinentry
+LDADD = $(COMMON_LIBS) ../pinentry/libpinentry.a \
 	../assuan/libassuan.a ../secmem/libsecmem.a \
 	$(LIBCAP) $(LIBICONV)
 
diff --git a/tty/pinentry-tty.c b/tty/pinentry-tty.c
index 5891697..8c15eac 100644
--- a/tty/pinentry-tty.c
+++ b/tty/pinentry-tty.c
@@ -1,7 +1,7 @@
 /* pinentry-curses.c - A secure curses dialog for PIN entry, library version
    Copyright (C) 2014 Serge Voilokov
    Copyright (C) 2015 Daniel Kahn Gillmor <dkg at fifthhorseman.net>
- * Copyright (C) 2015 g10 Code GmbH
+   Copyright (C) 2015 g10 Code GmbH
 
    This file is part of PINENTRY.
 

-----------------------------------------------------------------------

Summary of changes:
 configure.ac                                     |  49 ++++++++-
 curses/Makefile.am                               |   7 +-
 doc/pinentry.texi                                |  59 ++++++++--
 gtk+-2/Makefile.am                               |   7 +-
 gtk+-2/pinentry-gtk-2.c                          |  33 +++++-
 pinentry/Makefile.am                             |   8 +-
 pinentry/password-cache.c                        | 131 +++++++++++++++++++++++
 pinentry/{pinentry-curses.h => password-cache.h} |  33 +++---
 pinentry/pinentry.c                              |  83 +++++++++++++-
 pinentry/pinentry.h                              |  26 ++++-
 qt4/Makefile.am                                  |   8 +-
 tty/Makefile.am                                  |   6 +-
 tty/pinentry-tty.c                               |   2 +-
 13 files changed, 397 insertions(+), 55 deletions(-)
 create mode 100644 pinentry/password-cache.c
 copy pinentry/{pinentry-curses.h => password-cache.h} (55%)


hooks/post-receive
-- 
The standard pinentry collection
http://git.gnupg.org




More information about the Gnupg-commits mailing list