Blame src/w32-util.c

Packit d7e8d0
/* w32-util.c - Utility functions for the W32 API
Packit d7e8d0
 * Copyright (C) 1999 Free Software Foundation, Inc
Packit d7e8d0
 * Copyright (C) 2001 Werner Koch (dd9jn)
Packit d7e8d0
 * Copyright (C) 2001, 2002, 2003, 2004, 2007, 2013 g10 Code GmbH
Packit d7e8d0
 *
Packit d7e8d0
 * This file is part of GPGME.
Packit d7e8d0
 *
Packit d7e8d0
 * GPGME is free software; you can redistribute it and/or modify it
Packit d7e8d0
 * under the terms of the GNU Lesser General Public License as
Packit d7e8d0
 * published by the Free Software Foundation; either version 2.1 of
Packit d7e8d0
 * the License, or (at your option) any later version.
Packit d7e8d0
 *
Packit d7e8d0
 * GPGME is distributed in the hope that it will be useful, but
Packit d7e8d0
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit d7e8d0
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit d7e8d0
 * Lesser General Public License for more details.
Packit d7e8d0
 *
Packit d7e8d0
 * You should have received a copy of the GNU Lesser General Public
Packit Service 30b792
 * License along with this program; if not, see <https://gnu.org/licenses/>.
Packit Service 30b792
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit Service 30b792
 */
Packit d7e8d0
Packit d7e8d0
#ifdef HAVE_CONFIG_H
Packit d7e8d0
#include <config.h>
Packit d7e8d0
#endif
Packit d7e8d0
#include <stdio.h>
Packit d7e8d0
#include <stdlib.h>
Packit d7e8d0
#include <string.h>
Packit d7e8d0
#include <assert.h>
Packit d7e8d0
#include <errno.h>
Packit d7e8d0
#include <stdint.h>
Packit d7e8d0
#ifdef HAVE_SYS_TIME_H
Packit d7e8d0
# include <sys/time.h>
Packit d7e8d0
#endif
Packit d7e8d0
#ifdef HAVE_SYS_TYPES_H
Packit d7e8d0
# include <sys/types.h>
Packit d7e8d0
#endif
Packit d7e8d0
#ifdef HAVE_SYS_STAT_H
Packit d7e8d0
# include <sys/stat.h>
Packit d7e8d0
#endif
Packit d7e8d0
#ifdef HAVE_UNISTD_H
Packit d7e8d0
# include <unistd.h>
Packit d7e8d0
#endif
Packit d7e8d0
#include <fcntl.h>
Packit d7e8d0
#include <io.h>
Packit d7e8d0
Packit d7e8d0
#if __MINGW64_VERSION_MAJOR >= 2
Packit d7e8d0
# define _WIN32_IE 0x0501 /* Required by mingw64 toolkit.  */
Packit d7e8d0
#else
Packit d7e8d0
# define _WIN32_IE 0x0400 /* Required for SHGetSpecialFolderPathA.  */
Packit d7e8d0
#endif
Packit d7e8d0
Packit d7e8d0
/* We need to include the windows stuff here prior to shlobj.h so that
Packit d7e8d0
   we get the right winsock version.  This is usually done in util.h
Packit d7e8d0
   but that header also redefines some Windows functions which we need
Packit d7e8d0
   to avoid unless having included shlobj.h.  */
Packit d7e8d0
#include <winsock2.h>
Packit d7e8d0
#include <ws2tcpip.h>
Packit d7e8d0
#include <windows.h>
Packit d7e8d0
#include <shlobj.h>
Packit d7e8d0
Packit d7e8d0
#include "util.h"
Packit d7e8d0
#include "ath.h"
Packit d7e8d0
#include "sema.h"
Packit d7e8d0
#include "debug.h"
Packit d7e8d0
#include "sys-util.h"
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
#define HAVE_ALLOW_SET_FOREGROUND_WINDOW 1
Packit d7e8d0
#ifndef F_OK
Packit d7e8d0
# define F_OK 0
Packit d7e8d0
#endif
Packit d7e8d0
Packit Service 30b792
/* The Registry key used by GNUPG.  */
Packit Service 30b792
#ifdef _WIN64
Packit Service 30b792
# define GNUPG_REGKEY_2  "Software\\Wow6432Node\\GNU\\GnuPG"
Packit Service 30b792
#else
Packit Service 30b792
# define GNUPG_REGKEY_2  "Software\\GNU\\GnuPG"
Packit Service 30b792
#endif
Packit Service 30b792
#ifdef _WIN64
Packit Service 30b792
# define GNUPG_REGKEY_3  "Software\\Wow6432Node\\GnuPG"
Packit Service 30b792
#else
Packit Service 30b792
# define GNUPG_REGKEY_3  "Software\\GnuPG"
Packit Service 30b792
#endif
Packit d7e8d0
Packit d7e8d0
DEFINE_STATIC_LOCK (get_path_lock);
Packit d7e8d0
Packit d7e8d0
/* The module handle of this DLL.  If we are linked statically,
Packit d7e8d0
   dllmain does not exists and thus the value of my_hmodule will be
Packit d7e8d0
   NULL.  The effect is that a GetModuleFileName always returns the
Packit d7e8d0
   file name of the DLL or executable which contains the gpgme code.  */
Packit d7e8d0
static HMODULE my_hmodule;
Packit d7e8d0
Packit d7e8d0
/* These variables store the malloced name of alternative default
Packit d7e8d0
   binaries.  The are set only once by gpgme_set_global_flag.  */
Packit d7e8d0
static char *default_gpg_name;
Packit d7e8d0
static char *default_gpgconf_name;
Packit d7e8d0
/* If this variable is not NULL the value is assumed to be the
Packit d7e8d0
   installation directory.  The variable may only be set once by
Packit d7e8d0
   gpgme_set_global_flag and accessed by _gpgme_get_inst_dir.  */
Packit d7e8d0
static char *override_inst_dir;
Packit d7e8d0
Packit d7e8d0
#define RTLD_LAZY 0
Packit d7e8d0
Packit d7e8d0
static GPG_ERR_INLINE void *
Packit d7e8d0
dlopen (const char * name, int flag)
Packit d7e8d0
{
Packit d7e8d0
  void * hd = LoadLibrary (name);
Packit d7e8d0
Packit d7e8d0
  (void)flag;
Packit d7e8d0
  return hd;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
static GPG_ERR_INLINE void *
Packit d7e8d0
dlsym (void * hd, const char * sym)
Packit d7e8d0
{
Packit d7e8d0
  if (hd && sym)
Packit d7e8d0
    {
Packit d7e8d0
      void * fnc = GetProcAddress (hd, sym);
Packit d7e8d0
      if (!fnc)
Packit d7e8d0
        return NULL;
Packit d7e8d0
      return fnc;
Packit d7e8d0
    }
Packit d7e8d0
  return NULL;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
static GPG_ERR_INLINE int
Packit d7e8d0
dlclose (void * hd)
Packit d7e8d0
{
Packit d7e8d0
  if (hd)
Packit d7e8d0
    {
Packit d7e8d0
      FreeLibrary (hd);
Packit d7e8d0
      return 0;
Packit d7e8d0
    }
Packit d7e8d0
  return -1;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Return a malloced string encoded in UTF-8 from the wide char input
Packit d7e8d0
   string STRING.  Caller must free this value.  Returns NULL and sets
Packit d7e8d0
   ERRNO on failure.  Calling this function with STRING set to NULL is
Packit d7e8d0
   not defined.  */
Packit d7e8d0
static char *
Packit d7e8d0
wchar_to_utf8 (const wchar_t *string)
Packit d7e8d0
{
Packit d7e8d0
  int n;
Packit d7e8d0
  char *result;
Packit d7e8d0
Packit d7e8d0
  n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
Packit d7e8d0
  if (n < 0)
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (EINVAL);
Packit d7e8d0
      return NULL;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  result = malloc (n+1);
Packit d7e8d0
  if (!result)
Packit d7e8d0
    return NULL;
Packit d7e8d0
Packit d7e8d0
  n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
Packit d7e8d0
  if (n < 0)
Packit d7e8d0
    {
Packit d7e8d0
      free (result);
Packit d7e8d0
      gpg_err_set_errno (EINVAL);
Packit d7e8d0
      result = NULL;
Packit d7e8d0
    }
Packit d7e8d0
  return result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit Service 30b792
/* Return a malloced wide char string from an UTF-8 encoded input
Packit Service 30b792
   string STRING.  Caller must free this value. On failure returns
Packit Service 30b792
   NULL; caller may use GetLastError to get the actual error number.
Packit Service 30b792
   Calling this function with STRING set to NULL is not defined. */
Packit Service 30b792
static wchar_t *
Packit Service 30b792
utf8_to_wchar (const char *string)
Packit Service 30b792
{
Packit Service 30b792
  int n;
Packit Service 30b792
  wchar_t *result;
Packit Service 30b792
Packit Service 30b792
Packit Service 30b792
  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
Packit Service 30b792
  if (n < 0)
Packit Service 30b792
    return NULL;
Packit Service 30b792
Packit Service 30b792
  result = (wchar_t *) malloc ((n+1) * sizeof *result);
Packit Service 30b792
  if (!result)
Packit Service 30b792
    return NULL;
Packit Service 30b792
Packit Service 30b792
  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
Packit Service 30b792
  if (n < 0)
Packit Service 30b792
    {
Packit Service 30b792
      free (result);
Packit Service 30b792
      return NULL;
Packit Service 30b792
    }
Packit Service 30b792
  return result;
Packit Service 30b792
}
Packit Service 30b792
Packit Service 30b792
Packit Service 30b792
/* Same as utf8_to_wchar but calling it with NULL returns
Packit Service 30b792
   NULL.  So a return value of NULL only indicates failure
Packit Service 30b792
   if STRING is not set to NULL. */
Packit Service 30b792
static wchar_t *
Packit Service 30b792
utf8_to_wchar0 (const char *string)
Packit Service 30b792
{
Packit Service 30b792
  if (!string)
Packit Service 30b792
    return NULL;
Packit Service 30b792
Packit Service 30b792
  return utf8_to_wchar (string);
Packit Service 30b792
}
Packit Service 30b792
Packit Service 30b792
Packit d7e8d0
/* Replace all forward slashes by backslashes.  */
Packit d7e8d0
static void
Packit d7e8d0
replace_slashes (char *string)
Packit d7e8d0
{
Packit d7e8d0
  for (; *string; string++)
Packit d7e8d0
    if (*string == '/')
Packit d7e8d0
      *string = '\\';
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Get the base name of NAME.  Returns a pointer into NAME right after
Packit d7e8d0
   the last slash or backslash or to NAME if no slash or backslash
Packit d7e8d0
   exists.  */
Packit d7e8d0
static const char *
Packit d7e8d0
get_basename (const char *name)
Packit d7e8d0
{
Packit d7e8d0
  const char *mark, *s;
Packit d7e8d0
Packit d7e8d0
  for (mark=NULL, s=name; *s; s++)
Packit d7e8d0
    if (*s == '/' || *s == '\\')
Packit d7e8d0
      mark = s;
Packit d7e8d0
Packit d7e8d0
  return mark? mark+1 : name;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
void
Packit d7e8d0
_gpgme_allow_set_foreground_window (pid_t pid)
Packit d7e8d0
{
Packit d7e8d0
#ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
Packit d7e8d0
  static int initialized;
Packit d7e8d0
  static BOOL (WINAPI * func)(DWORD);
Packit d7e8d0
  void *handle;
Packit d7e8d0
Packit d7e8d0
  if (!initialized)
Packit d7e8d0
    {
Packit d7e8d0
      /* Available since W2000; thus we dynload it.  */
Packit d7e8d0
      initialized = 1;
Packit d7e8d0
      handle = dlopen ("user32.dll", RTLD_LAZY);
Packit d7e8d0
      if (handle)
Packit d7e8d0
        {
Packit d7e8d0
          func = dlsym (handle, "AllowSetForegroundWindow");
Packit d7e8d0
          if (!func)
Packit d7e8d0
            {
Packit d7e8d0
              dlclose (handle);
Packit d7e8d0
              handle = NULL;
Packit d7e8d0
            }
Packit d7e8d0
        }
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  if (!pid || pid == (pid_t)(-1))
Packit d7e8d0
    {
Packit Service 30b792
      TRACE (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", NULL,
Packit d7e8d0
	      "no action for pid %d", (int)pid);
Packit d7e8d0
    }
Packit d7e8d0
  else if (func)
Packit d7e8d0
    {
Packit d7e8d0
      int rc = func (pid);
Packit Service 30b792
      TRACE (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", NULL,
Packit d7e8d0
	      "called for pid %d; result=%d", (int)pid, rc);
Packit d7e8d0
Packit d7e8d0
    }
Packit d7e8d0
  else
Packit d7e8d0
    {
Packit Service 30b792
      TRACE (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", NULL,
Packit d7e8d0
	      "function not available");
Packit d7e8d0
    }
Packit d7e8d0
#endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit Service 30b792
/* Wrapper around CancelSynchronousIo which is only available since
Packit Service 30b792
 * Vista.  */
Packit Service 30b792
void
Packit Service 30b792
_gpgme_w32_cancel_synchronous_io (HANDLE thread)
Packit Service 30b792
{
Packit Service 30b792
  static int initialized;
Packit Service 30b792
  static BOOL (WINAPI * func)(DWORD);
Packit Service 30b792
  void *handle;
Packit Service 30b792
Packit Service 30b792
  if (!initialized)
Packit Service 30b792
    {
Packit Service 30b792
      /* Available since Vista; thus we dynload it.  */
Packit Service 30b792
      initialized = 1;
Packit Service 30b792
      handle = dlopen ("kernel32.dll", RTLD_LAZY);
Packit Service 30b792
      if (handle)
Packit Service 30b792
        {
Packit Service 30b792
          func = dlsym (handle, "CancelSynchronousIo");
Packit Service 30b792
          if (!func)
Packit Service 30b792
            {
Packit Service 30b792
              dlclose (handle);
Packit Service 30b792
              handle = NULL;
Packit Service 30b792
            }
Packit Service 30b792
        }
Packit Service 30b792
    }
Packit Service 30b792
Packit Service 30b792
  if (func)
Packit Service 30b792
    {
Packit Service 30b792
      if (!func (thread) && GetLastError() != ERROR_NOT_FOUND)
Packit Service 30b792
        {
Packit Service 30b792
          TRACE (DEBUG_ENGINE, "gpgme:CancelSynchronousIo", NULL,
Packit Service 30b792
                  "called for thread %p: ec=%d", thread, GetLastError ());
Packit Service 30b792
        }
Packit Service 30b792
    }
Packit Service 30b792
  else
Packit Service 30b792
    {
Packit Service 30b792
      TRACE (DEBUG_ENGINE, "gpgme:CancelSynchronousIo", NULL,
Packit Service 30b792
	      "function not available");
Packit Service 30b792
    }
Packit Service 30b792
}
Packit Service 30b792
Packit Service 30b792
Packit d7e8d0
/* Return a string from the W32 Registry or NULL in case of error.
Packit d7e8d0
   Caller must release the return value.  A NULL for root is an alias
Packit d7e8d0
   for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
Packit d7e8d0
static char *
Packit d7e8d0
read_w32_registry_string (const char *root, const char *dir, const char *name)
Packit d7e8d0
{
Packit d7e8d0
  HKEY root_key, key_handle;
Packit d7e8d0
  DWORD n1, nbytes, type;
Packit d7e8d0
  char *result = NULL;
Packit d7e8d0
Packit d7e8d0
  if (!root)
Packit d7e8d0
    root_key = HKEY_CURRENT_USER;
Packit d7e8d0
  else if (!strcmp( root, "HKEY_CLASSES_ROOT"))
Packit d7e8d0
    root_key = HKEY_CLASSES_ROOT;
Packit d7e8d0
  else if (!strcmp( root, "HKEY_CURRENT_USER"))
Packit d7e8d0
    root_key = HKEY_CURRENT_USER;
Packit d7e8d0
  else if (!strcmp( root, "HKEY_LOCAL_MACHINE"))
Packit d7e8d0
    root_key = HKEY_LOCAL_MACHINE;
Packit d7e8d0
  else if (!strcmp( root, "HKEY_USERS"))
Packit d7e8d0
    root_key = HKEY_USERS;
Packit d7e8d0
  else if (!strcmp( root, "HKEY_PERFORMANCE_DATA"))
Packit d7e8d0
    root_key = HKEY_PERFORMANCE_DATA;
Packit d7e8d0
  else if (!strcmp( root, "HKEY_CURRENT_CONFIG"))
Packit d7e8d0
    root_key = HKEY_CURRENT_CONFIG;
Packit d7e8d0
  else
Packit d7e8d0
    return NULL;
Packit d7e8d0
Packit d7e8d0
  if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle))
Packit d7e8d0
    {
Packit d7e8d0
      if (root)
Packit d7e8d0
        return NULL; /* no need for a RegClose, so return direct */
Packit d7e8d0
      /* It seems to be common practise to fall back to HKLM. */
Packit d7e8d0
      if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
Packit d7e8d0
        return NULL; /* still no need for a RegClose, so return direct */
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  nbytes = 1;
Packit d7e8d0
  if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
Packit d7e8d0
    {
Packit d7e8d0
      if (root)
Packit d7e8d0
        goto leave;
Packit d7e8d0
      /* Try to fallback to HKLM also vor a missing value.  */
Packit d7e8d0
      RegCloseKey (key_handle);
Packit d7e8d0
      if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
Packit d7e8d0
        return NULL; /* Nope.  */
Packit d7e8d0
      if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
Packit d7e8d0
        goto leave;
Packit d7e8d0
    }
Packit d7e8d0
  n1 = nbytes + 1;
Packit d7e8d0
  result = malloc (n1);
Packit d7e8d0
  if (!result)
Packit d7e8d0
    goto leave;
Packit d7e8d0
  if (RegQueryValueExA (key_handle, name, 0, &type, (LPBYTE) result, &n1))
Packit d7e8d0
    {
Packit d7e8d0
      free (result);
Packit d7e8d0
      result = NULL;
Packit d7e8d0
      goto leave;
Packit d7e8d0
    }
Packit d7e8d0
  result[nbytes] = 0; /* Make sure it is really a string.  */
Packit d7e8d0
Packit d7e8d0
 leave:
Packit d7e8d0
  RegCloseKey (key_handle);
Packit d7e8d0
  return result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Return the name of the directory with the gpgme DLL or the EXE (if
Packit d7e8d0
   statically linked).  May return NULL on severe errors. */
Packit d7e8d0
const char *
Packit d7e8d0
_gpgme_get_inst_dir (void)
Packit d7e8d0
{
Packit d7e8d0
  static char *inst_dir;
Packit d7e8d0
Packit d7e8d0
  if (override_inst_dir)
Packit d7e8d0
    return override_inst_dir;
Packit d7e8d0
Packit d7e8d0
  LOCK (get_path_lock);
Packit d7e8d0
  if (!inst_dir)
Packit d7e8d0
    {
Packit d7e8d0
      wchar_t *moddir;
Packit d7e8d0
Packit d7e8d0
      moddir = malloc ((MAX_PATH+5) * sizeof *moddir);
Packit d7e8d0
      if (moddir)
Packit d7e8d0
        {
Packit d7e8d0
          if (!GetModuleFileNameW (my_hmodule, moddir, MAX_PATH))
Packit d7e8d0
            *moddir = 0;
Packit d7e8d0
          if (!*moddir)
Packit d7e8d0
            gpg_err_set_errno (ENOENT);
Packit d7e8d0
          else
Packit d7e8d0
            {
Packit d7e8d0
              inst_dir = wchar_to_utf8 (moddir);
Packit d7e8d0
              if (inst_dir)
Packit d7e8d0
                {
Packit d7e8d0
                  char *p = strrchr (inst_dir, '\\');
Packit d7e8d0
                  if (p)
Packit d7e8d0
                    *p = 0;
Packit d7e8d0
                }
Packit d7e8d0
            }
Packit d7e8d0
          free (moddir);
Packit d7e8d0
        }
Packit d7e8d0
    }
Packit d7e8d0
  UNLOCK (get_path_lock);
Packit d7e8d0
  return inst_dir;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static char *
Packit d7e8d0
find_program_in_dir (const char *dir, const char *name)
Packit d7e8d0
{
Packit d7e8d0
  char *result;
Packit d7e8d0
Packit d7e8d0
  result = _gpgme_strconcat (dir, "\\", name, NULL);
Packit d7e8d0
  if (!result)
Packit d7e8d0
    return NULL;
Packit d7e8d0
Packit Service 30b792
  if (_gpgme_access (result, F_OK))
Packit d7e8d0
    {
Packit d7e8d0
      free (result);
Packit d7e8d0
      return NULL;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  return result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static char *
Packit d7e8d0
find_program_at_standard_place (const char *name)
Packit d7e8d0
{
Packit Service 30b792
  wchar_t path[MAX_PATH];
Packit d7e8d0
  char *result = NULL;
Packit d7e8d0
Packit Service 30b792
  /* See https://wiki.tcl-lang.org/page/Getting+Windows+%22special+folders%22+with+Ffidl for details on compatibility.
Packit d7e8d0
Packit d7e8d0
     We First try the generic place and then fallback to the x86
Packit d7e8d0
     (i.e. 32 bit) place.  This will prefer a 64 bit of the program
Packit d7e8d0
     over a 32 bit version on 64 bit Windows if installed.  */
Packit Service 30b792
  if (SHGetSpecialFolderPathW (NULL, path, CSIDL_PROGRAM_FILES, 0))
Packit d7e8d0
    {
Packit Service 30b792
      char *utf8_path = wchar_to_utf8 (path);
Packit Service 30b792
      result = _gpgme_strconcat (utf8_path, "\\", name, NULL);
Packit Service 30b792
      free (utf8_path);
Packit Service 30b792
      if (result && _gpgme_access (result, F_OK))
Packit d7e8d0
        {
Packit d7e8d0
          free (result);
Packit d7e8d0
          result = NULL;
Packit d7e8d0
        }
Packit d7e8d0
    }
Packit d7e8d0
  if (!result
Packit Service 30b792
      && SHGetSpecialFolderPathW (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
Packit d7e8d0
    {
Packit Service 30b792
      char *utf8_path = wchar_to_utf8 (path);
Packit Service 30b792
      result = _gpgme_strconcat (utf8_path, "\\", name, NULL);
Packit Service 30b792
      free (utf8_path);
Packit Service 30b792
      if (result && _gpgme_access (result, F_OK))
Packit d7e8d0
        {
Packit d7e8d0
          free (result);
Packit d7e8d0
          result = NULL;
Packit d7e8d0
        }
Packit d7e8d0
    }
Packit d7e8d0
  return result;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Set the default name for the gpg binary.  This function may only be
Packit d7e8d0
   called by gpgme_set_global_flag.  Returns 0 on success.  */
Packit d7e8d0
int
Packit d7e8d0
_gpgme_set_default_gpg_name (const char *name)
Packit d7e8d0
{
Packit d7e8d0
  if (!default_gpg_name)
Packit d7e8d0
    {
Packit d7e8d0
      default_gpg_name = _gpgme_strconcat (name, ".exe", NULL);
Packit d7e8d0
      if (default_gpg_name)
Packit d7e8d0
        replace_slashes (default_gpg_name);
Packit d7e8d0
    }
Packit d7e8d0
  return !default_gpg_name;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
/* Set the default name for the gpgconf binary.  This function may only be
Packit d7e8d0
   called by gpgme_set_global_flag.  Returns 0 on success.  */
Packit d7e8d0
int
Packit d7e8d0
_gpgme_set_default_gpgconf_name (const char *name)
Packit d7e8d0
{
Packit d7e8d0
  if (!default_gpgconf_name)
Packit d7e8d0
    {
Packit d7e8d0
      default_gpgconf_name = _gpgme_strconcat (name, ".exe", NULL);
Packit d7e8d0
      if (default_gpgconf_name)
Packit d7e8d0
        replace_slashes (default_gpgconf_name);
Packit d7e8d0
    }
Packit d7e8d0
  return !default_gpgconf_name;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Set the override installation directory.  This function may only be
Packit d7e8d0
   called by gpgme_set_global_flag.  Returns 0 on success.  */
Packit d7e8d0
int
Packit d7e8d0
_gpgme_set_override_inst_dir (const char *dir)
Packit d7e8d0
{
Packit d7e8d0
  if (!override_inst_dir)
Packit d7e8d0
    {
Packit d7e8d0
      override_inst_dir = strdup (dir);
Packit d7e8d0
      if (override_inst_dir)
Packit d7e8d0
        {
Packit d7e8d0
          replace_slashes (override_inst_dir);
Packit d7e8d0
          /* Remove a trailing slash.  */
Packit d7e8d0
          if (*override_inst_dir
Packit d7e8d0
              && override_inst_dir[strlen (override_inst_dir)-1] == '\\')
Packit d7e8d0
            override_inst_dir[strlen (override_inst_dir)-1] = 0;
Packit d7e8d0
        }
Packit d7e8d0
    }
Packit d7e8d0
  return !override_inst_dir;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Return the full file name of the GPG binary.  This function is used
Packit d7e8d0
   iff gpgconf was not found and thus it can be assumed that gpg2 is
Packit d7e8d0
   not installed.  This function is only called by get_gpgconf_item
Packit d7e8d0
   and may not be called concurrently. */
Packit d7e8d0
char *
Packit d7e8d0
_gpgme_get_gpg_path (void)
Packit d7e8d0
{
Packit d7e8d0
  char *gpg = NULL;
Packit d7e8d0
  const char *name, *inst_dir;
Packit d7e8d0
Packit d7e8d0
  name = default_gpg_name? get_basename (default_gpg_name) : "gpg.exe";
Packit d7e8d0
Packit d7e8d0
  /* 1. Try to find gpg.exe in the installation directory of gpgme.  */
Packit d7e8d0
  inst_dir = _gpgme_get_inst_dir ();
Packit d7e8d0
  if (inst_dir)
Packit d7e8d0
    {
Packit d7e8d0
      gpg = find_program_in_dir (inst_dir, name);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* 2. Try to find gpg.exe using that ancient registry key.  */
Packit d7e8d0
  if (!gpg)
Packit d7e8d0
    {
Packit d7e8d0
      char *dir;
Packit d7e8d0
Packit d7e8d0
      dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
Packit Service 30b792
                                      GNUPG_REGKEY_2,
Packit d7e8d0
                                      "Install Directory");
Packit d7e8d0
      if (dir)
Packit d7e8d0
        {
Packit d7e8d0
          gpg = find_program_in_dir (dir, name);
Packit d7e8d0
          free (dir);
Packit d7e8d0
        }
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* 3. Try to find gpg.exe below CSIDL_PROGRAM_FILES.  */
Packit d7e8d0
  if (!gpg)
Packit d7e8d0
    {
Packit d7e8d0
      name = default_gpg_name? default_gpg_name : "GNU\\GnuPG\\gpg.exe";
Packit d7e8d0
      gpg = find_program_at_standard_place (name);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* 4. Print a debug message if not found.  */
Packit d7e8d0
  if (!gpg)
Packit Service 30b792
    _gpgme_debug (NULL, DEBUG_ENGINE, -1, NULL, NULL, NULL,
Packit Service 30b792
                  "_gpgme_get_gpg_path: '%s' not found", name);
Packit d7e8d0
Packit d7e8d0
  return gpg;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* This function is only called by get_gpgconf_item and may not be
Packit d7e8d0
   called concurrently.  */
Packit d7e8d0
char *
Packit d7e8d0
_gpgme_get_gpgconf_path (void)
Packit d7e8d0
{
Packit d7e8d0
  char *gpgconf = NULL;
Packit d7e8d0
  const char *inst_dir, *name;
Packit d7e8d0
Packit d7e8d0
  name = default_gpgconf_name? get_basename(default_gpgconf_name):"gpgconf.exe";
Packit d7e8d0
Packit d7e8d0
  /* 1. Try to find gpgconf.exe in the installation directory of gpgme.  */
Packit d7e8d0
  inst_dir = _gpgme_get_inst_dir ();
Packit d7e8d0
  if (inst_dir)
Packit d7e8d0
    {
Packit d7e8d0
      gpgconf = find_program_in_dir (inst_dir, name);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* 2. Try to find gpgconf.exe from GnuPG >= 2.1 below CSIDL_PROGRAM_FILES. */
Packit d7e8d0
  if (!gpgconf)
Packit d7e8d0
    {
Packit d7e8d0
      const char *name2 = (default_gpgconf_name ? default_gpgconf_name
Packit d7e8d0
                           /**/                 : "GnuPG\\bin\\gpgconf.exe");
Packit d7e8d0
      gpgconf = find_program_at_standard_place (name2);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* 3. Try to find gpgconf.exe using the Windows registry. */
Packit d7e8d0
  if (!gpgconf)
Packit d7e8d0
    {
Packit d7e8d0
      char *dir;
Packit d7e8d0
Packit d7e8d0
      dir = read_w32_registry_string (NULL,
Packit Service 30b792
                                      GNUPG_REGKEY_2,
Packit d7e8d0
                                      "Install Directory");
Packit d7e8d0
      if (!dir)
Packit d7e8d0
        {
Packit d7e8d0
          char *tmp = read_w32_registry_string (NULL,
Packit Service 30b792
                                                GNUPG_REGKEY_3,
Packit d7e8d0
                                                "Install Directory");
Packit d7e8d0
          if (tmp)
Packit d7e8d0
            {
Packit d7e8d0
              dir = _gpgme_strconcat (tmp, "\\bin", NULL);
Packit d7e8d0
              free (tmp);
Packit d7e8d0
              if (!dir)
Packit d7e8d0
                return NULL;
Packit d7e8d0
            }
Packit d7e8d0
        }
Packit d7e8d0
      if (dir)
Packit d7e8d0
        {
Packit d7e8d0
          gpgconf = find_program_in_dir (dir, name);
Packit d7e8d0
          free (dir);
Packit d7e8d0
        }
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* 4. Try to find gpgconf.exe from Gpg4win below CSIDL_PROGRAM_FILES.  */
Packit d7e8d0
  if (!gpgconf)
Packit d7e8d0
    {
Packit d7e8d0
      gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe");
Packit d7e8d0
    }
Packit d7e8d0
Packit Service 30b792
  /* 5. Try to find gpgconf.exe relative to us.  */
Packit Service 30b792
  if (!gpgconf && inst_dir)
Packit Service 30b792
    {
Packit Service 30b792
      char *dir = _gpgme_strconcat (inst_dir, "\\..\\..\\GnuPG\\bin", NULL);
Packit Service 30b792
      gpgconf = find_program_in_dir (dir, name);
Packit Service 30b792
      free (dir);
Packit Service 30b792
    }
Packit Service 30b792
Packit d7e8d0
  /* 5. Print a debug message if not found.  */
Packit d7e8d0
  if (!gpgconf)
Packit Service 30b792
    _gpgme_debug (NULL, DEBUG_ENGINE, -1, NULL, NULL, NULL,
Packit Service 30b792
                  "_gpgme_get_gpgconf_path: '%s' not found",name);
Packit d7e8d0
Packit d7e8d0
  return gpgconf;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
const char *
Packit d7e8d0
_gpgme_get_w32spawn_path (void)
Packit d7e8d0
{
Packit d7e8d0
  static char *w32spawn_program;
Packit d7e8d0
  const char *inst_dir;
Packit d7e8d0
Packit d7e8d0
  inst_dir = _gpgme_get_inst_dir ();
Packit d7e8d0
  LOCK (get_path_lock);
Packit d7e8d0
  if (!w32spawn_program)
Packit d7e8d0
    w32spawn_program = find_program_in_dir (inst_dir, "gpgme-w32spawn.exe");
Packit d7e8d0
  UNLOCK (get_path_lock);
Packit d7e8d0
  return w32spawn_program;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Return an integer value from gpgme specific configuration
Packit d7e8d0
   entries. VALUE receives that value; function returns true if a value
Packit d7e8d0
   has been configured and false if not. */
Packit d7e8d0
int
Packit d7e8d0
_gpgme_get_conf_int (const char *key, int *value)
Packit d7e8d0
{
Packit d7e8d0
  char *tmp = read_w32_registry_string (NULL, "Software\\GNU\\gpgme", key);
Packit d7e8d0
  if (!tmp)
Packit d7e8d0
    return 0;
Packit d7e8d0
  *value = atoi (tmp);
Packit d7e8d0
  free (tmp);
Packit d7e8d0
  return 1;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit Service 30b792

Packit d7e8d0
/* mkstemp extracted from libc/sysdeps/posix/tempname.c.  Copyright
Packit d7e8d0
   (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
Packit d7e8d0
Packit d7e8d0
   The GNU C Library is free software; you can redistribute it and/or
Packit d7e8d0
   modify it under the terms of the GNU Lesser General Public
Packit d7e8d0
   License as published by the Free Software Foundation; either
Packit d7e8d0
   version 2.1 of the License, or (at your option) any later version.  */
Packit d7e8d0
Packit d7e8d0
static const char letters[] =
Packit d7e8d0
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Packit d7e8d0
Packit d7e8d0
/* Generate a temporary file name based on TMPL.  TMPL must match the
Packit d7e8d0
   rules for mk[s]temp (i.e. end in "XXXXXX").  The name constructed
Packit d7e8d0
   does not exist at the time of the call to mkstemp.  TMPL is
Packit d7e8d0
   overwritten with the result.  */
Packit d7e8d0
static int
Packit d7e8d0
my_mkstemp (char *tmpl)
Packit d7e8d0
{
Packit d7e8d0
  int len;
Packit d7e8d0
  char *XXXXXX;
Packit d7e8d0
  static uint64_t value;
Packit d7e8d0
  uint64_t random_time_bits;
Packit d7e8d0
  unsigned int count;
Packit d7e8d0
  int fd = -1;
Packit d7e8d0
  int save_errno = errno;
Packit d7e8d0
Packit d7e8d0
  /* A lower bound on the number of temporary files to attempt to
Packit d7e8d0
     generate.  The maximum total number of temporary file names that
Packit d7e8d0
     can exist for a given template is 62**6.  It should never be
Packit d7e8d0
     necessary to try all these combinations.  Instead if a reasonable
Packit d7e8d0
     number of names is tried (we define reasonable as 62**3) fail to
Packit d7e8d0
     give the system administrator the chance to remove the problems.  */
Packit d7e8d0
#define ATTEMPTS_MIN (62 * 62 * 62)
Packit d7e8d0
Packit d7e8d0
  /* The number of times to attempt to generate a temporary file.  To
Packit d7e8d0
     conform to POSIX, this must be no smaller than TMP_MAX.  */
Packit d7e8d0
#if ATTEMPTS_MIN < TMP_MAX
Packit d7e8d0
  unsigned int attempts = TMP_MAX;
Packit d7e8d0
#else
Packit d7e8d0
  unsigned int attempts = ATTEMPTS_MIN;
Packit d7e8d0
#endif
Packit d7e8d0
Packit d7e8d0
  len = strlen (tmpl);
Packit d7e8d0
  if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (EINVAL);
Packit d7e8d0
      return -1;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* This is where the Xs start.  */
Packit d7e8d0
  XXXXXX = &tmpl[len - 6];
Packit d7e8d0
Packit d7e8d0
  /* Get some more or less random data.  */
Packit d7e8d0
  {
Packit d7e8d0
    FILETIME ft;
Packit d7e8d0
Packit d7e8d0
    GetSystemTimeAsFileTime (&ft;;
Packit d7e8d0
    random_time_bits = (((uint64_t)ft.dwHighDateTime << 32)
Packit d7e8d0
                        | (uint64_t)ft.dwLowDateTime);
Packit d7e8d0
  }
Packit d7e8d0
  value += random_time_bits ^ ath_self ();
Packit d7e8d0
Packit d7e8d0
  for (count = 0; count < attempts; value += 7777, ++count)
Packit d7e8d0
    {
Packit d7e8d0
      uint64_t v = value;
Packit d7e8d0
Packit d7e8d0
      /* Fill in the random bits.  */
Packit d7e8d0
      XXXXXX[0] = letters[v % 62];
Packit d7e8d0
      v /= 62;
Packit d7e8d0
      XXXXXX[1] = letters[v % 62];
Packit d7e8d0
      v /= 62;
Packit d7e8d0
      XXXXXX[2] = letters[v % 62];
Packit d7e8d0
      v /= 62;
Packit d7e8d0
      XXXXXX[3] = letters[v % 62];
Packit d7e8d0
      v /= 62;
Packit d7e8d0
      XXXXXX[4] = letters[v % 62];
Packit d7e8d0
      v /= 62;
Packit d7e8d0
      XXXXXX[5] = letters[v % 62];
Packit d7e8d0
Packit d7e8d0
      fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
Packit d7e8d0
      if (fd >= 0)
Packit d7e8d0
	{
Packit d7e8d0
	  gpg_err_set_errno (save_errno);
Packit d7e8d0
	  return fd;
Packit d7e8d0
	}
Packit d7e8d0
      else if (errno != EEXIST)
Packit d7e8d0
	return -1;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  /* We got out of the loop because we ran out of combinations to try.  */
Packit d7e8d0
  gpg_err_set_errno (EEXIST);
Packit d7e8d0
  return -1;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
int
Packit d7e8d0
_gpgme_mkstemp (int *fd, char **name)
Packit d7e8d0
{
Packit d7e8d0
  char tmp[MAX_PATH + 2];
Packit d7e8d0
  char *tmpname;
Packit d7e8d0
  int err;
Packit d7e8d0
Packit d7e8d0
  *fd = -1;
Packit d7e8d0
  *name = NULL;
Packit d7e8d0
Packit d7e8d0
  err = GetTempPathA (MAX_PATH + 1, tmp);
Packit d7e8d0
  if (err == 0 || err > MAX_PATH + 1)
Packit d7e8d0
    strcpy (tmp,"c:\\windows\\temp");
Packit d7e8d0
  else
Packit d7e8d0
    {
Packit d7e8d0
      int len = strlen(tmp);
Packit d7e8d0
Packit d7e8d0
      /* GetTempPath may return with \ on the end */
Packit d7e8d0
      while(len > 0 && tmp[len - 1] == '\\')
Packit d7e8d0
	{
Packit d7e8d0
	  tmp[len-1] = '\0';
Packit d7e8d0
	  len--;
Packit d7e8d0
	}
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  tmpname = _gpgme_strconcat (tmp, "\\gpgme-XXXXXX", NULL);
Packit d7e8d0
  if (!tmpname)
Packit d7e8d0
    return -1;
Packit d7e8d0
  *fd = my_mkstemp (tmpname);
Packit d7e8d0
  if (*fd < 0)
Packit d7e8d0
    {
Packit d7e8d0
      free (tmpname);
Packit d7e8d0
      return -1;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  *name = tmpname;
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit Service 30b792
/* Like access but using windows _waccess */
Packit Service 30b792
int
Packit Service 30b792
_gpgme_access (const char *path, int mode)
Packit d7e8d0
{
Packit Service 30b792
  wchar_t *u16 = utf8_to_wchar0 (path);
Packit Service 30b792
  int r = _waccess (u16, mode);
Packit d7e8d0
Packit Service 30b792
  free(u16);
Packit Service 30b792
  return r;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit Service 30b792
/* Like CreateProcessA but mapping the arguments to wchar API */
Packit Service 30b792
int _gpgme_create_process_utf8 (const char *application_name_utf8,
Packit Service 30b792
                                char *command_line_utf8,
Packit Service 30b792
                                LPSECURITY_ATTRIBUTES lpProcessAttributes,
Packit Service 30b792
                                LPSECURITY_ATTRIBUTES lpThreadAttributes,
Packit Service 30b792
                                BOOL bInheritHandles,
Packit Service 30b792
                                DWORD dwCreationFlags,
Packit Service 30b792
                                void *lpEnvironment,
Packit Service 30b792
                                char *working_directory_utf8,
Packit Service 30b792
                                LPSTARTUPINFOA si,
Packit Service 30b792
                                LPPROCESS_INFORMATION lpProcessInformation)
Packit Service 30b792
{
Packit Service 30b792
  BOOL ret;
Packit Service 30b792
  wchar_t *application_name = utf8_to_wchar0 (application_name_utf8);
Packit Service 30b792
  wchar_t *command_line = utf8_to_wchar0 (command_line_utf8);
Packit Service 30b792
  wchar_t *working_directory = utf8_to_wchar0 (working_directory_utf8);
Packit Service 30b792
Packit Service 30b792
  STARTUPINFOW siw;
Packit Service 30b792
  memset (&siw, 0, sizeof siw);
Packit Service 30b792
  if (si)
Packit Service 30b792
    {
Packit Service 30b792
      siw.cb = sizeof (siw);
Packit Service 30b792
      siw.dwFlags = si->dwFlags;
Packit Service 30b792
      siw.wShowWindow = si->wShowWindow;
Packit Service 30b792
      siw.hStdInput = si->hStdInput;
Packit Service 30b792
      siw.hStdOutput = si->hStdOutput;
Packit Service 30b792
      siw.hStdError = si->hStdError;
Packit Service 30b792
      siw.dwX = si->dwX;
Packit Service 30b792
      siw.dwY = si->dwY;
Packit Service 30b792
      siw.dwXSize = si->dwXSize;
Packit Service 30b792
      siw.dwYSize = si->dwYSize;
Packit Service 30b792
      siw.dwXCountChars = si->dwXCountChars;
Packit Service 30b792
      siw.dwYCountChars = si->dwYCountChars;
Packit Service 30b792
      siw.dwFillAttribute = si->dwFillAttribute;
Packit Service 30b792
      siw.lpDesktop = utf8_to_wchar0 (si->lpDesktop);
Packit Service 30b792
      siw.lpTitle = utf8_to_wchar0 (si->lpTitle);
Packit Service 30b792
    }
Packit Service 30b792
Packit Service 30b792
  ret = CreateProcessW (application_name,
Packit Service 30b792
                        command_line,
Packit Service 30b792
                        lpProcessAttributes,
Packit Service 30b792
                        lpThreadAttributes,
Packit Service 30b792
                        bInheritHandles,
Packit Service 30b792
                        dwCreationFlags,
Packit Service 30b792
                        lpEnvironment,
Packit Service 30b792
                        working_directory,
Packit Service 30b792
                        si ? &siw : NULL,
Packit Service 30b792
                        lpProcessInformation);
Packit Service 30b792
  free (siw.lpTitle);
Packit Service 30b792
  free (siw.lpDesktop);
Packit Service 30b792
  free (application_name);
Packit Service 30b792
  free (command_line);
Packit Service 30b792
  free (working_directory);
Packit Service 30b792
  return ret;
Packit Service 30b792
}
Packit Service 30b792

Packit d7e8d0
/* Entry point called by the DLL loader.  */
Packit d7e8d0
#ifdef DLL_EXPORT
Packit d7e8d0
int WINAPI
Packit d7e8d0
DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
Packit d7e8d0
{
Packit d7e8d0
  (void)reserved;
Packit d7e8d0
Packit d7e8d0
  if (reason == DLL_PROCESS_ATTACH)
Packit d7e8d0
    my_hmodule = hinst;
Packit d7e8d0
Packit d7e8d0
  return TRUE;
Packit d7e8d0
}
Packit d7e8d0
#endif /*DLL_EXPORT*/