aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--common/homedir.c241
-rw-r--r--common/logging.c16
-rw-r--r--common/logging.h1
-rw-r--r--doc/opt-homedir.texi14
5 files changed, 214 insertions, 62 deletions
diff --git a/NEWS b/NEWS
index 370d9c4a5..3b2016f3a 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-Noteworthy changes in version 2.1.0beta4 (unreleased)
+Noteworthy changes in version 2.1.0-betaN (unreleased)
-----------------------------------------------------
* GPG now accepts a space separated fingerprint as a user ID. This
@@ -20,6 +20,8 @@ Noteworthy changes in version 2.1.0beta4 (unreleased)
* Better support fo CCID readers. Now, internal CCID driver supports
readers with no auto configuration feature.
+ * Support installation as portable application under Windows.
+
Noteworthy changes in version 2.1.0beta3 (2011-12-20)
-----------------------------------------------------
diff --git a/common/homedir.c b/common/homedir.c
index 28e5c9a2f..9fec78fc3 100644
--- a/common/homedir.c
+++ b/common/homedir.c
@@ -1,5 +1,6 @@
/* homedir.c - Setup the home directory.
* Copyright (C) 2004, 2006, 2007, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Werner Koch
*
* This file is part of GnuPG.
*
@@ -33,6 +34,9 @@
#include <fcntl.h>
#ifdef HAVE_W32_SYSTEM
+#include <winsock2.h> /* Due to the stupid mingw64 requirement to
+ include this header before windows.h which
+ is often implicitly included. */
#include <shlobj.h>
#ifndef CSIDL_APPDATA
#define CSIDL_APPDATA 0x001a
@@ -53,6 +57,33 @@
#include "util.h"
#include "sysutils.h"
+#ifdef HAVE_W32_SYSTEM
+/* A flag used to indicate that a control file for gpgconf has been
+ detected. Under Windows the presence of this file indicates a
+ portable installations and triggers several changes:
+
+ - The GNUGHOME directory is fixed relative to installation
+ directory. All other means to set the home directory are ignore.
+
+ - All registry variables will be ignored.
+
+ This flag is not used on Unix systems.
+ */
+static int w32_portable_app;
+#endif /*HAVE_W32_SYSTEM*/
+
+#ifdef HAVE_W32_SYSTEM
+/* This flag is true if this process' binary has been installed under
+ bin and not in the root directory. */
+static int w32_bin_is_bin;
+#endif /*HAVE_W32_SYSTEM*/
+
+
+#ifdef HAVE_W32_SYSTEM
+static const char *w32_rootdir (void);
+#endif
+
+
#ifdef HAVE_W32_SYSTEM
static void
@@ -124,28 +155,39 @@ standard_homedir (void)
if (!dir)
{
- char path[MAX_PATH];
+ const char *rdir;
- /* It might be better to use LOCAL_APPDATA because this is
- defined as "non roaming" and thus more likely to be kept
- locally. For private keys this is desired. However, given
- that many users copy private keys anyway forth and back,
- using a system roaming services might be better than to let
- them do it manually. A security conscious user will anyway
- use the registry entry to have better control. */
- if (w32_shgetfolderpath (NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE,
- NULL, 0, path) >= 0)
+ rdir = w32_rootdir ();
+ if (w32_portable_app)
{
- char *tmp = xmalloc (strlen (path) + 6 +1);
- strcpy (stpcpy (tmp, path), "\\gnupg");
- dir = tmp;
-
- /* Try to create the directory if it does not yet exists. */
- if (access (dir, F_OK))
- w32_try_mkdir (dir);
+ dir = xstrconcat (rdir, DIRSEP_S "home", NULL);
}
else
- dir = GNUPG_DEFAULT_HOMEDIR;
+ {
+ char path[MAX_PATH];
+
+ /* It might be better to use LOCAL_APPDATA because this is
+ defined as "non roaming" and thus more likely to be kept
+ locally. For private keys this is desired. However,
+ given that many users copy private keys anyway forth and
+ back, using a system roaming services might be better
+ than to let them do it manually. A security conscious
+ user will anyway use the registry entry to have better
+ control. */
+ if (w32_shgetfolderpath (NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE,
+ NULL, 0, path) >= 0)
+ {
+ char *tmp = xmalloc (strlen (path) + 6 +1);
+ strcpy (stpcpy (tmp, path), "\\gnupg");
+ dir = tmp;
+
+ /* Try to create the directory if it does not yet exists. */
+ if (access (dir, F_OK))
+ w32_try_mkdir (dir);
+ }
+ else
+ dir = GNUPG_DEFAULT_HOMEDIR;
+ }
}
return dir;
#else/*!HAVE_W32_SYSTEM*/
@@ -160,6 +202,13 @@ default_homedir (void)
{
const char *dir;
+#ifdef HAVE_W32_SYSTEM
+ /* For a portable application we only use the standard homedir. */
+ w32_rootdir ();
+ if (w32_portable_app)
+ return standard_homedir ();
+#endif /*HAVE_W32_SYSTEM*/
+
dir = getenv ("GNUPGHOME");
#ifdef HAVE_W32_SYSTEM
if (!dir || !*dir)
@@ -197,6 +246,37 @@ default_homedir (void)
#ifdef HAVE_W32_SYSTEM
+/* Check whether gpgconf is installed and if so read the gpgconf.ctl
+ file. */
+static void
+check_portable_app (const char *dir)
+{
+ char *fname;
+
+ fname = xstrconcat (dir, DIRSEP_S "gpgconf.exe", NULL);
+ if (access (fname, F_OK))
+ log_error ("required binary '%s' is not installed\n", fname);
+ else
+ {
+ strcpy (fname + strlen (fname) - 3, ".ctl");
+ if (!access (fname, F_OK))
+ {
+ /* gpgconf.ctl file found. Record this fact. */
+ w32_portable_app = 1;
+ {
+ unsigned int flags;
+ log_get_prefix (&flags);
+ log_set_prefix (NULL, (flags | JNLIB_LOG_NO_REGISTRY));
+ }
+ /* FIXME: We should read the file to detect special flags
+ and print a warning if we don't understand them */
+ }
+ }
+ xfree (fname);
+}
+
+
+/* Determine the root directory of the gnupg installation on Windows. */
static const char *
w32_rootdir (void)
{
@@ -229,11 +309,17 @@ w32_rootdir (void)
if (p)
{
*p = 0;
+
+ check_portable_app (dir);
+
/* If we are installed below "bin" we strip that and use
the top directory instead. */
p = strrchr (dir, DIRSEP_C);
if (p && !strcmp (p+1, "bin"))
- *p = 0;
+ {
+ *p = 0;
+ w32_bin_is_bin = 1;
+ }
}
if (!p)
{
@@ -255,8 +341,17 @@ w32_commondir (void)
if (!dir)
{
+ const char *rdir;
char path[MAX_PATH];
+ /* Make sure that w32_rootdir has been called so that we are
+ able to check the portable application flag. The common dir
+ is the identical to the rootdir. In that case there is also
+ no need to strdup its value. */
+ rdir = w32_rootdir ();
+ if (w32_portable_app)
+ return rdir;
+
if (w32_shgetfolderpath (NULL, CSIDL_COMMON_APPDATA,
NULL, 0, path) >= 0)
{
@@ -270,7 +365,7 @@ w32_commondir (void)
{
/* Ooops: Not defined - probably an old Windows version.
Use the installation directory instead. */
- dir = xstrdup (w32_rootdir ());
+ dir = xstrdup (rdir);
}
}
@@ -315,7 +410,19 @@ gnupg_bindir (void)
name = xstrconcat (w32_rootdir (), DIRSEP_S "bin", NULL);
return name;
#elif defined(HAVE_W32_SYSTEM)
- return w32_rootdir ();
+ const char *rdir;
+
+ rdir = w32_rootdir ();
+ if (w32_bin_is_bin)
+ {
+ static char *name;
+
+ if (!name)
+ name = xstrconcat (rdir, DIRSEP_S "bin", NULL);
+ return name;
+ }
+ else
+ return rdir;
#else /*!HAVE_W32_SYSTEM*/
return GNUPG_BINDIR;
#endif /*!HAVE_W32_SYSTEM*/
@@ -390,41 +497,54 @@ gnupg_cachedir (void)
if (!dir)
{
- char path[MAX_PATH];
- const char *s1[] = { "GNU", "cache", "gnupg", NULL };
- int s1_len;
- const char **comp;
-
- s1_len = 0;
- for (comp = s1; *comp; comp++)
- s1_len += 1 + strlen (*comp);
+ const char *rdir;
- if (w32_shgetfolderpath (NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE,
- NULL, 0, path) >= 0)
+ rdir = w32_rootdir ();
+ if (w32_portable_app)
+ {
+ dir = xstrconcat (rdir,
+ DIRSEP_S, "var",
+ DIRSEP_S, "cache",
+ DIRSEP_S, "gnupg", NULL);
+ }
+ else
{
- char *tmp = xmalloc (strlen (path) + s1_len + 1);
- char *p;
+ char path[MAX_PATH];
+ const char *s1[] = { "GNU", "cache", "gnupg", NULL };
+ int s1_len;
+ const char **comp;
- p = stpcpy (tmp, path);
+ s1_len = 0;
for (comp = s1; *comp; comp++)
- {
- p = stpcpy (p, "\\");
- p = stpcpy (p, *comp);
+ s1_len += 1 + strlen (*comp);
- if (access (tmp, F_OK))
- w32_try_mkdir (tmp);
- }
+ if (w32_shgetfolderpath (NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE,
+ NULL, 0, path) >= 0)
+ {
+ char *tmp = xmalloc (strlen (path) + s1_len + 1);
+ char *p;
- dir = tmp;
- }
- else
- {
- dir = "c:\\temp\\cache\\gnupg";
+ p = stpcpy (tmp, path);
+ for (comp = s1; *comp; comp++)
+ {
+ p = stpcpy (p, "\\");
+ p = stpcpy (p, *comp);
+
+ if (access (tmp, F_OK))
+ w32_try_mkdir (tmp);
+ }
+
+ dir = tmp;
+ }
+ else
+ {
+ dir = "c:\\temp\\cache\\gnupg";
#ifdef HAVE_W32CE_SYSTEM
- dir += 2;
- w32_try_mkdir ("\\temp\\cache");
- w32_try_mkdir ("\\temp\\cache\\gnupg");
+ dir += 2;
+ w32_try_mkdir ("\\temp\\cache");
+ w32_try_mkdir ("\\temp\\cache\\gnupg");
#endif
+ }
}
}
return dir;
@@ -449,16 +569,21 @@ dirmngr_socket_name (void)
s1 = default_homedir ();
# else
- char s1[MAX_PATH];
- const char *s2;
-
- /* We need something akin CSIDL_COMMON_PROGRAMS, but local
- (non-roaming). This is becuase the file needs to be on the
- local machine and makes only sense on that machine.
- CSIDL_WINDOWS seems to be the only location which guarantees
- that. */
- if (w32_shgetfolderpath (NULL, CSIDL_WINDOWS, NULL, 0, s1) < 0)
- strcpy (s1, "C:\\WINDOWS");
+ char s1buf[MAX_PATH];
+ const char *s1, *s2;
+
+ s1 = default_homedir ();
+ if (!w32_portable_app)
+ {
+ /* We need something akin CSIDL_COMMON_PROGRAMS, but local
+ (non-roaming). This is because the file needs to be on
+ the local machine and makes only sense on that machine.
+ CSIDL_WINDOWS seems to be the only location which
+ guarantees that. */
+ if (w32_shgetfolderpath (NULL, CSIDL_WINDOWS, NULL, 0, s1buf) < 0)
+ strcpy (s1buf, "C:\\WINDOWS");
+ s1 = s1buf;
+ }
# endif
s2 = DIRSEP_S "S.dirmngr";
name = xmalloc (strlen (s1) + strlen (s2) + 1);
diff --git a/common/logging.c b/common/logging.c
index 73b0dbe59..f78df9141 100644
--- a/common/logging.c
+++ b/common/logging.c
@@ -96,6 +96,9 @@ static char prefix_buffer[80];
static int with_time;
static int with_prefix;
static int with_pid;
+#ifdef HAVE_W32_SYSTEM
+static int no_registry;
+#endif
static int (*get_pid_suffix_cb)(unsigned long *r_value);
static int running_detached;
static int force_prefixes;
@@ -561,6 +564,9 @@ log_set_prefix (const char *text, unsigned int flags)
with_time = (flags & JNLIB_LOG_WITH_TIME);
with_pid = (flags & JNLIB_LOG_WITH_PID);
running_detached = (flags & JNLIB_LOG_RUN_DETACHED);
+#ifdef HAVE_W32_SYSTEM
+ no_registry = (flags & JNLIB_LOG_NO_REGISTRY);
+#endif
}
@@ -578,6 +584,10 @@ log_get_prefix (unsigned int *flags)
*flags |= JNLIB_LOG_WITH_PID;
if (running_detached)
*flags |= JNLIB_LOG_RUN_DETACHED;
+#ifdef HAVE_W32_SYSTEM
+ if (no_registry)
+ *flags |= JNLIB_LOG_NO_REGISTRY;
+#endif
}
return prefix_buffer;
}
@@ -624,8 +634,10 @@ do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
#ifdef HAVE_W32_SYSTEM
char *tmp;
- tmp = read_w32_registry_string (NULL, "Software\\GNU\\GnuPG",
- "DefaultLogFile");
+ tmp = (no_registry
+ ? NULL
+ : read_w32_registry_string (NULL, "Software\\GNU\\GnuPG",
+ "DefaultLogFile"));
log_set_file (tmp && *tmp? tmp : NULL);
jnlib_free (tmp);
#else
diff --git a/common/logging.h b/common/logging.h
index 89913e6e5..3b38f7370 100644
--- a/common/logging.h
+++ b/common/logging.h
@@ -42,6 +42,7 @@
#define JNLIB_LOG_WITH_TIME 2
#define JNLIB_LOG_WITH_PID 4
#define JNLIB_LOG_RUN_DETACHED 256
+#define JNLIB_LOG_NO_REGISTRY 512
int log_get_errorcount (int clear);
void log_inc_errorcount (void);
diff --git a/doc/opt-homedir.texi b/doc/opt-homedir.texi
index e382f6368..033a9016b 100644
--- a/doc/opt-homedir.texi
+++ b/doc/opt-homedir.texi
@@ -5,6 +5,18 @@ Set the name of the home directory to @var{dir}. If this option is not
used, the home directory defaults to @file{~/.gnupg}. It is only
recognized when given on the command line. It also overrides any home
directory stated through the environment variable @env{GNUPGHOME} or
-(on W32 systems) by means of the Registry entry
+(on Windows systems) by means of the Registry entry
@var{HKCU\Software\GNU\GnuPG:HomeDir}.
+On Windows systems it is possible to install GnuPG as a portable
+application. In this case only this command line option is
+considered, all other ways to set a home directory are ignored.
+
+To install GnuPG as a portable application under Windows, create an
+empty file name @file{gpgconf.ctl} in the same directory as the tool
+@file{gpgconf.exe}. The root of the installation is than that
+directory; or, if @file{gpgconf.exe} has been installed directly below
+a directory named @file{bin}, its parent directory. You also need to
+make sure that the following directories exist and are writable:
+@file{ROOT/home} for the GnuPG home and @file{ROOT/var/cache/gnupg}
+for internal cache files.