aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--agent/gpg-agent.c3
-rw-r--r--common/homedir.c243
-rw-r--r--common/util.h3
-rw-r--r--tools/gpg-connect-agent.c2
-rw-r--r--tools/gpgconf.c3
5 files changed, 228 insertions, 26 deletions
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 3e23a193e..d140ba5d9 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -1020,9 +1020,6 @@ main (int argc, char **argv )
finalize_rereadable_options ();
- /* Turn the homedir into an absolute one. */
- gnupg_set_homedir (make_absfilename (gnupg_homedir (), NULL));
-
/* Print a warning if an argument looks like an option. */
if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
{
diff --git a/common/homedir.c b/common/homedir.c
index 8992bc69c..58f100f1a 100644
--- a/common/homedir.c
+++ b/common/homedir.c
@@ -53,16 +53,23 @@
#endif
#endif /*HAVE_W32_SYSTEM*/
+#ifdef HAVE_STAT
+#include <sys/stat.h> /* for stat() */
+#endif
+
#include "util.h"
#include "sysutils.h"
-
+#include "zb32.h"
/* The GnuPG homedir. This is only accessed by the functions
* gnupg_homedir and gnupg_set_homedir. Malloced. */
static char *the_gnupg_homedir;
+/* Flag indicating that home directory is not the default one. */
+static byte non_default_homedir;
+
#ifdef HAVE_W32_SYSTEM
/* A flag used to indicate that a control file for gpgconf has been
@@ -76,13 +83,13 @@ static char *the_gnupg_homedir;
This flag is not used on Unix systems.
*/
-static int w32_portable_app;
+static byte 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 as often used before GnuPG 2.1. */
-static int w32_bin_is_bin;
+static byte w32_bin_is_bin;
#endif /*HAVE_W32_SYSTEM*/
@@ -150,6 +157,20 @@ w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
#endif /*HAVE_W32_SYSTEM*/
+/* Check whether DIR is the default homedir. */
+static int
+is_gnupg_default_homedir (const char *dir)
+{
+ int result;
+ char *a = make_absfilename (dir, NULL);
+ char *b = make_absfilename (GNUPG_DEFAULT_HOMEDIR, NULL);
+ result = !compare_filenames (a, b);
+ xfree (b);
+ xfree (a);
+ return result;
+}
+
+
/* Get the standard home directory. In general this function should
not be used as it does not consider a registry value (under W32) or
the GNUPGHOME environment variable. It is better to use
@@ -248,6 +269,8 @@ default_homedir (void)
#endif /*HAVE_W32_SYSTEM*/
if (!dir || !*dir)
dir = GNUPG_DEFAULT_HOMEDIR;
+ else if (!is_gnupg_default_homedir (dir))
+ non_default_homedir = 1;
return dir;
}
@@ -382,27 +405,217 @@ gnupg_set_homedir (const char *newdir)
{
if (!newdir || !*newdir)
newdir = default_homedir ();
+ else if (!is_gnupg_default_homedir (newdir))
+ non_default_homedir = 1;
xfree (the_gnupg_homedir);
- the_gnupg_homedir = xstrdup (newdir);
+ the_gnupg_homedir = make_absfilename (newdir, NULL);;
}
/* Return the homedir. The returned string is valid until another
- * gnupg-set-homedir call. Note that this may be a relative string.
- * This function replaced the former global opt.homedir. */
+ * gnupg-set-homedir call. This is always an absolute directory name.
+ * The function replaces the former global var opt.homedir. */
const char *
gnupg_homedir (void)
{
/* If a homedir has not been set, set it to the default. */
if (!the_gnupg_homedir)
- the_gnupg_homedir = xstrdup (default_homedir ());
+ the_gnupg_homedir = make_absfilename (default_homedir (), NULL);
return the_gnupg_homedir;
}
+/* Return whether the home dir is the default one. */
+int
+gnupg_default_homedir_p (void)
+{
+ return !non_default_homedir;
+}
+
+
+/* Helper for gnupg-socketdir. This is a global function, so that
+ * gpgconf can use it for its --create-socketdir command. If
+ * SKIP_CHECKS is set permission checks etc. are not done. The
+ * function always returns a malloced directory name and stores these
+ * bit flags at R_INFO:
+ *
+ * 1 := Internal error, stat failed, out of core, etc.
+ * 2 := No /run/user directory.
+ * 4 := Directory not owned by the user, not a directory
+ * or wrong permissions.
+ * 8 := Same as 4 but for the subdir.
+ * 16 := mkdir failed
+ * 32 := Non default homedir; checking subdir.
+ * 64 := Subdir does not exist.
+ * 128 := Using homedir as fallback.
+ */
+char *
+_gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
+{
+#if defined(HAVE_W32_SYSTEM) || !defined(HAVE_STAT)
+
+ (void)skip_checks;
+ *r_info = 0;
+ name = xstrdup (gnupg_homedir ());
+
+#else /* Unix and stat(2) available. */
+
+ static const char * const bases[] = { "/run", "/var/run", NULL};
+ int i;
+ struct stat sb;
+ char prefix[13 + 1 + 20 + 6 + 1];
+ const char *s;
+ char *name = NULL;
+
+ *r_info = 0;
+
+ /* First make sure that non_default_homedir can be set. */
+ gnupg_homedir ();
+
+ /* It has been suggested to first check XDG_RUNTIME_DIR envvar.
+ * However, the specs state that the lifetime of the directory MUST
+ * be bound to the user being logged in. Now GnuPG may also be run
+ * as a background process with no (desktop) user logged in. Thus
+ * we better don't do that. */
+
+ /* Check whether we have a /run/user dir. */
+ for (i=0; bases[i]; i++)
+ {
+ snprintf (prefix, sizeof prefix, "%s/user/%u",
+ bases[i], (unsigned int)getuid ());
+ if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
+ break;
+ }
+ if (!bases[i])
+ {
+ *r_info |= 2; /* No /run/user directory. */
+ goto leave;
+ }
+
+ if (sb.st_uid != getuid ())
+ {
+ *r_info |= 4; /* Not owned by the user. */
+ if (!skip_checks)
+ goto leave;
+ }
+
+ if (strlen (prefix) + 7 >= sizeof prefix)
+ {
+ *r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
+ goto leave;
+ }
+ strcat (prefix, "/gnupg");
+
+ /* Check whether the gnupg sub directory has proper permissions. */
+ if (stat (prefix, &sb))
+ {
+ if (errno != ENOENT)
+ {
+ *r_info |= 1; /* stat failed. */
+ goto leave;
+ }
+
+ /* Try to create the directory and check again. */
+ if (gnupg_mkdir (prefix, "-rwx"))
+ {
+ *r_info |= 16; /* mkdir failed. */
+ goto leave;
+ }
+ if (stat (prefix, &sb))
+ {
+ *r_info |= 1; /* stat failed. */
+ goto leave;
+ }
+ }
+ /* Check that it is a directory, owned by the user, and only the
+ * user has permissions to use it. */
+ if (!S_ISDIR(sb.st_mode)
+ || sb.st_uid != getuid ()
+ || (sb.st_mode & (S_IRWXG|S_IRWXO)))
+ {
+ *r_info |= 4; /* Bad permissions or not a directory. */
+ if (!skip_checks)
+ goto leave;
+ }
+
+ /* If a non default homedir is used, we check whether an
+ * corresponding sub directory below the socket dir is available
+ * and use that. We has the non default homedir to keep the new
+ * subdir short enough. */
+ if (non_default_homedir)
+ {
+ char sha1buf[20];
+ char *suffix;
+
+ *r_info |= 32; /* Testing subdir. */
+ s = gnupg_homedir ();
+ gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, s, strlen (s));
+ suffix = zb32_encode (sha1buf, 8*15);
+ if (!suffix)
+ {
+ *r_info |= 1; /* Out of core etc. */
+ goto leave;
+ }
+ name = strconcat (prefix, "/d.", suffix, NULL);
+ xfree (suffix);
+ if (!name)
+ {
+ *r_info |= 1; /* Out of core etc. */
+ goto leave;
+ }
+
+ /* Stat that directory and check constraints. Note that we
+ * do not auto create such a directory because we would not
+ * have a way to remove it. Thus the directory needs to be
+ * pre-created. The command
+ * gpgconf --create-socketdir
+ * can be used tocreate that directory. */
+ if (stat (name, &sb))
+ {
+ if (errno != ENOENT)
+ *r_info |= 1; /* stat failed. */
+ else
+ *r_info |= 64; /* Subdir does not exist. */
+ if (!skip_checks)
+ {
+ xfree (name);
+ name = NULL;
+ goto leave;
+ }
+ }
+ else if (!S_ISDIR(sb.st_mode)
+ || sb.st_uid != getuid ()
+ || (sb.st_mode & (S_IRWXG|S_IRWXO)))
+ {
+ *r_info |= 8; /* Bad permissions or subdir is not a directory. */
+ if (!skip_checks)
+ {
+ xfree (name);
+ name = NULL;
+ goto leave;
+ }
+ }
+ }
+ else
+ name = xstrdup (prefix);
+
+ leave:
+ /* If nothing works fall back to the homedir. */
+ if (!name)
+ {
+ *r_info |= 128; /* Fallback. */
+ name = xstrdup (gnupg_homedir ());
+ }
+
+#endif /* Unix */
+
+ return name;
+}
+
+
/*
* Return the name of the socket dir. That is the directory used for
- * the IPC local sockets. This is an absolute filename.
+ * the IPC local sockets. This is an absolute directory name.
*/
const char *
gnupg_socketdir (void)
@@ -411,18 +624,8 @@ gnupg_socketdir (void)
if (!name)
{
- /* Check XDG variable. */
-
- /* XDG is not set: Check whether we have a /run directory. */
-
- /* If there is no run directpry we assume a /var/run directory. */
-
- /* Check that the user directory exists or create it if
- * required, */
-
- /* If nothing works fall back to the homedir. */
- if (!name)
- name = make_absfilename (gnupg_homedir (), NULL);
+ unsigned int dummy;
+ name = _gnupg_socketdir_internal (0, &dummy);
}
return name;
diff --git a/common/util.h b/common/util.h
index 0621047df..c84847ad7 100644
--- a/common/util.h
+++ b/common/util.h
@@ -222,6 +222,7 @@ const char *standard_homedir (void);
const char *default_homedir (void);
void gnupg_set_homedir (const char *newdir);
const char *gnupg_homedir (void);
+int gnupg_default_homedir_p (void);
const char *gnupg_socketdir (void);
const char *gnupg_sysconfdir (void);
const char *gnupg_bindir (void);
@@ -233,6 +234,8 @@ const char *gnupg_cachedir (void);
const char *dirmngr_sys_socket_name (void);
const char *dirmngr_user_socket_name (void);
+char *_gnupg_socketdir_internal (int skip_checks, unsigned *r_info);
+
/* All module names. We also include gpg and gpgsm for the sake for
gpgconf. */
#define GNUPG_MODULE_NAME_AGENT 1
diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c
index 0eb43fbdd..1cd554f1f 100644
--- a/tools/gpg-connect-agent.c
+++ b/tools/gpg-connect-agent.c
@@ -555,7 +555,7 @@ get_var_ext (const char *name)
log_error ("getcwd failed: %s\n", strerror (errno));
}
else if (!strcmp (s, "homedir"))
- result = make_filename (gnupg_homedir (), NULL);
+ result = xstrdup (gnupg_homedir ());
else if (!strcmp (s, "sysconfdir"))
result = xstrdup (gnupg_sysconfdir ());
else if (!strcmp (s, "bindir"))
diff --git a/tools/gpgconf.c b/tools/gpgconf.c
index 63cc65458..fb1032bba 100644
--- a/tools/gpgconf.c
+++ b/tools/gpgconf.c
@@ -383,8 +383,7 @@ main (int argc, char **argv)
xfree (tmp);
}
{
- /* We need to use make_filename to expand a possible "~/". */
- char *tmp = make_filename (default_homedir (), NULL);
+ char *tmp = xstrdup (gnupg_homedir ());
es_fprintf (outfp, "homedir:%s\n", gc_percent_escape (tmp));
xfree (tmp);
}