agent: Tell pinentry the hostname the agent is running on.
[gnupg.git] / agent / call-pinentry.c
index 4de897a..9931665 100644 (file)
@@ -15,7 +15,7 @@
  * 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/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -31,6 +31,7 @@
 # include <sys/wait.h>
 # include <sys/types.h>
 # include <signal.h>
+# include <sys/utsname.h>
 #endif
 #include <npth.h>
 
@@ -225,6 +226,7 @@ getinfo_pid_cb (void *opaque, const void *buffer, size_t length)
   return 0;
 }
 
+
 /* Fork off the pin entry if this has not already been done.  Note,
    that this function must always be used to acquire the lock for the
    pinentry - we will serialize _all_ pinentry calls.
@@ -243,6 +245,7 @@ start_pinentry (ctrl_t ctrl)
   unsigned long pinentry_pid;
   const char *value;
   struct timespec abstime;
+  char *flavor_version;
   int err;
 
   npth_clock_gettime (&abstime);
@@ -354,6 +357,19 @@ start_pinentry (ctrl_t ctrl)
   if (DBG_IPC)
     log_debug ("connection to PIN entry established\n");
 
+  value = session_env_getenv (ctrl->session_env, "PINENTRY_USER_DATA");
+  if (value != NULL)
+    {
+      char *optstr;
+      if (asprintf (&optstr, "OPTION pinentry-user-data=%s", value) < 0 )
+       return unlock_pinentry (out_of_core ());
+      rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
+                           NULL);
+      xfree (optstr);
+      if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION)
+        return unlock_pinentry (rc);
+    }
+
   rc = assuan_transact (entry_ctx,
                         opt.no_grab? "OPTION no-grab":"OPTION grab",
                         NULL, NULL, NULL, NULL, NULL, NULL);
@@ -491,6 +507,18 @@ start_pinentry (ctrl_t ctrl)
         }
     }
 
+  if (opt.pinentry_timeout)
+    {
+      char *optstr;
+      if ((optstr = xtryasprintf ("SETTIMEOUT %lu", opt.pinentry_timeout)))
+        {
+          assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
+                           NULL);
+          /* We ignore errors because this is just a fancy thing.  */
+          xfree (optstr);
+        }
+    }
+
   /* Tell the pinentry the name of a file it shall touch after having
      messed with the tty.  This is optional and only supported by
      newer pinentries and thus we do no error checking. */
@@ -513,6 +541,52 @@ start_pinentry (ctrl_t ctrl)
         }
     }
 
+  /* Tell Pinentry about our client.  */
+  if (ctrl->client_pid)
+    {
+      char *optstr;
+      const char *nodename = "";
+
+#ifndef HAVE_W32_SYSTEM
+      struct utsname utsbuf;
+      if (!uname (&utsbuf))
+        nodename = utsbuf.nodename;
+#endif /*!HAVE_W32_SYSTEM*/
+
+      if ((optstr = xtryasprintf ("OPTION owner=%lu %s",
+                                  ctrl->client_pid, nodename)))
+        {
+          assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
+                           NULL);
+          /* We ignore errors because this is just a fancy thing and
+             older pinentries do not support this feature.  */
+          xfree (optstr);
+        }
+    }
+
+
+  /* Ask the pinentry for its version and flavor and store that as a
+   * string in MB.  This information is useful for helping users to
+   * figure out Pinentry problems.  */
+  {
+    membuf_t mb;
+
+    init_membuf (&mb, 256);
+    if (assuan_transact (entry_ctx, "GETINFO flavor",
+                         put_membuf_cb, &mb, NULL, NULL, NULL, NULL))
+      put_membuf_str (&mb, "unknown");
+    put_membuf_str (&mb, " ");
+    if (assuan_transact (entry_ctx, "GETINFO version",
+                         put_membuf_cb, &mb, NULL, NULL, NULL, NULL))
+      put_membuf_str (&mb, "unknown");
+    put_membuf_str (&mb, " ");
+    if (assuan_transact (entry_ctx, "GETINFO ttyinfo",
+                         put_membuf_cb, &mb, NULL, NULL, NULL, NULL))
+      put_membuf_str (&mb, "? ? ?");
+    put_membuf (&mb, "", 1);
+    flavor_version = get_membuf (&mb, NULL);
+  }
+
 
   /* Now ask the Pinentry for its PID.  If the Pinentry is new enough
      it will send the pid back and we will use an inquire to notify
@@ -530,7 +604,7 @@ start_pinentry (ctrl_t ctrl)
     log_error ("pinentry did not return a PID\n");
   else
     {
-      rc = agent_inq_pinentry_launched (ctrl, pinentry_pid);
+      rc = agent_inq_pinentry_launched (ctrl, pinentry_pid, flavor_version);
       if (gpg_err_code (rc) == GPG_ERR_CANCELED
           || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
         return unlock_pinentry (gpg_err_make (GPG_ERR_SOURCE_DEFAULT,
@@ -538,6 +612,8 @@ start_pinentry (ctrl_t ctrl)
       rc = 0;
     }
 
+  xfree (flavor_version);
+
   return 0;
 }
 
@@ -717,11 +793,12 @@ setup_qualitybar (ctrl_t ctrl)
   char *tmpstr, *tmpstr2;
   const char *tooltip;
 
+  (void)ctrl;
+
   /* TRANSLATORS: This string is displayed by Pinentry as the label
      for the quality bar.  */
   tmpstr = try_percent_escape (L_("Quality:"), "\t\r\n\f\v");
-  snprintf (line, DIM(line)-1, "SETQUALITYBAR %s", tmpstr? tmpstr:"");
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SETQUALITYBAR %s", tmpstr? tmpstr:"");
   xfree (tmpstr);
   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc == 103 /*(Old assuan error code)*/
@@ -749,8 +826,7 @@ setup_qualitybar (ctrl_t ctrl)
     }
   tmpstr = try_percent_escape (tooltip, "\t\r\n\f\v");
   xfree (tmpstr2);
-  snprintf (line, DIM(line)-1, "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
   xfree (tmpstr);
   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc == 103 /*(Old assuan error code)*/
@@ -873,27 +949,25 @@ agent_askpin (ctrl_t ctrl,
   if (keyinfo && (cache_mode == CACHE_MODE_NORMAL
                   || cache_mode == CACHE_MODE_USER
                   || cache_mode == CACHE_MODE_SSH))
-    snprintf (line, DIM(line)-1, "SETKEYINFO %c/%s",
+    snprintf (line, DIM(line), "SETKEYINFO %c/%s",
              cache_mode == CACHE_MODE_USER? 'u' :
              cache_mode == CACHE_MODE_SSH? 's' : 'n',
              keyinfo);
   else
-    snprintf (line, DIM(line)-1, "SETKEYINFO --clear");
+    snprintf (line, DIM(line), "SETKEYINFO --clear");
 
   rc = assuan_transact (entry_ctx, line,
                        NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD)
     return unlock_pinentry (rc);
 
-  snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SETDESC %s", desc_text);
   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return unlock_pinentry (rc);
 
-  snprintf (line, DIM(line)-1, "SETPROMPT %s",
+  snprintf (line, DIM(line), "SETPROMPT %s",
             prompt_text? prompt_text : is_pin? L_("PIN:") : L_("Passphrase:"));
-  line[DIM(line)-1] = 0;
   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return unlock_pinentry (rc);
@@ -910,8 +984,7 @@ agent_askpin (ctrl_t ctrl,
 
   if (initial_errtext)
     {
-      snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "SETERROR %s", initial_errtext);
       rc = assuan_transact (entry_ctx, line,
                             NULL, NULL, NULL, NULL, NULL, NULL);
       if (rc)
@@ -920,9 +993,8 @@ agent_askpin (ctrl_t ctrl,
 
   if (pininfo->with_repeat)
     {
-      snprintf (line, DIM(line)-1, "SETREPEATERROR %s",
+      snprintf (line, DIM(line), "SETREPEATERROR %s",
                 L_("does not match - try again"));
-      line[DIM(line)-1] = 0;
       rc = assuan_transact (entry_ctx, line,
                             NULL, NULL, NULL, NULL, NULL, NULL);
       if (rc)
@@ -942,9 +1014,8 @@ agent_askpin (ctrl_t ctrl,
           /* TRANSLATORS: The string is appended to an error message in
              the pinentry.  The %s is the actual error message, the
              two %d give the current and maximum number of tries. */
-          snprintf (line, DIM(line)-1, L_("SETERROR %s (try %d of %d)"),
+          snprintf (line, DIM(line), L_("SETERROR %s (try %d of %d)"),
                     errtext, pininfo->failed_tries+1, pininfo->max_tries);
-          line[DIM(line)-1] = 0;
           rc = assuan_transact (entry_ctx, line,
                                 NULL, NULL, NULL, NULL, NULL, NULL);
           if (rc)
@@ -954,8 +1025,7 @@ agent_askpin (ctrl_t ctrl,
 
       if (pininfo->with_repeat)
         {
-          snprintf (line, DIM(line)-1, "SETREPEAT %s", L_("Repeat:"));
-          line[DIM(line)-1] = 0;
+          snprintf (line, DIM(line), "SETREPEAT %s", L_("Repeat:"));
           rc = assuan_transact (entry_ctx, line,
                                 NULL, NULL, NULL, NULL, NULL, NULL);
           if (rc)
@@ -1086,12 +1156,12 @@ agent_get_passphrase (ctrl_t ctrl,
   if (keyinfo && (cache_mode == CACHE_MODE_NORMAL
                   || cache_mode == CACHE_MODE_USER
                   || cache_mode == CACHE_MODE_SSH))
-    snprintf (line, DIM(line)-1, "SETKEYINFO %c/%s",
+    snprintf (line, DIM(line), "SETKEYINFO %c/%s",
              cache_mode == CACHE_MODE_USER? 'u' :
              cache_mode == CACHE_MODE_SSH? 's' : 'n',
              keyinfo);
   else
-    snprintf (line, DIM(line)-1, "SETKEYINFO --clear");
+    snprintf (line, DIM(line), "SETKEYINFO --clear");
 
   rc = assuan_transact (entry_ctx, line,
                        NULL, NULL, NULL, NULL, NULL, NULL);
@@ -1100,16 +1170,14 @@ agent_get_passphrase (ctrl_t ctrl,
 
 
   if (desc)
-    snprintf (line, DIM(line)-1, "SETDESC %s", desc);
+    snprintf (line, DIM(line), "SETDESC %s", desc);
   else
-    snprintf (line, DIM(line)-1, "RESET");
-  line[DIM(line)-1] = 0;
+    snprintf (line, DIM(line), "RESET");
   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return unlock_pinentry (rc);
 
-  snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SETPROMPT %s", prompt);
   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return unlock_pinentry (rc);
@@ -1123,8 +1191,7 @@ agent_get_passphrase (ctrl_t ctrl,
 
   if (errtext)
     {
-      snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "SETERROR %s", errtext);
       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
       if (rc)
         return unlock_pinentry (rc);
@@ -1191,10 +1258,9 @@ agent_get_confirmation (ctrl_t ctrl,
     return rc;
 
   if (desc)
-    snprintf (line, DIM(line)-1, "SETDESC %s", desc);
+    snprintf (line, DIM(line), "SETDESC %s", desc);
   else
-    snprintf (line, DIM(line)-1, "RESET");
-  line[DIM(line)-1] = 0;
+    snprintf (line, DIM(line), "RESET");
   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   /* Most pinentries out in the wild return the old Assuan error code
      for canceled which gets translated to an assuan Cancel error and
@@ -1207,8 +1273,7 @@ agent_get_confirmation (ctrl_t ctrl,
 
   if (ok)
     {
-      snprintf (line, DIM(line)-1, "SETOK %s", ok);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "SETOK %s", ok);
       rc = assuan_transact (entry_ctx,
                             line, NULL, NULL, NULL, NULL, NULL, NULL);
       if (rc)
@@ -1221,8 +1286,7 @@ agent_get_confirmation (ctrl_t ctrl,
          the standard cancel.  */
       if (with_cancel)
         {
-          snprintf (line, DIM(line)-1, "SETNOTOK %s", notok);
-          line[DIM(line)-1] = 0;
+          snprintf (line, DIM(line), "SETNOTOK %s", notok);
           rc = assuan_transact (entry_ctx,
                                 line, NULL, NULL, NULL, NULL, NULL, NULL);
         }
@@ -1231,8 +1295,7 @@ agent_get_confirmation (ctrl_t ctrl,
 
       if (gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
        {
-         snprintf (line, DIM(line)-1, "SETCANCEL %s", notok);
-         line[DIM(line)-1] = 0;
+         snprintf (line, DIM(line), "SETCANCEL %s", notok);
          rc = assuan_transact (entry_ctx, line,
                                 NULL, NULL, NULL, NULL, NULL, NULL);
        }
@@ -1268,10 +1331,9 @@ agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
     return rc;
 
   if (desc)
-    snprintf (line, DIM(line)-1, "SETDESC %s", desc);
+    snprintf (line, DIM(line), "SETDESC %s", desc);
   else
-    snprintf (line, DIM(line)-1, "RESET");
-  line[DIM(line)-1] = 0;
+    snprintf (line, DIM(line), "RESET");
   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   /* Most pinentries out in the wild return the old Assuan error code
      for canceled which gets translated to an assuan Cancel error and
@@ -1284,8 +1346,7 @@ agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
 
   if (ok_btn)
     {
-      snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "SETOK %s", ok_btn);
       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
                             NULL, NULL, NULL);
       if (rc)
@@ -1340,18 +1401,16 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
     return rc;
 
   if (desc)
-    snprintf (line, DIM(line)-1, "SETDESC %s", desc);
+    snprintf (line, DIM(line), "SETDESC %s", desc);
   else
-    snprintf (line, DIM(line)-1, "RESET");
-  line[DIM(line)-1] = 0;
+    snprintf (line, DIM(line), "RESET");
   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return unlock_pinentry (rc);
 
   if (ok_btn)
     {
-      snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "SETOK %s", ok_btn);
       rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
       if (rc)
         return unlock_pinentry (rc);
@@ -1451,7 +1510,7 @@ agent_clear_passphrase (ctrl_t ctrl,
   if (rc)
     return rc;
 
-  snprintf (line, DIM(line)-1, "CLEARPASSPHRASE %c/%s",
+  snprintf (line, DIM(line), "CLEARPASSPHRASE %c/%s",
            cache_mode == CACHE_MODE_USER? 'u' :
            cache_mode == CACHE_MODE_SSH? 's' : 'n',
            keyinfo);