core: Fix condition-always-true warning in trace macro.
[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 <http://www.gnu.org/licenses/>.
20  **/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <stdint.h>
31 #ifdef HAVE_SYS_TIME_H
32 # include <sys/time.h>
33 #endif
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37 #ifdef HAVE_SYS_STAT_H
38 # include <sys/stat.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <fcntl.h>
44 #include <io.h>
45
46 #if __MINGW64_VERSION_MAJOR >= 2
47 # define _WIN32_IE 0x0501 /* Required by mingw64 toolkit.  */
48 #else
49 # define _WIN32_IE 0x0400 /* Required for SHGetSpecialFolderPathA.  */
50 #endif
51
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.  */
56 #include <winsock2.h>
57 #include <ws2tcpip.h>
58 #include <windows.h>
59 #include <shlobj.h>
60
61 #include "util.h"
62 #include "ath.h"
63 #include "sema.h"
64 #include "debug.h"
65 #include "sys-util.h"
66
67
68 #ifndef HAVE_W32CE_SYSTEM
69 #define HAVE_ALLOW_SET_FOREGROUND_WINDOW 1
70 #endif
71 #ifndef F_OK
72 # define F_OK 0
73 #endif
74
75
76 DEFINE_STATIC_LOCK (get_path_lock);
77
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;
83
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;
92
93 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
94
95 #define RTLD_LAZY 0
96
97 static GPG_ERR_INLINE void *
98 dlopen (const char * name, int flag)
99 {
100   void * hd = LoadLibrary (name);
101   return hd;
102 }
103
104 static GPG_ERR_INLINE void *
105 dlsym (void * hd, const char * sym)
106 {
107   if (hd && sym)
108     {
109       void * fnc = GetProcAddress (hd, sym);
110       if (!fnc)
111         return NULL;
112       return fnc;
113     }
114   return NULL;
115 }
116
117 static GPG_ERR_INLINE int
118 dlclose (void * hd)
119 {
120   if (hd)
121     {
122       FreeLibrary (hd);
123       return 0;
124     }
125   return -1;
126 }
127 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
128
129
130 /* Return a malloced string encoded in UTF-8 from the wide char input
131    string STRING.  Caller must free this value.  Returns NULL and sets
132    ERRNO on failure.  Calling this function with STRING set to NULL is
133    not defined.  */
134 static char *
135 wchar_to_utf8 (const wchar_t *string)
136 {
137   int n;
138   char *result;
139
140   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
141   if (n < 0)
142     {
143       gpg_err_set_errno (EINVAL);
144       return NULL;
145     }
146
147   result = malloc (n+1);
148   if (!result)
149     return NULL;
150
151   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
152   if (n < 0)
153     {
154       free (result);
155       gpg_err_set_errno (EINVAL);
156       result = NULL;
157     }
158   return result;
159 }
160
161
162 /* Replace all forward slashes by backslashes.  */
163 static void
164 replace_slashes (char *string)
165 {
166   for (; *string; string++)
167     if (*string == '/')
168       *string = '\\';
169 }
170
171
172 /* Get the base name of NAME.  Returns a pointer into NAME right after
173    the last slash or backslash or to NAME if no slash or backslash
174    exists.  */
175 static const char *
176 get_basename (const char *name)
177 {
178   const char *mark, *s;
179
180   for (mark=NULL, s=name; *s; s++)
181     if (*s == '/' || *s == '\\')
182       mark = s;
183
184   return mark? mark+1 : name;
185 }
186
187
188 void
189 _gpgme_allow_set_foreground_window (pid_t pid)
190 {
191 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
192   static int initialized;
193   static BOOL (WINAPI * func)(DWORD);
194   void *handle;
195
196   if (!initialized)
197     {
198       /* Available since W2000; thus we dynload it.  */
199       initialized = 1;
200       handle = dlopen ("user32.dll", RTLD_LAZY);
201       if (handle)
202         {
203           func = dlsym (handle, "AllowSetForegroundWindow");
204           if (!func)
205             {
206               dlclose (handle);
207               handle = NULL;
208             }
209         }
210     }
211
212   if (!pid || pid == (pid_t)(-1))
213     {
214       TRACE1 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
215               "no action for pid %d", (int)pid);
216     }
217   else if (func)
218     {
219       int rc = func (pid);
220       TRACE2 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
221               "called for pid %d; result=%d", (int)pid, rc);
222
223     }
224   else
225     {
226       TRACE0 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
227               "function not available");
228     }
229 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
230 }
231
232
233 /* Return a string from the W32 Registry or NULL in case of error.
234    Caller must release the return value.  A NULL for root is an alias
235    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
236 static char *
237 read_w32_registry_string (const char *root, const char *dir, const char *name)
238 {
239   HKEY root_key, key_handle;
240   DWORD n1, nbytes, type;
241   char *result = NULL;
242
243   if (!root)
244     root_key = HKEY_CURRENT_USER;
245   else if (!strcmp( root, "HKEY_CLASSES_ROOT"))
246     root_key = HKEY_CLASSES_ROOT;
247   else if (!strcmp( root, "HKEY_CURRENT_USER"))
248     root_key = HKEY_CURRENT_USER;
249   else if (!strcmp( root, "HKEY_LOCAL_MACHINE"))
250     root_key = HKEY_LOCAL_MACHINE;
251   else if (!strcmp( root, "HKEY_USERS"))
252     root_key = HKEY_USERS;
253   else if (!strcmp( root, "HKEY_PERFORMANCE_DATA"))
254     root_key = HKEY_PERFORMANCE_DATA;
255   else if (!strcmp( root, "HKEY_CURRENT_CONFIG"))
256     root_key = HKEY_CURRENT_CONFIG;
257   else
258     return NULL;
259
260   if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle))
261     {
262       if (root)
263         return NULL; /* no need for a RegClose, so return direct */
264       /* It seems to be common practise to fall back to HKLM. */
265       if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
266         return NULL; /* still no need for a RegClose, so return direct */
267     }
268
269   nbytes = 1;
270   if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
271     {
272       if (root)
273         goto leave;
274       /* Try to fallback to HKLM also vor a missing value.  */
275       RegCloseKey (key_handle);
276       if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
277         return NULL; /* Nope.  */
278       if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
279         goto leave;
280     }
281   n1 = nbytes + 1;
282   result = malloc (n1);
283   if (!result)
284     goto leave;
285   if (RegQueryValueExA (key_handle, name, 0, &type, (LPBYTE) result, &n1))
286     {
287       free (result);
288       result = NULL;
289       goto leave;
290     }
291   result[nbytes] = 0; /* Make sure it is really a string.  */
292
293 #ifndef HAVE_W32CE_SYSTEM
294   /* Windows CE does not have an environment.  */
295   if (type == REG_EXPAND_SZ && strchr (result, '%'))
296     {
297       char *tmp;
298
299       n1 += 1000;
300       tmp = malloc (n1 + 1);
301       if (!tmp)
302         goto leave;
303       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
304       if (nbytes && nbytes > n1)
305         {
306           free (tmp);
307           n1 = nbytes;
308           tmp = malloc (n1 + 1);
309           if (!tmp)
310             goto leave;
311           nbytes = ExpandEnvironmentStrings (result, tmp, n1);
312           if (nbytes && nbytes > n1) {
313             free (tmp); /* Oops - truncated, better don't expand at all. */
314             goto leave;
315           }
316           tmp[nbytes] = 0;
317           free (result);
318           result = tmp;
319         }
320       else if (nbytes)  /* Okay, reduce the length. */
321         {
322           tmp[nbytes] = 0;
323           free (result);
324           result = malloc (strlen (tmp)+1);
325           if (!result)
326             result = tmp;
327           else
328             {
329               strcpy (result, tmp);
330               free (tmp);
331             }
332         }
333       else  /* Error - don't expand. */
334         {
335           free (tmp);
336         }
337     }
338 #endif
339
340  leave:
341   RegCloseKey (key_handle);
342   return result;
343 }
344
345
346 /* Return the name of the directory with the gpgme DLL or the EXE (if
347    statically linked).  May return NULL on severe errors. */
348 const char *
349 _gpgme_get_inst_dir (void)
350 {
351   static char *inst_dir;
352
353   if (override_inst_dir)
354     return override_inst_dir;
355
356   LOCK (get_path_lock);
357   if (!inst_dir)
358     {
359       wchar_t *moddir;
360
361       moddir = malloc ((MAX_PATH+5) * sizeof *moddir);
362       if (moddir)
363         {
364           if (!GetModuleFileNameW (my_hmodule, moddir, MAX_PATH))
365             *moddir = 0;
366           if (!*moddir)
367             gpg_err_set_errno (ENOENT);
368           else
369             {
370               inst_dir = wchar_to_utf8 (moddir);
371               if (inst_dir)
372                 {
373                   char *p = strrchr (inst_dir, '\\');
374                   if (p)
375                     *p = 0;
376                 }
377             }
378           free (moddir);
379         }
380     }
381   UNLOCK (get_path_lock);
382   return inst_dir;
383 }
384
385
386 static char *
387 find_program_in_dir (const char *dir, const char *name)
388 {
389   char *result;
390
391   result = malloc (strlen (dir) + 1 + strlen (name) + 1);
392   if (!result)
393     return NULL;
394
395   strcpy (stpcpy (stpcpy (result, dir), "\\"), name);
396   if (access (result, F_OK))
397     {
398       free (result);
399       return NULL;
400     }
401
402   return result;
403 }
404
405
406 static char *
407 find_program_at_standard_place (const char *name)
408 {
409   char path[MAX_PATH];
410   char *result = NULL;
411
412   /* See http://wiki.tcl.tk/17492 for details on compatibility.
413
414      We First try the generic place and then fallback to the x86
415      (i.e. 32 bit) place.  This will prefer a 64 bit of the program
416      over a 32 bit version on 64 bit Windows if installed.  */
417   if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0)
418       || SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
419     {
420       result = malloc (strlen (path) + 1 + strlen (name) + 1);
421       if (result)
422         {
423           strcpy (stpcpy (stpcpy (result, path), "\\"), name);
424           if (access (result, F_OK))
425             {
426               free (result);
427               result = NULL;
428             }
429         }
430     }
431   return result;
432 }
433
434
435 /* Set the default name for the gpg binary.  This function may only be
436    called by gpgme_set_global_flag.  Returns 0 on success.  */
437 int
438 _gpgme_set_default_gpg_name (const char *name)
439 {
440   if (!default_gpg_name)
441     {
442       default_gpg_name = malloc (strlen (name) + 5);
443       if (default_gpg_name)
444         {
445           strcpy (stpcpy (default_gpg_name, name), ".exe");
446           replace_slashes (default_gpg_name);
447         }
448     }
449   return !default_gpg_name;
450 }
451
452 /* Set the default name for the gpgconf binary.  This function may only be
453    called by gpgme_set_global_flag.  Returns 0 on success.  */
454 int
455 _gpgme_set_default_gpgconf_name (const char *name)
456 {
457   if (!default_gpgconf_name)
458     {
459       default_gpgconf_name = malloc (strlen (name) + 5);
460       if (default_gpgconf_name)
461         {
462           strcpy (stpcpy (default_gpgconf_name, name), ".exe");
463           replace_slashes (default_gpgconf_name);
464         }
465     }
466   return !default_gpgconf_name;
467 }
468
469
470 /* Set the override installation directory.  This function may only be
471    called by gpgme_set_global_flag.  Returns 0 on success.  */
472 int
473 _gpgme_set_override_inst_dir (const char *dir)
474 {
475   if (!override_inst_dir)
476     {
477       override_inst_dir = malloc (strlen (dir) + 1);
478       if (override_inst_dir)
479         {
480           strcpy (override_inst_dir, dir);
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                                       "Software\\GNU\\GnuPG",
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                                       "Software\\GNU\\GnuPG",
573                                       "Install Directory");
574       if (!dir)
575         {
576           char *tmp = read_w32_registry_string (NULL,
577                                                 "Software\\GnuPG",
578                                                 "Install Directory");
579           if (tmp)
580             {
581               if (gpgrt_asprintf (&dir, "%s\\bin", tmp) == -1)
582                 return NULL;
583               free (tmp);
584             }
585         }
586       if (dir)
587         {
588           gpgconf = find_program_in_dir (dir, name);
589           free (dir);
590         }
591     }
592
593   /* 4. Try to find gpgconf.exe from Gpg4win below CSIDL_PROGRAM_FILES.  */
594   if (!gpgconf)
595     {
596       gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe");
597     }
598
599   /* 5. Print a debug message if not found.  */
600   if (!gpgconf)
601     _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",name);
602
603   return gpgconf;
604 }
605
606
607 const char *
608 _gpgme_get_w32spawn_path (void)
609 {
610   static char *w32spawn_program;
611   const char *inst_dir;
612
613   inst_dir = _gpgme_get_inst_dir ();
614   LOCK (get_path_lock);
615   if (!w32spawn_program)
616     w32spawn_program = find_program_in_dir (inst_dir, "gpgme-w32spawn.exe");
617   UNLOCK (get_path_lock);
618   return w32spawn_program;
619 }
620
621
622 /* Return an integer value from gpgme specific configuration
623    entries. VALUE receives that value; function returns true if a value
624    has been configured and false if not. */
625 int
626 _gpgme_get_conf_int (const char *key, int *value)
627 {
628   char *tmp = read_w32_registry_string (NULL, "Software\\GNU\\gpgme", key);
629   if (!tmp)
630     return 0;
631   *value = atoi (tmp);
632   free (tmp);
633   return 1;
634 }
635
636 \f
637 #ifdef HAVE_W32CE_SYSTEM
638 int
639 _gpgme_mkstemp (int *fd, char **name)
640 {
641   return -1;
642 }
643 #else
644
645 /* mkstemp extracted from libc/sysdeps/posix/tempname.c.  Copyright
646    (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
647
648    The GNU C Library is free software; you can redistribute it and/or
649    modify it under the terms of the GNU Lesser General Public
650    License as published by the Free Software Foundation; either
651    version 2.1 of the License, or (at your option) any later version.  */
652
653 static const char letters[] =
654 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
655
656 /* Generate a temporary file name based on TMPL.  TMPL must match the
657    rules for mk[s]temp (i.e. end in "XXXXXX").  The name constructed
658    does not exist at the time of the call to mkstemp.  TMPL is
659    overwritten with the result.  */
660 static int
661 my_mkstemp (char *tmpl)
662 {
663   int len;
664   char *XXXXXX;
665   static uint64_t value;
666   uint64_t random_time_bits;
667   unsigned int count;
668   int fd = -1;
669   int save_errno = errno;
670
671   /* A lower bound on the number of temporary files to attempt to
672      generate.  The maximum total number of temporary file names that
673      can exist for a given template is 62**6.  It should never be
674      necessary to try all these combinations.  Instead if a reasonable
675      number of names is tried (we define reasonable as 62**3) fail to
676      give the system administrator the chance to remove the problems.  */
677 #define ATTEMPTS_MIN (62 * 62 * 62)
678
679   /* The number of times to attempt to generate a temporary file.  To
680      conform to POSIX, this must be no smaller than TMP_MAX.  */
681 #if ATTEMPTS_MIN < TMP_MAX
682   unsigned int attempts = TMP_MAX;
683 #else
684   unsigned int attempts = ATTEMPTS_MIN;
685 #endif
686
687   len = strlen (tmpl);
688   if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
689     {
690       gpg_err_set_errno (EINVAL);
691       return -1;
692     }
693
694   /* This is where the Xs start.  */
695   XXXXXX = &tmpl[len - 6];
696
697   /* Get some more or less random data.  */
698   {
699     FILETIME ft;
700
701     GetSystemTimeAsFileTime (&ft);
702     random_time_bits = (((uint64_t)ft.dwHighDateTime << 32)
703                         | (uint64_t)ft.dwLowDateTime);
704   }
705   value += random_time_bits ^ ath_self ();
706
707   for (count = 0; count < attempts; value += 7777, ++count)
708     {
709       uint64_t v = value;
710
711       /* Fill in the random bits.  */
712       XXXXXX[0] = letters[v % 62];
713       v /= 62;
714       XXXXXX[1] = letters[v % 62];
715       v /= 62;
716       XXXXXX[2] = letters[v % 62];
717       v /= 62;
718       XXXXXX[3] = letters[v % 62];
719       v /= 62;
720       XXXXXX[4] = letters[v % 62];
721       v /= 62;
722       XXXXXX[5] = letters[v % 62];
723
724       fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
725       if (fd >= 0)
726         {
727           gpg_err_set_errno (save_errno);
728           return fd;
729         }
730       else if (errno != EEXIST)
731         return -1;
732     }
733
734   /* We got out of the loop because we ran out of combinations to try.  */
735   gpg_err_set_errno (EEXIST);
736   return -1;
737 }
738
739 \f
740 int
741 _gpgme_mkstemp (int *fd, char **name)
742 {
743   char tmp[MAX_PATH + 2];
744   char *tmpname;
745   int err;
746
747   *fd = -1;
748   *name = NULL;
749
750   err = GetTempPathA (MAX_PATH + 1, tmp);
751   if (err == 0 || err > MAX_PATH + 1)
752     strcpy (tmp,"c:\\windows\\temp");
753   else
754     {
755       int len = strlen(tmp);
756
757       /* GetTempPath may return with \ on the end */
758       while(len > 0 && tmp[len - 1] == '\\')
759         {
760           tmp[len-1] = '\0';
761           len--;
762         }
763     }
764
765   tmpname = malloc (strlen (tmp) + 13 + 1);
766   if (!tmpname)
767     return -1;
768   strcpy (stpcpy (tmpname, tmp), "\\gpgme-XXXXXX");
769   *fd = my_mkstemp (tmpname);
770   if (fd < 0)
771     {
772       free (tmpname);
773       return -1;
774     }
775
776   *name = tmpname;
777   return 0;
778 }
779 #endif
780
781
782 \f
783 #ifdef HAVE_W32CE_SYSTEM
784 /* Return a malloced string with the replacement value for the
785    GPGME_DEBUG envvar.  Caller must release.  Returns NULL if not
786    set.  */
787 char *
788 _gpgme_w32ce_get_debug_envvar (void)
789 {
790   char *tmp;
791
792   tmp = read_w32_registry_string (NULL, "\\Software\\GNU\\gpgme", "debug");
793   if (tmp && !*tmp)
794     {
795       free (tmp);
796       tmp = NULL;
797     }
798   return tmp;
799 }
800 #endif /*HAVE_W32CE_SYSTEM*/
801
802
803 /* Entry point called by the DLL loader.  */
804 #ifdef DLL_EXPORT
805 int WINAPI
806 DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
807 {
808   (void)reserved;
809
810   if (reason == DLL_PROCESS_ATTACH)
811     my_hmodule = hinst;
812
813   return TRUE;
814 }
815 #endif /*DLL_EXPORT*/