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 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, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
32 #ifdef HAVE_SYS_TIME_H
33 # include <sys/time.h>
35 #include <sys/types.h>
43 #define _WIN32_IE 0x0400 /* Required for SHGetSpecialFolderPathA. */
45 /* We need to include the windows stuff here prior to shlobj.h so that
46 we get the right winsock version. This is usually done in util.h
47 but that header also redefines some Windows functions which we need
48 to avoid unless having included shlobj.h. */
60 #ifndef HAVE_W32CE_SYSTEM
61 #define HAVE_ALLOW_SET_FOREGROUND_WINDOW 1
68 DEFINE_STATIC_LOCK (get_path_lock);
71 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
75 static __inline__ void *
76 dlopen (const char * name, int flag)
78 void * hd = LoadLibrary (name);
82 static __inline__ void *
83 dlsym (void * hd, const char * sym)
87 void * fnc = GetProcAddress (hd, sym);
105 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
109 _gpgme_allow_set_foreground_window (pid_t pid)
111 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
112 static int initialized;
113 static BOOL (WINAPI * func)(DWORD);
118 /* Available since W2000; thus we dynload it. */
120 handle = dlopen ("user32.dll", RTLD_LAZY);
123 func = dlsym (handle, "AllowSetForegroundWindow");
132 if (!pid || pid == (pid_t)(-1))
134 TRACE1 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
135 "no action for pid %d", (int)pid);
140 TRACE2 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
141 "called for pid %d; result=%d", (int)pid, rc);
146 TRACE0 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
147 "function not available");
149 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
153 /* Return a string from the W32 Registry or NULL in case of error.
154 Caller must release the return value. A NULL for root is an alias
155 for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
157 read_w32_registry_string (const char *root, const char *dir, const char *name)
159 HKEY root_key, key_handle;
160 DWORD n1, nbytes, type;
164 root_key = HKEY_CURRENT_USER;
165 else if (!strcmp( root, "HKEY_CLASSES_ROOT"))
166 root_key = HKEY_CLASSES_ROOT;
167 else if (!strcmp( root, "HKEY_CURRENT_USER"))
168 root_key = HKEY_CURRENT_USER;
169 else if (!strcmp( root, "HKEY_LOCAL_MACHINE"))
170 root_key = HKEY_LOCAL_MACHINE;
171 else if (!strcmp( root, "HKEY_USERS"))
172 root_key = HKEY_USERS;
173 else if (!strcmp( root, "HKEY_PERFORMANCE_DATA"))
174 root_key = HKEY_PERFORMANCE_DATA;
175 else if (!strcmp( root, "HKEY_CURRENT_CONFIG"))
176 root_key = HKEY_CURRENT_CONFIG;
180 if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle))
183 return NULL; /* no need for a RegClose, so return direct */
184 /* It seems to be common practise to fall back to HKLM. */
185 if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
186 return NULL; /* still no need for a RegClose, so return direct */
190 if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
194 /* Try to fallback to HKLM also vor a missing value. */
195 RegCloseKey (key_handle);
196 if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
197 return NULL; /* Nope. */
198 if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
202 result = malloc (n1);
205 if (RegQueryValueExA (key_handle, name, 0, &type, (LPBYTE) result, &n1))
211 result[nbytes] = 0; /* Make sure it is really a string. */
213 #ifndef HAVE_W32CE_SYSTEM
214 /* Windows CE does not have an environment. */
215 if (type == REG_EXPAND_SZ && strchr (result, '%'))
220 tmp = malloc (n1 + 1);
223 nbytes = ExpandEnvironmentStrings (result, tmp, n1);
224 if (nbytes && nbytes > n1)
228 tmp = malloc (n1 + 1);
231 nbytes = ExpandEnvironmentStrings (result, tmp, n1);
232 if (nbytes && nbytes > n1) {
233 free (tmp); /* Oops - truncated, better don't expand at all. */
240 else if (nbytes) /* Okay, reduce the length. */
244 result = malloc (strlen (tmp)+1);
249 strcpy (result, tmp);
253 else /* Error - don't expand. */
261 RegCloseKey (key_handle);
268 find_program_in_registry (const char *name)
270 char *program = NULL;
272 program = read_w32_registry_string (NULL, "Software\\GNU\\GnuPG", name);
277 TRACE2 (DEBUG_CTX, "gpgme:find_program_in_registry", 0,
278 "found %s in registry: `%s'", name, program);
279 for (i = 0; program[i]; i++)
281 if (program[i] == '/')
291 find_program_in_inst_dir (const char *name)
296 tmp = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
297 "Software\\GNU\\GnuPG",
298 "Install Directory");
302 result = malloc (strlen (tmp) + 1 + strlen (name) + 1);
309 strcpy (stpcpy (stpcpy (result, tmp), "\\"), name);
311 if (access (result, F_OK))
322 find_program_at_standard_place (const char *name)
327 /* See http://wiki.tcl.tk/17492 for details on compatibility. */
328 if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0))
330 result = malloc (strlen (path) + 1 + strlen (name) + 1);
333 strcpy (stpcpy (stpcpy (result, path), "\\"), name);
334 if (access (result, F_OK))
346 _gpgme_get_gpg_path (void)
348 static char *gpg_program;
350 LOCK (get_path_lock);
353 gpg_program = find_program_in_registry ("gpgProgram");
356 gpg_program = find_program_in_inst_dir ("gpg.exe");
358 gpg_program = find_program_at_standard_place ("GNU\\GnuPG\\gpg.exe");
359 UNLOCK (get_path_lock);
365 _gpgme_get_gpgsm_path (void)
367 static char *gpgsm_program;
369 LOCK (get_path_lock);
372 gpgsm_program = find_program_in_registry ("gpgsmProgram");
375 gpgsm_program = find_program_in_inst_dir ("gpgsm.exe");
377 gpgsm_program = find_program_at_standard_place ("GNU\\GnuPG\\gpgsm.exe");
378 UNLOCK (get_path_lock);
379 return gpgsm_program;
384 _gpgme_get_gpgconf_path (void)
386 static char *gpgconf_program;
388 LOCK (get_path_lock);
390 if (!gpgconf_program)
391 gpgconf_program = find_program_in_registry ("gpgconfProgram");
393 if (!gpgconf_program)
394 gpgconf_program = find_program_in_inst_dir ("gpgconf.exe");
395 if (!gpgconf_program)
397 = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe");
398 UNLOCK (get_path_lock);
399 return gpgconf_program;
404 _gpgme_get_g13_path (void)
406 static char *g13_program;
408 LOCK (get_path_lock);
411 g13_program = find_program_in_registry ("g13Program");
414 g13_program = find_program_in_inst_dir ("g13.exe");
416 g13_program = find_program_at_standard_place ("GNU\\GnuPG\\g13.exe");
417 UNLOCK (get_path_lock);
423 _gpgme_get_uiserver_socket_path (void)
425 static char *socket_path;
427 const char name[] = "S.uiserver";
432 homedir = _gpgme_get_default_homedir ();
436 socket_path = malloc (strlen (homedir) + 1 + strlen (name) + 1);
440 strcpy (stpcpy (stpcpy (socket_path, homedir), "\\"), name);
446 _gpgme_get_w32spawn_path (void)
448 static char *w32spawn_program;
450 LOCK (get_path_lock);
451 if (!w32spawn_program)
452 w32spawn_program = find_program_in_inst_dir ("gpgme-w32spawn.exe");
453 if (!w32spawn_program)
455 = find_program_at_standard_place ("GNU\\GnuPG\\gpgme-w32spawn.exe");
456 UNLOCK (get_path_lock);
457 return w32spawn_program;
461 /* Return an integer value from gpgme specific configuration
462 entries. VALUE receives that value; function returns true if a value
463 has been configured and false if not. */
465 _gpgme_get_conf_int (const char *key, int *value)
467 char *tmp = read_w32_registry_string (NULL, "Software\\GNU\\gpgme", key);
476 /* mkstemp extracted from libc/sysdeps/posix/tempname.c. Copyright
477 (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
479 The GNU C Library is free software; you can redistribute it and/or
480 modify it under the terms of the GNU Lesser General Public
481 License as published by the Free Software Foundation; either
482 version 2.1 of the License, or (at your option) any later version. */
484 static const char letters[] =
485 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
487 /* Generate a temporary file name based on TMPL. TMPL must match the
488 rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed
489 does not exist at the time of the call to mkstemp. TMPL is
490 overwritten with the result. */
496 static uint64_t value;
497 uint64_t random_time_bits;
499 HANDLE fd = INVALID_HANDLE_VALUE;
500 int save_errno = errno;
502 /* A lower bound on the number of temporary files to attempt to
503 generate. The maximum total number of temporary file names that
504 can exist for a given template is 62**6. It should never be
505 necessary to try all these combinations. Instead if a reasonable
506 number of names is tried (we define reasonable as 62**3) fail to
507 give the system administrator the chance to remove the problems. */
508 #define ATTEMPTS_MIN (62 * 62 * 62)
510 /* The number of times to attempt to generate a temporary file. To
511 conform to POSIX, this must be no smaller than TMP_MAX. */
512 #if ATTEMPTS_MIN < TMP_MAX
513 unsigned int attempts = TMP_MAX;
515 unsigned int attempts = ATTEMPTS_MIN;
519 if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
521 gpg_err_set_errno (EINVAL);
525 /* This is where the Xs start. */
526 XXXXXX = &tmpl[len - 6];
528 /* Get some more or less random data. */
532 GetSystemTimeAsFileTime (&ft);
533 random_time_bits = (((uint64_t)ft.dwHighDateTime << 32)
534 | (uint64_t)ft.dwLowDateTime);
536 value += random_time_bits ^ ath_self ();
538 for (count = 0; count < attempts; value += 7777, ++count)
542 /* Fill in the random bits. */
543 XXXXXX[0] = letters[v % 62];
545 XXXXXX[1] = letters[v % 62];
547 XXXXXX[2] = letters[v % 62];
549 XXXXXX[3] = letters[v % 62];
551 XXXXXX[4] = letters[v % 62];
553 XXXXXX[5] = letters[v % 62];
555 fd = CreateFileA (tmpl,
556 GENERIC_WRITE|GENERIC_READ,
557 FILE_SHARE_READ|FILE_SHARE_WRITE,
560 FILE_ATTRIBUTE_NORMAL,
562 if (fd != INVALID_HANDLE_VALUE)
564 gpg_err_set_errno (save_errno);
567 else if (GetLastError () != ERROR_FILE_EXISTS)
569 gpg_err_set_errno (EIO);
574 /* We got out of the loop because we ran out of combinations to try. */
575 gpg_err_set_errno (EEXIST);
581 _gpgme_mkstemp (int *fd, char **name)
583 char tmp[MAX_PATH + 2];
590 err = GetTempPathA (MAX_PATH + 1, tmp);
591 if (err == 0 || err > MAX_PATH + 1)
592 strcpy (tmp,"c:\\windows\\temp");
595 int len = strlen(tmp);
597 /* GetTempPath may return with \ on the end */
598 while(len > 0 && tmp[len - 1] == '\\')
605 tmpname = malloc (strlen (tmp) + 13 + 1);
608 strcpy (stpcpy (tmpname, tmp), "\\gpgme-XXXXXX");
609 *fd = mkstemp (tmpname);
619 #ifdef HAVE_W32CE_SYSTEM
620 /* Return a malloced string with the replacement value for the
621 GPGME_DEBUG envvar. Caller must release. Returns NULL if not
624 _gpgme_w32ce_get_debug_envvar (void)
628 tmp = read_w32_registry_string (NULL, "\\Software\\GNU\\gpgme", "debug");
636 #endif /*HAVE_W32CE_SYSTEM*/