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