Preparing a release candidate.
[gnupg.git] / agent / command-ssh.c
index 1adf8ba..c262cad 100644 (file)
@@ -5,7 +5,7 @@
  *
  * 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 2 of the License, or
+ * 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,
@@ -14,9 +14,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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 /* Only v2 of the ssh-agent protocol is implemented.  */
@@ -421,10 +419,8 @@ stream_read_string (estream_t stream, unsigned int secure,
                    unsigned char **string, u32 *string_size)
 {
   gpg_error_t err;
-  unsigned char *buffer;
-  u32 length;
-
-  buffer = NULL;
+  unsigned char *buffer = NULL;
+  u32 length = 0;
 
   /* Read string length.  */
   err = stream_read_uint32 (stream, &length);
@@ -786,6 +782,8 @@ add_control_entry (ctrl_t ctrl, const char *hexgrip, int ttl)
   FILE *fp;
   int disabled;
 
+  (void)ctrl;
+
   err = open_control_file (&fp, 1);
   if (err)
     return err;
@@ -796,7 +794,7 @@ add_control_entry (ctrl_t ctrl, const char *hexgrip, int ttl)
       struct tm *tp;
       time_t atime = time (NULL);
 
-      /* Not yet in the file - add it. Becuase the file has been
+      /* Not yet in the file - add it. Because the file has been
          opened in append mode, we simply need to write to it.  */
       tp = localtime (&atime);
       fprintf (fp, "# Key added on %04d-%02d-%02d %02d:%02d:%02d\n%s %d\n",
@@ -1786,6 +1784,8 @@ ssh_handler_request_identities (ctrl_t ctrl,
   char *cardsn;
   gpg_error_t ret_err;
 
+  (void)request;
+
   /* Prepare buffer stream.  */
 
   key_directory = NULL;
@@ -1964,7 +1964,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
   if (ctrl_fp)
     fclose (ctrl_fp);
 
-  free (key_directory);
+  xfree (key_directory);
   xfree (key_path);
   xfree (buffer);
   xfree (key_type);
@@ -2317,6 +2317,18 @@ ssh_key_to_protected_buffer (gcry_sexp_t key, const char *passphrase,
 
 
 
+/* Callback function to compare the first entered PIN with the one
+   currently being entered. */
+static int
+reenter_compare_cb (struct pin_entry_info_s *pi)
+{
+  const char *pin1 = pi->check_cb_arg;
+
+  if (!strcmp (pin1, pi->pin))
+    return 0; /* okay */
+  return -1;
+}
+
 /* Store the ssh KEY into our local key storage and protect it after
    asking for a passphrase.  Cache that passphrase.  TTL is the
    maximum caching time for that key.  If the key already exists in
@@ -2329,11 +2341,13 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
   unsigned char key_grip_raw[20];
   char key_grip[41];
   unsigned char *buffer = NULL;
-  unsigned int buffer_n;
+  size_t buffer_n;
   char *description = NULL;
+  const char *description2 = _("Please re-enter this passphrase");
   char *comment = NULL;
+  const char *initial_errtext = NULL;
   unsigned int i;
-  struct pin_entry_info_s *pi = NULL;
+  struct pin_entry_info_s *pi = NULL, *pi2;
 
   err = ssh_key_grip (key, key_grip_raw);
   if (err)
@@ -2361,18 +2375,38 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
     }
 
 
-  pi = gcry_calloc_secure (1, sizeof (*pi) + 100 + 1);
+  pi = gcry_calloc_secure (2, sizeof (*pi) + 100 + 1);
   if (!pi)
     {
       err = gpg_error_from_syserror ();
       goto out;
     }
+  pi2 = pi + (sizeof *pi + 100 + 1);
   pi->max_length = 100;
   pi->max_tries = 1;
-  err = agent_askpin (ctrl, description, NULL, NULL, pi);
+  pi2->max_length = 100;
+  pi2->max_tries = 1;
+  pi2->check_cb = reenter_compare_cb;
+  pi2->check_cb_arg = pi->pin;
+
+ next_try:
+  err = agent_askpin (ctrl, description, NULL, initial_errtext, pi);
+  initial_errtext = NULL;
   if (err)
     goto out;
 
+  /* Unless the passphrase is empty, ask to confirm it.  */
+  if (pi->pin && *pi->pin)
+    {
+      err = agent_askpin (ctrl, description2, NULL, NULL, pi2);
+      if (err == -1)
+       { /* The re-entered one did not match and the user did not
+            hit cancel. */
+         initial_errtext = _("does not match - try again");
+         goto next_try;
+       }
+    }
+
   err = ssh_key_to_protected_buffer (key, pi->pin, &buffer, &buffer_n);
   if (err)
     goto out;
@@ -2400,7 +2434,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
   xfree (pi);
   xfree (buffer);
   xfree (comment);
-  free (description); /* (asprintf allocated, thus regular free.)  */
+  xfree (description); 
 
   return err;
 }
@@ -2511,6 +2545,8 @@ ssh_handler_remove_identity (ctrl_t ctrl,
   gpg_error_t ret_err;
   gpg_error_t err;
 
+  (void)ctrl;
+
   /* Receive key.  */
 
   key_blob = NULL;
@@ -2560,6 +2596,9 @@ ssh_handler_remove_all_identities (ctrl_t ctrl,
 {
   gpg_error_t ret_err;
   gpg_error_t err;
+
+  (void)ctrl;
+  (void)request;
   
   err = ssh_identities_remove_all ();
 
@@ -2602,6 +2641,9 @@ ssh_handler_lock (ctrl_t ctrl, estream_t request, estream_t response)
 {
   gpg_error_t ret_err;
   gpg_error_t err;
+
+  (void)ctrl;
+  (void)request;
   
   err = ssh_lock ();
 
@@ -2620,6 +2662,9 @@ ssh_handler_unlock (ctrl_t ctrl, estream_t request, estream_t response)
   gpg_error_t ret_err;
   gpg_error_t err;
   
+  (void)ctrl;
+  (void)request;
+
   err = ssh_unlock ();
 
   if (! err)
@@ -2646,7 +2691,8 @@ request_spec_lookup (int type)
       break;
   if (i == DIM (request_specs))
     {
-      log_info ("ssh request %u is not supported\n", type);
+      if (opt.verbose)
+        log_info ("ssh request %u is not supported\n", type);
       spec = NULL;
     }
   else
@@ -2821,36 +2867,33 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
 
 /* Start serving client on SOCK_CLIENT.  */
 void
-start_command_handler_ssh (int sock_client)
+start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
 {
-  struct server_control_s ctrl;
   estream_t stream_sock;
   gpg_error_t err;
   int ret;
 
-  /* Setup control structure.  */
-
-  memset (&ctrl, 0, sizeof (ctrl));
-  agent_init_default_ctrl (&ctrl);
-  ctrl.connection_fd = sock_client;
-
   /* Because the ssh protocol does not send us information about the
      the current TTY setting, we resort here to use those from startup
      or those explictly set.  */
-  if (!ctrl.display && opt.startup_display)
-    ctrl.display = strdup (opt.startup_display);
-  if (!ctrl.ttyname && opt.startup_ttyname)
-    ctrl.ttyname = strdup (opt.startup_ttyname);
-  if (!ctrl.ttytype && opt.startup_ttytype)
-    ctrl.ttytype = strdup (opt.startup_ttytype);
-  if (!ctrl.lc_ctype && opt.startup_lc_ctype)
-    ctrl.lc_ctype = strdup (opt.startup_lc_ctype);
-  if (!ctrl.lc_messages && opt.startup_lc_messages)
-    ctrl.lc_messages = strdup (opt.startup_lc_messages);
+  if (!ctrl->display && opt.startup_display)
+    ctrl->display = strdup (opt.startup_display);
+  if (!ctrl->ttyname && opt.startup_ttyname)
+    ctrl->ttyname = strdup (opt.startup_ttyname);
+  if (!ctrl->ttytype && opt.startup_ttytype)
+    ctrl->ttytype = strdup (opt.startup_ttytype);
+  if (!ctrl->lc_ctype && opt.startup_lc_ctype)
+    ctrl->lc_ctype = strdup (opt.startup_lc_ctype);
+  if (!ctrl->lc_messages && opt.startup_lc_messages)
+    ctrl->lc_messages = strdup (opt.startup_lc_messages);
+  if (!ctrl->xauthority && opt.startup_xauthority)
+    ctrl->xauthority = strdup (opt.startup_xauthority);
+  if (!ctrl->pinentry_user_data && opt.startup_pinentry_user_data)
+    ctrl->pinentry_user_data = strdup (opt.startup_pinentry_user_data);
 
 
   /* Create stream from socket.  */
-  stream_sock = es_fdopen (sock_client, "r+");
+  stream_sock = es_fdopen (FD2INT(sock_client), "r+");
   if (!stream_sock)
     {
       err = gpg_error_from_syserror ();
@@ -2870,20 +2913,23 @@ start_command_handler_ssh (int sock_client)
     }
 
   /* Main processing loop. */
-  while ( !ssh_request_process (&ctrl, stream_sock) )
-    ;
+  while ( !ssh_request_process (ctrl, stream_sock) )
+    {
+      /* Check wether we have reached EOF before trying to read
+        another request.  */
+      int c;
+
+      c = es_fgetc (stream_sock);
+      if (c == EOF)
+        break;
+      es_ungetc (c, stream_sock);
+    }
 
   /* Reset the SCD in case it has been used. */
-  agent_reset_scd (&ctrl);
+  agent_reset_scd (ctrl);
 
 
  out:
   if (stream_sock)
     es_fclose (stream_sock);
-
-  free (ctrl.display);
-  free (ctrl.ttyname);
-  free (ctrl.ttytype);
-  free (ctrl.lc_ctype);
-  free (ctrl.lc_messages);
 }