1 /* w32-util.c - Utility functions for the W32 API
2 * Copyright (C) 1999 Free Software Foundation, Inc
3 * Copyright (C) 2001 Werner Koch (dd9jn)
4 * Copyright (C) 2001, 2002, 2003, 2004, 2007, 2013 g10 Code GmbH
6 * This file is part of GPGME.
8 * GPGME is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as
10 * published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
13 * GPGME is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this program; if not, see <https://www.gnu.org/licenses/>.
31 #ifdef HAVE_SYS_TIME_H
32 # include <sys/time.h>
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
37 #ifdef HAVE_SYS_STAT_H
38 # include <sys/stat.h>
46 #if __MINGW64_VERSION_MAJOR >= 2
47 # define _WIN32_IE 0x0501 /* Required by mingw64 toolkit. */
49 # define _WIN32_IE 0x0400 /* Required for SHGetSpecialFolderPathA. */
52 /* We need to include the windows stuff here prior to shlobj.h so that
53 we get the right winsock version. This is usually done in util.h
54 but that header also redefines some Windows functions which we need
55 to avoid unless having included shlobj.h. */
68 #ifndef HAVE_W32CE_SYSTEM
69 #define HAVE_ALLOW_SET_FOREGROUND_WINDOW 1
76 DEFINE_STATIC_LOCK (get_path_lock);
78 /* The module handle of this DLL. If we are linked statically,
79 dllmain does not exists and thus the value of my_hmodule will be
80 NULL. The effect is that a GetModuleFileName always returns the
81 file name of the DLL or executable which contains the gpgme code. */
82 static HMODULE my_hmodule;
84 /* These variables store the malloced name of alternative default
85 binaries. The are set only once by gpgme_set_global_flag. */
86 static char *default_gpg_name;
87 static char *default_gpgconf_name;
88 /* If this variable is not NULL the value is assumed to be the
89 installation directory. The variable may only be set once by
90 gpgme_set_global_flag and accessed by _gpgme_get_inst_dir. */
91 static char *override_inst_dir;
93 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
97 static GPG_ERR_INLINE void *
98 dlopen (const char * name, int flag)
100 void * hd = LoadLibrary (name);
106 static GPG_ERR_INLINE void *
107 dlsym (void * hd, const char * sym)
111 void * fnc = GetProcAddress (hd, sym);
119 static GPG_ERR_INLINE int
129 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
132 /* Return a malloced string encoded in UTF-8 from the wide char input
133 string STRING. Caller must free this value. Returns NULL and sets
134 ERRNO on failure. Calling this function with STRING set to NULL is
137 wchar_to_utf8 (const wchar_t *string)
142 n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
145 gpg_err_set_errno (EINVAL);
149 result = malloc (n+1);
153 n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
157 gpg_err_set_errno (EINVAL);
164 /* Replace all forward slashes by backslashes. */
166 replace_slashes (char *string)
168 for (; *string; string++)
174 /* Get the base name of NAME. Returns a pointer into NAME right after
175 the last slash or backslash or to NAME if no slash or backslash
178 get_basename (const char *name)
180 const char *mark, *s;
182 for (mark=NULL, s=name; *s; s++)
183 if (*s == '/' || *s == '\\')
186 return mark? mark+1 : name;
191 _gpgme_allow_set_foreground_window (pid_t pid)
193 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
194 static int initialized;
195 static BOOL (WINAPI * func)(DWORD);
200 /* Available since W2000; thus we dynload it. */
202 handle = dlopen ("user32.dll", RTLD_LAZY);
205 func = dlsym (handle, "AllowSetForegroundWindow");
214 if (!pid || pid == (pid_t)(-1))
216 TRACE1 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
217 "no action for pid %d", (int)pid);
222 TRACE2 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
223 "called for pid %d; result=%d", (int)pid, rc);
228 TRACE0 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
229 "function not available");
231 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
235 /* Return a string from the W32 Registry or NULL in case of error.
236 Caller must release the return value. A NULL for root is an alias
237 for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
239 read_w32_registry_string (const char *root, const char *dir, const char *name)
241 HKEY root_key, key_handle;
242 DWORD n1, nbytes, type;
246 root_key = HKEY_CURRENT_USER;
247 else if (!strcmp( root, "HKEY_CLASSES_ROOT"))
248 root_key = HKEY_CLASSES_ROOT;
249 else if (!strcmp( root, "HKEY_CURRENT_USER"))
250 root_key = HKEY_CURRENT_USER;
251 else if (!strcmp( root, "HKEY_LOCAL_MACHINE"))
252 root_key = HKEY_LOCAL_MACHINE;
253 else if (!strcmp( root, "HKEY_USERS"))
254 root_key = HKEY_USERS;
255 else if (!strcmp( root, "HKEY_PERFORMANCE_DATA"))
256 root_key = HKEY_PERFORMANCE_DATA;
257 else if (!strcmp( root, "HKEY_CURRENT_CONFIG"))
258 root_key = HKEY_CURRENT_CONFIG;
262 if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle))
265 return NULL; /* no need for a RegClose, so return direct */
266 /* It seems to be common practise to fall back to HKLM. */
267 if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
268 return NULL; /* still no need for a RegClose, so return direct */
272 if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
276 /* Try to fallback to HKLM also vor a missing value. */
277 RegCloseKey (key_handle);
278 if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
279 return NULL; /* Nope. */
280 if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
284 result = malloc (n1);
287 if (RegQueryValueExA (key_handle, name, 0, &type, (LPBYTE) result, &n1))
293 result[nbytes] = 0; /* Make sure it is really a string. */
295 #ifndef HAVE_W32CE_SYSTEM
296 /* Windows CE does not have an environment. */
297 if (type == REG_EXPAND_SZ && strchr (result, '%'))
302 tmp = malloc (n1 + 1);
305 nbytes = ExpandEnvironmentStrings (result, tmp, n1);
306 if (nbytes && nbytes > n1)
310 tmp = malloc (n1 + 1);
313 nbytes = ExpandEnvironmentStrings (result, tmp, n1);
314 if (nbytes && nbytes > n1) {
315 free (tmp); /* Oops - truncated, better don't expand at all. */
322 else if (nbytes) /* Okay, reduce the length. */
326 result = malloc (strlen (tmp)+1);
331 strcpy (result, tmp);
335 else /* Error - don't expand. */
343 RegCloseKey (key_handle);
348 /* Return the name of the directory with the gpgme DLL or the EXE (if
349 statically linked). May return NULL on severe errors. */
351 _gpgme_get_inst_dir (void)
353 static char *inst_dir;
355 if (override_inst_dir)
356 return override_inst_dir;
358 LOCK (get_path_lock);
363 moddir = malloc ((MAX_PATH+5) * sizeof *moddir);
366 if (!GetModuleFileNameW (my_hmodule, moddir, MAX_PATH))
369 gpg_err_set_errno (ENOENT);
372 inst_dir = wchar_to_utf8 (moddir);
375 char *p = strrchr (inst_dir, '\\');
383 UNLOCK (get_path_lock);
389 find_program_in_dir (const char *dir, const char *name)
393 result = _gpgme_strconcat (dir, "\\", name, NULL);
397 if (access (result, F_OK))
408 find_program_at_standard_place (const char *name)
413 /* See http://wiki.tcl.tk/17492 for details on compatibility.
415 We First try the generic place and then fallback to the x86
416 (i.e. 32 bit) place. This will prefer a 64 bit of the program
417 over a 32 bit version on 64 bit Windows if installed. */
418 if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0))
420 result = _gpgme_strconcat (path, "\\", name, NULL);
421 if (result && access (result, F_OK))
428 && SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
430 result = _gpgme_strconcat (path, "\\", name, NULL);
431 if (result && access (result, F_OK))
441 /* Set the default name for the gpg binary. This function may only be
442 called by gpgme_set_global_flag. Returns 0 on success. */
444 _gpgme_set_default_gpg_name (const char *name)
446 if (!default_gpg_name)
448 default_gpg_name = _gpgme_strconcat (name, ".exe", NULL);
449 if (default_gpg_name)
450 replace_slashes (default_gpg_name);
452 return !default_gpg_name;
455 /* Set the default name for the gpgconf binary. This function may only be
456 called by gpgme_set_global_flag. Returns 0 on success. */
458 _gpgme_set_default_gpgconf_name (const char *name)
460 if (!default_gpgconf_name)
462 default_gpgconf_name = _gpgme_strconcat (name, ".exe", NULL);
463 if (default_gpgconf_name)
464 replace_slashes (default_gpgconf_name);
466 return !default_gpgconf_name;
470 /* Set the override installation directory. This function may only be
471 called by gpgme_set_global_flag. Returns 0 on success. */
473 _gpgme_set_override_inst_dir (const char *dir)
475 if (!override_inst_dir)
477 override_inst_dir = strdup (dir);
478 if (override_inst_dir)
480 replace_slashes (override_inst_dir);
481 /* Remove a trailing slash. */
482 if (*override_inst_dir
483 && override_inst_dir[strlen (override_inst_dir)-1] == '\\')
484 override_inst_dir[strlen (override_inst_dir)-1] = 0;
487 return !override_inst_dir;
491 /* Return the full file name of the GPG binary. This function is used
492 iff gpgconf was not found and thus it can be assumed that gpg2 is
493 not installed. This function is only called by get_gpgconf_item
494 and may not be called concurrently. */
496 _gpgme_get_gpg_path (void)
499 const char *name, *inst_dir;
501 name = default_gpg_name? get_basename (default_gpg_name) : "gpg.exe";
503 /* 1. Try to find gpg.exe in the installation directory of gpgme. */
504 inst_dir = _gpgme_get_inst_dir ();
507 gpg = find_program_in_dir (inst_dir, name);
510 /* 2. Try to find gpg.exe using that ancient registry key. */
515 dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
516 "Software\\GNU\\GnuPG",
517 "Install Directory");
520 gpg = find_program_in_dir (dir, name);
525 /* 3. Try to find gpg.exe below CSIDL_PROGRAM_FILES. */
528 name = default_gpg_name? default_gpg_name : "GNU\\GnuPG\\gpg.exe";
529 gpg = find_program_at_standard_place (name);
532 /* 4. Print a debug message if not found. */
534 _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found", name);
540 /* This function is only called by get_gpgconf_item and may not be
541 called concurrently. */
543 _gpgme_get_gpgconf_path (void)
545 char *gpgconf = NULL;
546 const char *inst_dir, *name;
548 name = default_gpgconf_name? get_basename(default_gpgconf_name):"gpgconf.exe";
550 /* 1. Try to find gpgconf.exe in the installation directory of gpgme. */
551 inst_dir = _gpgme_get_inst_dir ();
554 gpgconf = find_program_in_dir (inst_dir, name);
557 /* 2. Try to find gpgconf.exe from GnuPG >= 2.1 below CSIDL_PROGRAM_FILES. */
560 const char *name2 = (default_gpgconf_name ? default_gpgconf_name
561 /**/ : "GnuPG\\bin\\gpgconf.exe");
562 gpgconf = find_program_at_standard_place (name2);
565 /* 3. Try to find gpgconf.exe using the Windows registry. */
570 dir = read_w32_registry_string (NULL,
571 "Software\\GNU\\GnuPG",
572 "Install Directory");
575 char *tmp = read_w32_registry_string (NULL,
577 "Install Directory");
580 if (gpgrt_asprintf (&dir, "%s\\bin", tmp) == -1)
587 gpgconf = find_program_in_dir (dir, name);
592 /* 4. Try to find gpgconf.exe from Gpg4win below CSIDL_PROGRAM_FILES. */
595 gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe");
598 /* 5. Print a debug message if not found. */
600 _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",name);
607 _gpgme_get_w32spawn_path (void)
609 static char *w32spawn_program;
610 const char *inst_dir;
612 inst_dir = _gpgme_get_inst_dir ();
613 LOCK (get_path_lock);
614 if (!w32spawn_program)
615 w32spawn_program = find_program_in_dir (inst_dir, "gpgme-w32spawn.exe");
616 UNLOCK (get_path_lock);
617 return w32spawn_program;
621 /* Return an integer value from gpgme specific configuration
622 entries. VALUE receives that value; function returns true if a value
623 has been configured and false if not. */
625 _gpgme_get_conf_int (const char *key, int *value)
627 char *tmp = read_w32_registry_string (NULL, "Software\\GNU\\gpgme", key);
636 #ifdef HAVE_W32CE_SYSTEM
638 _gpgme_mkstemp (int *fd, char **name)
644 /* mkstemp extracted from libc/sysdeps/posix/tempname.c. Copyright
645 (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
647 The GNU C Library is free software; you can redistribute it and/or
648 modify it under the terms of the GNU Lesser General Public
649 License as published by the Free Software Foundation; either
650 version 2.1 of the License, or (at your option) any later version. */
652 static const char letters[] =
653 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
655 /* Generate a temporary file name based on TMPL. TMPL must match the
656 rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed
657 does not exist at the time of the call to mkstemp. TMPL is
658 overwritten with the result. */
660 my_mkstemp (char *tmpl)
664 static uint64_t value;
665 uint64_t random_time_bits;
668 int save_errno = errno;
670 /* A lower bound on the number of temporary files to attempt to
671 generate. The maximum total number of temporary file names that
672 can exist for a given template is 62**6. It should never be
673 necessary to try all these combinations. Instead if a reasonable
674 number of names is tried (we define reasonable as 62**3) fail to
675 give the system administrator the chance to remove the problems. */
676 #define ATTEMPTS_MIN (62 * 62 * 62)
678 /* The number of times to attempt to generate a temporary file. To
679 conform to POSIX, this must be no smaller than TMP_MAX. */
680 #if ATTEMPTS_MIN < TMP_MAX
681 unsigned int attempts = TMP_MAX;
683 unsigned int attempts = ATTEMPTS_MIN;
687 if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
689 gpg_err_set_errno (EINVAL);
693 /* This is where the Xs start. */
694 XXXXXX = &tmpl[len - 6];
696 /* Get some more or less random data. */
700 GetSystemTimeAsFileTime (&ft);
701 random_time_bits = (((uint64_t)ft.dwHighDateTime << 32)
702 | (uint64_t)ft.dwLowDateTime);
704 value += random_time_bits ^ ath_self ();
706 for (count = 0; count < attempts; value += 7777, ++count)
710 /* Fill in the random bits. */
711 XXXXXX[0] = letters[v % 62];
713 XXXXXX[1] = letters[v % 62];
715 XXXXXX[2] = letters[v % 62];
717 XXXXXX[3] = letters[v % 62];
719 XXXXXX[4] = letters[v % 62];
721 XXXXXX[5] = letters[v % 62];
723 fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
726 gpg_err_set_errno (save_errno);
729 else if (errno != EEXIST)
733 /* We got out of the loop because we ran out of combinations to try. */
734 gpg_err_set_errno (EEXIST);
740 _gpgme_mkstemp (int *fd, char **name)
742 char tmp[MAX_PATH + 2];
749 err = GetTempPathA (MAX_PATH + 1, tmp);
750 if (err == 0 || err > MAX_PATH + 1)
751 strcpy (tmp,"c:\\windows\\temp");
754 int len = strlen(tmp);
756 /* GetTempPath may return with \ on the end */
757 while(len > 0 && tmp[len - 1] == '\\')
764 tmpname = _gpgme_strconcat (tmp, "\\gpgme-XXXXXX", NULL);
767 *fd = my_mkstemp (tmpname);
781 #ifdef HAVE_W32CE_SYSTEM
782 /* Return a malloced string with the replacement value for the
783 GPGME_DEBUG envvar. Caller must release. Returns NULL if not
786 _gpgme_w32ce_get_debug_envvar (void)
790 tmp = read_w32_registry_string (NULL, "\\Software\\GNU\\gpgme", "debug");
798 #endif /*HAVE_W32CE_SYSTEM*/
801 /* Entry point called by the DLL loader. */
804 DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
808 if (reason == DLL_PROCESS_ATTACH)
813 #endif /*DLL_EXPORT*/