[Pkg-gnupg-commit] [gnupg2] 96/205: sm: Implement pinentry loopback and reading passphrases from fd.

Daniel Kahn Gillmor dkg at fifthhorseman.net
Wed May 11 08:38:22 UTC 2016


This is an automated email from the git hooks/post-receive script.

dkg pushed a commit to branch experimental
in repository gnupg2.

commit eea139c56ef55081d8cd8df2a35ce507386e0f17
Author: Justus Winter <justus at g10code.com>
Date:   Mon Mar 7 18:09:41 2016 +0100

    sm: Implement pinentry loopback and reading passphrases from fd.
    
    * doc/gpgsm.texi: Document '--pinentry-mode' and '--passphrase-fd'.
    * sm/Makefile.am (gpgsm_SOURCES): Add new files
    * sm/call-agent.c (struct default_inq_parm_s): New definition.
    (start_agent): Pass in the pinentry mode.
    (default_inq_cb): Handle 'PASSPHRASE' and 'NEW_PASSPHRASE' inquiries.
    Adapt all call sites to the new callback cookie.
    * sm/gpgsm.c (cmd_and_opt_values): Add new values.
    (opts): Add new options.
    (main): Handle new options.
    * sm/gpgsm.h (struct opt): Add field 'pinentry_mode'.
    * sm/passphrase.c: New file.
    * sm/passphrase.h: Likewise.
    
    GnuPG-bug-id: 1970
    Signed-off-by: Justus Winter <justus at g10code.com>
---
 doc/gpgsm.texi  | 28 ++++++++++++++++++
 sm/Makefile.am  |  3 +-
 sm/call-agent.c | 85 +++++++++++++++++++++++++++++++++++++++++------------
 sm/gpgsm.c      | 22 +++++++++++++-
 sm/gpgsm.h      |  2 ++
 sm/passphrase.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sm/passphrase.h | 27 +++++++++++++++++
 7 files changed, 237 insertions(+), 20 deletions(-)

diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi
index dc57e4b..b585975 100644
--- a/doc/gpgsm.texi
+++ b/doc/gpgsm.texi
@@ -737,6 +737,34 @@ This is actually not a debugging option but only useful as such.  It
 lets @command{gpgsm} ignore all notAfter dates, this is used by the regression
 tests.
 
+ at item --passphrase-fd @code{n}
+ at opindex passphrase-fd
+Read the passphrase from file descriptor @code{n}. Only the first line
+will be read from file descriptor @code{n}. If you use 0 for @code{n},
+the passphrase will be read from STDIN. This can only be used if only
+one passphrase is supplied.
+
+Note that this passphrase is only used if the option @option{--batch}
+has also been given.
+
+ at item --pinentry-mode @code{mode}
+ at opindex pinentry-mode
+Set the pinentry mode to @code{mode}.  Allowed values for @code{mode}
+are:
+ at table @asis
+  @item default
+  Use the default of the agent, which is @code{ask}.
+  @item ask
+  Force the use of the Pinentry.
+  @item cancel
+  Emulate use of Pinentry's cancel button.
+  @item error
+  Return a Pinentry error (``No Pinentry'').
+  @item loopback
+  Redirect Pinentry queries to the caller.  Note that in contrast to
+  Pinentry the user is not prompted again if he enters a bad password.
+ at end table
+
 @item --no-common-certs-import
 @opindex no-common-certs-import
 Suppress the import of common certificates on keybox creation.
diff --git a/sm/Makefile.am b/sm/Makefile.am
index 43e3598..11f86e9 100644
--- a/sm/Makefile.am
+++ b/sm/Makefile.am
@@ -54,7 +54,8 @@ gpgsm_SOURCES = \
 	certreqgen.c \
 	certreqgen-ui.c \
 	minip12.c minip12.h \
-	qualified.c
+	qualified.c \
+	passphrase.c passphrase.h
 
 
 common_libs = ../kbx/libkeybox509.a $(libcommon)
diff --git a/sm/call-agent.c b/sm/call-agent.c
index c7d4c5a..8c1c727 100644
--- a/sm/call-agent.c
+++ b/sm/call-agent.c
@@ -37,6 +37,8 @@
 #include "asshelp.h"
 #include "keydb.h" /* fixme: Move this to import.c */
 #include "membuf.h"
+#include "shareddefs.h"
+#include "passphrase.h"
 
 
 static assuan_context_t agent_ctx = NULL;
@@ -74,6 +76,11 @@ struct import_key_parm_s
   size_t keylen;
 };
 
+struct default_inq_parm_s
+{
+  ctrl_t ctrl;
+  assuan_context_t ctx;
+};
 
 

 /* Print a warning if the server's version number is less than our
@@ -151,6 +158,20 @@ start_agent (ctrl_t ctrl)
              agents.  */
           assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
                            NULL, NULL, NULL, NULL, NULL, NULL);
+
+          /* Pass on the pinentry mode.  */
+          if (opt.pinentry_mode)
+            {
+              char *tmp = xasprintf ("OPTION pinentry-mode=%s",
+                                     str_pinentry_mode (opt.pinentry_mode));
+              rc = assuan_transact (agent_ctx, tmp,
+                               NULL, NULL, NULL, NULL, NULL, NULL);
+              xfree (tmp);
+              if (rc)
+                log_error ("setting pinentry mode '%s' failed: %s\n",
+                           str_pinentry_mode (opt.pinentry_mode),
+                           gpg_strerror (rc));
+            }
         }
     }
 
@@ -163,14 +184,14 @@ start_agent (ctrl_t ctrl)
   return rc;
 }
 
-
 /* This is the default inquiry callback.  It mainly handles the
    Pinentry notifications.  */
 static gpg_error_t
 default_inq_cb (void *opaque, const char *line)
 {
-  gpg_error_t err;
-  ctrl_t ctrl = opaque;
+  gpg_error_t err = 0;
+  struct default_inq_parm_s *parm = opaque;
+  ctrl_t ctrl = parm->ctrl;
 
   if (has_leading_keyword (line, "PINENTRY_LAUNCHED"))
     {
@@ -180,10 +201,18 @@ default_inq_cb (void *opaque, const char *line)
                    "PINENTRY_LAUNCHED");
       /* We do not pass errors to avoid breaking other code.  */
     }
+  else if ((has_leading_keyword (line, "PASSPHRASE")
+            || has_leading_keyword (line, "NEW_PASSPHRASE"))
+           && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK
+           && have_static_passphrase ())
+    {
+      const char *s = get_static_passphrase ();
+      err = assuan_send_data (parm->ctx, s, strlen (s));
+    }
   else
     log_error ("ignoring gpg-agent inquiry '%s'\n", line);
 
-  return 0;
+  return err;
 }
 
 
@@ -200,6 +229,7 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
   char *p, line[ASSUAN_LINELENGTH];
   membuf_t data;
   size_t len;
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_buf = NULL;
   rc = start_agent (ctrl);
@@ -239,7 +269,7 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
 
   init_membuf (&data, 1024);
   rc = assuan_transact (agent_ctx, "PKSIGN",
-                        put_membuf_cb, &data, default_inq_cb, ctrl,
+                        put_membuf_cb, &data, default_inq_cb, &inq_parm,
                         NULL, NULL);
   if (rc)
     {
@@ -272,6 +302,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
   const char *hashopt;
   unsigned char *sigbuf;
   size_t sigbuflen;
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   (void)desc;
 
@@ -306,7 +337,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
   snprintf (line, DIM(line)-1, "SCD PKSIGN %s %s", hashopt, keyid);
   line[DIM(line)-1] = 0;
   rc = assuan_transact (agent_ctx, line,
-                        put_membuf_cb, &data, default_inq_cb, ctrl,
+                        put_membuf_cb, &data, default_inq_cb, &inq_parm,
                         NULL, NULL);
   if (rc)
     {
@@ -356,7 +387,10 @@ inq_ciphertext_cb (void *opaque, const char *line)
       assuan_end_confidential (parm->ctx);
     }
   else
-    rc = default_inq_cb (parm->ctrl, line);
+    {
+      struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+      rc = default_inq_cb (&inq_parm, line);
+    }
 
   return rc;
 }
@@ -476,7 +510,10 @@ inq_genkey_parms (void *opaque, const char *line)
       rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
     }
   else
-    rc = default_inq_cb (parm->ctrl, line);
+    {
+      struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+      rc = default_inq_cb (&inq_parm, line);
+    }
 
   return rc;
 }
@@ -544,6 +581,7 @@ gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_pubkey = NULL;
   rc = start_agent (ctrl);
@@ -561,7 +599,7 @@ gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
   init_membuf (&data, 1024);
   rc = assuan_transact (agent_ctx, line,
                         put_membuf_cb, &data,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   if (rc)
     {
       xfree (get_membuf (&data, &len));
@@ -631,6 +669,7 @@ gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno)
 {
   int rc;
   char *serialno = NULL;
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_serialno = NULL;
   rc = start_agent (ctrl);
@@ -639,7 +678,7 @@ gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno)
 
   rc = assuan_transact (agent_ctx, "SCD SERIALNO",
                         NULL, NULL,
-                        default_inq_cb, ctrl,
+                        default_inq_cb, &inq_parm,
                         scd_serialno_status_cb, &serialno);
   if (!rc && !serialno)
     rc = gpg_error (GPG_ERR_INTERNAL);
@@ -700,6 +739,7 @@ gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list)
 {
   int rc;
   strlist_t list = NULL;
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_list = NULL;
   rc = start_agent (ctrl);
@@ -708,7 +748,7 @@ gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list)
 
   rc = assuan_transact (agent_ctx, "SCD LEARN --force",
                         NULL, NULL,
-                        default_inq_cb, ctrl,
+                        default_inq_cb, &inq_parm,
                         scd_keypairinfo_status_cb, &list);
   if (!rc && !list)
     rc = gpg_error (GPG_ERR_NO_DATA);
@@ -797,6 +837,7 @@ gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert)
   int rc;
   char *fpr, *dn, *dnfmt;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   rc = start_agent (ctrl);
   if (rc)
@@ -825,7 +866,7 @@ gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert)
   xfree (fpr);
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   return rc;
 }
 
@@ -983,6 +1024,7 @@ gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   rc = start_agent (ctrl);
   if (rc)
@@ -1005,7 +1047,7 @@ gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
   line[DIM(line)-1] = 0;
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   return rc;
 }
 
@@ -1018,6 +1060,7 @@ gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   rc = start_agent (ctrl);
   if (rc)
@@ -1027,7 +1070,7 @@ gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc)
   line[DIM(line)-1] = 0;
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   return rc;
 }
 
@@ -1128,6 +1171,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
   char line[ASSUAN_LINELENGTH];
   char *arg4 = NULL;
   membuf_t data;
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_passphrase = NULL;
 
@@ -1146,7 +1190,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
   init_membuf_secure (&data, 64);
   err = assuan_transact (agent_ctx, line,
                          put_membuf_cb, &data,
-                         default_inq_cb, NULL, NULL, NULL);
+                         default_inq_cb, &inq_parm, NULL, NULL);
 
   if (err)
     xfree (get_membuf (&data, NULL));
@@ -1174,6 +1218,7 @@ gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport,
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_kek = NULL;
   err = start_agent (ctrl);
@@ -1186,7 +1231,7 @@ gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport,
   init_membuf_secure (&data, 64);
   err = assuan_transact (agent_ctx, line,
                          put_membuf_cb, &data,
-                         default_inq_cb, ctrl, NULL, NULL);
+                         default_inq_cb, &inq_parm, NULL, NULL);
   if (err)
     {
       xfree (get_membuf (&data, &len));
@@ -1217,7 +1262,10 @@ inq_import_key_parms (void *opaque, const char *line)
       assuan_end_confidential (parm->ctx);
     }
   else
-    err = default_inq_cb (parm->ctrl, line);
+    {
+      struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+      err = default_inq_cb (&inq_parm, line);
+    }
 
   return err;
 }
@@ -1259,6 +1307,7 @@ gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc,
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_result = NULL;
 
@@ -1280,7 +1329,7 @@ gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc,
   init_membuf_secure (&data, 1024);
   err = assuan_transact (agent_ctx, line,
                          put_membuf_cb, &data,
-                         default_inq_cb, ctrl, NULL, NULL);
+                         default_inq_cb, &inq_parm, NULL, NULL);
   if (err)
     {
       xfree (get_membuf (&data, &len));
diff --git a/sm/gpgsm.c b/sm/gpgsm.c
index 364dd43..fc6d1c7 100644
--- a/sm/gpgsm.c
+++ b/sm/gpgsm.c
@@ -32,6 +32,8 @@
 #include <gcrypt.h>
 #include <assuan.h> /* malloc hooks */
 
+#include "passphrase.h"
+#include "../common/shareddefs.h"
 #include "../kbx/keybox.h" /* malloc hooks */
 #include "i18n.h"
 #include "keydb.h"
@@ -120,6 +122,8 @@ enum cmd_and_opt_values {
   oProtectToolProgram,
   oFakedSystemTime,
 
+  oPassphraseFD,
+  oPinentryMode,
 
   oAssumeArmor,
   oAssumeBase64,
@@ -243,6 +247,9 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_s_s (oP12Charset, "p12-charset", "@"),
 
+  ARGPARSE_s_i (oPassphraseFD,    "passphrase-fd", "@"),
+  ARGPARSE_s_s (oPinentryMode,    "pinentry-mode", "@"),
+
   ARGPARSE_s_n (oAssumeArmor, "assume-armor",
                 N_("assume input is in PEM format")),
   ARGPARSE_s_n (oAssumeBase64, "assume-base64",
@@ -910,7 +917,7 @@ main ( int argc, char **argv)
   estream_t auditfp = NULL;
   estream_t htmlauditfp = NULL;
   struct assuan_malloc_hooks malloc_hooks;
-
+  int pwfd = -1;
   /*mtrace();*/
 
   early_system_init ();
@@ -1150,6 +1157,16 @@ main ( int argc, char **argv)
           opt.p12_charset = pargs.r.ret_str;
           break;
 
+        case oPassphraseFD:
+	  pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
+	  break;
+
+        case oPinentryMode:
+	  opt.pinentry_mode = parse_pinentry_mode (pargs.r.ret_str);
+	  if (opt.pinentry_mode == -1)
+            log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
+	  break;
+
           /* Input encoding selection.  */
         case oAssumeArmor:
           ctrl.autodetect_encoding = 0;
@@ -1458,6 +1475,9 @@ main ( int argc, char **argv)
   if (log_get_errorcount(0))
     gpgsm_exit(2);
 
+  if (pwfd != -1)	/* Read the passphrase now.  */
+    read_passphrase_from_fd (pwfd);
+
   /* Now that we have the options parsed we need to update the default
      control structure.  */
   gpgsm_init_default_ctrl (&ctrl);
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 44b4798..5aad4b1 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -84,6 +84,8 @@ struct
 
   int with_keygrip; /* Option --with-keygrip active.  */
 
+  int pinentry_mode;
+
   int armor;        /* force base64 armoring (see also ctrl.with_base64) */
   int no_armor;     /* don't try to figure out whether data is base64 armored*/
 
diff --git a/sm/passphrase.c b/sm/passphrase.c
new file mode 100644
index 0000000..6ad2b0a
--- /dev/null
+++ b/sm/passphrase.c
@@ -0,0 +1,90 @@
+/* passphrase.c -  Get a passphrase
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ *               2005, 2006, 2007, 2009, 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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/>.
+ */
+
+#include <config.h>
+#include <unistd.h>
+
+#include "passphrase.h"
+#include "gpgsm.h"
+#include "../common/shareddefs.h"
+#include "../common/ttyio.h"
+
+static char *fd_passwd = NULL;
+
+int
+have_static_passphrase ()
+{
+  return (!!fd_passwd
+          && (opt.batch || opt.pinentry_mode == PINENTRY_MODE_LOOPBACK));
+}
+
+/* Return a static passphrase.  The returned value is only valid as
+   long as no other passphrase related function is called.  NULL may
+   be returned if no passphrase has been set; better use
+   have_static_passphrase first.  */
+const char *
+get_static_passphrase (void)
+{
+  return fd_passwd;
+}
+
+void
+read_passphrase_from_fd (int fd)
+{
+  int i, len;
+  char *pw;
+
+  if (!opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK)
+    { /* Not used but we have to do a dummy read, so that it won't end
+         up at the begin of the message if the quite usual trick to
+         prepend the passphtrase to the message is used. */
+      char buf[1];
+
+      while (!(read (fd, buf, 1) != 1 || *buf == '\n'))
+        ;
+      *buf = 0;
+      return;
+    }
+
+  for (pw = NULL, i = len = 100; ; i++)
+    {
+      if (i >= len-1)
+        {
+          char *pw2 = pw;
+          len += 100;
+          pw = xmalloc_secure (len);
+          if (pw2)
+            {
+              memcpy (pw, pw2, i);
+              xfree (pw2);
+            }
+          else
+            i = 0;
+	}
+      if (read (fd, pw+i, 1) != 1 || pw[i] == '\n')
+        break;
+    }
+  pw[i] = 0;
+  if (!opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK)
+    tty_printf("\b\b\b   \n" );
+
+  xfree (fd_passwd);
+  fd_passwd = pw;
+}
diff --git a/sm/passphrase.h b/sm/passphrase.h
new file mode 100644
index 0000000..3401a0b
--- /dev/null
+++ b/sm/passphrase.h
@@ -0,0 +1,27 @@
+/* passphrase.h -  Get a passphrase
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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	GPGSM_PASSPHRASE_H
+#define	GPGSM_PASSPHRASE_H
+
+int have_static_passphrase (void);
+const char *get_static_passphrase (void);
+void read_passphrase_from_fd (int fd);
+
+#endif	/* GPGSM_PASSPHRASE_H */

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gnupg2.git



More information about the Pkg-gnupg-commit mailing list