From 239c1fdc28dcd0dc7aa5341be7c966da2231642a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 22 Dec 2023 12:47:39 +0100 Subject: [PATCH] common: Add keyword socketdir to gpgconf.ctl * common/homedir.c (enum wantdir_values): New enums. (unix_rootdir): Change arg to use the enums. Adjust all callers. Add support for the socketdir keyword. (_gnupg_socketdir_internal): Take care of the socketdir keyword in gpgconf.ctl. * doc/tools.texi (Files used by gpgconf): Briefly explain the gpgconf.ctl syntax. --- common/homedir.c | 139 +++++++++++++++++++++++++++++-------------- doc/opt-homedir.texi | 10 ---- doc/tools.texi | 28 ++++++++- 3 files changed, 120 insertions(+), 57 deletions(-) diff --git a/common/homedir.c b/common/homedir.c index 641dba1ae..2b99c9bdc 100644 --- a/common/homedir.c +++ b/common/homedir.c @@ -77,6 +77,14 @@ #endif +/* Mode flags for unix_rootdir. */ +enum wantdir_values { + WANTDIR_ROOT = 0, + WANTDIR_SYSCONF, + WANTDIR_SOCKET +}; + + /* The GnuPG homedir. This is only accessed by the functions * gnupg_homedir and gnupg_set_homedir. Malloced. */ static char *the_gnupg_homedir; @@ -491,11 +499,12 @@ w32_rootdir (void) * file system. If WANT_SYSCONFDIR is true the optional sysconfdir * entry is returned. */ static const char * -unix_rootdir (int want_sysconfdir) +unix_rootdir (enum wantdir_values wantdir) { static int checked; static char *dir; /* for the rootdir */ static char *sdir; /* for the sysconfdir */ + static char *s2dir; /* for the socketdir */ if (!checked) { @@ -510,8 +519,10 @@ unix_rootdir (int want_sysconfdir) estream_t fp; char *rootdir; char *sysconfdir; + char *socketdir; const char *name; int ignoreall = 0; + int okay; for (;;) { @@ -602,12 +613,14 @@ unix_rootdir (int want_sysconfdir) linelen = 0; rootdir = NULL; sysconfdir = NULL; + socketdir = NULL; while ((length = es_read_line (fp, &line, &linelen, NULL)) > 0) { static const char *names[] = { "rootdir", "sysconfdir", + "socketdir", ".enable" }; int i; @@ -662,6 +675,11 @@ unix_rootdir (int want_sysconfdir) xfree (sysconfdir); sysconfdir = p; } + else if (!strcmp (name, "socketdir")) + { + xfree (socketdir); + socketdir = p; + } else { xfree (rootdir); @@ -677,6 +695,7 @@ unix_rootdir (int want_sysconfdir) xfree (line); xfree (rootdir); xfree (sysconfdir); + xfree (socketdir); checked = 1; return NULL; } @@ -684,29 +703,26 @@ unix_rootdir (int want_sysconfdir) xfree (buffer); xfree (line); + okay = 0; if (ignoreall) - { - xfree (rootdir); - xfree (sysconfdir); - sdir = dir = NULL; - } + ; else if (!rootdir || !*rootdir || *rootdir != '/') { log_info ("invalid rootdir '%s' specified in gpgconf.ctl\n", rootdir); - xfree (rootdir); - xfree (sysconfdir); - dir = NULL; } else if (sysconfdir && (!*sysconfdir || *sysconfdir != '/')) { log_info ("invalid sysconfdir '%s' specified in gpgconf.ctl\n", sysconfdir); - xfree (rootdir); - xfree (sysconfdir); - dir = NULL; + } + else if (socketdir && (!*socketdir || *socketdir != '/')) + { + log_info ("invalid socketdir '%s' specified in gpgconf.ctl\n", + socketdir); } else { + okay = 1; while (*rootdir && rootdir[strlen (rootdir)-1] == '/') rootdir[strlen (rootdir)-1] = 0; dir = rootdir; @@ -720,11 +736,34 @@ unix_rootdir (int want_sysconfdir) gpgrt_annotate_leaked_object (sdir); /* log_info ("want sysconfdir '%s'\n", sdir); */ } + if (socketdir) + { + while (*socketdir && socketdir[strlen (socketdir)-1] == '/') + socketdir[strlen (socketdir)-1] = 0; + s2dir = socketdir; + gpgrt_annotate_leaked_object (s2dir); + /* log_info ("want socketdir '%s'\n", s2dir); */ + } + } + + if (!okay) + { + xfree (rootdir); + xfree (sysconfdir); + xfree (socketdir); + dir = sdir = s2dir = NULL; } checked = 1; } - return want_sysconfdir? sdir : dir; + switch (wantdir) + { + case WANTDIR_ROOT: return dir; + case WANTDIR_SYSCONF: return sdir; + case WANTDIR_SOCKET: return s2dir; + } + + return NULL; /* Not reached. */ } #endif /* Unix */ @@ -1035,7 +1074,8 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info) }; int i; struct stat sb; - char prefix[19 + 1 + 20 + 6 + 1]; + char prefixbuffer[19 + 1 + 20 + 6 + 1]; + const char *prefix; const char *s; char *name = NULL; @@ -1050,35 +1090,42 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info) * as a background process with no (desktop) user logged in. Thus * we better don't do that. */ - /* Check whether we have a /run/[gnupg/]user dir. */ - for (i=0; bases[i]; i++) + prefix = unix_rootdir (WANTDIR_SOCKET); + if (!prefix) { - 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; + /* gpgconf.ctl does not specify a directory. Check whether we + * have the usual /run/[gnupg/]user dir. */ + for (i=0; bases[i]; i++) + { + snprintf (prefixbuffer, sizeof prefixbuffer, "%s/user/%u", + bases[i], (unsigned int)getuid ()); + prefix = prefixbuffer; + 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 prefixbuffer) + { + *r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */ + goto leave; + } + strcat (prefixbuffer, "/gnupg"); } - 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. */ + /* Check whether the gnupg sub directory (or the specified diretory) + * has proper permissions. */ if (stat (prefix, &sb)) { if (errno != ENOENT) @@ -1238,7 +1285,7 @@ gnupg_sysconfdir (void) } return name; #else /*!HAVE_W32_SYSTEM*/ - const char *dir = unix_rootdir (1); + const char *dir = unix_rootdir (WANTDIR_SYSCONF); if (dir) return dir; else @@ -1267,7 +1314,7 @@ gnupg_bindir (void) else return rdir; #else /*!HAVE_W32_SYSTEM*/ - rdir = unix_rootdir (0); + rdir = unix_rootdir (WANTDIR_ROOT); if (rdir) { if (!name) @@ -1294,7 +1341,7 @@ gnupg_libexecdir (void) static char *name; const char *rdir; - rdir = unix_rootdir (0); + rdir = unix_rootdir (WANTDIR_ROOT); if (rdir) { if (!name) @@ -1324,7 +1371,7 @@ gnupg_libdir (void) #else /*!HAVE_W32_SYSTEM*/ const char *rdir; - rdir = unix_rootdir (0); + rdir = unix_rootdir (WANTDIR_ROOT); if (rdir) { if (!name) @@ -1355,7 +1402,7 @@ gnupg_datadir (void) #else /*!HAVE_W32_SYSTEM*/ const char *rdir; - rdir = unix_rootdir (0); + rdir = unix_rootdir (WANTDIR_ROOT); if (rdir) { if (!name) @@ -1387,7 +1434,7 @@ gnupg_localedir (void) #else /*!HAVE_W32_SYSTEM*/ const char *rdir; - rdir = unix_rootdir (0); + rdir = unix_rootdir (WANTDIR_ROOT); if (rdir) { if (!name) diff --git a/doc/opt-homedir.texi b/doc/opt-homedir.texi index 07993d29d..15ae1970d 100644 --- a/doc/opt-homedir.texi +++ b/doc/opt-homedir.texi @@ -13,13 +13,3 @@ directory stated through the environment variable @env{GNUPGHOME} or 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. - -@efindex gpgconf.ctl -To install GnuPG as a portable application under Windows, create an -empty file named @file{gpgconf.ctl} in the same directory as the tool -@file{gpgconf.exe}. The root of the installation is then 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@value{LOCALCACHEDIR}} -for internal cache files. diff --git a/doc/tools.texi b/doc/tools.texi index eefa4f9d6..a1c161c3a 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -1122,10 +1122,36 @@ More fields may be added in future to the output. @table @file +@item gpgconf.ctl +@cindex gpgconf.ctl + Under Unix @file{gpgconf.ctl} may be used to change some of the + compiled in directories where the GnuPG components are expected. This + file is expected in the same directory as @file{gpgconf}. The + physical installation directories are evaluated and no symlinks. + Blank lines and lines starting with pound sign are ignored in the + file. The keywords must be followed by optional white space, an equal + sign, optional white space, and the value. Environment variables are + substituted in standard shell manner, the final value must start with + a slash, trailing slashes are stripped. Valid keywords are + @code{rootdir}, @code{sysconfdir}, @code{socketdir}, and + @code{.enable}. No errors are printed for unknown keywords. The + @code{.enable} keyword is special: if the keyword is used and its + value evaluates to true the entire file is ignored. + + Under Windows this file is used to install GnuPG as a portable + application. An empty file named @file{gpgconf.ctl} is expected in + the same directory as the tool @file{gpgconf.exe}. The root of the + installation is then 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@value{LOCALCACHEDIR}} for internal cache files. + + @item /etc/gnupg/gpgconf.conf @cindex gpgconf.conf If this file exists, it is processed as a global configuration file. - This is a legacy mechanism which should not be used tigether with + This is a legacy mechanism which should not be used together with the modern global per component configuration files. A commented example can be found in the @file{examples} directory of the distribution.