1f8ef6dc3ea01b177d65230b5c4b2c06f0113df6
[gpgme.git] / src / w32-util.c
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 *
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 *
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
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 *
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 /* Replace all forward slashes by backslashes.  */
172 static void
173 replace_slashes (char *string)
174 {
175   for (; *string; string++)
176     if (*string == '/')
177       *string = '\\';
178 }
179
180
181 /* Get the base name of NAME.  Returns a pointer into NAME right after
182    the last slash or backslash or to NAME if no slash or backslash
183    exists.  */
184 static const char *
185 get_basename (const char *name)
186 {
187   const char *mark, *s;
188
189   for (mark=NULL, s=name; *s; s++)
190     if (*s == '/' || *s == '\\')
191       mark = s;
192
193   return mark? mark+1 : name;
194 }
195
196
197 void
198 _gpgme_allow_set_foreground_window (pid_t pid)
199 {
200 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
201   static int initialized;
202   static BOOL (WINAPI * func)(DWORD);
203   void *handle;
204
205   if (!initialized)
206     {
207       /* Available since W2000; thus we dynload it.  */
208       initialized = 1;
209       handle = dlopen ("user32.dll", RTLD_LAZY);
210       if (handle)
211         {
212           func = dlsym (handle, "AllowSetForegroundWindow");
213           if (!func)
214             {
215               dlclose (handle);
216               handle = NULL;
217             }
218         }
219     }
220
221   if (!pid || pid == (pid_t)(-1))
222     {
223       TRACE (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
224               "no action for pid %d", (int)pid);
225     }
226   else if (func)
227     {
228       int rc = func (pid);
229       TRACE (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
230               "called for pid %d; result=%d", (int)pid, rc);
231
232     }
233   else
234     {
235       TRACE (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
236               "function not available");
237     }
238 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
239 }
240
241
242 /* Wrapper around CancelSynchronousIo which is only available since
243  * Vista.  */
244 void
245 _gpgme_w32_cancel_synchronous_io (HANDLE thread)
246 {
247   static int initialized;
248   static BOOL (WINAPI * func)(DWORD);
249   void *handle;
250
251   if (!initialized)
252     {
253       /* Available since Vista; thus we dynload it.  */
254       initialized = 1;
255       handle = dlopen ("kernel32.dll", RTLD_LAZY);
256       if (handle)
257         {
258           func = dlsym (handle, "CancelSynchronousIo");
259           if (!func)
260             {
261               dlclose (handle);
262               handle = NULL;
263             }
264         }
265     }
266
267   if (func)
268     {
269       if (!func (thread) && GetLastError() != ERROR_NOT_FOUND)
270         {
271           TRACE (DEBUG_ENGINE, "gpgme:CancelSynchronousIo", 0,
272                   "called for thread %p: ec=%d", thread, GetLastError ());
273         }
274     }
275   else
276     {
277       TRACE (DEBUG_ENGINE, "gpgme:CancelSynchronousIo", 0,
278               "function not available");
279     }
280 }
281
282
283 /* Return a string from the W32 Registry or NULL in case of error.
284    Caller must release the return value.  A NULL for root is an alias
285    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
286 static char *
287 read_w32_registry_string (const char *root, const char *dir, const char *name)
288 {
289   HKEY root_key, key_handle;
290   DWORD n1, nbytes, type;
291   char *result = NULL;
292
293   if (!root)
294     root_key = HKEY_CURRENT_USER;
295   else if (!strcmp( root, "HKEY_CLASSES_ROOT"))
296     root_key = HKEY_CLASSES_ROOT;
297   else if (!strcmp( root, "HKEY_CURRENT_USER"))
298     root_key = HKEY_CURRENT_USER;
299   else if (!strcmp( root, "HKEY_LOCAL_MACHINE"))
300     root_key = HKEY_LOCAL_MACHINE;
301   else if (!strcmp( root, "HKEY_USERS"))
302     root_key = HKEY_USERS;
303   else if (!strcmp( root, "HKEY_PERFORMANCE_DATA"))
304     root_key = HKEY_PERFORMANCE_DATA;
305   else if (!strcmp( root, "HKEY_CURRENT_CONFIG"))
306     root_key = HKEY_CURRENT_CONFIG;
307   else
308     return NULL;
309
310   if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle))
311     {
312       if (root)
313         return NULL; /* no need for a RegClose, so return direct */
314       /* It seems to be common practise to fall back to HKLM. */
315       if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
316         return NULL; /* still no need for a RegClose, so return direct */
317     }
318
319   nbytes = 1;
320   if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
321     {
322       if (root)
323         goto leave;
324       /* Try to fallback to HKLM also vor a missing value.  */
325       RegCloseKey (key_handle);
326       if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
327         return NULL; /* Nope.  */
328       if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
329         goto leave;
330     }
331   n1 = nbytes + 1;
332   result = malloc (n1);
333   if (!result)
334     goto leave;
335   if (RegQueryValueExA (key_handle, name, 0, &type, (LPBYTE) result, &n1))
336     {
337       free (result);
338       result = NULL;
339       goto leave;
340     }
341   result[nbytes] = 0; /* Make sure it is really a string.  */
342
343  leave:
344   RegCloseKey (key_handle);
345   return result;
346 }
347
348
349 /* Return the name of the directory with the gpgme DLL or the EXE (if
350    statically linked).  May return NULL on severe errors. */
351 const char *
352 _gpgme_get_inst_dir (void)
353 {
354   static char *inst_dir;
355
356   if (override_inst_dir)
357     return override_inst_dir;
358
359   LOCK (get_path_lock);
360   if (!inst_dir)
361     {
362       wchar_t *moddir;
363
364       moddir = malloc ((MAX_PATH+5) * sizeof *moddir);
365       if (moddir)
366         {
367           if (!GetModuleFileNameW (my_hmodule, moddir, MAX_PATH))
368             *moddir = 0;
369           if (!*moddir)
370             gpg_err_set_errno (ENOENT);
371           else
372             {
373               inst_dir = wchar_to_utf8 (moddir);
374               if (inst_dir)
375                 {
376                   char *p = strrchr (inst_dir, '\\');
377                   if (p)
378                     *p = 0;
379                 }
380             }
381           free (moddir);
382         }
383     }
384   UNLOCK (get_path_lock);
385   return inst_dir;
386 }
387
388
389 static char *
390 find_program_in_dir (const char *dir, const char *name)
391 {
392   char *result;
393
394   result = _gpgme_strconcat (dir, "\\", name, NULL);
395   if (!result)
396     return NULL;
397
398   if (access (result, F_OK))
399     {
400       free (result);
401       return NULL;
402     }
403
404   return result;
405 }
406
407
408 static char *
409 find_program_at_standard_place (const char *name)
410 {
411   char path[MAX_PATH];
412   char *result = NULL;
413
414   /* See https://wiki.tcl-lang.org/page/Getting+Windows+%22special+folders%22+with+Ffidl for details on compatibility.
415
416      We First try the generic place and then fallback to the x86
417      (i.e. 32 bit) place.  This will prefer a 64 bit of the program
418      over a 32 bit version on 64 bit Windows if installed.  */
419   if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0))
420     {
421       result = _gpgme_strconcat (path, "\\", name, NULL);
422       if (result && access (result, F_OK))
423         {
424           free (result);
425           result = NULL;
426         }
427     }
428   if (!result
429       && SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
430     {
431       result = _gpgme_strconcat (path, "\\", name, NULL);
432       if (result && access (result, F_OK))
433         {
434           free (result);
435           result = NULL;
436         }
437     }
438   return result;
439 }
440
441
442 /* Set the default name for the gpg binary.  This function may only be
443    called by gpgme_set_global_flag.  Returns 0 on success.  */
444 int
445 _gpgme_set_default_gpg_name (const char *name)
446 {
447   if (!default_gpg_name)
448     {
449       default_gpg_name = _gpgme_strconcat (name, ".exe", NULL);
450       if (default_gpg_name)
451         replace_slashes (default_gpg_name);
452     }
453   return !default_gpg_name;
454 }
455
456 /* Set the default name for the gpgconf binary.  This function may only be
457    called by gpgme_set_global_flag.  Returns 0 on success.  */
458 int
459 _gpgme_set_default_gpgconf_name (const char *name)
460 {
461   if (!default_gpgconf_name)
462     {
463       default_gpgconf_name = _gpgme_strconcat (name, ".exe", NULL);
464       if (default_gpgconf_name)
465         replace_slashes (default_gpgconf_name);
466     }
467   return !default_gpgconf_name;
468 }
469
470
471 /* Set the override installation directory.  This function may only be
472    called by gpgme_set_global_flag.  Returns 0 on success.  */
473 int
474 _gpgme_set_override_inst_dir (const char *dir)
475 {
476   if (!override_inst_dir)
477     {
478       override_inst_dir = strdup (dir);
479       if (override_inst_dir)
480         {
481           replace_slashes (override_inst_dir);
482           /* Remove a trailing slash.  */
483           if (*override_inst_dir
484               && override_inst_dir[strlen (override_inst_dir)-1] == '\\')
485             override_inst_dir[strlen (override_inst_dir)-1] = 0;
486         }
487     }
488   return !override_inst_dir;
489 }
490
491
492 /* Return the full file name of the GPG binary.  This function is used
493    iff gpgconf was not found and thus it can be assumed that gpg2 is
494    not installed.  This function is only called by get_gpgconf_item
495    and may not be called concurrently. */
496 char *
497 _gpgme_get_gpg_path (void)
498 {
499   char *gpg = NULL;
500   const char *name, *inst_dir;
501
502   name = default_gpg_name? get_basename (default_gpg_name) : "gpg.exe";
503
504   /* 1. Try to find gpg.exe in the installation directory of gpgme.  */
505   inst_dir = _gpgme_get_inst_dir ();
506   if (inst_dir)
507     {
508       gpg = find_program_in_dir (inst_dir, name);
509     }
510
511   /* 2. Try to find gpg.exe using that ancient registry key.  */
512   if (!gpg)
513     {
514       char *dir;
515
516       dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
517                                       GNUPG_REGKEY_2,
518                                       "Install Directory");
519       if (dir)
520         {
521           gpg = find_program_in_dir (dir, name);
522           free (dir);
523         }
524     }
525
526   /* 3. Try to find gpg.exe below CSIDL_PROGRAM_FILES.  */
527   if (!gpg)
528     {
529       name = default_gpg_name? default_gpg_name : "GNU\\GnuPG\\gpg.exe";
530       gpg = find_program_at_standard_place (name);
531     }
532
533   /* 4. Print a debug message if not found.  */
534   if (!gpg)
535     _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found", name);
536
537   return gpg;
538 }
539
540
541 /* This function is only called by get_gpgconf_item and may not be
542    called concurrently.  */
543 char *
544 _gpgme_get_gpgconf_path (void)
545 {
546   char *gpgconf = NULL;
547   const char *inst_dir, *name;
548
549   name = default_gpgconf_name? get_basename(default_gpgconf_name):"gpgconf.exe";
550
551   /* 1. Try to find gpgconf.exe in the installation directory of gpgme.  */
552   inst_dir = _gpgme_get_inst_dir ();
553   if (inst_dir)
554     {
555       gpgconf = find_program_in_dir (inst_dir, name);
556     }
557
558   /* 2. Try to find gpgconf.exe from GnuPG >= 2.1 below CSIDL_PROGRAM_FILES. */
559   if (!gpgconf)
560     {
561       const char *name2 = (default_gpgconf_name ? default_gpgconf_name
562                            /**/                 : "GnuPG\\bin\\gpgconf.exe");
563       gpgconf = find_program_at_standard_place (name2);
564     }
565
566   /* 3. Try to find gpgconf.exe using the Windows registry. */
567   if (!gpgconf)
568     {
569       char *dir;
570
571       dir = read_w32_registry_string (NULL,
572                                       GNUPG_REGKEY_2,
573                                       "Install Directory");
574       if (!dir)
575         {
576           char *tmp = read_w32_registry_string (NULL,
577                                                 GNUPG_REGKEY_3,
578                                                 "Install Directory");
579           if (tmp)
580             {
581               dir = _gpgme_strconcat (tmp, "\\bin", NULL);
582               free (tmp);
583               if (!dir)
584                 return NULL;
585             }
586         }
587       if (dir)
588         {
589           gpgconf = find_program_in_dir (dir, name);
590           free (dir);
591         }
592     }
593
594   /* 4. Try to find gpgconf.exe from Gpg4win below CSIDL_PROGRAM_FILES.  */
595   if (!gpgconf)
596     {
597       gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe");
598     }
599
600   /* 5. Try to find gpgconf.exe relative to us.  */
601   if (!gpgconf && inst_dir)
602     {
603       char *dir = _gpgme_strconcat (inst_dir, "\\..\\..\\GnuPG\\bin");
604       gpgconf = find_program_in_dir (dir, name);
605       free (dir);
606     }
607
608   /* 5. Print a debug message if not found.  */
609   if (!gpgconf)
610     _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",name);
611
612   return gpgconf;
613 }
614
615
616 const char *
617 _gpgme_get_w32spawn_path (void)
618 {
619   static char *w32spawn_program;
620   const char *inst_dir;
621
622   inst_dir = _gpgme_get_inst_dir ();
623   LOCK (get_path_lock);
624   if (!w32spawn_program)
625     w32spawn_program = find_program_in_dir (inst_dir, "gpgme-w32spawn.exe");
626   UNLOCK (get_path_lock);
627   return w32spawn_program;
628 }
629
630
631 /* Return an integer value from gpgme specific configuration
632    entries. VALUE receives that value; function returns true if a value
633    has been configured and false if not. */
634 int
635 _gpgme_get_conf_int (const char *key, int *value)
636 {
637   char *tmp = read_w32_registry_string (NULL, "Software\\GNU\\gpgme", key);
638   if (!tmp)
639     return 0;
640   *value = atoi (tmp);
641   free (tmp);
642   return 1;
643 }
644
645
646 \f
647 /* mkstemp extracted from libc/sysdeps/posix/tempname.c.  Copyright
648    (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
649
650    The GNU C Library is free software; you can redistribute it and/or
651    modify it under the terms of the GNU Lesser General Public
652    License as published by the Free Software Foundation; either
653    version 2.1 of the License, or (at your option) any later version.  */
654
655 static const char letters[] =
656 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
657
658 /* Generate a temporary file name based on TMPL.  TMPL must match the
659    rules for mk[s]temp (i.e. end in "XXXXXX").  The name constructed
660    does not exist at the time of the call to mkstemp.  TMPL is
661    overwritten with the result.  */
662 static int
663 my_mkstemp (char *tmpl)
664 {
665   int len;
666   char *XXXXXX;
667   static uint64_t value;
668   uint64_t random_time_bits;
669   unsigned int count;
670   int fd = -1;
671   int save_errno = errno;
672
673   /* A lower bound on the number of temporary files to attempt to
674      generate.  The maximum total number of temporary file names that
675      can exist for a given template is 62**6.  It should never be
676      necessary to try all these combinations.  Instead if a reasonable
677      number of names is tried (we define reasonable as 62**3) fail to
678      give the system administrator the chance to remove the problems.  */
679 #define ATTEMPTS_MIN (62 * 62 * 62)
680
681   /* The number of times to attempt to generate a temporary file.  To
682      conform to POSIX, this must be no smaller than TMP_MAX.  */
683 #if ATTEMPTS_MIN < TMP_MAX
684   unsigned int attempts = TMP_MAX;
685 #else
686   unsigned int attempts = ATTEMPTS_MIN;
687 #endif
688
689   len = strlen (tmpl);
690   if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
691     {
692       gpg_err_set_errno (EINVAL);
693       return -1;
694     }
695
696   /* This is where the Xs start.  */
697   XXXXXX = &tmpl[len - 6];
698
699   /* Get some more or less random data.  */
700   {
701     FILETIME ft;
702
703     GetSystemTimeAsFileTime (&ft);
704     random_time_bits = (((uint64_t)ft.dwHighDateTime << 32)
705                         | (uint64_t)ft.dwLowDateTime);
706   }
707   value += random_time_bits ^ ath_self ();
708
709   for (count = 0; count < attempts; value += 7777, ++count)
710     {
711       uint64_t v = value;
712
713       /* Fill in the random bits.  */
714       XXXXXX[0] = letters[v % 62];
715       v /= 62;
716       XXXXXX[1] = letters[v % 62];
717       v /= 62;
718       XXXXXX[2] = letters[v % 62];
719       v /= 62;
720       XXXXXX[3] = letters[v % 62];
721       v /= 62;
722       XXXXXX[4] = letters[v % 62];
723       v /= 62;
724       XXXXXX[5] = letters[v % 62];
725
726       fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
727       if (fd >= 0)
728         {
729           gpg_err_set_errno (save_errno);
730           return fd;
731         }
732       else if (errno != EEXIST)
733         return -1;
734     }
735
736   /* We got out of the loop because we ran out of combinations to try.  */
737   gpg_err_set_errno (EEXIST);
738   return -1;
739 }
740
741 \f
742 int
743 _gpgme_mkstemp (int *fd, char **name)
744 {
745   char tmp[MAX_PATH + 2];
746   char *tmpname;
747   int err;
748
749   *fd = -1;
750   *name = NULL;
751
752   err = GetTempPathA (MAX_PATH + 1, tmp);
753   if (err == 0 || err > MAX_PATH + 1)
754     strcpy (tmp,"c:\\windows\\temp");
755   else
756     {
757       int len = strlen(tmp);
758
759       /* GetTempPath may return with \ on the end */
760       while(len > 0 && tmp[len - 1] == '\\')
761         {
762           tmp[len-1] = '\0';
763           len--;
764         }
765     }
766
767   tmpname = _gpgme_strconcat (tmp, "\\gpgme-XXXXXX", NULL);
768   if (!tmpname)
769     return -1;
770   *fd = my_mkstemp (tmpname);
771   if (*fd < 0)
772     {
773       free (tmpname);
774       return -1;
775     }
776
777   *name = tmpname;
778   return 0;
779 }
780
781
782 \f
783 /* Entry point called by the DLL loader.  */
784 #ifdef DLL_EXPORT
785 int WINAPI
786 DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
787 {
788   (void)reserved;
789
790   if (reason == DLL_PROCESS_ATTACH)
791     my_hmodule = hinst;
792
793   return TRUE;
794 }
795 #endif /*DLL_EXPORT*/