core: Make the status-fd monitor work for all gpgsm commands.
[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://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
102   (void)flag;
103   return hd;
104 }
105
106 static GPG_ERR_INLINE void *
107 dlsym (void * hd, const char * sym)
108 {
109   if (hd && sym)
110     {
111       void * fnc = GetProcAddress (hd, sym);
112       if (!fnc)
113         return NULL;
114       return fnc;
115     }
116   return NULL;
117 }
118
119 static GPG_ERR_INLINE int
120 dlclose (void * hd)
121 {
122   if (hd)
123     {
124       FreeLibrary (hd);
125       return 0;
126     }
127   return -1;
128 }
129 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
130
131
132 /* Return a malloced string encoded in UTF-8 from the wide char input
133    string STRING.  Caller must free this value.  Returns NULL and sets
134    ERRNO on failure.  Calling this function with STRING set to NULL is
135    not defined.  */
136 static char *
137 wchar_to_utf8 (const wchar_t *string)
138 {
139   int n;
140   char *result;
141
142   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
143   if (n < 0)
144     {
145       gpg_err_set_errno (EINVAL);
146       return NULL;
147     }
148
149   result = malloc (n+1);
150   if (!result)
151     return NULL;
152
153   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
154   if (n < 0)
155     {
156       free (result);
157       gpg_err_set_errno (EINVAL);
158       result = NULL;
159     }
160   return result;
161 }
162
163
164 /* Replace all forward slashes by backslashes.  */
165 static void
166 replace_slashes (char *string)
167 {
168   for (; *string; string++)
169     if (*string == '/')
170       *string = '\\';
171 }
172
173
174 /* Get the base name of NAME.  Returns a pointer into NAME right after
175    the last slash or backslash or to NAME if no slash or backslash
176    exists.  */
177 static const char *
178 get_basename (const char *name)
179 {
180   const char *mark, *s;
181
182   for (mark=NULL, s=name; *s; s++)
183     if (*s == '/' || *s == '\\')
184       mark = s;
185
186   return mark? mark+1 : name;
187 }
188
189
190 void
191 _gpgme_allow_set_foreground_window (pid_t pid)
192 {
193 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
194   static int initialized;
195   static BOOL (WINAPI * func)(DWORD);
196   void *handle;
197
198   if (!initialized)
199     {
200       /* Available since W2000; thus we dynload it.  */
201       initialized = 1;
202       handle = dlopen ("user32.dll", RTLD_LAZY);
203       if (handle)
204         {
205           func = dlsym (handle, "AllowSetForegroundWindow");
206           if (!func)
207             {
208               dlclose (handle);
209               handle = NULL;
210             }
211         }
212     }
213
214   if (!pid || pid == (pid_t)(-1))
215     {
216       TRACE1 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
217               "no action for pid %d", (int)pid);
218     }
219   else if (func)
220     {
221       int rc = func (pid);
222       TRACE2 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
223               "called for pid %d; result=%d", (int)pid, rc);
224
225     }
226   else
227     {
228       TRACE0 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
229               "function not available");
230     }
231 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
232 }
233
234
235 /* Return a string from the W32 Registry or NULL in case of error.
236    Caller must release the return value.  A NULL for root is an alias
237    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
238 static char *
239 read_w32_registry_string (const char *root, const char *dir, const char *name)
240 {
241   HKEY root_key, key_handle;
242   DWORD n1, nbytes, type;
243   char *result = NULL;
244
245   if (!root)
246     root_key = HKEY_CURRENT_USER;
247   else if (!strcmp( root, "HKEY_CLASSES_ROOT"))
248     root_key = HKEY_CLASSES_ROOT;
249   else if (!strcmp( root, "HKEY_CURRENT_USER"))
250     root_key = HKEY_CURRENT_USER;
251   else if (!strcmp( root, "HKEY_LOCAL_MACHINE"))
252     root_key = HKEY_LOCAL_MACHINE;
253   else if (!strcmp( root, "HKEY_USERS"))
254     root_key = HKEY_USERS;
255   else if (!strcmp( root, "HKEY_PERFORMANCE_DATA"))
256     root_key = HKEY_PERFORMANCE_DATA;
257   else if (!strcmp( root, "HKEY_CURRENT_CONFIG"))
258     root_key = HKEY_CURRENT_CONFIG;
259   else
260     return NULL;
261
262   if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle))
263     {
264       if (root)
265         return NULL; /* no need for a RegClose, so return direct */
266       /* It seems to be common practise to fall back to HKLM. */
267       if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
268         return NULL; /* still no need for a RegClose, so return direct */
269     }
270
271   nbytes = 1;
272   if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
273     {
274       if (root)
275         goto leave;
276       /* Try to fallback to HKLM also vor a missing value.  */
277       RegCloseKey (key_handle);
278       if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
279         return NULL; /* Nope.  */
280       if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
281         goto leave;
282     }
283   n1 = nbytes + 1;
284   result = malloc (n1);
285   if (!result)
286     goto leave;
287   if (RegQueryValueExA (key_handle, name, 0, &type, (LPBYTE) result, &n1))
288     {
289       free (result);
290       result = NULL;
291       goto leave;
292     }
293   result[nbytes] = 0; /* Make sure it is really a string.  */
294
295 #ifndef HAVE_W32CE_SYSTEM
296   /* Windows CE does not have an environment.  */
297   if (type == REG_EXPAND_SZ && strchr (result, '%'))
298     {
299       char *tmp;
300
301       n1 += 1000;
302       tmp = malloc (n1 + 1);
303       if (!tmp)
304         goto leave;
305       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
306       if (nbytes && nbytes > n1)
307         {
308           free (tmp);
309           n1 = nbytes;
310           tmp = malloc (n1 + 1);
311           if (!tmp)
312             goto leave;
313           nbytes = ExpandEnvironmentStrings (result, tmp, n1);
314           if (nbytes && nbytes > n1) {
315             free (tmp); /* Oops - truncated, better don't expand at all. */
316             goto leave;
317           }
318           tmp[nbytes] = 0;
319           free (result);
320           result = tmp;
321         }
322       else if (nbytes)  /* Okay, reduce the length. */
323         {
324           tmp[nbytes] = 0;
325           free (result);
326           result = malloc (strlen (tmp)+1);
327           if (!result)
328             result = tmp;
329           else
330             {
331               strcpy (result, tmp);
332               free (tmp);
333             }
334         }
335       else  /* Error - don't expand. */
336         {
337           free (tmp);
338         }
339     }
340 #endif
341
342  leave:
343   RegCloseKey (key_handle);
344   return result;
345 }
346
347
348 /* Return the name of the directory with the gpgme DLL or the EXE (if
349    statically linked).  May return NULL on severe errors. */
350 const char *
351 _gpgme_get_inst_dir (void)
352 {
353   static char *inst_dir;
354
355   if (override_inst_dir)
356     return override_inst_dir;
357
358   LOCK (get_path_lock);
359   if (!inst_dir)
360     {
361       wchar_t *moddir;
362
363       moddir = malloc ((MAX_PATH+5) * sizeof *moddir);
364       if (moddir)
365         {
366           if (!GetModuleFileNameW (my_hmodule, moddir, MAX_PATH))
367             *moddir = 0;
368           if (!*moddir)
369             gpg_err_set_errno (ENOENT);
370           else
371             {
372               inst_dir = wchar_to_utf8 (moddir);
373               if (inst_dir)
374                 {
375                   char *p = strrchr (inst_dir, '\\');
376                   if (p)
377                     *p = 0;
378                 }
379             }
380           free (moddir);
381         }
382     }
383   UNLOCK (get_path_lock);
384   return inst_dir;
385 }
386
387
388 static char *
389 find_program_in_dir (const char *dir, const char *name)
390 {
391   char *result;
392
393   result = _gpgme_strconcat (dir, "\\", name, NULL);
394   if (!result)
395     return NULL;
396
397   if (access (result, F_OK))
398     {
399       free (result);
400       return NULL;
401     }
402
403   return result;
404 }
405
406
407 static char *
408 find_program_at_standard_place (const char *name)
409 {
410   char path[MAX_PATH];
411   char *result = NULL;
412
413   /* See http://wiki.tcl.tk/17492 for details on compatibility.
414
415      We First try the generic place and then fallback to the x86
416      (i.e. 32 bit) place.  This will prefer a 64 bit of the program
417      over a 32 bit version on 64 bit Windows if installed.  */
418   if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0))
419     {
420       result = _gpgme_strconcat (path, "\\", name, NULL);
421       if (result && access (result, F_OK))
422         {
423           free (result);
424           result = NULL;
425         }
426     }
427   if (!result
428       && SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
429     {
430       result = _gpgme_strconcat (path, "\\", name, NULL);
431       if (result && access (result, F_OK))
432         {
433           free (result);
434           result = NULL;
435         }
436     }
437   return result;
438 }
439
440
441 /* Set the default name for the gpg binary.  This function may only be
442    called by gpgme_set_global_flag.  Returns 0 on success.  */
443 int
444 _gpgme_set_default_gpg_name (const char *name)
445 {
446   if (!default_gpg_name)
447     {
448       default_gpg_name = _gpgme_strconcat (name, ".exe", NULL);
449       if (default_gpg_name)
450         replace_slashes (default_gpg_name);
451     }
452   return !default_gpg_name;
453 }
454
455 /* Set the default name for the gpgconf binary.  This function may only be
456    called by gpgme_set_global_flag.  Returns 0 on success.  */
457 int
458 _gpgme_set_default_gpgconf_name (const char *name)
459 {
460   if (!default_gpgconf_name)
461     {
462       default_gpgconf_name = _gpgme_strconcat (name, ".exe", NULL);
463       if (default_gpgconf_name)
464         replace_slashes (default_gpgconf_name);
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 = strdup (dir);
478       if (override_inst_dir)
479         {
480           replace_slashes (override_inst_dir);
481           /* Remove a trailing slash.  */
482           if (*override_inst_dir
483               && override_inst_dir[strlen (override_inst_dir)-1] == '\\')
484             override_inst_dir[strlen (override_inst_dir)-1] = 0;
485         }
486     }
487   return !override_inst_dir;
488 }
489
490
491 /* Return the full file name of the GPG binary.  This function is used
492    iff gpgconf was not found and thus it can be assumed that gpg2 is
493    not installed.  This function is only called by get_gpgconf_item
494    and may not be called concurrently. */
495 char *
496 _gpgme_get_gpg_path (void)
497 {
498   char *gpg = NULL;
499   const char *name, *inst_dir;
500
501   name = default_gpg_name? get_basename (default_gpg_name) : "gpg.exe";
502
503   /* 1. Try to find gpg.exe in the installation directory of gpgme.  */
504   inst_dir = _gpgme_get_inst_dir ();
505   if (inst_dir)
506     {
507       gpg = find_program_in_dir (inst_dir, name);
508     }
509
510   /* 2. Try to find gpg.exe using that ancient registry key.  */
511   if (!gpg)
512     {
513       char *dir;
514
515       dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
516                                       "Software\\GNU\\GnuPG",
517                                       "Install Directory");
518       if (dir)
519         {
520           gpg = find_program_in_dir (dir, name);
521           free (dir);
522         }
523     }
524
525   /* 3. Try to find gpg.exe below CSIDL_PROGRAM_FILES.  */
526   if (!gpg)
527     {
528       name = default_gpg_name? default_gpg_name : "GNU\\GnuPG\\gpg.exe";
529       gpg = find_program_at_standard_place (name);
530     }
531
532   /* 4. Print a debug message if not found.  */
533   if (!gpg)
534     _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found", name);
535
536   return gpg;
537 }
538
539
540 /* This function is only called by get_gpgconf_item and may not be
541    called concurrently.  */
542 char *
543 _gpgme_get_gpgconf_path (void)
544 {
545   char *gpgconf = NULL;
546   const char *inst_dir, *name;
547
548   name = default_gpgconf_name? get_basename(default_gpgconf_name):"gpgconf.exe";
549
550   /* 1. Try to find gpgconf.exe in the installation directory of gpgme.  */
551   inst_dir = _gpgme_get_inst_dir ();
552   if (inst_dir)
553     {
554       gpgconf = find_program_in_dir (inst_dir, name);
555     }
556
557   /* 2. Try to find gpgconf.exe from GnuPG >= 2.1 below CSIDL_PROGRAM_FILES. */
558   if (!gpgconf)
559     {
560       const char *name2 = (default_gpgconf_name ? default_gpgconf_name
561                            /**/                 : "GnuPG\\bin\\gpgconf.exe");
562       gpgconf = find_program_at_standard_place (name2);
563     }
564
565   /* 3. Try to find gpgconf.exe using the Windows registry. */
566   if (!gpgconf)
567     {
568       char *dir;
569
570       dir = read_w32_registry_string (NULL,
571                                       "Software\\GNU\\GnuPG",
572                                       "Install Directory");
573       if (!dir)
574         {
575           char *tmp = read_w32_registry_string (NULL,
576                                                 "Software\\GnuPG",
577                                                 "Install Directory");
578           if (tmp)
579             {
580               dir = _gpgme_strconcat (tmp, "\\bin", NULL);
581               free (tmp);
582               if (!dir)
583                 return NULL;
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 = _gpgme_strconcat (tmp, "\\gpgme-XXXXXX", NULL);
766   if (!tmpname)
767     return -1;
768   *fd = my_mkstemp (tmpname);
769   if (*fd < 0)
770     {
771       free (tmpname);
772       return -1;
773     }
774
775   *name = tmpname;
776   return 0;
777 }
778 #endif
779
780
781 \f
782 #ifdef HAVE_W32CE_SYSTEM
783 /* Return a malloced string with the replacement value for the
784    GPGME_DEBUG envvar.  Caller must release.  Returns NULL if not
785    set.  */
786 char *
787 _gpgme_w32ce_get_debug_envvar (void)
788 {
789   char *tmp;
790
791   tmp = read_w32_registry_string (NULL, "\\Software\\GNU\\gpgme", "debug");
792   if (tmp && !*tmp)
793     {
794       free (tmp);
795       tmp = NULL;
796     }
797   return tmp;
798 }
799 #endif /*HAVE_W32CE_SYSTEM*/
800
801
802 /* Entry point called by the DLL loader.  */
803 #ifdef DLL_EXPORT
804 int WINAPI
805 DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
806 {
807   (void)reserved;
808
809   if (reason == DLL_PROCESS_ATTACH)
810     my_hmodule = hinst;
811
812   return TRUE;
813 }
814 #endif /*DLL_EXPORT*/