Imported Upstream version 1.12.0
[platform/upstream/gpgme.git] / src / w32-util.c
index 9aba26f..30dd081 100644 (file)
@@ -16,7 +16,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * License along with this program; if not, see <https://www.gnu.org/licenses/>.
  **/
 
 #ifdef HAVE_CONFIG_H
 # define F_OK 0
 #endif
 
+/* The Registry key used by GNUPG.  */
+#ifdef _WIN64
+# define GNUPG_REGKEY_2  "Software\\Wow6432Node\\GNU\\GnuPG"
+#else
+# define GNUPG_REGKEY_2  "Software\\GNU\\GnuPG"
+#endif
+#ifdef _WIN64
+# define GNUPG_REGKEY_3  "Software\\Wow6432Node\\GnuPG"
+#else
+# define GNUPG_REGKEY_3  "Software\\GnuPG"
+#endif
 
 DEFINE_STATIC_LOCK (get_path_lock);
 
@@ -85,7 +96,10 @@ static HMODULE my_hmodule;
    binaries.  The are set only once by gpgme_set_global_flag.  */
 static char *default_gpg_name;
 static char *default_gpgconf_name;
-
+/* If this variable is not NULL the value is assumed to be the
+   installation directory.  The variable may only be set once by
+   gpgme_set_global_flag and accessed by _gpgme_get_inst_dir.  */
+static char *override_inst_dir;
 
 #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
 
@@ -95,6 +109,8 @@ static GPG_ERR_INLINE void *
 dlopen (const char * name, int flag)
 {
   void * hd = LoadLibrary (name);
+
+  (void)flag;
   return hd;
 }
 
@@ -347,6 +363,9 @@ _gpgme_get_inst_dir (void)
 {
   static char *inst_dir;
 
+  if (override_inst_dir)
+    return override_inst_dir;
+
   LOCK (get_path_lock);
   if (!inst_dir)
     {
@@ -382,11 +401,10 @@ find_program_in_dir (const char *dir, const char *name)
 {
   char *result;
 
-  result = malloc (strlen (dir) + 1 + strlen (name) + 1);
+  result = _gpgme_strconcat (dir, "\\", name, NULL);
   if (!result)
     return NULL;
 
-  strcpy (stpcpy (stpcpy (result, dir), "\\"), name);
   if (access (result, F_OK))
     {
       free (result);
@@ -403,18 +421,28 @@ find_program_at_standard_place (const char *name)
   char path[MAX_PATH];
   char *result = NULL;
 
-  /* See http://wiki.tcl.tk/17492 for details on compatibility.  */
+  /* See http://wiki.tcl.tk/17492 for details on compatibility.
+
+     We First try the generic place and then fallback to the x86
+     (i.e. 32 bit) place.  This will prefer a 64 bit of the program
+     over a 32 bit version on 64 bit Windows if installed.  */
   if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0))
     {
-      result = malloc (strlen (path) + 1 + strlen (name) + 1);
-      if (result)
+      result = _gpgme_strconcat (path, "\\", name, NULL);
+      if (result && access (result, F_OK))
         {
-          strcpy (stpcpy (stpcpy (result, path), "\\"), name);
-          if (access (result, F_OK))
-            {
-              free (result);
-              result = NULL;
-            }
+          free (result);
+          result = NULL;
+        }
+    }
+  if (!result
+      && SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0))
+    {
+      result = _gpgme_strconcat (path, "\\", name, NULL);
+      if (result && access (result, F_OK))
+        {
+          free (result);
+          result = NULL;
         }
     }
   return result;
@@ -428,12 +456,9 @@ _gpgme_set_default_gpg_name (const char *name)
 {
   if (!default_gpg_name)
     {
-      default_gpg_name = malloc (strlen (name) + 5);
+      default_gpg_name = _gpgme_strconcat (name, ".exe", NULL);
       if (default_gpg_name)
-        {
-          strcpy (stpcpy (default_gpg_name, name), ".exe");
-          replace_slashes (default_gpg_name);
-        }
+        replace_slashes (default_gpg_name);
     }
   return !default_gpg_name;
 }
@@ -445,14 +470,32 @@ _gpgme_set_default_gpgconf_name (const char *name)
 {
   if (!default_gpgconf_name)
     {
-      default_gpgconf_name = malloc (strlen (name) + 5);
+      default_gpgconf_name = _gpgme_strconcat (name, ".exe", NULL);
       if (default_gpgconf_name)
+        replace_slashes (default_gpgconf_name);
+    }
+  return !default_gpgconf_name;
+}
+
+
+/* Set the override installation directory.  This function may only be
+   called by gpgme_set_global_flag.  Returns 0 on success.  */
+int
+_gpgme_set_override_inst_dir (const char *dir)
+{
+  if (!override_inst_dir)
+    {
+      override_inst_dir = strdup (dir);
+      if (override_inst_dir)
         {
-          strcpy (stpcpy (default_gpgconf_name, name), ".exe");
-          replace_slashes (default_gpgconf_name);
+          replace_slashes (override_inst_dir);
+          /* Remove a trailing slash.  */
+          if (*override_inst_dir
+              && override_inst_dir[strlen (override_inst_dir)-1] == '\\')
+            override_inst_dir[strlen (override_inst_dir)-1] = 0;
         }
     }
-  return !default_gpgconf_name;
+  return !override_inst_dir;
 }
 
 
@@ -481,7 +524,7 @@ _gpgme_get_gpg_path (void)
       char *dir;
 
       dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
-                                      "Software\\GNU\\GnuPG",
+                                      GNUPG_REGKEY_2,
                                       "Install Directory");
       if (dir)
         {
@@ -530,15 +573,27 @@ _gpgme_get_gpgconf_path (void)
       gpgconf = find_program_at_standard_place (name2);
     }
 
-  /* 3. Try to find gpgconf.exe using that ancient registry key.  This
-        should eventually be removed.  */
+  /* 3. Try to find gpgconf.exe using the Windows registry. */
   if (!gpgconf)
     {
       char *dir;
 
-      dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
-                                      "Software\\GNU\\GnuPG",
+      dir = read_w32_registry_string (NULL,
+                                      GNUPG_REGKEY_2,
                                       "Install Directory");
+      if (!dir)
+        {
+          char *tmp = read_w32_registry_string (NULL,
+                                                GNUPG_REGKEY_3,
+                                                "Install Directory");
+          if (tmp)
+            {
+              dir = _gpgme_strconcat (tmp, "\\bin", NULL);
+              free (tmp);
+              if (!dir)
+                return NULL;
+            }
+        }
       if (dir)
         {
           gpgconf = find_program_in_dir (dir, name);
@@ -552,6 +607,14 @@ _gpgme_get_gpgconf_path (void)
       gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe");
     }
 
+  /* 5. Try to find gpgconf.exe relative to us.  */
+  if (!gpgconf && inst_dir)
+    {
+      char *dir = _gpgme_strconcat (inst_dir, "\\..\\..\\GnuPG\\bin");
+      gpgconf = find_program_in_dir (dir, name);
+      free (dir);
+    }
+
   /* 5. Print a debug message if not found.  */
   if (!gpgconf)
     _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",name);
@@ -614,7 +677,7 @@ static const char letters[] =
    does not exist at the time of the call to mkstemp.  TMPL is
    overwritten with the result.  */
 static int
-mkstemp (char *tmpl)
+my_mkstemp (char *tmpl)
 {
   int len;
   char *XXXXXX;
@@ -718,12 +781,11 @@ _gpgme_mkstemp (int *fd, char **name)
        }
     }
 
-  tmpname = malloc (strlen (tmp) + 13 + 1);
+  tmpname = _gpgme_strconcat (tmp, "\\gpgme-XXXXXX", NULL);
   if (!tmpname)
     return -1;
-  strcpy (stpcpy (tmpname, tmp), "\\gpgme-XXXXXX");
-  *fd = mkstemp (tmpname);
-  if (fd < 0)
+  *fd = my_mkstemp (tmpname);
+  if (*fd < 0)
     {
       free (tmpname);
       return -1;