wks: Install gpg-wks-client under libexec
[gnupg.git] / sm / call-agent.c
index 59b1509..c7facbb 100644 (file)
@@ -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,8 +76,48 @@ struct import_key_parm_s
   size_t keylen;
 };
 
+struct default_inq_parm_s
+{
+  ctrl_t ctrl;
+  assuan_context_t ctx;
+};
 
 \f
+/* Print a warning if the server's version number is less than our
+   version number.  Returns an error code on a connection problem.  */
+static gpg_error_t
+warn_version_mismatch (ctrl_t ctrl, assuan_context_t ctx,
+                       const char *servername, int mode)
+{
+  gpg_error_t err;
+  char *serverversion;
+  const char *myversion = strusage (13);
+
+  err = get_assuan_server_version (ctx, mode, &serverversion);
+  if (err)
+    log_error (_("error getting version from '%s': %s\n"),
+               servername, gpg_strerror (err));
+  else if (!compare_version_strings (serverversion, myversion))
+    {
+      char *warn;
+
+      warn = xtryasprintf (_("server '%s' is older than us (%s < %s)"),
+                           servername, serverversion, myversion);
+      if (!warn)
+        err = gpg_error_from_syserror ();
+      else
+        {
+          log_info (_("WARNING: %s\n"), warn);
+          gpgsm_status2 (ctrl, STATUS_WARNING, "server_version_mismatch 0",
+                         warn, NULL);
+          xfree (warn);
+        }
+    }
+  xfree (serverversion);
+  return err;
+}
+
+
 /* Try to connect to the agent via socket or fork it off and work by
    pipes.  Handle the server's initial greeting */
 static int
@@ -91,20 +133,44 @@ start_agent (ctrl_t ctrl)
     {
       rc = start_new_gpg_agent (&agent_ctx,
                                 GPG_ERR_SOURCE_DEFAULT,
-                                opt.homedir,
                                 opt.agent_program,
                                 opt.lc_ctype, opt.lc_messages,
                                 opt.session_env,
-                                1, opt.verbose, DBG_ASSUAN,
+                                opt.autostart, opt.verbose, DBG_IPC,
                                 gpgsm_status2, ctrl);
 
-      if (!rc)
+      if (!opt.autostart && gpg_err_code (rc) == GPG_ERR_NO_AGENT)
+        {
+          static int shown;
+
+          if (!shown)
+            {
+              shown = 1;
+              log_info (_("no gpg-agent running in this session\n"));
+            }
+        }
+      else if (!rc && !(rc = warn_version_mismatch (ctrl, agent_ctx,
+                                                    GPG_AGENT_NAME, 0)))
         {
           /* Tell the agent that we support Pinentry notifications.  No
              error checking so that it will work also with older
              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));
+            }
         }
     }
 
@@ -117,26 +183,14 @@ start_agent (ctrl_t ctrl)
   return rc;
 }
 
-
-
-static gpg_error_t
-membuf_data_cb (void *opaque, const void *buffer, size_t length)
-{
-  membuf_t *data = opaque;
-
-  if (buffer)
-    put_membuf (data, buffer, length);
-  return 0;
-}
-
-
 /* 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"))
     {
@@ -146,10 +200,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;
 }
 
 
@@ -166,6 +228,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);
@@ -205,7 +268,7 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
 
   init_membuf (&data, 1024);
   rc = assuan_transact (agent_ctx, "PKSIGN",
-                        membuf_data_cb, &data, default_inq_cb, ctrl,
+                        put_membuf_cb, &data, default_inq_cb, &inq_parm,
                         NULL, NULL);
   if (rc)
     {
@@ -238,6 +301,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;
 
@@ -272,7 +336,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,
-                        membuf_data_cb, &data, default_inq_cb, ctrl,
+                        put_membuf_cb, &data, default_inq_cb, &inq_parm,
                         NULL, NULL);
   if (rc)
     {
@@ -322,7 +386,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;
 }
@@ -382,7 +449,7 @@ gpgsm_agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
   cipher_parm.ciphertext = ciphertext;
   cipher_parm.ciphertextlen = ciphertextlen;
   rc = assuan_transact (agent_ctx, "PKDECRYPT",
-                        membuf_data_cb, &data,
+                        put_membuf_cb, &data,
                         inq_ciphertext_cb, &cipher_parm, NULL, NULL);
   if (rc)
     {
@@ -442,7 +509,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;
 }
@@ -477,7 +547,7 @@ gpgsm_agent_genkey (ctrl_t ctrl,
   if (!gk_parm.sexplen)
     return gpg_error (GPG_ERR_INV_VALUE);
   rc = assuan_transact (agent_ctx, "GENKEY",
-                        membuf_data_cb, &data,
+                        put_membuf_cb, &data,
                         inq_genkey_parms, &gk_parm, NULL, NULL);
   if (rc)
     {
@@ -510,6 +580,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);
@@ -526,8 +597,8 @@ gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
 
   init_membuf (&data, 1024);
   rc = assuan_transact (agent_ctx, line,
-                        membuf_data_cb, &data,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        put_membuf_cb, &data,
+                        default_inq_cb, &inq_parm, NULL, NULL);
   if (rc)
     {
       xfree (get_membuf (&data, &len));
@@ -568,7 +639,7 @@ store_serialno (const char *line)
 }
 
 
-/* Callback for the gpgsm_agent_serialno fucntion.  */
+/* Callback for the gpgsm_agent_serialno function.  */
 static gpg_error_t
 scd_serialno_status_cb (void *opaque, const char *line)
 {
@@ -597,6 +668,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);
@@ -605,7 +677,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);
@@ -620,7 +692,7 @@ gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno)
 
 
 \f
-/* Callback for the gpgsm_agent_serialno fucntion.  */
+/* Callback for the gpgsm_agent_serialno function.  */
 static gpg_error_t
 scd_keypairinfo_status_cb (void *opaque, const char *line)
 {
@@ -666,6 +738,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);
@@ -674,7 +747,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);
@@ -763,6 +836,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)
@@ -791,7 +865,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;
 }
 
@@ -921,6 +995,10 @@ gpgsm_agent_learn (ctrl_t ctrl)
   if (rc)
     return rc;
 
+  rc = warn_version_mismatch (ctrl, agent_ctx, SCDAEMON_NAME, 2);
+  if (rc)
+    return rc;
+
   init_membuf (&data, 4096);
   learn_parm.error = 0;
   learn_parm.ctrl = ctrl;
@@ -945,6 +1023,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)
@@ -967,7 +1046,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;
 }
 
@@ -980,6 +1059,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)
@@ -989,7 +1069,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;
 }
 
@@ -1090,6 +1170,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;
 
@@ -1107,8 +1188,8 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
 
   init_membuf_secure (&data, 64);
   err = assuan_transact (agent_ctx, line,
-                         membuf_data_cb, &data,
-                         default_inq_cb, NULL, NULL, NULL);
+                         put_membuf_cb, &data,
+                         default_inq_cb, &inq_parm, NULL, NULL);
 
   if (err)
     xfree (get_membuf (&data, NULL));
@@ -1136,6 +1217,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);
@@ -1147,8 +1229,8 @@ gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport,
 
   init_membuf_secure (&data, 64);
   err = assuan_transact (agent_ctx, line,
-                         membuf_data_cb, &data,
-                         default_inq_cb, ctrl, NULL, NULL);
+                         put_membuf_cb, &data,
+                         default_inq_cb, &inq_parm, NULL, NULL);
   if (err)
     {
       xfree (get_membuf (&data, &len));
@@ -1179,7 +1261,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;
 }
@@ -1221,6 +1306,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;
 
@@ -1241,8 +1327,8 @@ gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc,
 
   init_membuf_secure (&data, 1024);
   err = assuan_transact (agent_ctx, line,
-                         membuf_data_cb, &data,
-                         default_inq_cb, ctrl, NULL, NULL);
+                         put_membuf_cb, &data,
+                         default_inq_cb, &inq_parm, NULL, NULL);
   if (err)
     {
       xfree (get_membuf (&data, &len));