Fix a memory access and a double slash bug.
[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
89
90 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
91
92 #define RTLD_LAZY 0
93
94 static GPG_ERR_INLINE void *
95 dlopen (const char * name, int flag)
96 {
97   void * hd = LoadLibrary (name);
98   return hd;
99 }
100
101 static GPG_ERR_INLINE void *
102 dlsym (void * hd, const char * sym)
103 {
104   if (hd && sym)
105     {
106       void * fnc = GetProcAddress (hd, sym);
107       if (!fnc)
108         return NULL;
109       return fnc;
110     }
111   return NULL;
112 }
113
114 static GPG_ERR_INLINE int
115 dlclose (void * hd)
116 {
117   if (hd)
118     {
119       FreeLibrary (hd);
120       return 0;
121     }
122   return -1;
123 }
124 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
125
126
127 /* Return a malloced string encoded in UTF-8 from the wide char input
128    string STRING.  Caller must free this value.  Returns NULL and sets
129    ERRNO on failure.  Calling this function with STRING set to NULL is
130    not defined.  */
131 static char *
132 wchar_to_utf8 (const wchar_t *string)
133 {
134   int n;
135   char *result;
136
137   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
138   if (n < 0)
139     {
140       gpg_err_set_errno (EINVAL);
141       return NULL;
142     }
143
144   result = malloc (n+1);
145   if (!result)
146     return NULL;
147
148   n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
149   if (n < 0)
150     {
151       free (result);
152       gpg_err_set_errno (EINVAL);
153       result = NULL;
154     }
155   return result;
156 }
157
158
159 /* Replace all forward slashes by backslashes.  */
160 static void
161 replace_slashes (char *string)
162 {
163   for (; *string; string++)
164     if (*string == '/')
165       *string = '\\';
166 }
167
168
169 /* Get the base name of NAME.  Returns a pointer into NAME right after
170    the last slash or backslash or to NAME if no slash or backslash
171    exists.  */
172 static const char *
173 get_basename (const char *name)
174 {
175   const char *mark, *s;
176
177   for (mark=NULL, s=name; *s; s++)
178     if (*s == '/' || *s == '\\')
179       mark = s;
180
181   return mark? mark+1 : name;
182 }
183
184
185 void
186 _gpgme_allow_set_foreground_window (pid_t pid)
187 {
188 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
189   static int initialized;
190   static BOOL (WINAPI * func)(DWORD);
191   void *handle;
192
193   if (!initialized)
194     {
195       /* Available since W2000; thus we dynload it.  */
196       initialized = 1;
197       handle = dlopen ("user32.dll", RTLD_LAZY);
198       if (handle)
199         {
200           func = dlsym (handle, "AllowSetForegroundWindow");
201           if (!func)
202             {
203               dlclose (handle);
204               handle = NULL;
205             }
206         }
207     }
208
209   if (!pid || pid == (pid_t)(-1))
210     {
211       TRACE1 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
212               "no action for pid %d", (int)pid);
213     }
214   else if (func)
215     {
216       int rc = func (pid);
217       TRACE2 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
218               "called for pid %d; result=%d", (int)pid, rc);
219
220     }
221   else
222     {
223       TRACE0 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
224               "function not available");
225     }
226 #endif /* HAVE_ALLOW_SET_FOREGROUND_WINDOW */
227 }
228
229
230 /* Return a string from the W32 Registry or NULL in case of error.
231    Caller must release the return value.  A NULL for root is an alias
232    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
233 static char *
234 read_w32_registry_string (const char *root, const char *dir, const char *name)
235 {
236   HKEY root_key, key_handle;
237   DWORD n1, nbytes, type;
238   char *result = NULL;
239
240   if (!root)
241     root_key = HKEY_CURRENT_USER;
242   else if (!strcmp( root, "HKEY_CLASSES_ROOT"))
243     root_key = HKEY_CLASSES_ROOT;
244   else if (!strcmp( root, "HKEY_CURRENT_USER"))
245     root_key = HKEY_CURRENT_USER;
246   else if (!strcmp( root, "HKEY_LOCAL_MACHINE"))
247     root_key = HKEY_LOCAL_MACHINE;
248   else if (!strcmp( root, "HKEY_USERS"))
249     root_key = HKEY_USERS;
250   else if (!strcmp( root, "HKEY_PERFORMANCE_DATA"))
251     root_key = HKEY_PERFORMANCE_DATA;
252   else if (!strcmp( root, "HKEY_CURRENT_CONFIG"))
253     root_key = HKEY_CURRENT_CONFIG;
254   else
255     return NULL;
256
257   if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle))
258     {
259       if (root)
260         return NULL; /* no need for a RegClose, so return direct */
261       /* It seems to be common practise to fall back to HKLM. */
262       if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
263         return NULL; /* still no need for a RegClose, so return direct */
264     }
265
266   nbytes = 1;
267   if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
268     {
269       if (root)
270         goto leave;
271       /* Try to fallback to HKLM also vor a missing value.  */
272       RegCloseKey (key_handle);
273       if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
274         return NULL; /* Nope.  */
275       if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
276         goto leave;
277     }
278   n1 = nbytes + 1;
279   result = malloc (n1);
280   if (!result)
281     goto leave;
282   if (RegQueryValueExA (key_handle, name, 0, &type, (LPBYTE) result, &n1))
283     {
284       free (result);
285       result = NULL;
286       goto leave;
287     }
288   result[nbytes] = 0; /* Make sure it is really a string.  */
289
290 #ifndef HAVE_W32CE_SYSTEM
291   /* Windows CE does not have an environment.  */
292   if (type == REG_EXPAND_SZ && strchr (result, '%'))
293     {
294       char *tmp;
295
296       n1 += 1000;
297       tmp = malloc (n1 + 1);
298       if (!tmp)
299         goto leave;
300       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
301       if (nbytes && nbytes > n1)
302         {
303           free (tmp);
304           n1 = nbytes;
305           tmp = malloc (n1 + 1);
306           if (!tmp)
307             goto leave;
308           nbytes = ExpandEnvironmentStrings (result, tmp, n1);
309           if (nbytes && nbytes > n1) {
310             free (tmp); /* Oops - truncated, better don't expand at all. */
311             goto leave;
312           }
313           tmp[nbytes] = 0;
314           free (result);
315           result = tmp;
316         }
317       else if (nbytes)  /* Okay, reduce the length. */
318         {
319           tmp[nbytes] = 0;
320           free (result);
321           result = malloc (strlen (tmp)+1);
322           if (!result)
323             result = tmp;
324           else
325             {
326               strcpy (result, tmp);
327               free (tmp);
328             }
329         }
330       else  /* Error - don't expand. */
331         {
332           free (tmp);
333         }
334     }
335 #endif
336
337  leave:
338   RegCloseKey (key_handle);
339   return result;
340 }
341
342
343 /* Return the name of the directory with the gpgme DLL or the EXE (if
344    statically linked).  May return NULL on severe errors. */
345 const char *
346 _gpgme_get_inst_dir (void)
347 {
348   static char *inst_dir;
349
350   LOCK (get_path_lock);
351   if (!inst_dir)
352     {
353       wchar_t *moddir;
354
355       moddir = malloc ((MAX_PATH+5) * sizeof *moddir);
356       if (moddir)
357         {
358           if (!GetModuleFileNameW (my_hmodule, moddir, MAX_PATH))
359             *moddir = 0;
360           if (!*moddir)
361             gpg_err_set_errno (ENOENT);
362           else
363             {
364               inst_dir = wchar_to_utf8 (moddir);
365               if (inst_dir)
366                 {
367                   char *p = strrchr (inst_dir, '\\');
368                   if (p)
369                     *p = 0;
370                 }
371             }
372           free (moddir);
373         }
374     }
375   UNLOCK (get_path_lock);
376   return inst_dir;
377 }
378
379
380 static char *
381 find_program_in_dir (const char *dir, const char *name)
382 {
383   char *result;
384
385   result = malloc (strlen (dir) + 1 + strlen (name) + 1);
386   if (!result)
387     return NULL;
388
389   strcpy (stpcpy (stpcpy (result, dir), "\\"), name);
390   if (access (result, F_OK))
391     {
392       free (result);
393       return NULL;
394     }
395
396   return result;
397 }
398
399
400 static char *
401 find_program_in_inst_dir (const char *inst_dir, const char *name)
402 {
403   char *result;
404   char *dir;
405
406   /* If an installation directory has been passed, this overrides a
407      location given by the registry.  The idea here is that we prefer
408      a program installed alongside with gpgme.  We don't want the
409      registry to override this to have a better isolation of an gpgme
410      aware applications for other effects.  Note that the "Install
411      Directory" registry item has been used for ages in Gpg4win and
412      earlier GnuPG windows installers.  It is technically not anymore
413      required.  */
414   if (inst_dir)
415     {
416       result = find_program_in_dir (inst_dir, name);
417       if (result)
418         return result;
419     }
420
421   dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
422                                   "Software\\GNU\\GnuPG",
423                                   "Install Directory");
424   if (dir)
425     {
426       result = find_program_in_dir (dir, name);
427       free (dir);
428       return result;
429     }
430   return NULL;
431 }
432
433
434 static char *
435 find_program_at_standard_place (const char *name)
436 {
437   char path[MAX_PATH];
438   char *result = NULL;
439
440   /* See http://wiki.tcl.tk/17492 for details on compatibility.  */
441   if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0))
442     {
443       result = malloc (strlen (path) + 1 + strlen (name) + 1);
444       if (result)
445         {
446           strcpy (stpcpy (stpcpy (result, path), "\\"), name);
447           if (access (result, F_OK))
448             {
449               free (result);
450               result = NULL;
451             }
452         }
453     }
454   return result;
455 }
456
457
458 /* Set the default name for the gpg binary.  This function may only be
459    called by gpgme_set_global_flag.  Returns 0 on success.  */
460 int
461 _gpgme_set_default_gpg_name (const char *name)
462 {
463   if (!default_gpg_name)
464     {
465       default_gpg_name = malloc (strlen (name) + 5);
466       if (default_gpg_name)
467         {
468           strcpy (stpcpy (default_gpg_name, name), ".exe");
469           replace_slashes (default_gpg_name);
470         }
471     }
472   return !default_gpg_name;
473 }
474
475 /* Set the default name for the gpgconf binary.  This function may only be
476    called by gpgme_set_global_flag.  Returns 0 on success.  */
477 int
478 _gpgme_set_default_gpgconf_name (const char *name)
479 {
480   if (!default_gpgconf_name)
481     {
482       default_gpgconf_name = malloc (strlen (name) + 5);
483       if (default_gpgconf_name)
484         {
485           strcpy (stpcpy (default_gpgconf_name, name), ".exe");
486           replace_slashes (default_gpgconf_name);
487         }
488     }
489   return !default_gpgconf_name;
490 }
491
492
493 /* Return the full file name of the GPG binary.  This function is used
494    if gpgconf was not found and thus it can be assumed that gpg2 is
495    not installed.  This function is only called by get_gpgconf_item
496    and may not be called concurrently. */
497 char *
498 _gpgme_get_gpg_path (void)
499 {
500   char *gpg;
501   const char *inst_dir, *name;
502
503   inst_dir = _gpgme_get_inst_dir ();
504   gpg = find_program_in_inst_dir
505     (inst_dir,
506      default_gpg_name? get_basename (default_gpg_name) : "gpg.exe");
507   if (!gpg)
508     {
509       name = (default_gpg_name? default_gpg_name
510               /* */           : "GNU\\GnuPG\\gpg.exe");
511       gpg = find_program_at_standard_place (name);
512       if (!gpg)
513         _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found",
514                       name);
515     }
516
517   return gpg;
518 }
519
520
521 /* This function is only called by get_gpgconf_item and may not be
522    called concurrently.  */
523 char *
524 _gpgme_get_gpgconf_path (void)
525 {
526   char *gpgconf;
527   const char *inst_dir, *name;
528
529   inst_dir = _gpgme_get_inst_dir ();
530   gpgconf = find_program_in_inst_dir
531     (inst_dir,
532      default_gpgconf_name? get_basename (default_gpgconf_name) : "gpgconf.exe");
533   if (!gpgconf)
534     {
535       name = (default_gpgconf_name? default_gpgconf_name
536               /* */               : "GNU\\GnuPG\\gpgconf.exe");
537       gpgconf = find_program_at_standard_place (name);
538       if (!gpgconf)
539         _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",
540                       name);
541     }
542   return gpgconf;
543 }
544
545
546 const char *
547 _gpgme_get_w32spawn_path (void)
548 {
549   static char *w32spawn_program;
550   const char *inst_dir;
551
552   inst_dir = _gpgme_get_inst_dir ();
553   LOCK (get_path_lock);
554   if (!w32spawn_program)
555     w32spawn_program = find_program_in_inst_dir (inst_dir,"gpgme-w32spawn.exe");
556   if (!w32spawn_program)
557     w32spawn_program
558       = find_program_at_standard_place ("GNU\\GnuPG\\gpgme-w32spawn.exe");
559   UNLOCK (get_path_lock);
560   return w32spawn_program;
561 }
562
563
564 /* Return an integer value from gpgme specific configuration
565    entries. VALUE receives that value; function returns true if a value
566    has been configured and false if not. */
567 int
568 _gpgme_get_conf_int (const char *key, int *value)
569 {
570   char *tmp = read_w32_registry_string (NULL, "Software\\GNU\\gpgme", key);
571   if (!tmp)
572     return 0;
573   *value = atoi (tmp);
574   free (tmp);
575   return 1;
576 }
577
578 \f
579 #ifdef HAVE_W32CE_SYSTEM
580 int
581 _gpgme_mkstemp (int *fd, char **name)
582 {
583   return -1;
584 }
585 #else
586
587 /* mkstemp extracted from libc/sysdeps/posix/tempname.c.  Copyright
588    (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
589
590    The GNU C Library is free software; you can redistribute it and/or
591    modify it under the terms of the GNU Lesser General Public
592    License as published by the Free Software Foundation; either
593    version 2.1 of the License, or (at your option) any later version.  */
594
595 static const char letters[] =
596 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
597
598 /* Generate a temporary file name based on TMPL.  TMPL must match the
599    rules for mk[s]temp (i.e. end in "XXXXXX").  The name constructed
600    does not exist at the time of the call to mkstemp.  TMPL is
601    overwritten with the result.  */
602 static int
603 mkstemp (char *tmpl)
604 {
605   int len;
606   char *XXXXXX;
607   static uint64_t value;
608   uint64_t random_time_bits;
609   unsigned int count;
610   int fd = -1;
611   int save_errno = errno;
612
613   /* A lower bound on the number of temporary files to attempt to
614      generate.  The maximum total number of temporary file names that
615      can exist for a given template is 62**6.  It should never be
616      necessary to try all these combinations.  Instead if a reasonable
617      number of names is tried (we define reasonable as 62**3) fail to
618      give the system administrator the chance to remove the problems.  */
619 #define ATTEMPTS_MIN (62 * 62 * 62)
620
621   /* The number of times to attempt to generate a temporary file.  To
622      conform to POSIX, this must be no smaller than TMP_MAX.  */
623 #if ATTEMPTS_MIN < TMP_MAX
624   unsigned int attempts = TMP_MAX;
625 #else
626   unsigned int attempts = ATTEMPTS_MIN;
627 #endif
628
629   len = strlen (tmpl);
630   if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
631     {
632       gpg_err_set_errno (EINVAL);
633       return -1;
634     }
635
636   /* This is where the Xs start.  */
637   XXXXXX = &tmpl[len - 6];
638
639   /* Get some more or less random data.  */
640   {
641     FILETIME ft;
642
643     GetSystemTimeAsFileTime (&ft);
644     random_time_bits = (((uint64_t)ft.dwHighDateTime << 32)
645                         | (uint64_t)ft.dwLowDateTime);
646   }
647   value += random_time_bits ^ ath_self ();
648
649   for (count = 0; count < attempts; value += 7777, ++count)
650     {
651       uint64_t v = value;
652
653       /* Fill in the random bits.  */
654       XXXXXX[0] = letters[v % 62];
655       v /= 62;
656       XXXXXX[1] = letters[v % 62];
657       v /= 62;
658       XXXXXX[2] = letters[v % 62];
659       v /= 62;
660       XXXXXX[3] = letters[v % 62];
661       v /= 62;
662       XXXXXX[4] = letters[v % 62];
663       v /= 62;
664       XXXXXX[5] = letters[v % 62];
665
666       fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
667       if (fd >= 0)
668         {
669           gpg_err_set_errno (save_errno);
670           return fd;
671         }
672       else if (errno != EEXIST)
673         return -1;
674     }
675
676   /* We got out of the loop because we ran out of combinations to try.  */
677   gpg_err_set_errno (EEXIST);
678   return -1;
679 }
680
681 \f
682 int
683 _gpgme_mkstemp (int *fd, char **name)
684 {
685   char tmp[MAX_PATH + 2];
686   char *tmpname;
687   int err;
688
689   *fd = -1;
690   *name = NULL;
691
692   err = GetTempPathA (MAX_PATH + 1, tmp);
693   if (err == 0 || err > MAX_PATH + 1)
694     strcpy (tmp,"c:\\windows\\temp");
695   else
696     {
697       int len = strlen(tmp);
698
699       /* GetTempPath may return with \ on the end */
700       while(len > 0 && tmp[len - 1] == '\\')
701         {
702           tmp[len-1] = '\0';
703           len--;
704         }
705     }
706
707   tmpname = malloc (strlen (tmp) + 13 + 1);
708   if (!tmpname)
709     return -1;
710   strcpy (stpcpy (tmpname, tmp), "\\gpgme-XXXXXX");
711   *fd = mkstemp (tmpname);
712   if (fd < 0)
713     {
714       free (tmpname);
715       return -1;
716     }
717
718   *name = tmpname;
719   return 0;
720 }
721 #endif
722
723
724 \f
725 #ifdef HAVE_W32CE_SYSTEM
726 /* Return a malloced string with the replacement value for the
727    GPGME_DEBUG envvar.  Caller must release.  Returns NULL if not
728    set.  */
729 char *
730 _gpgme_w32ce_get_debug_envvar (void)
731 {
732   char *tmp;
733
734   tmp = read_w32_registry_string (NULL, "\\Software\\GNU\\gpgme", "debug");
735   if (tmp && !*tmp)
736     {
737       free (tmp);
738       tmp = NULL;
739     }
740   return tmp;
741 }
742 #endif /*HAVE_W32CE_SYSTEM*/
743
744
745 /* Entry point called by the DLL loader.  */
746 #ifdef DLL_EXPORT
747 int WINAPI
748 DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
749 {
750   (void)reserved;
751
752   if (reason == DLL_PROCESS_ATTACH)
753     my_hmodule = hinst;
754
755   return TRUE;
756 }
757 #endif /*DLL_EXPORT*/