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
5 *
6 * This file is part of GPGME.
7 *
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.
12 *
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.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this program; if not, see <https://gnu.org/licenses/>.
20 * SPDX-License-Identifier: LGPL-2.1-or-later
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <errno.h>
31 #include <stdint.h>
32 #ifdef HAVE_SYS_TIME_H
33 # include <sys/time.h>
34 #endif
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
37 #endif
38 #ifdef HAVE_SYS_STAT_H
39 # include <sys/stat.h>
40 #endif
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <fcntl.h>
45 #include <io.h>
46
47 #if __MINGW64_VERSION_MAJOR >= 2
48 # define _WIN32_IE 0x0501 /* Required by mingw64 toolkit. */
49 #else
50 # define _WIN32_IE 0x0400 /* Required for SHGetSpecialFolderPathA. */
51 #endif
52
53 /* We need to include the windows stuff here prior to shlobj.h so that
54 we get the right winsock version. This is usually done in util.h
55 but that header also redefines some Windows functions which we need
56 to avoid unless having included shlobj.h. */
57 #include <winsock2.h>
58 #include <ws2tcpip.h>
59 #include <windows.h>
60 #include <shlobj.h>
61
62 #include "util.h"
63 #include "ath.h"
64 #include "sema.h"
65 #include "debug.h"
66 #include "sys-util.h"
67
68
69 #define HAVE_ALLOW_SET_FOREGROUND_WINDOW 1
70 #ifndef F_OK
71 # define F_OK 0
72 #endif
73
74 /* The Registry key used by GNUPG. */
75 #ifdef _WIN64
76 # define GNUPG_REGKEY_2 "Software\\Wow6432Node\\GNU\\GnuPG"
77 #else
78 # define GNUPG_REGKEY_2 "Software\\GNU\\GnuPG"
79 #endif
80 #ifdef _WIN64
81 # define GNUPG_REGKEY_3 "Software\\Wow6432Node\\GnuPG"
82 #else
83 # define GNUPG_REGKEY_3 "Software\\GnuPG"
84 #endif
85
86 DEFINE_STATIC_LOCK (get_path_lock);
87
88 /* The module handle of this DLL. If we are linked statically,
89 dllmain does not exists and thus the value of my_hmodule will be
90 NULL. The effect is that a GetModuleFileName always returns the
91 file name of the DLL or executable which contains the gpgme code. */
92 static HMODULE my_hmodule;
93
94 /* These variables store the malloced name of alternative default
95 binaries. The are set only once by gpgme_set_global_flag. */
96 static char *default_gpg_name;
97 static char *default_gpgconf_name;
98 /* If this variable is not NULL the value is assumed to be the
99 installation directory. The variable may only be set once by
100 gpgme_set_global_flag and accessed by _gpgme_get_inst_dir. */
101 static char *override_inst_dir;
102
103 #define RTLD_LAZY 0
104
105 static GPG_ERR_INLINE void *
dlopen(const char * name,int flag)106 dlopen (const char * name, int flag)
107 {
108 void * hd = LoadLibrary (name);
109
110 (void)flag;
111 return hd;
112 }
113
114 static GPG_ERR_INLINE void *
dlsym(void * hd,const char * sym)115 dlsym (void * hd, const char * sym)
116 {
117 if (hd && sym)
118 {
119 void * fnc = GetProcAddress (hd, sym);
120 if (!fnc)
121 return NULL;
122 return fnc;
123 }
124 return NULL;
125 }
126
127 static GPG_ERR_INLINE int
dlclose(void * hd)128 dlclose (void * hd)
129 {
130 if (hd)
131 {
132 FreeLibrary (hd);
133 return 0;
134 }
135 return -1;
136 }
137
138
139 /* Return a malloced string encoded in UTF-8 from the wide char input
140 string STRING. Caller must free this value. Returns NULL and sets
141 ERRNO on failure. Calling this function with STRING set to NULL is
142 not defined. */
143 static char *
wchar_to_utf8(const wchar_t * string)144 wchar_to_utf8 (const wchar_t *string)
145 {
146 int n;
147 char *result;
148
149 n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
150 if (n < 0)
151 {
152 gpg_err_set_errno (EINVAL);
153 return NULL;
154 }
155
156 result = malloc (n+1);
157 if (!result)
158 return NULL;
159
160 n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
161 if (n < 0)
162 {
163 free (result);
164 gpg_err_set_errno (EINVAL);
165 result = NULL;
166 }
167 return result;
168 }
169
170
171 /* Return a malloced wide char string from an UTF-8 encoded input
172 string STRING. Caller must free this value. On failure returns
173 NULL; caller may use GetLastError to get the actual error number.
174 Calling this function with STRING set to NULL is not defined. */
175 static wchar_t *
utf8_to_wchar(const char * string)176 utf8_to_wchar (const char *string)
177 {
178 int n;
179 wchar_t *result;
180
181
182 n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
183 if (n < 0)
184 return NULL;
185
186 result = (wchar_t *) malloc ((n+1) * sizeof *result);
187 if (!result)
188 return NULL;
189
190 n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
191 if (n < 0)
192 {
193 free (result);
194 return NULL;
195 }
196 return result;
197 }
198
199
200 /* Same as utf8_to_wchar but calling it with NULL returns
201 NULL. So a return value of NULL only indicates failure
202 if STRING is not set to NULL. */
203 static wchar_t *
utf8_to_wchar0(const char * string)204 utf8_to_wchar0 (const char *string)
205 {
206 if (!string)
207 return NULL;
208
209 return utf8_to_wchar (string);
210 }
211
212
213 /* Replace all forward slashes by backslashes. */
214 static void
replace_slashes(char * string)215 replace_slashes (char *string)
216 {
217 for (; *string; string++)
218 if (*string == '/')
219 *string = '\\';
220 }
221
222
223 /* Get the base name of NAME. Returns a pointer into NAME right after
224 the last slash or backslash or to NAME if no slash or backslash
225 exists. */
226 static const char *
get_basename(const char * name)227 get_basename (const char *name)
228 {
229 const char *mark, *s;
230
231 for (mark=NULL, s=name; *s; s++)
232 if (*s == '/' || *s == '\\')
233 mark = s;
234
235 return mark? mark+1 : name;
236 }
237
238
239 void
_gpgme_allow_set_foreground_window(pid_t pid)240 _gpgme_allow_set_foreground_window (pid_t pid)
241 {
242 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
243 static int initialized;
244 static BOOL (WINAPI * func)(DWORD);
245 void *handle;
246
247 if (!initialized)
248 {
249 /* Available since W2000; thus we dynload it. */
250 initialized = 1;
251 handle = dlopen ("user32.dll", RTLD_LAZY);
252 if (handle)
253 {
254 func = dlsym (handle, "AllowSetForegroundWindow");
255 if (!func)
256 {
257 dlclose (handle);
258 handle = NULL;
259 }
260 }
261 }
262
263 if (!pid || pid == (pid_t)(-1))
264 {
265 TRACE (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", NULL,
266 "no action for pid %d", (int)pid);
267 }
268 else if (func)
269 {
270 int rc = func (pid);
271 TRACE (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", NULL,
272 "called for pid %d; result=%d", (int)pid, rc);
273
274 }
275 else
276 {
277 TRACE (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", NULL,
278 "function not available");
279 }
280 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
281 }
282
283
284 /* Wrapper around CancelSynchronousIo which is only available since
285 * Vista. */
286 void
_gpgme_w32_cancel_synchronous_io(HANDLE thread)287 _gpgme_w32_cancel_synchronous_io (HANDLE thread)
288 {
289 static int initialized;
290 static BOOL (WINAPI * func)(DWORD);
291 void *handle;
292
293 if (!initialized)
294 {
295 /* Available since Vista; thus we dynload it. */
296 initialized = 1;
297 handle = dlopen ("kernel32.dll", RTLD_LAZY);
298 if (handle)
299 {
300 func = dlsym (handle, "CancelSynchronousIo");
301 if (!func)
302 {
303 dlclose (handle);
304 handle = NULL;
305 }
306 }
307 }
308
309 if (func)
310 {
311 if (!func ((DWORD)thread) && GetLastError() != ERROR_NOT_FOUND)
312 {
313 TRACE (DEBUG_ENGINE, "gpgme:CancelSynchronousIo", NULL,
314 "called for thread %p: ec=%u",
315 thread, (unsigned int)GetLastError ());
316 }
317 }
318 else
319 {
320 TRACE (DEBUG_ENGINE, "gpgme:CancelSynchronousIo", NULL,
321 "function not available");
322 }
323 }
324
325
326 /* Return a string from the W32 Registry or NULL in case of error.
327 Caller must release the return value. A NULL for root is an alias
328 for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
329 static char *
read_w32_registry_string(const char * root,const char * dir,const char * name)330 read_w32_registry_string (const char *root, const char *dir, const char *name)
331 {
332 HKEY root_key, key_handle;
333 DWORD n1, nbytes, type;
334 char *result = NULL;
335
336 if (!root)
337 root_key = HKEY_CURRENT_USER;
338 else if (!strcmp( root, "HKEY_CLASSES_ROOT"))
339 root_key = HKEY_CLASSES_ROOT;
340 else if (!strcmp( root, "HKEY_CURRENT_USER"))
341 root_key = HKEY_CURRENT_USER;
342 else if (!strcmp( root, "HKEY_LOCAL_MACHINE"))
343 root_key = HKEY_LOCAL_MACHINE;
344 else if (!strcmp( root, "HKEY_USERS"))
345 root_key = HKEY_USERS;
346 else if (!strcmp( root, "HKEY_PERFORMANCE_DATA"))
347 root_key = HKEY_PERFORMANCE_DATA;
348 else if (!strcmp( root, "HKEY_CURRENT_CONFIG"))
349 root_key = HKEY_CURRENT_CONFIG;
350 else
351 return NULL;
352
353 if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle))
354 {
355 if (root)
356 return NULL; /* no need for a RegClose, so return direct */
357 /* It seems to be common practise to fall back to HKLM. */
358 if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
359 return NULL; /* still no need for a RegClose, so return direct */
360 }
361
362 nbytes = 1;
363 if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
364 {
365 if (root)
366 goto leave;
367 /* Try to fallback to HKLM also vor a missing value. */
368 RegCloseKey (key_handle);
369 if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
370 return NULL; /* Nope. */
371 if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
372 goto leave;
373 }
374 n1 = nbytes + 1;
375 result = malloc (n1);
376 if (!result)
377 goto leave;
378 if (RegQueryValueExA (key_handle, name, 0, &type, (LPBYTE) result, &n1))
379 {
380 free (result);
381 result = NULL;
382 goto leave;
383 }
384 result[nbytes] = 0; /* Make sure it is really a string. */
385
386 leave:
387 RegCloseKey (key_handle);
388 return result;
389 }
390
391
392 /* Return the name of the directory with the gpgme DLL or the EXE (if
393 statically linked). May return NULL on severe errors. */
394 const char *
_gpgme_get_inst_dir(void)395 _gpgme_get_inst_dir (void)
396 {
397 static char *inst_dir;
398
399 if (override_inst_dir)
400 return override_inst_dir;
401
402 LOCK (get_path_lock);
403 if (!inst_dir)
404 {
405 wchar_t *moddir;
406
407 moddir = malloc ((MAX_PATH+5) * sizeof *moddir);
408 if (moddir)
409 {
410 if (!GetModuleFileNameW (my_hmodule, moddir, MAX_PATH))
411 *moddir = 0;
412 if (!*moddir)
413 gpg_err_set_errno (ENOENT);
414 else
415 {
416 inst_dir = wchar_to_utf8 (moddir);
417 if (inst_dir)
418 {
419 char *p = strrchr (inst_dir, '\\');
420 if (p)
421 *p = 0;
422 }
423 }
424 free (moddir);
425 }
426 }
427 UNLOCK (get_path_lock);
428 return inst_dir;
429 }
430
431
432 static char *
find_program_in_dir(const char * dir,const char * name)433 find_program_in_dir (const char *dir, const char *name)
434 {
435 char *result;
436
437 result = _gpgme_strconcat (dir, "\\", name, NULL);
438 if (!result)
439 return NULL;
440
441 if (_gpgme_access (result, F_OK))
442 {
443 free (result);
444 return NULL;
445 }
446
447 return result;
448 }
449
450
451 static char *
find_program_at_standard_place(const char * name)452 find_program_at_standard_place (const char *name)
453 {
454 wchar_t path[MAX_PATH];
455 char *result = NULL;
456
457 /* See https://wiki.tcl-lang.org/page/Getting+Windows+%22special+folders%22+with+Ffidl for details on compatibility.
458
459 We First try the generic place and then fallback to the x86
460 (i.e. 32 bit) place. This will prefer a 64 bit of the program
461 over a 32 bit version on 64 bit Windows if installed. */
462 if (SHGetSpecialFolderPathW (NULL, path, CSIDL_PROGRAM_FILES, 0))
463 {
464 char *utf8_path = wchar_to_utf8 (path);
465 result = _gpgme_strconcat (utf8_path, "\\", name, NULL);
466 free (utf8_path);
467 if (result && _gpgme_access (result, F_OK))
468 {
469 free (result);
470 result = NULL;
471 }
472 }
473 if (!result
474 && SHGetSpecialFolderPathW (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
475 {
476 char *utf8_path = wchar_to_utf8 (path);
477 result = _gpgme_strconcat (utf8_path, "\\", name, NULL);
478 free (utf8_path);
479 if (result && _gpgme_access (result, F_OK))
480 {
481 free (result);
482 result = NULL;
483 }
484 }
485 return result;
486 }
487
488
489 /* Set the default name for the gpg binary. This function may only be
490 called by gpgme_set_global_flag. Returns 0 on success. */
491 int
_gpgme_set_default_gpg_name(const char * name)492 _gpgme_set_default_gpg_name (const char *name)
493 {
494 if (!default_gpg_name)
495 {
496 default_gpg_name = _gpgme_strconcat (name, ".exe", NULL);
497 if (default_gpg_name)
498 replace_slashes (default_gpg_name);
499 }
500 return !default_gpg_name;
501 }
502
503 /* Set the default name for the gpgconf binary. This function may only be
504 called by gpgme_set_global_flag. Returns 0 on success. */
505 int
_gpgme_set_default_gpgconf_name(const char * name)506 _gpgme_set_default_gpgconf_name (const char *name)
507 {
508 if (!default_gpgconf_name)
509 {
510 default_gpgconf_name = _gpgme_strconcat (name, ".exe", NULL);
511 if (default_gpgconf_name)
512 replace_slashes (default_gpgconf_name);
513 }
514 return !default_gpgconf_name;
515 }
516
517
518 /* Set the override installation directory. This function may only be
519 called by gpgme_set_global_flag. Returns 0 on success. */
520 int
_gpgme_set_override_inst_dir(const char * dir)521 _gpgme_set_override_inst_dir (const char *dir)
522 {
523 if (!override_inst_dir)
524 {
525 override_inst_dir = strdup (dir);
526 if (override_inst_dir)
527 {
528 replace_slashes (override_inst_dir);
529 /* Remove a trailing slash. */
530 if (*override_inst_dir
531 && override_inst_dir[strlen (override_inst_dir)-1] == '\\')
532 override_inst_dir[strlen (override_inst_dir)-1] = 0;
533 }
534 }
535 return !override_inst_dir;
536 }
537
538
539 /* Return the full file name of the GPG binary. This function is used
540 iff gpgconf was not found and thus it can be assumed that gpg2 is
541 not installed. This function is only called by get_gpgconf_item
542 and may not be called concurrently. */
543 char *
_gpgme_get_gpg_path(void)544 _gpgme_get_gpg_path (void)
545 {
546 char *gpg = NULL;
547 const char *name, *inst_dir;
548
549 name = default_gpg_name? get_basename (default_gpg_name) : "gpg.exe";
550
551 /* 1. Try to find gpg.exe in the installation directory of gpgme. */
552 inst_dir = _gpgme_get_inst_dir ();
553 if (inst_dir)
554 {
555 gpg = find_program_in_dir (inst_dir, name);
556 }
557
558 /* 2. Try to find gpg.exe using that ancient registry key. */
559 if (!gpg)
560 {
561 char *dir;
562
563 dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
564 GNUPG_REGKEY_2,
565 "Install Directory");
566 if (dir)
567 {
568 gpg = find_program_in_dir (dir, name);
569 free (dir);
570 }
571 }
572
573 /* 3. Try to find gpg.exe below CSIDL_PROGRAM_FILES. */
574 if (!gpg)
575 {
576 name = default_gpg_name? default_gpg_name : "GNU\\GnuPG\\gpg.exe";
577 gpg = find_program_at_standard_place (name);
578 }
579
580 /* 4. Print a debug message if not found. */
581 if (!gpg)
582 _gpgme_debug (NULL, DEBUG_ENGINE, -1, NULL, NULL, NULL,
583 "_gpgme_get_gpg_path: '%s' not found", name);
584
585 return gpg;
586 }
587
588
589 /* This function is only called by get_gpgconf_item and may not be
590 called concurrently. */
591 char *
_gpgme_get_gpgconf_path(void)592 _gpgme_get_gpgconf_path (void)
593 {
594 char *gpgconf = NULL;
595 const char *inst_dir, *name;
596
597 name = default_gpgconf_name? get_basename(default_gpgconf_name):"gpgconf.exe";
598
599 /* 1. Try to find gpgconf.exe in the installation directory of gpgme. */
600 inst_dir = _gpgme_get_inst_dir ();
601 if (inst_dir)
602 {
603 gpgconf = find_program_in_dir (inst_dir, name);
604 }
605
606 /* 2. Try to find gpgconf.exe from GnuPG >= 2.1 below CSIDL_PROGRAM_FILES. */
607 if (!gpgconf)
608 {
609 const char *name2 = (default_gpgconf_name ? default_gpgconf_name
610 /**/ : "GnuPG\\bin\\gpgconf.exe");
611 gpgconf = find_program_at_standard_place (name2);
612 }
613
614 /* 3. Try to find gpgconf.exe using the Windows registry. */
615 if (!gpgconf)
616 {
617 char *dir;
618
619 dir = read_w32_registry_string (NULL,
620 GNUPG_REGKEY_2,
621 "Install Directory");
622 if (!dir)
623 {
624 char *tmp = read_w32_registry_string (NULL,
625 GNUPG_REGKEY_3,
626 "Install Directory");
627 if (tmp)
628 {
629 dir = _gpgme_strconcat (tmp, "\\bin", NULL);
630 free (tmp);
631 if (!dir)
632 return NULL;
633 }
634 }
635 if (dir)
636 {
637 gpgconf = find_program_in_dir (dir, name);
638 free (dir);
639 }
640 }
641
642 /* 4. Try to find gpgconf.exe from Gpg4win below CSIDL_PROGRAM_FILES. */
643 if (!gpgconf)
644 {
645 gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe");
646 }
647
648 /* 5. Try to find gpgconf.exe relative to us. */
649 if (!gpgconf && inst_dir)
650 {
651 char *dir = _gpgme_strconcat (inst_dir, "\\..\\..\\GnuPG\\bin", NULL);
652 gpgconf = find_program_in_dir (dir, name);
653 free (dir);
654 }
655
656 /* 5. Print a debug message if not found. */
657 if (!gpgconf)
658 _gpgme_debug (NULL, DEBUG_ENGINE, -1, NULL, NULL, NULL,
659 "_gpgme_get_gpgconf_path: '%s' not found",name);
660
661 return gpgconf;
662 }
663
664
665 const char *
_gpgme_get_w32spawn_path(void)666 _gpgme_get_w32spawn_path (void)
667 {
668 static char *w32spawn_program;
669 const char *inst_dir;
670
671 inst_dir = _gpgme_get_inst_dir ();
672 LOCK (get_path_lock);
673 if (!w32spawn_program)
674 w32spawn_program = find_program_in_dir (inst_dir, "gpgme-w32spawn.exe");
675 UNLOCK (get_path_lock);
676 return w32spawn_program;
677 }
678
679
680 /* Return an integer value from gpgme specific configuration
681 entries. VALUE receives that value; function returns true if a value
682 has been configured and false if not. */
683 int
_gpgme_get_conf_int(const char * key,int * value)684 _gpgme_get_conf_int (const char *key, int *value)
685 {
686 char *tmp = read_w32_registry_string (NULL, "Software\\GNU\\gpgme", key);
687 if (!tmp)
688 return 0;
689 *value = atoi (tmp);
690 free (tmp);
691 return 1;
692 }
693
694
695
696 /* mkstemp extracted from libc/sysdeps/posix/tempname.c. Copyright
697 (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
698
699 The GNU C Library is free software; you can redistribute it and/or
700 modify it under the terms of the GNU Lesser General Public
701 License as published by the Free Software Foundation; either
702 version 2.1 of the License, or (at your option) any later version. */
703
704 static const char letters[] =
705 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
706
707 /* Generate a temporary file name based on TMPL. TMPL must match the
708 rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed
709 does not exist at the time of the call to mkstemp. TMPL is
710 overwritten with the result. */
711 static int
my_mkstemp(char * tmpl)712 my_mkstemp (char *tmpl)
713 {
714 int len;
715 char *XXXXXX;
716 static uint64_t value;
717 uint64_t random_time_bits;
718 unsigned int count;
719 int fd = -1;
720 int save_errno = errno;
721
722 /* A lower bound on the number of temporary files to attempt to
723 generate. The maximum total number of temporary file names that
724 can exist for a given template is 62**6. It should never be
725 necessary to try all these combinations. Instead if a reasonable
726 number of names is tried (we define reasonable as 62**3) fail to
727 give the system administrator the chance to remove the problems. */
728 #define ATTEMPTS_MIN (62 * 62 * 62)
729
730 /* The number of times to attempt to generate a temporary file. To
731 conform to POSIX, this must be no smaller than TMP_MAX. */
732 #if ATTEMPTS_MIN < TMP_MAX
733 unsigned int attempts = TMP_MAX;
734 #else
735 unsigned int attempts = ATTEMPTS_MIN;
736 #endif
737
738 len = strlen (tmpl);
739 if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
740 {
741 gpg_err_set_errno (EINVAL);
742 return -1;
743 }
744
745 /* This is where the Xs start. */
746 XXXXXX = &tmpl[len - 6];
747
748 /* Get some more or less random data. */
749 {
750 FILETIME ft;
751
752 GetSystemTimeAsFileTime (&ft);
753 random_time_bits = (((uint64_t)ft.dwHighDateTime << 32)
754 | (uint64_t)ft.dwLowDateTime);
755 }
756 value += random_time_bits ^ ath_self ();
757
758 for (count = 0; count < attempts; value += 7777, ++count)
759 {
760 uint64_t v = value;
761
762 /* Fill in the random bits. */
763 XXXXXX[0] = letters[v % 62];
764 v /= 62;
765 XXXXXX[1] = letters[v % 62];
766 v /= 62;
767 XXXXXX[2] = letters[v % 62];
768 v /= 62;
769 XXXXXX[3] = letters[v % 62];
770 v /= 62;
771 XXXXXX[4] = letters[v % 62];
772 v /= 62;
773 XXXXXX[5] = letters[v % 62];
774
775 fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
776 if (fd >= 0)
777 {
778 gpg_err_set_errno (save_errno);
779 return fd;
780 }
781 else if (errno != EEXIST)
782 return -1;
783 }
784
785 /* We got out of the loop because we ran out of combinations to try. */
786 gpg_err_set_errno (EEXIST);
787 return -1;
788 }
789
790
791 int
_gpgme_mkstemp(int * fd,char ** name)792 _gpgme_mkstemp (int *fd, char **name)
793 {
794 char tmp[MAX_PATH + 2];
795 char *tmpname;
796 int err;
797
798 *fd = -1;
799 *name = NULL;
800
801 err = GetTempPathA (MAX_PATH + 1, tmp);
802 if (err == 0 || err > MAX_PATH + 1)
803 strcpy (tmp,"c:\\windows\\temp");
804 else
805 {
806 int len = strlen(tmp);
807
808 /* GetTempPath may return with \ on the end */
809 while(len > 0 && tmp[len - 1] == '\\')
810 {
811 tmp[len-1] = '\0';
812 len--;
813 }
814 }
815
816 tmpname = _gpgme_strconcat (tmp, "\\gpgme-XXXXXX", NULL);
817 if (!tmpname)
818 return -1;
819 *fd = my_mkstemp (tmpname);
820 if (*fd < 0)
821 {
822 free (tmpname);
823 return -1;
824 }
825
826 *name = tmpname;
827 return 0;
828 }
829
830
831 /* Like access but using windows _waccess */
832 int
_gpgme_access(const char * path,int mode)833 _gpgme_access (const char *path, int mode)
834 {
835 wchar_t *u16 = utf8_to_wchar0 (path);
836 int r = _waccess (u16, mode);
837
838 free(u16);
839 return r;
840 }
841
842
843 /* Like CreateProcessA but mapping the arguments to wchar API */
_gpgme_create_process_utf8(const char * application_name_utf8,char * command_line_utf8,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,void * lpEnvironment,char * working_directory_utf8,LPSTARTUPINFOA si,LPPROCESS_INFORMATION lpProcessInformation)844 int _gpgme_create_process_utf8 (const char *application_name_utf8,
845 char *command_line_utf8,
846 LPSECURITY_ATTRIBUTES lpProcessAttributes,
847 LPSECURITY_ATTRIBUTES lpThreadAttributes,
848 BOOL bInheritHandles,
849 DWORD dwCreationFlags,
850 void *lpEnvironment,
851 char *working_directory_utf8,
852 LPSTARTUPINFOA si,
853 LPPROCESS_INFORMATION lpProcessInformation)
854 {
855 BOOL ret;
856 wchar_t *application_name = utf8_to_wchar0 (application_name_utf8);
857 wchar_t *command_line = utf8_to_wchar0 (command_line_utf8);
858 wchar_t *working_directory = utf8_to_wchar0 (working_directory_utf8);
859
860 STARTUPINFOW siw;
861 memset (&siw, 0, sizeof siw);
862 if (si)
863 {
864 siw.cb = sizeof (siw);
865 siw.dwFlags = si->dwFlags;
866 siw.wShowWindow = si->wShowWindow;
867 siw.hStdInput = si->hStdInput;
868 siw.hStdOutput = si->hStdOutput;
869 siw.hStdError = si->hStdError;
870 siw.dwX = si->dwX;
871 siw.dwY = si->dwY;
872 siw.dwXSize = si->dwXSize;
873 siw.dwYSize = si->dwYSize;
874 siw.dwXCountChars = si->dwXCountChars;
875 siw.dwYCountChars = si->dwYCountChars;
876 siw.dwFillAttribute = si->dwFillAttribute;
877 siw.lpDesktop = utf8_to_wchar0 (si->lpDesktop);
878 siw.lpTitle = utf8_to_wchar0 (si->lpTitle);
879 }
880
881 ret = CreateProcessW (application_name,
882 command_line,
883 lpProcessAttributes,
884 lpThreadAttributes,
885 bInheritHandles,
886 dwCreationFlags,
887 lpEnvironment,
888 working_directory,
889 si ? &siw : NULL,
890 lpProcessInformation);
891 free (siw.lpTitle);
892 free (siw.lpDesktop);
893 free (application_name);
894 free (command_line);
895 free (working_directory);
896 return ret;
897 }
898
899 /* Entry point called by the DLL loader. */
900 #ifdef DLL_EXPORT
901 int WINAPI
DllMain(HINSTANCE hinst,DWORD reason,LPVOID reserved)902 DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
903 {
904 (void)reserved;
905
906 if (reason == DLL_PROCESS_ATTACH)
907 my_hmodule = hinst;
908
909 return TRUE;
910 }
911 #endif /*DLL_EXPORT*/
912