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