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.
This commit is contained in:
Werner Koch 2023-12-22 12:47:39 +01:00
parent 2376cdff13
commit 239c1fdc28
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 120 additions and 57 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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.