core: Fix duplication of close_notify_handler for gpgsm. master
authorNIIBE Yutaka <gniibe@fsij.org>
Fri, 19 Apr 2019 05:54:52 +0000 (14:54 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Fri, 19 Apr 2019 05:54:52 +0000 (14:54 +0900)
* src/engine-gpgsm.c [!USE_DESCRIPTOR_PASSING] (gpgsm_new): Remove
last call to _gpgme_io_set_close_notify.

--

It is called just after the code in question for all cases.

GnuPG-bug-id: 4456
Fixes-commit: dd21ec997cf4b6ba18538c63c728478110ad1f60
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
15 files changed:
NEWS
configure.ac
lang/cpp/src/gpggencardkeyinteractor.cpp
lang/cpp/src/gpggencardkeyinteractor.h
lang/python/doc/rst/_build/README
src/assuan-support.c
src/debug.c
src/dirinfo.c
src/engine-gpgsm.c
src/engine.c
src/posix-util.c
src/sys-util.h
src/w32-glib-io.c
src/w32-io.c
src/w32-util.c

diff --git a/NEWS b/NEWS
index 9c11df3..07f4efb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,13 +1,60 @@
-Noteworthy changes in version 1.12.1 (unreleased)
+Noteworthy changes in version 1.13.1 (unreleased)
 -------------------------------------------------
 
+
+Noteworthy changes in version 1.13.0 (2019-03-26)
+-------------------------------------------------
+
+ * Support GPGME_AUDITLOG_DIAG for gpgsm.  [#4426]
+
+ * New context flag "trust-model".
+
+ * Removed support for WindowsCE and Windows ME.
+
+ * Aligned the gpgrt-config code with our other libaries.
+
+ * Auto-check for all installed Python versions.  [#3354]
+
+ * Fixed generating card key in the C++ bindings.  [#4428]
+
+ * Fixed a segv due to bad parameters in genkey.  [#4192]
+
+ * Fixed crash if the plaintext is ignored in a CMS verify.
+
+ * Fixed memleak on Windows.  [T4238]
+
+ * Tweaked the Windows I/O code.
+
+ * Fixed random crashes on Windows due to closing an arbitrary
+   handle.  [#4237]
+
+ * Fixed a segv on Windows.  [#4369]
+
+ * Fixed test suite problems related to dtags.  [#4298]
+
+ * Fixed bunch of python bugs.  [#4242,commit 9de1c96ac3cf]
+
+ * Several fixes to the Common Lisp bindings.
+
+ * Fixed minor bugs in gpgme-json.  [#4331,#4341,#4342,#4343
+
+ * Require trace level 8 to dump all I/O data.
+
+ * The compiler must now support variadic macros.
+
  * Interface changes relative to the 1.12.0 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ gpgme_set_ctx_flag               EXTENDED: New flag 'trust-model'.
  cpp: Context::create                       NEW.
  cpp: Key::isBad                            NEW.
  cpp: Subkey::isBad                         NEW.
  cpp: UserID::isBad                         NEW.
  cpp: UserID::Signature::isBad              NEW.
+ cpp: GenCardKeyInteractor::setAlgo         NEW.
+
+ [c=C33/A22/R0 cpp=C15/A9/R0 qt=C10/A3/R3]
+
+ Release-info: https://dev.gnupg.org/T4376
 
 
 Noteworthy changes in version 1.12.0 (2018-10-08)
index e59a2f8..e8a0815 100644 (file)
@@ -29,7 +29,7 @@ min_automake_version="1.14"
 # for the LT versions.
 m4_define([mym4_package],[gpgme])
 m4_define([mym4_major], [1])
-m4_define([mym4_minor], [12])
+m4_define([mym4_minor], [13])
 m4_define([mym4_micro], [1])
 
 # Below is m4 magic to extract and compute the git revision number,
@@ -51,20 +51,20 @@ AC_INIT([mym4_package],[mym4_version], [https://bugs.gnupg.org])
 #   (Interfaces added:                 AGE++)
 #   (Interfaces removed:               AGE=0)
 #
-LIBGPGME_LT_CURRENT=32
-LIBGPGME_LT_AGE=21
+LIBGPGME_LT_CURRENT=33
+LIBGPGME_LT_AGE=22
 LIBGPGME_LT_REVISION=0
 
 # If there is an ABI break in gpgmepp or qgpgme also bump the
 # version in IMPORTED_LOCATION in the GpgmeppConfig-w32.cmake.in.in
 
-LIBGPGMEPP_LT_CURRENT=14
-LIBGPGMEPP_LT_AGE=8
+LIBGPGMEPP_LT_CURRENT=15
+LIBGPGMEPP_LT_AGE=9
 LIBGPGMEPP_LT_REVISION=0
 
 LIBQGPGME_LT_CURRENT=10
 LIBQGPGME_LT_AGE=3
-LIBQGPGME_LT_REVISION=2
+LIBQGPGME_LT_REVISION=3
 ################################################
 
 AC_SUBST(LIBGPGME_LT_CURRENT)
index 831e4c4..b109866 100644 (file)
@@ -36,11 +36,12 @@ using namespace GpgME;
 class GpgGenCardKeyInteractor::Private
 {
 public:
-    Private() : keysize("2048"), backup(false)
+    Private() : keysize("2048"), backup(false), algo(RSA)
     {
 
     }
     std::string name, email, backupFileName, expiry, serial, keysize;
+    Algo algo;
     bool backup;
 };
 
@@ -82,6 +83,11 @@ std::string GpgGenCardKeyInteractor::backupFileName() const
     return d->backupFileName;
 }
 
+void GpgGenCardKeyInteractor::setAlgo(Algo algo)
+{
+    d->algo = algo;
+}
+
 namespace GpgGenCardKeyInteractor_Private
 {
 enum {
@@ -104,6 +110,14 @@ enum {
     QUIT,
     SAVE,
 
+    KEY_ATTR,
+    KEY_ALGO1,
+    KEY_ALGO2,
+    KEY_ALGO3,
+    KEY_CURVE1,
+    KEY_CURVE2,
+    KEY_CURVE3,
+
     ERROR = EditInteractor::ErrorState
 };
 }
@@ -118,6 +132,16 @@ const char *GpgGenCardKeyInteractor::action(Error &err) const
         return "admin";
     case COMMAND:
         return "generate";
+    case KEY_ATTR:
+        return "key-attr";
+    case KEY_ALGO1:
+    case KEY_ALGO2:
+    case KEY_ALGO3:
+        return d->algo == RSA ? "1" : "2";
+    case KEY_CURVE1:
+    case KEY_CURVE2:
+    case KEY_CURVE3:
+        return "1"; // Only cv25519 supported.
     case NAME:
         return d->name.c_str();
     case EMAIL:
@@ -193,10 +217,90 @@ unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char
     case DO_ADMIN:
         if (status == GPGME_STATUS_GET_LINE &&
                 strcmp(args, "cardedit.prompt") == 0) {
+            return KEY_ATTR;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    // Handling for key-attr subcommand
+    case KEY_ATTR:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.prompt") == 0) {
+            // Happens if key attr is not yet supported.
             return COMMAND;
         }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.genkeys.algo") == 0) {
+            return KEY_ALGO1;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case KEY_ALGO1:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.genkeys.size") == 0) {
+            return SIZE;
+        }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.curve") == 0) {
+            return KEY_CURVE1;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case KEY_ALGO2:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.genkeys.size") == 0) {
+            return SIZE2;
+        }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.curve") == 0) {
+            return KEY_CURVE2;
+        }
         err = GENERAL_ERROR;
         return ERROR;
+    case KEY_ALGO3:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.genkeys.size") == 0) {
+            return SIZE3;
+        }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.curve") == 0) {
+            return KEY_CURVE3;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case KEY_CURVE1:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.genkeys.algo") == 0) {
+            return KEY_ALGO2;
+        }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.prompt") == 0) {
+            return COMMAND;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case KEY_CURVE2:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.genkeys.algo") == 0) {
+            return KEY_ALGO3;
+        }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.prompt") == 0) {
+            return COMMAND;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case KEY_CURVE3:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.genkeys.algo") == 0) {
+            return KEY_ALGO3;
+        }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.prompt") == 0) {
+            return COMMAND;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    // End key-attr handling
     case COMMAND:
         if (status == GPGME_STATUS_GET_LINE &&
                 strcmp(args, "cardedit.genkeys.backup_enc") == 0) {
@@ -213,14 +317,21 @@ unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char
                 strcmp(args, "cardedit.genkeys.size") == 0) {
             return SIZE;
         }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.valid") == 0) {
+            return EXPIRE;
+        }
         err = GENERAL_ERROR;
         return ERROR;
     case REPLACE:
         if (status == GPGME_STATUS_GET_LINE &&
                 strcmp(args, "cardedit.genkeys.size") == 0) {
-            printf("Moving to SIZE\n");
             return SIZE;
         }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.valid") == 0) {
+            return EXPIRE;
+        }
         err = GENERAL_ERROR;
         return ERROR;
     case SIZE:
@@ -232,6 +343,14 @@ unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char
                 strcmp(args, "keygen.valid") == 0) {
             return EXPIRE;
         }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.genkeys.algo") == 0) {
+            return KEY_ALGO2;
+        }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.prompt") == 0) {
+            return COMMAND;
+        }
         err = GENERAL_ERROR;
         return ERROR;
     case SIZE2:
@@ -243,6 +362,14 @@ unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char
                 strcmp(args, "keygen.valid") == 0) {
             return EXPIRE;
         }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.genkeys.algo") == 0) {
+            return KEY_ALGO3;
+        }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.prompt") == 0) {
+            return COMMAND;
+        }
         err = GENERAL_ERROR;
         return ERROR;
     case SIZE3:
@@ -250,6 +377,10 @@ unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char
                 strcmp(args, "keygen.valid") == 0) {
             return EXPIRE;
         }
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "cardedit.prompt") == 0) {
+            return COMMAND;
+        }
         err = GENERAL_ERROR;
         return ERROR;
     case EXPIRE:
index d6a7b7b..3d9c713 100644 (file)
@@ -56,6 +56,12 @@ public:
     void setDoBackup(bool value);
     void setExpiry(const std::string &timeString);
 
+    enum Algo {
+        RSA = 1,
+        ECC = 2
+    };
+    void setAlgo(Algo algo);
+
     std::string backupFileName() const;
 
 private:
index 07d5fbb..c8f8c12 100644 (file)
@@ -1 +1 @@
-Directory for Sphinx's built documentation.
\ No newline at end of file
+Directory for Sphinx's built documentation.
index 8c331c6..09db329 100644 (file)
@@ -158,7 +158,7 @@ my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
          void (*atfork) (void *opaque, int reserved),
          void *atforkvalue, unsigned int flags)
 {
-  int err;
+  int err = 0;
   struct spawn_fd_item_s *fd_items;
   int i;
 
@@ -209,10 +209,58 @@ my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
   fd_items[i].fd = -1;
   fd_items[i].dup_to = -1;
 
-  err = _gpgme_io_spawn (name, (char*const*)argv,
-                         (IOSPAWN_FLAG_NOCLOSE | IOSPAWN_FLAG_DETACHED),
-                        fd_items, atfork, atforkvalue, r_pid);
-  if (! err)
+#ifdef HAVE_W32_SYSTEM
+  /* Fix up a potential logger fd so that on windows the fd
+   * translation can work through gpgme-w32spawn.
+   *
+   * We do this here as a hack because we would
+   * otherwise have to change assuan_api and the current
+   * plan in 2019 is to change away from this to gpgrt
+   * based IPC. */
+  if (argv)
+    {
+      int loc = 0;
+      while (argv[loc])
+        {
+          if (!strcmp ("--logger-fd", argv[loc]))
+            {
+              long logger_fd = -1;
+              char *tail;
+              int k = 0;
+              loc++;
+              if (!argv[loc])
+                {
+                  err = GPG_ERR_INV_ARG;
+                  break;
+                }
+              logger_fd = strtol (argv[loc], &tail, 10);
+              if (tail == argv[loc] || logger_fd < 0)
+                {
+                  err = GPG_ERR_INV_ARG;
+                  break;
+                }
+              while (fd_items[k++].fd != -1)
+                {
+                  if (fd_items[k].fd == logger_fd)
+                    {
+                      fd_items[k].arg_loc = loc;
+                      break;
+                    }
+                }
+              break;
+            }
+          loc++;
+        }
+    }
+#endif
+
+  if (!err)
+    {
+      err = _gpgme_io_spawn (name, (char*const*)argv,
+                             (IOSPAWN_FLAG_NOCLOSE | IOSPAWN_FLAG_DETACHED),
+                             fd_items, atfork, atforkvalue, r_pid);
+    }
+  if (!err)
     {
       i = 0;
 
index 81c2a90..79e38ce 100644 (file)
@@ -255,6 +255,8 @@ _gpgme_debug (int level, int mode, const char *func, const char *tagname,
   va_list arg_ptr;
   int saved_errno;
   int need_lf;
+  char *output;
+  int out_len;
 
   if (debug_level < level)
     return 0;
@@ -307,7 +309,12 @@ _gpgme_debug (int level, int mode, const char *func, const char *tagname,
     }
   need_lf = (mode != -1 && (!format || !*format));
 
-  vfprintf (errfp, format, arg_ptr);
+  out_len = gpgrt_vasprintf (&output, format, arg_ptr);
+  if (out_len >= 0)
+    {
+      fwrite (output, out_len, 1, errfp);
+      free (output);
+    }
   va_end (arg_ptr);
   if (need_lf || (format && *format && format[strlen (format) - 1] != '\n'))
     putc ('\n', errfp);
index d481199..5db6109 100644 (file)
@@ -260,7 +260,7 @@ get_gpgconf_item (int what)
       char *pgmname;
 
       pgmname = dirinfo.disable_gpgconf? NULL : _gpgme_get_gpgconf_path ();
-      if (pgmname && access (pgmname, F_OK))
+      if (pgmname && _gpgme_access (pgmname, F_OK))
         {
           _gpgme_debug (DEBUG_INIT, -1, NULL, NULL, NULL,
                         "gpgme-dinfo: gpgconf='%s' [not installed]\n", pgmname);
index 396f19c..07fde4a 100644 (file)
@@ -549,8 +549,6 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir,
          || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
                                         close_notify_handler, gpgsm)
          || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
-                                        close_notify_handler, gpgsm)
-         || _gpgme_io_set_close_notify (gpgsm->diag_cb.fd,
                                         close_notify_handler, gpgsm)))
     {
       err = gpg_error (GPG_ERR_GENERAL);
index b3df01a..05979c1 100644 (file)
@@ -461,6 +461,7 @@ _gpgme_set_engine_info (gpgme_engine_info_t info, gpgme_protocol_t proto,
         {
           free (new_file_name);
           free (new_home_dir);
+          return gpg_error_from_syserror ();
         }
     }
 
index 881856c..cddb31f 100644 (file)
@@ -157,3 +157,10 @@ _gpgme_allow_set_foreground_window (pid_t pid)
   (void)pid;
   /* Not needed.  */
 }
+
+/* See w32-util.c */
+int
+_gpgme_access (const char *path, int mode)
+{
+  return access (path, mode);
+}
index 6cb2224..e537613 100644 (file)
@@ -28,9 +28,22 @@ int _gpgme_set_override_inst_dir (const char *dir);
 char *_gpgme_get_gpg_path (void);
 char *_gpgme_get_gpgconf_path (void);
 
+int _gpgme_access (const char *path_utf8, int mode);
+
 #ifdef HAVE_W32_SYSTEM
 const char *_gpgme_get_inst_dir (void);
 void _gpgme_w32_cancel_synchronous_io (HANDLE thread);
+/* See CreateProcessA returns true on success */
+int _gpgme_create_process_utf8 (const char *application_name_utf8,
+                                char *command_line_utf8,
+                                LPSECURITY_ATTRIBUTES lpProcessAttributes,
+                                LPSECURITY_ATTRIBUTES lpThreadAttributes,
+                                BOOL bInheritHandles,
+                                DWORD dwCreationFlags,
+                                void *lpEnvironment,
+                                char *working_directory_utf8,
+                                LPSTARTUPINFOA lpStartupInfo,
+                                LPPROCESS_INFORMATION lpProcessInformation);
 #endif
 
 #endif /* SYS_UTIL_H */
index 8c8722c..e2e3b8a 100644 (file)
@@ -421,12 +421,13 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
       return TRACE_SYSRES (-1);
     }
 
-  return TRACE_SUC ("read=0x%x/%p, write=0x%x/%p, channel=%p",
-                    filedes[0],
-                    (HANDLE) _get_osfhandle (giochannel_table[filedes[0]].fd),
-                    filedes[1],
-                    (HANDLE) _get_osfhandle (giochannel_table[filedes[1]].fd),
-                    giochannel_table[1 - inherit_idx].chan);
+  TRACE_SUC ("read=0x%x/%p, write=0x%x/%p, channel=%p",
+            filedes[0],
+            (HANDLE) _get_osfhandle (giochannel_table[filedes[0]].fd),
+            filedes[1],
+            (HANDLE) _get_osfhandle (giochannel_table[filedes[1]].fd),
+            giochannel_table[1 - inherit_idx].chan);
+  return 0;
 }
 
 
@@ -1081,5 +1082,7 @@ _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
       return TRACE_SYSRES (-1);
     }
 
-  return TRACE_SUC ("");
+  TRACE_SUC ("");
+
+  return 0;
 }
index 919ca6f..c5c21f5 100644 (file)
@@ -1389,6 +1389,7 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
   int tmp_fd;
   char *tmp_name;
   const char *spawnhelper;
+  static int spawn_warning_shown = 0;
 
   TRACE_BEG  (DEBUG_SYSIO, "_gpgme_io_spawn", path,
              "path=%s", path);
@@ -1456,36 +1457,40 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
          up their installation this should also be properly communicated
          as otherwise calls to gnupg will result in unsupported protocol
          errors that do not explain a lot. */
-      char *msg;
-      gpgrt_asprintf (&msg, "gpgme-w32spawn.exe was not found in the "
-                            "detected installation directory of GpgME"
-                            "\n\t\"%s\"\n\n"
-                            "Crypto operations will not work.\n\n"
-                            "If you see this it indicates a problem "
-                            "with your installation.\n"
-                            "Please report the problem to your "
-                            "distributor of GpgME.\n\n"
-                            "Developer's Note: The install dir can be "
-                            "manually set with: gpgme_set_global_flag",
-                            _gpgme_get_inst_dir ());
-      MessageBoxA (NULL, msg, "GpgME not installed correctly", MB_OK);
-      gpgrt_free (msg);
+      if (!spawn_warning_shown)
+        {
+          char *msg;
+          gpgrt_asprintf (&msg, "gpgme-w32spawn.exe was not found in the "
+                                "detected installation directory of GpgME"
+                                "\n\t\"%s\"\n\n"
+                                "Crypto operations will not work.\n\n"
+                                "If you see this it indicates a problem "
+                                "with your installation.\n"
+                                "Please report the problem to your "
+                                "distributor of GpgME.\n\n"
+                                "Developer's Note: The install dir can be "
+                                "manually set with: gpgme_set_global_flag",
+                                _gpgme_get_inst_dir ());
+          MessageBoxA (NULL, msg, "GpgME not installed correctly", MB_OK);
+          gpgrt_free (msg);
+          spawn_warning_shown = 1;
+        }
       gpg_err_set_errno (EIO);
       close (tmp_fd);
       DeleteFileA (tmp_name);
       free (tmp_name);
       return TRACE_SYSRES (-1);
     }
-  if (!CreateProcessA (spawnhelper,
-                      arg_string,
-                      &sec_attr,     /* process security attributes */
-                      &sec_attr,     /* thread security attributes */
-                      FALSE,         /* inherit handles */
-                      cr_flags,      /* creation flags */
-                      NULL,          /* environment */
-                      NULL,          /* use current drive/directory */
-                      &si,           /* startup information */
-                      &pi))          /* returns process information */
+  if (!_gpgme_create_process_utf8 (spawnhelper,
+                                   arg_string,
+                                   &sec_attr, /* process security attributes */
+                                   &sec_attr, /* thread security attributes */
+                                   FALSE,     /* inherit handles */
+                                   cr_flags,  /* creation flags */
+                                   NULL,      /* environment */
+                                   NULL,      /* use current drive/directory */
+                                   &si,       /* startup information */
+                                   &pi))      /* returns process information */
     {
       int lasterr = (int)GetLastError ();
       TRACE_LOG  ("CreateProcess failed: ec=%d", lasterr);
index 9802d9c..fba4344 100644 (file)
@@ -168,6 +168,48 @@ wchar_to_utf8 (const wchar_t *string)
 }
 
 
+/* Return a malloced wide char string from an UTF-8 encoded input
+   string STRING.  Caller must free this value. On failure returns
+   NULL; caller may use GetLastError to get the actual error number.
+   Calling this function with STRING set to NULL is not defined. */
+static wchar_t *
+utf8_to_wchar (const char *string)
+{
+  int n;
+  wchar_t *result;
+
+
+  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
+  if (n < 0)
+    return NULL;
+
+  result = (wchar_t *) malloc ((n+1) * sizeof *result);
+  if (!result)
+    return NULL;
+
+  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
+  if (n < 0)
+    {
+      free (result);
+      return NULL;
+    }
+  return result;
+}
+
+
+/* Same as utf8_to_wchar but calling it with NULL returns
+   NULL.  So a return value of NULL only indicates failure
+   if STRING is not set to NULL. */
+static wchar_t *
+utf8_to_wchar0 (const char *string)
+{
+  if (!string)
+    return NULL;
+
+  return utf8_to_wchar (string);
+}
+
+
 /* Replace all forward slashes by backslashes.  */
 static void
 replace_slashes (char *string)
@@ -395,7 +437,7 @@ find_program_in_dir (const char *dir, const char *name)
   if (!result)
     return NULL;
 
-  if (access (result, F_OK))
+  if (_gpgme_access (result, F_OK))
     {
       free (result);
       return NULL;
@@ -408,7 +450,7 @@ find_program_in_dir (const char *dir, const char *name)
 static char *
 find_program_at_standard_place (const char *name)
 {
-  char path[MAX_PATH];
+  wchar_t path[MAX_PATH];
   char *result = NULL;
 
   /* See https://wiki.tcl-lang.org/page/Getting+Windows+%22special+folders%22+with+Ffidl for details on compatibility.
@@ -416,20 +458,24 @@ find_program_at_standard_place (const char *name)
      We First try the generic place and then fallback to the x86
      (i.e. 32 bit) place.  This will prefer a 64 bit of the program
      over a 32 bit version on 64 bit Windows if installed.  */
-  if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0))
+  if (SHGetSpecialFolderPathW (NULL, path, CSIDL_PROGRAM_FILES, 0))
     {
-      result = _gpgme_strconcat (path, "\\", name, NULL);
-      if (result && access (result, F_OK))
+      char *utf8_path = wchar_to_utf8 (path);
+      result = _gpgme_strconcat (utf8_path, "\\", name, NULL);
+      free (utf8_path);
+      if (result && _gpgme_access (result, F_OK))
         {
           free (result);
           result = NULL;
         }
     }
   if (!result
-      && SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
+      && SHGetSpecialFolderPathW (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
     {
-      result = _gpgme_strconcat (path, "\\", name, NULL);
-      if (result && access (result, F_OK))
+      char *utf8_path = wchar_to_utf8 (path);
+      result = _gpgme_strconcat (utf8_path, "\\", name, NULL);
+      free (utf8_path);
+      if (result && _gpgme_access (result, F_OK))
         {
           free (result);
           result = NULL;
@@ -781,6 +827,73 @@ _gpgme_mkstemp (int *fd, char **name)
 }
 
 
+/* Like access but using windows _waccess */
+int
+_gpgme_access (const char *path, int mode)
+{
+  wchar_t *u16 = utf8_to_wchar0 (path);
+  int r = _waccess (u16, mode);
+
+  free(u16);
+  return r;
+}
+
+
+/* Like CreateProcessA but mapping the arguments to wchar API */
+int _gpgme_create_process_utf8 (const char *application_name_utf8,
+                                char *command_line_utf8,
+                                LPSECURITY_ATTRIBUTES lpProcessAttributes,
+                                LPSECURITY_ATTRIBUTES lpThreadAttributes,
+                                BOOL bInheritHandles,
+                                DWORD dwCreationFlags,
+                                void *lpEnvironment,
+                                char *working_directory_utf8,
+                                LPSTARTUPINFOA si,
+                                LPPROCESS_INFORMATION lpProcessInformation)
+{
+  BOOL ret;
+  wchar_t *application_name = utf8_to_wchar0 (application_name_utf8);
+  wchar_t *command_line = utf8_to_wchar0 (command_line_utf8);
+  wchar_t *working_directory = utf8_to_wchar0 (working_directory_utf8);
+
+  STARTUPINFOW siw;
+  memset (&siw, 0, sizeof siw);
+  if (si)
+    {
+      siw.cb = sizeof (siw);
+      siw.dwFlags = si->dwFlags;
+      siw.wShowWindow = si->wShowWindow;
+      siw.hStdInput = si->hStdInput;
+      siw.hStdOutput = si->hStdOutput;
+      siw.hStdError = si->hStdError;
+      siw.dwX = si->dwX;
+      siw.dwY = si->dwY;
+      siw.dwXSize = si->dwXSize;
+      siw.dwYSize = si->dwYSize;
+      siw.dwXCountChars = si->dwXCountChars;
+      siw.dwYCountChars = si->dwYCountChars;
+      siw.dwFillAttribute = si->dwFillAttribute;
+      siw.lpDesktop = utf8_to_wchar0 (si->lpDesktop);
+      siw.lpTitle = utf8_to_wchar0 (si->lpTitle);
+    }
+
+  ret = CreateProcessW (application_name,
+                        command_line,
+                        lpProcessAttributes,
+                        lpThreadAttributes,
+                        bInheritHandles,
+                        dwCreationFlags,
+                        lpEnvironment,
+                        working_directory,
+                        si ? &siw : NULL,
+                        lpProcessInformation);
+  free (siw.lpTitle);
+  free (siw.lpDesktop);
+  free (application_name);
+  free (command_line);
+  free (working_directory);
+  return ret;
+}
 \f
 /* Entry point called by the DLL loader.  */
 #ifdef DLL_EXPORT