Blame src/w32-util.c

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