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