agent: Minor fix for Windows.
[gnupg.git] / agent / command.c
index a2d4931..e387db5 100644 (file)
@@ -37,7 +37,7 @@
 
 #include "agent.h"
 #include <assuan.h>
-#include "i18n.h"
+#include "../common/i18n.h"
 #include "cvt-openpgp.h"
 #include "../common/ssh-utils.h"
 #include "../common/asshelp.h"
@@ -434,7 +434,7 @@ leave_cmd (assuan_context_t ctx, gpg_error_t err)
 static const char hlp_geteventcounter[] =
   "GETEVENTCOUNTER\n"
   "\n"
-  "Return a status line named EVENTCOUNTER with the current values\n"
+  "Return a status line named EVENTCOUNTER with the current values\n"
   "of all event counters.  The values are decimal numbers in the range\n"
   "0 to UINT_MAX and wrapping around to 0.  The actual values should\n"
   "not be relied upon, they shall only be used to detect a change.\n"
@@ -791,7 +791,6 @@ cmd_pksign (assuan_context_t ctx, char *line)
 
   line = skip_options (line);
 
-  p = line;
   for (p=line; *p && *p != ' ' && *p != '\t'; p++)
     ;
   *p = '\0';
@@ -927,7 +926,6 @@ cmd_genkey (assuan_context_t ctx, char *line)
     }
   line = skip_options (line);
 
-  p = line;
   for (p=line; *p && *p != ' ' && *p != '\t'; p++)
     ;
   *p = '\0';
@@ -1203,7 +1201,7 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
 
       if (!agent_raw_key_from_file (ctrl, grip, &key))
         {
-          ssh_get_fingerprint_string (key, &fpr);
+          ssh_get_fingerprint_string (key, GCRY_MD_MD5, &fpr);
           gcry_sexp_release (key);
         }
     }
@@ -2007,7 +2005,7 @@ static const char hlp_keywrap_key[] =
   "KEYWRAP_KEY [--clear] <mode>\n"
   "\n"
   "Return a key to wrap another key.  For now the key is returned\n"
-  "verbatim and and thus makes not much sense because an eavesdropper on\n"
+  "verbatim and thus makes not much sense because an eavesdropper on\n"
   "the gpg-agent connection will see the key as well as the wrapped key.\n"
   "However, this function may either be equipped with a public key\n"
   "mechanism or not used at all if the key is a pre-shared key.  In any\n"
@@ -2105,7 +2103,6 @@ cmd_import_key (assuan_context_t ctx, char *line)
   force = has_option (line, "--force");
   line = skip_options (line);
 
-  p = line;
   for (p=line; *p && *p != ' ' && *p != '\t'; p++)
     ;
   *p = '\0';
@@ -2433,23 +2430,25 @@ cmd_export_key (assuan_context_t ctx, char *line)
 
 \f
 static const char hlp_delete_key[] =
-  "DELETE_KEY [--force] <hexstring_with_keygrip>\n"
+  "DELETE_KEY [--force|--stub-only] <hexstring_with_keygrip>\n"
   "\n"
   "Delete a secret key from the key store.  If --force is used\n"
   "and a loopback pinentry is allowed, the agent will not ask\n"
-  "the user for confirmation.";
+  "the user for confirmation.  If --stub-only is used the key will\n"
+  "only be deleted if it is a reference to a token.";
 static gpg_error_t
 cmd_delete_key (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err;
-  int force;
+  int force, stub_only;
   unsigned char grip[20];
 
   if (ctrl->restricted)
     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
 
   force = has_option (line, "--force");
+  stub_only = has_option (line, "--stub-only");
   line = skip_options (line);
 
   /* If the use of a loopback pinentry has been disabled, we assume
@@ -2461,7 +2460,8 @@ cmd_delete_key (assuan_context_t ctx, char *line)
   if (err)
     goto leave;
 
-  err = agent_delete_key (ctrl, ctrl->server_local->keydesc, grip, force );
+  err = agent_delete_key (ctrl, ctrl->server_local->keydesc, grip,
+                          force, stub_only);
   if (err)
     goto leave;
 
@@ -2474,6 +2474,12 @@ cmd_delete_key (assuan_context_t ctx, char *line)
 
 
 \f
+#if SIZEOF_TIME_T > SIZEOF_UNSIGNED_LONG
+#define KEYTOCARD_TIMESTAMP_FORMAT "(10:created-at10:%010llu))"
+#else
+#define KEYTOCARD_TIMESTAMP_FORMAT "(10:created-at10:%010lu))"
+#endif
+
 static const char hlp_keytocard[] =
   "KEYTOCARD [--force] <hexstring_with_keygrip> <serialno> <id> <timestamp>\n"
   "\n";
@@ -2486,7 +2492,7 @@ cmd_keytocard (assuan_context_t ctx, char *line)
   unsigned char grip[20];
   gcry_sexp_t s_skey = NULL;
   unsigned char *keydata;
-  size_t keydatalen, timestamplen;
+  size_t keydatalen;
   const char *serialno, *timestamp_str, *id;
   unsigned char *shadow_info = NULL;
   time_t timestamp;
@@ -2499,11 +2505,15 @@ cmd_keytocard (assuan_context_t ctx, char *line)
 
   err = parse_keygrip (ctx, line, grip);
   if (err)
-    return err;
+    goto leave;
 
   if (agent_key_available (grip))
-    return gpg_error (GPG_ERR_NO_SECKEY);
+    {
+      err =gpg_error (GPG_ERR_NO_SECKEY);
+      goto leave;
+    }
 
+  /* Fixme: Replace the parsing code by split_fields().  */
   line += 40;
   while (*line && (*line == ' ' || *line == '\t'))
     line++;
@@ -2511,7 +2521,10 @@ cmd_keytocard (assuan_context_t ctx, char *line)
   while (*line && (*line != ' ' && *line != '\t'))
     line++;
   if (!*line)
-    return gpg_error (GPG_ERR_MISSING_VALUE);
+    {
+      err = gpg_error (GPG_ERR_MISSING_VALUE);
+      goto leave;
+    }
   *line = '\0';
   line++;
   while (*line && (*line == ' ' || *line == '\t'))
@@ -2520,7 +2533,10 @@ cmd_keytocard (assuan_context_t ctx, char *line)
   while (*line && (*line != ' ' && *line != '\t'))
     line++;
   if (!*line)
-    return gpg_error (GPG_ERR_MISSING_VALUE);
+    {
+      err = gpg_error (GPG_ERR_MISSING_VALUE);
+      goto leave;
+    }
   *line = '\0';
   line++;
   while (*line && (*line == ' ' || *line == '\t'))
@@ -2530,9 +2546,12 @@ cmd_keytocard (assuan_context_t ctx, char *line)
     line++;
   if (*line)
     *line = '\0';
-  timestamplen = line - timestamp_str;
-  if (timestamplen != 15)
-    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if ((timestamp = isotime2epoch (timestamp_str)) == (time_t)(-1))
+    {
+      err = gpg_error (GPG_ERR_INV_TIME);
+      goto leave;
+    }
 
   err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip,
                              &shadow_info, CACHE_MODE_IGNORE, NULL,
@@ -2540,34 +2559,36 @@ cmd_keytocard (assuan_context_t ctx, char *line)
   if (err)
     {
       xfree (shadow_info);
-      return err;
+      goto leave;
     }
   if (shadow_info)
     {
       /* Key is on a smartcard already.  */
       xfree (shadow_info);
       gcry_sexp_release (s_skey);
-      return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
+      err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
+      goto leave;
     }
 
   keydatalen =  gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
   keydata = xtrymalloc_secure (keydatalen + 30);
   if (keydata == NULL)
     {
+      err = gpg_error_from_syserror ();
       gcry_sexp_release (s_skey);
-      return gpg_error_from_syserror ();
+      goto leave;
     }
 
   gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
   gcry_sexp_release (s_skey);
   keydatalen--;                        /* Decrement for last '\0'.  */
   /* Add timestamp "created-at" in the private key */
-  timestamp = isotime2epoch (timestamp_str);
-  snprintf (keydata+keydatalen-1, 30, "(10:created-at10:%010lu))", timestamp);
+  snprintf (keydata+keydatalen-1, 30, KEYTOCARD_TIMESTAMP_FORMAT, timestamp);
   keydatalen += 10 + 19 - 1;
   err = divert_writekey (ctrl, force, serialno, id, keydata, keydatalen);
   xfree (keydata);
 
+ leave:
   return leave_cmd (ctx, err);
 }
 
@@ -2631,7 +2652,7 @@ static const char hlp_putval[] =
   "try to connect to that daemon.  Only if that fails they may start\n"
   "an own instance of the service daemon. \n"
   "\n"
-  "KEY is an an arbitrary symbol with the same syntax rules as keys\n"
+  "KEY is an arbitrary symbol with the same syntax rules as keys\n"
   "for shell environment variables.  PERCENT_ESCAPED_VALUE is the\n"
   "corresponding value; they should be similar to the values of\n"
   "envronment variables but gpg-agent does not enforce any\n"
@@ -2831,6 +2852,7 @@ static const char hlp_getinfo[] =
   "  cmd_has_option\n"
   "              - Returns OK if the command CMD implements the option OPT.\n"
   "  connections - Return number of active connections.\n"
+  "  jent_active - Returns OK if Libgcrypt's JENT is active.\n"
   "  restricted  - Returns OK if the connection is in restricted mode.\n";
 static gpg_error_t
 cmd_getinfo (assuan_context_t ctx, char *line)
@@ -2971,6 +2993,24 @@ cmd_getinfo (assuan_context_t ctx, char *line)
                 get_agent_active_connection_count ());
       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
     }
+  else if (!strcmp (line, "jent_active"))
+    {
+#if GCRYPT_VERSION_NUMBER >= 0x010800
+      char *buf;
+      char *fields[5];
+
+      buf = gcry_get_config (0, "rng-type");
+      if (buf
+          && split_fields_colon (buf, fields, DIM (fields)) >= 5
+          && atoi (fields[4]) > 0)
+        rc = 0;
+      else
+        rc = gpg_error (GPG_ERR_FALSE);
+      gcry_free (buf);
+#else
+      rc = gpg_error (GPG_ERR_FALSE);
+#endif
+    }
   else
     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
   return rc;
@@ -3288,6 +3328,8 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
 
   for (;;)
     {
+      pid_t client_pid;
+
       rc = assuan_accept (ctx);
       if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1)
         {
@@ -3299,7 +3341,12 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
           break;
         }
 
-      ctrl->server_local->connect_from_self = (assuan_get_pid (ctx)==getpid ());
+      client_pid = assuan_get_pid (ctx);
+      ctrl->server_local->connect_from_self = (client_pid == getpid ());
+      if (client_pid != ASSUAN_INVALID_PID)
+        ctrl->client_pid = (unsigned long)client_pid;
+      else
+        ctrl->client_pid = 0;
 
       rc = assuan_process (ctx);
       if (rc)