Remove keyserver helper code.
[gnupg.git] / agent / gpg-agent.c
index 3a86867..096d057 100644 (file)
@@ -1,6 +1,7 @@
 /* gpg-agent.c  -  The GnuPG Agent
  * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009,
  *               2010 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Werner Koch
  *
  * This file is part of GnuPG.
  *
 #include <time.h>
 #include <fcntl.h>
 #include <sys/stat.h>
-#ifndef HAVE_W32_SYSTEM
+#ifdef HAVE_W32_SYSTEM
+# ifndef WINVER
+#  define WINVER 0x0500  /* Same as in common/sysutils.c */
+# endif
+# ifdef HAVE_WINSOCK2_H
+#  include <winsock2.h>
+# endif
+# include <aclapi.h>
+# include <sddl.h>
+#else /*!HAVE_W32_SYSTEM*/
 # include <sys/socket.h>
 # include <sys/un.h>
 #endif /*!HAVE_W32_SYSTEM*/
@@ -51,7 +61,7 @@
 #include "gc-opt-flags.h"
 #include "exechelp.h"
 #include "asshelp.h"
-#include "../include/cipher.h" /* for PUBKEY_ALGO_ECDSA, PUBKEY_ALGO_ECDH */
+#include "openpgpdefs.h"  /* for PUBKEY_ALGO_ECDSA, PUBKEY_ALGO_ECDH */
 #include "../common/init.h"
 
 
@@ -106,12 +116,15 @@ enum cmd_and_opt_values
 
   oIgnoreCacheForSigning,
   oAllowMarkTrusted,
+  oNoAllowMarkTrusted,
   oAllowPresetPassphrase,
   oAllowLoopbackPinentry,
   oKeepTTY,
   oKeepDISPLAY,
   oSSHSupport,
+  oPuttySupport,
   oDisableScdaemon,
+  oDisableCheckOwnSocket,
   oWriteEnvFile
 };
 
@@ -125,8 +138,8 @@ static ARGPARSE_OPTS opts[] = {
 
   { 301, NULL, 0, N_("@Options:\n ") },
 
-  { oServer,   "server",     0, N_("run in server mode (foreground)") },
   { oDaemon,   "daemon",     0, N_("run in daemon mode (background)") },
+  { oServer,   "server",     0, N_("run in server mode (foreground)") },
   { oVerbose, "verbose",     0, N_("verbose") },
   { oQuiet,    "quiet",     0, N_("be somewhat more quiet") },
   { oSh,       "sh",        0, N_("sh-style command output") },
@@ -148,6 +161,7 @@ static ARGPARSE_OPTS opts[] = {
   { oScdaemonProgram, "scdaemon-program", 2 ,
                                N_("|PGM|use PGM as the SCdaemon program") },
   { oDisableScdaemon, "disable-scdaemon", 0, N_("do not use the SCdaemon") },
+  { oDisableCheckOwnSocket, "disable-check-own-socket", 0, "@" },
   { oFakedSystemTime, "faked-system-time", 2, "@" }, /* (epoch time) */
 
   { oBatch,      "batch",       0, "@" },
@@ -178,13 +192,21 @@ static ARGPARSE_OPTS opts[] = {
 
   { oIgnoreCacheForSigning, "ignore-cache-for-signing", 0,
                                N_("do not use the PIN cache when signing")},
-  { oAllowMarkTrusted, "allow-mark-trusted", 0,
-                             N_("allow clients to mark keys as \"trusted\"")},
+  { oNoAllowMarkTrusted, "no-allow-mark-trusted", 0,
+                            N_("disallow clients to mark keys as \"trusted\"")},
+  { oAllowMarkTrusted, "allow-mark-trusted", 0, "@"},
   { oAllowPresetPassphrase, "allow-preset-passphrase", 0,
                              N_("allow presetting passphrase")},
   { oAllowLoopbackPinentry, "allow-loopback-pinentry", 0,
                              N_("allow presetting passphrase")},
-  { oSSHSupport, "enable-ssh-support", 0, N_("enable ssh-agent emulation") },
+  { oSSHSupport, "enable-ssh-support", 0, N_("enable ssh support") },
+  { oPuttySupport, "enable-putty-support", 0,
+#ifdef HAVE_W32_SYSTEM
+      N_("enable putty support")
+#else
+      "@"
+#endif
+  },
   { oWriteEnvFile, "write-env-file", 2|8,
             N_("|FILE|write environment settings also to FILE")},
   {0}
@@ -216,6 +238,17 @@ static ARGPARSE_OPTS opts[] = {
 #endif
 
 
+#ifdef HAVE_W32_SYSTEM
+/* Flag indicating that support for Putty has been enabled.  */
+static int putty_support;
+/* A magic value used with WM_COPYDATA.  */
+#define PUTTY_IPC_MAGIC 0x804e50ba
+/* To avoid surprises we limit the size of the mapped IPC file to this
+   value.  Putty currently (0.62) uses 8k, thus 16k should be enough
+   for the foreseeable future.  */
+#define PUTTY_IPC_MAXLEN 16384
+#endif /*HAVE_W32_SYSTEM*/
+
 /* The list of open file descriptors at startup.  Note that this list
    has been allocated using the standard malloc.  */
 static int *startup_fd_list;
@@ -232,6 +265,9 @@ static int shutdown_pending;
 /* Counter for the currently running own socket checks.  */
 static int check_own_socket_running;
 
+/* Flags to indicate that check_own_socket shall not be called.  */
+static int disable_check_own_socket;
+
 /* It is possible that we are currently running under setuid permissions */
 static int maybe_setuid = 1;
 
@@ -330,7 +366,7 @@ my_strusage (int level)
 
   switch (level)
     {
-    case 11: p = "gpg-agent (GnuPG)";
+    case 11: p = "@GPG_AGENT@ (@GNUPG@)";
       break;
     case 13: p = VERSION; break;
     case 17: p = PRINTABLE_OS_NAME; break;
@@ -346,10 +382,10 @@ my_strusage (int level)
       break;
 
     case 1:
-    case 40: p =  _("Usage: gpg-agent [options] (-h for help)");
+    case 40: p =  _("Usage: @GPG_AGENT@ [options] (-h for help)");
       break;
-    case 41: p =  _("Syntax: gpg-agent [options] [command [args]]\n"
-                    "Secret key management for GnuPG\n");
+    case 41: p =  _("Syntax: @GPG_AGENT@ [options] [command [args]]\n"
+                    "Secret key management for @GNUPG@\n");
     break;
 
     default: p = NULL;
@@ -394,7 +430,7 @@ set_debug (void)
     }
   else
     {
-      log_error (_("invalid debug-level `%s' given\n"), debug_level);
+      log_error (_("invalid debug-level '%s' given\n"), debug_level);
       opt.debug = 0; /* Reset debugging, so that prior debug
                         statements won't have an undesired effect. */
     }
@@ -489,8 +525,9 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
       opt.enable_passhrase_history = 0;
       opt.ignore_cache_for_signing = 0;
-      opt.allow_mark_trusted = 0;
+      opt.allow_mark_trusted = 1;
       opt.disable_scdaemon = 0;
+      disable_check_own_socket = 0;
       return 1;
     }
 
@@ -521,6 +558,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     case oPinentryTouchFile: opt.pinentry_touch_file = pargs->r.ret_str; break;
     case oScdaemonProgram: opt.scdaemon_program = pargs->r.ret_str; break;
     case oDisableScdaemon: opt.disable_scdaemon = 1; break;
+    case oDisableCheckOwnSocket: disable_check_own_socket = 1; break;
 
     case oDefCacheTTL: opt.def_cache_ttl = pargs->r.ret_ulong; break;
     case oDefCacheTTLSSH: opt.def_cache_ttl_ssh = pargs->r.ret_ulong; break;
@@ -547,6 +585,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
 
     case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break;
+    case oNoAllowMarkTrusted: opt.allow_mark_trusted = 0; break;
 
     case oAllowPresetPassphrase: opt.allow_preset_passphrase = 1; break;
 
@@ -573,8 +612,6 @@ main (int argc, char **argv )
   unsigned configlineno;
   int parse_debug = 0;
   int default_config =1;
-  int greeting = 0;
-  int nogreeting = 0;
   int pipe_server = 0;
   int is_daemon = 0;
   int nodetach = 0;
@@ -601,7 +638,7 @@ main (int argc, char **argv )
   /* Please note that we may running SUID(ROOT), so be very CAREFUL
      when adding any stuff between here and the call to INIT_SECMEM()
      somewhere after the option parsing */
-  log_set_prefix ("gpg-agent", JNLIB_LOG_WITH_PREFIX|JNLIB_LOG_WITH_PID);
+  log_set_prefix (GPG_AGENT_NAME, JNLIB_LOG_WITH_PREFIX|JNLIB_LOG_WITH_PID);
 
   /* Make sure that our subsystems are ready.  */
   i18n_init ();
@@ -662,7 +699,7 @@ main (int argc, char **argv )
       }
     if (!err)
       {
-        s = ttyname (0);
+        s = gnupg_ttyname (0);
         if (s)
           err = session_env_setenv (opt.startup_env, "GPG_TTY", s);
       }
@@ -710,7 +747,8 @@ main (int argc, char **argv )
   */
 
   if (default_config)
-    configname = make_filename (opt.homedir, "gpg-agent.conf", NULL );
+    configname = make_filename (opt.homedir, GPG_AGENT_NAME EXTSEP_S "conf",
+                                NULL );
 
   argc = orig_argc;
   argv = orig_argv;
@@ -727,7 +765,7 @@ main (int argc, char **argv )
           if (default_config)
             {
               if( parse_debug )
-                log_info (_("NOTE: no default option file `%s'\n"),
+                log_info (_("NOTE: no default option file '%s'\n"),
                           configname );
               /* Save the default conf file name so that
                  reread_configuration is able to test whether the
@@ -738,7 +776,7 @@ main (int argc, char **argv )
            }
           else
             {
-              log_error (_("option file `%s': %s\n"),
+              log_error (_("option file '%s': %s\n"),
                          configname, strerror(errno) );
               exit(2);
            }
@@ -746,7 +784,7 @@ main (int argc, char **argv )
           configname = NULL;
        }
       if (parse_debug && configname )
-        log_info (_("reading options from `%s'\n"), configname );
+        log_info (_("reading options from '%s'\n"), configname );
       default_config = 0;
     }
 
@@ -772,7 +810,7 @@ main (int argc, char **argv )
                goto next_pass;
            }
           break;
-        case oNoGreeting: nogreeting = 1; break;
+        case oNoGreeting: /* Dummy option.  */ break;
         case oNoVerbose: opt.verbose = 0; break;
         case oNoOptions: break; /* no-options */
         case oHomedir: opt.homedir = pargs.r.ret_str; break;
@@ -808,6 +846,13 @@ main (int argc, char **argv )
         case oKeepDISPLAY: opt.keep_display = 1; break;
 
        case oSSHSupport:  opt.ssh_support = 1; break;
+        case oPuttySupport:
+#        ifdef HAVE_W32_SYSTEM
+          putty_support = 1;
+          opt.ssh_support = 1;
+#        endif
+          break;
+
         case oWriteEnvFile:
           if (pargs.r_type)
             env_file_name = pargs.r.ret_str;
@@ -836,20 +881,19 @@ main (int argc, char **argv )
   configname = NULL;
   if (log_get_errorcount(0))
     exit(2);
-  if (nogreeting )
-    greeting = 0;
 
-  if (greeting)
+  /* Turn the homedir into an absolute one. */
+  opt.homedir = make_absfilename (opt.homedir, NULL);
+
+  /* Print a warning if an argument looks like an option.  */
+  if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
     {
-      es_fprintf (es_stderr, "%s %s; %s\n",
-                  strusage(11), strusage(13), strusage(14) );
-      es_fprintf (es_stderr, "%s\n", strusage(15) );
-    }
-#ifdef IS_DEVELOPMENT_VERSION
-  /* We don't want to print it here because gpg-agent is useful of its
-     own and quite matured.  */
-  /*log_info ("NOTE: this is a development version!\n");*/
-#endif
+      int i;
+
+      for (i=0; i < argc; i++)
+        if (argv[i][0] == '-' && argv[i][1] == '-')
+          log_info (_("NOTE: '%s' is not considered an option\n"), argv[i]);
+    }
 
 #ifdef ENABLE_NLS
   /* gpg-agent usually does not output any messages because it runs in
@@ -913,11 +957,13 @@ main (int argc, char **argv )
       char *filename_esc;
 
       /* List options and default values in the GPG Conf format.  */
-      filename = make_filename (opt.homedir, "gpg-agent.conf", NULL );
+      filename = make_filename (opt.homedir, GPG_AGENT_NAME EXTSEP_S "conf",
+                                NULL );
       filename_esc = percent_escape (filename, NULL);
 
-      es_printf ("gpgconf-gpg-agent.conf:%lu:\"%s\n",
-              GC_OPT_FLAG_DEFAULT, filename_esc);
+      es_printf ("%s-%s.conf:%lu:\"%s\n",
+                 GPGCONF_NAME, GPG_AGENT_NAME,
+                 GC_OPT_FLAG_DEFAULT, filename_esc);
       xfree (filename);
       xfree (filename_esc);
 
@@ -955,10 +1001,15 @@ main (int argc, char **argv )
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       es_printf ("ignore-cache-for-signing:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
-      es_printf ("allow-mark-trusted:%lu:\n",
+      es_printf ("no-allow-mark-trusted:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       es_printf ("disable-scdaemon:%lu:\n",
               GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
+#ifdef HAVE_W32_SYSTEM
+      es_printf ("enable-putty-support:%lu:\n", GC_OPT_FLAG_NONE);
+#else
+      es_printf ("enable-ssh-support:%lu:\n", GC_OPT_FLAG_NONE);
+#endif
 
       agent_exit (0);
     }
@@ -974,8 +1025,8 @@ main (int argc, char **argv )
     }
 
   /* Make sure that we have a default ttyname. */
-  if (!default_ttyname && ttyname (1))
-    default_ttyname = xstrdup (ttyname (1));
+  if (!default_ttyname && gnupg_ttyname (1))
+    default_ttyname = xstrdup (gnupg_ttyname (1));
   if (!default_ttytype && getenv ("TERM"))
     default_ttytype = xstrdup (getenv ("TERM"));
 
@@ -1027,14 +1078,15 @@ main (int argc, char **argv )
 
       /* Create the sockets.  */
       socket_name = create_socket_name
-        ("S.gpg-agent", "gpg-XXXXXX/S.gpg-agent");
-      if (opt.ssh_support)
-       socket_name_ssh = create_socket_name
-          ("S.gpg-agent.ssh", "gpg-XXXXXX/S.gpg-agent.ssh");
+        (GPG_AGENT_SOCK_NAME, "gpg-XXXXXX/"GPG_AGENT_SOCK_NAME);
 
       fd = create_server_socket (socket_name, 0, &socket_nonce);
       if (opt.ssh_support)
-       fd_ssh = create_server_socket (socket_name_ssh, 1, &socket_nonce_ssh);
+        {
+          socket_name_ssh = create_socket_name
+            (GPG_AGENT_SSH_SOCK_NAME, "gpg-XXXXXX/"GPG_AGENT_SSH_SOCK_NAME);
+          fd_ssh = create_server_socket (socket_name_ssh, 1, &socket_nonce_ssh);
+        }
       else
        fd_ssh = GNUPG_INVALID_FD;
 
@@ -1046,8 +1098,12 @@ main (int argc, char **argv )
 
       fflush (NULL);
 #ifdef HAVE_W32_SYSTEM
+      (void)csh_style;
+      (void)nodetach;
+      (void)env_file_name;
       pid = getpid ();
-      es_printf ("set GPG_AGENT_INFO=%s;%lu;1\n", socket_name, (ulong)pid);
+      es_printf ("set %s=%s;%lu;1\n",
+                 GPG_AGENT_INFO_NAME, socket_name, (ulong)pid);
 #else /*!HAVE_W32_SYSTEM*/
       pid = fork ();
       if (pid == (pid_t)-1)
@@ -1057,7 +1113,7 @@ main (int argc, char **argv )
         }
       else if (pid)
         { /* We are the parent */
-          char *infostr, *infostr_ssh_sock;
+          char *infostr, *infostr_ssh_sock, *infostr_ssh_valid;
 
           /* Close the socket FD. */
           close (fd);
@@ -1078,8 +1134,8 @@ main (int argc, char **argv )
 #endif /*HAVE_SIGPROCMASK*/
 
           /* Create the info string: <name>:<pid>:<protocol_version> */
-          if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1",
-                        socket_name, (ulong)pid ) < 0)
+          if (asprintf (&infostr, "%s=%s:%lu:1",
+                        GPG_AGENT_INFO_NAME, socket_name, (ulong)pid ) < 0)
             {
               log_error ("out of core\n");
               kill (pid, SIGTERM);
@@ -1094,6 +1150,13 @@ main (int argc, char **argv )
                  kill (pid, SIGTERM);
                  exit (1);
                }
+             if (asprintf (&infostr_ssh_valid, "gnupg_SSH_AUTH_SOCK_by=%lu",
+                           (unsigned long)getpid()) < 0)
+               {
+                 log_error ("out of core\n");
+                 kill (pid, SIGTERM);
+                 exit (1);
+               }
            }
 
           *socket_name = 0; /* Don't let cleanup() remove the socket -
@@ -1107,7 +1170,7 @@ main (int argc, char **argv )
 
               fp = es_fopen (env_file_name, "w,mode=-rw");
               if (!fp)
-                log_error (_("error creating `%s': %s\n"),
+                log_error (_("error creating '%s': %s\n"),
                              env_file_name, strerror (errno));
               else
                 {
@@ -1132,7 +1195,8 @@ main (int argc, char **argv )
                   kill (pid, SIGTERM );
                   exit (1);
                 }
-              if (opt.ssh_support && putenv (infostr_ssh_sock))
+              if (opt.ssh_support && (putenv (infostr_ssh_sock)
+                                      || putenv (infostr_ssh_valid)))
                 {
                   log_error ("failed to set environment: %s\n",
                              strerror (errno) );
@@ -1168,7 +1232,7 @@ main (int argc, char **argv )
                 }
               else
                 {
-                  es_printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
+                  es_printf ( "%s; export %s;\n", infostr, GPG_AGENT_INFO_NAME);
                  if (opt.ssh_support)
                    {
                      es_printf ("%s; export SSH_AUTH_SOCK;\n",
@@ -1179,6 +1243,7 @@ main (int argc, char **argv )
              if (opt.ssh_support)
                {
                  xfree (infostr_ssh_sock);
+                 xfree (infostr_ssh_valid);
                }
               exit (0);
             }
@@ -1203,7 +1268,7 @@ main (int argc, char **argv )
                   if ( ! close (i)
                        && open ("/dev/null", i? O_WRONLY : O_RDONLY) == -1)
                     {
-                      log_error ("failed to open `%s': %s\n",
+                      log_error ("failed to open '%s': %s\n",
                                  "/dev/null", strerror (errno));
                       cleanup ();
                       exit (1);
@@ -1283,6 +1348,8 @@ agent_exit (int rc)
 static void
 agent_init_default_ctrl (ctrl_t ctrl)
 {
+  assert (ctrl->session_env);
+
   /* Note we ignore malloc errors because we can't do much about it
      and the request will fail anyway shortly after this
      initialization. */
@@ -1300,7 +1367,6 @@ agent_init_default_ctrl (ctrl_t ctrl)
     xfree (ctrl->lc_messages);
   ctrl->lc_messages = default_lc_messages? xtrystrdup (default_lc_messages)
                                     /**/ : NULL;
-
   ctrl->cache_ttl_opt_preset = CACHE_TTL_OPT_PRESET;
 }
 
@@ -1342,7 +1408,7 @@ reread_configuration (void)
   fp = fopen (config_filename, "r");
   if (!fp)
     {
-      log_info (_("option file `%s': %s\n"),
+      log_info (_("option file '%s': %s\n"),
                 config_filename, strerror(errno) );
       return;
     }
@@ -1462,7 +1528,7 @@ create_socket_name (char *standard_name, char *template)
       *p = 0;
       if (!mkdtemp (name))
        {
-         log_error (_("can't create directory `%s': %s\n"),
+         log_error (_("can't create directory '%s': %s\n"),
                     name, strerror (errno));
          agent_exit (2);
        }
@@ -1471,7 +1537,7 @@ create_socket_name (char *standard_name, char *template)
 
   if (strchr (name, PATHSEP_C))
     {
-      log_error (("`%s' are not allowed in the socket name\n"), PATHSEP_S);
+      log_error (("'%s' are not allowed in the socket name\n"), PATHSEP_S);
       agent_exit (2);
     }
   if (strlen (name) + 1 >= DIMof (struct sockaddr_un, sun_path) )
@@ -1508,7 +1574,7 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
   serv_addr->sun_family = AF_UNIX;
   if (strlen (name) + 1 >= sizeof (serv_addr->sun_path))
     {
-      log_error (_("socket name `%s' is too long\n"), name);
+      log_error (_("socket name '%s' is too long\n"), name);
       agent_exit (2);
     }
   strcpy (serv_addr->sun_path, name);
@@ -1552,7 +1618,7 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
     {
       /* We use gpg_strerror here because it allows us to get strings
          for some W32 socket error codes.  */
-      log_error (_("error binding socket to `%s': %s\n"),
+      log_error (_("error binding socket to '%s': %s\n"),
                 serv_addr->sun_path,
                  gpg_strerror (gpg_error_from_errno (errno)));
 
@@ -1570,7 +1636,7 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
     }
 
   if (opt.verbose)
-    log_info (_("listening on socket `%s'\n"), serv_addr->sun_path);
+    log_info (_("listening on socket '%s'\n"), serv_addr->sun_path);
 
   return fd;
 }
@@ -1589,10 +1655,10 @@ create_private_keys_directory (const char *home)
   if (stat (fname, &statbuf) && errno == ENOENT)
     {
       if (gnupg_mkdir (fname, "-rwx"))
-        log_error (_("can't create directory `%s': %s\n"),
+        log_error (_("can't create directory '%s': %s\n"),
                    fname, strerror (errno) );
       else if (!opt.quiet)
-        log_info (_("directory `%s' created\n"), fname);
+        log_info (_("directory '%s' created\n"), fname);
     }
   xfree (fname);
 }
@@ -1628,22 +1694,22 @@ create_directories (void)
                )
             {
               if (gnupg_mkdir (home, "-rwx"))
-                log_error (_("can't create directory `%s': %s\n"),
+                log_error (_("can't create directory '%s': %s\n"),
                            home, strerror (errno) );
               else
                 {
                   if (!opt.quiet)
-                    log_info (_("directory `%s' created\n"), home);
+                    log_info (_("directory '%s' created\n"), home);
                   create_private_keys_directory (home);
                 }
             }
         }
       else
-        log_error (_("stat() failed for `%s': %s\n"), home, strerror (errno));
+        log_error (_("stat() failed for '%s': %s\n"), home, strerror (errno));
     }
   else if ( !S_ISDIR(statbuf.st_mode))
     {
-      log_error (_("can't use `%s' as home directory\n"), home);
+      log_error (_("can't use '%s' as home directory\n"), home);
     }
   else /* exists and is a directory. */
     {
@@ -1792,6 +1858,196 @@ check_nonce (ctrl_t ctrl, assuan_sock_nonce_t *nonce)
 }
 
 
+#ifdef HAVE_W32_SYSTEM
+/* The window message processing function for Putty.  Warning: This
+   code runs as a native Windows thread.  Use of our own functions
+   needs to be bracket with pth_leave/pth_enter. */
+static LRESULT CALLBACK
+putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+  int ret = 0;
+  int w32rc;
+  COPYDATASTRUCT *cds;
+  const char *mapfile;
+  HANDLE maphd;
+  PSID mysid = NULL;
+  PSID mapsid = NULL;
+  void *data = NULL;
+  PSECURITY_DESCRIPTOR psd = NULL;
+  ctrl_t ctrl = NULL;
+
+  if (msg != WM_COPYDATA)
+    {
+      return DefWindowProc (hwnd, msg, wparam, lparam);
+    }
+
+  cds = (COPYDATASTRUCT*)lparam;
+  if (cds->dwData != PUTTY_IPC_MAGIC)
+    return 0;  /* Ignore data with the wrong magic.  */
+  mapfile = cds->lpData;
+  if (!cds->cbData || mapfile[cds->cbData - 1])
+    return 0;  /* Ignore empty and non-properly terminated strings.  */
+
+  if (DBG_ASSUAN)
+    {
+      npth_protect ();
+      log_debug ("ssh map file '%s'", mapfile);
+      npth_unprotect ();
+    }
+
+  maphd = OpenFileMapping (FILE_MAP_ALL_ACCESS, FALSE, mapfile);
+  if (DBG_ASSUAN)
+    {
+      npth_protect ();
+      log_debug ("ssh map handle %p\n", maphd);
+      npth_unprotect ();
+    }
+
+  if (!maphd || maphd == INVALID_HANDLE_VALUE)
+    return 0;
+
+  npth_protect ();
+
+  mysid = w32_get_user_sid ();
+  if (!mysid)
+    {
+      log_error ("error getting my sid\n");
+      goto leave;
+    }
+
+  w32rc = GetSecurityInfo (maphd, SE_KERNEL_OBJECT,
+                           OWNER_SECURITY_INFORMATION,
+                           &mapsid, NULL, NULL, NULL,
+                           &psd);
+  if (w32rc)
+    {
+      log_error ("error getting sid of ssh map file: rc=%d", w32rc);
+      goto leave;
+    }
+
+  if (DBG_ASSUAN)
+    {
+      char *sidstr;
+
+      if (!ConvertSidToStringSid (mysid, &sidstr))
+        sidstr = NULL;
+      log_debug ("          my sid: '%s'", sidstr? sidstr: "[error]");
+      LocalFree (sidstr);
+      if (!ConvertSidToStringSid (mapsid, &sidstr))
+        sidstr = NULL;
+      log_debug ("ssh map file sid: '%s'", sidstr? sidstr: "[error]");
+      LocalFree (sidstr);
+    }
+
+  if (!EqualSid (mysid, mapsid))
+    {
+      log_error ("ssh map file has a non-matching sid\n");
+      goto leave;
+    }
+
+  data = MapViewOfFile (maphd, FILE_MAP_ALL_ACCESS, 0, 0, 0);
+  if (DBG_ASSUAN)
+    log_debug ("ssh IPC buffer at %p\n", data);
+  if (!data)
+    goto leave;
+
+  /* log_printhex ("request:", data, 20); */
+
+  ctrl = xtrycalloc (1, sizeof *ctrl);
+  if (!ctrl)
+    {
+      log_error ("error allocating connection control data: %s\n",
+                 strerror (errno) );
+      goto leave;
+    }
+  ctrl->session_env = session_env_new ();
+  if (!ctrl->session_env)
+    {
+      log_error ("error allocating session environment block: %s\n",
+                 strerror (errno) );
+      goto leave;
+    }
+
+  agent_init_default_ctrl (ctrl);
+  if (!serve_mmapped_ssh_request (ctrl, data, PUTTY_IPC_MAXLEN))
+    ret = 1; /* Valid ssh message has been constructed.  */
+  agent_deinit_default_ctrl (ctrl);
+  /* log_printhex ("  reply:", data, 20); */
+
+ leave:
+  xfree (ctrl);
+  if (data)
+    UnmapViewOfFile (data);
+  xfree (mapsid);
+  if (psd)
+    LocalFree (psd);
+  xfree (mysid);
+  CloseHandle (maphd);
+
+  npth_unprotect ();
+
+  return ret;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+#ifdef HAVE_W32_SYSTEM
+/* The thread handling Putty's IPC requests.  */
+static void *
+putty_message_thread (void *arg)
+{
+  WNDCLASS wndwclass = {0, putty_message_proc, 0, 0,
+                        NULL, NULL, NULL, NULL, NULL, "Pageant"};
+  HWND hwnd;
+  MSG msg;
+
+  (void)arg;
+
+  if (opt.verbose)
+    log_info ("putty message loop thread started\n");
+
+  /* The message loop runs as thread independent from our nPth system.
+     This also means that we need to make sure that we switch back to
+     our system before calling any no-windows function.  */
+  npth_unprotect ();
+
+  /* First create a window to make sure that a message queue exists
+     for this thread.  */
+  if (!RegisterClass (&wndwclass))
+    {
+      npth_protect ();
+      log_error ("error registering Pageant window class");
+      return NULL;
+    }
+  hwnd = CreateWindowEx (0, "Pageant", "Pageant", 0,
+                         0, 0, 0, 0,
+                         HWND_MESSAGE,  /* hWndParent */
+                         NULL,          /* hWndMenu   */
+                         NULL,          /* hInstance  */
+                         NULL);         /* lpParm     */
+  if (!hwnd)
+    {
+      npth_protect ();
+      log_error ("error creating Pageant window");
+      return NULL;
+    }
+
+  while (GetMessage(&msg, NULL, 0, 0))
+    {
+      TranslateMessage(&msg);
+      DispatchMessage(&msg);
+    }
+
+  /* Back to nPth.  */
+  npth_protect ();
+
+  if (opt.verbose)
+    log_info ("putty message loop thread stopped\n");
+  return NULL;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
 /* This is the standard connection thread's main function.  */
 static void *
 start_connection_thread (void *arg)
@@ -1892,6 +2148,22 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
 # endif
 #endif
 
+  /* On Windows we need to fire up a separate thread to listen for
+     requests from Putty (an SSH client), so we can replace Putty's
+     Pageant (its ssh-agent implementation). */
+#ifdef HAVE_W32_SYSTEM
+  if (putty_support)
+    {
+      npth_t thread;
+
+      ret = npth_create (&thread, &tattr, putty_message_thread, NULL);
+      if (ret)
+        {
+          log_error ("error spawning putty message loop: %s\n", strerror (ret));
+        }
+    }
+#endif /*HAVE_W32_SYSTEM*/
+
   /* Set a flag to tell call-scd.c that it may enable event
      notifications.  */
   opt.sigusr2_enabled = 1;
@@ -2155,13 +2427,16 @@ check_own_socket (void)
   npth_attr_t tattr;
   int err;
 
+  if (disable_check_own_socket)
+    return;
+
   if (!opt.use_standard_socket)
     return; /* This check makes only sense in standard socket mode.  */
 
   if (check_own_socket_running || shutdown_pending)
     return;  /* Still running or already shutting down.  */
 
-  sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
+  sockname = make_filename (opt.homedir, GPG_AGENT_SOCK_NAME, NULL);
   if (!sockname)
     return; /* Out of memory.  */
 
@@ -2190,7 +2465,7 @@ check_for_running_agent (int silent, int mode)
 
   if (!mode)
     {
-      infostr = getenv ("GPG_AGENT_INFO");
+      infostr = getenv (GPG_AGENT_INFO_NAME);
       if (!infostr || !*infostr)
         {
           if (!check_for_running_agent (silent, 1))
@@ -2207,7 +2482,8 @@ check_for_running_agent (int silent, int mode)
           if (!check_for_running_agent (silent, 1))
             return 0; /* Okay, its running on the standard socket. */
           if (!silent)
-            log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
+            log_error (_("malformed %s environment variable\n"),
+                       GPG_AGENT_INFO_NAME);
           return -1;
         }
 
@@ -2229,7 +2505,7 @@ check_for_running_agent (int silent, int mode)
     }
   else /* MODE != 0 */
     {
-      infostr = make_filename (opt.homedir, "S.gpg-agent", NULL);
+      infostr = make_filename (opt.homedir, GPG_AGENT_SOCK_NAME, NULL);
       pid = (pid_t)(-1);
     }
 
@@ -2256,12 +2532,3 @@ check_for_running_agent (int silent, int mode)
   assuan_release (ctx);
   return 0;
 }
-
-/* TODO: it is also in misc, which is not linked with the agent */
-/* FIXME: The agent should not know about openpgp internals - weel
-   except for some stuff in cvt-openpgp.  */
-int
-map_pk_openpgp_to_gcry (int algo)
-{
-  return (algo==PUBKEY_ALGO_ECDSA ? GCRY_PK_ECDSA : (algo==PUBKEY_ALGO_ECDH ? GCRY_PK_ECDH : algo));
-}