mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-23 10:29:58 +01:00
gpgconf: Support reading global options (part 1).
* tools/gpgconf.c (main): Set the config directories. * tools/gpgconf-comp.c (gc_backend): Change the name of the config files. (struct gc_option): Add new field 'attr'. (retrieve_options_from_program): Rewrite to use gpgrt_argparser. -- We need to do larger changes to gpgconf so that it is possible to get also global config options and their attributes. The old code worked along its own list of option and used a generic option file parser. This has no support for global config files. We now use gnupgt_argparser so that we to do exactly the same as the component does and thus delivers the actual option values as seen by the component. This is just a first step and we need to change more things. Signed-off-by: Werner Koch <wk@gnupg.org> This is a backport from master (2.3).
This commit is contained in:
parent
f0d034ebf4
commit
7397872445
@ -1,6 +1,7 @@
|
|||||||
/* gpgconf-comp.c - Configuration utility for GnuPG.
|
/* gpgconf-comp.c - Configuration utility for GnuPG.
|
||||||
* Copyright (C) 2004, 2007-2011 Free Software Foundation, Inc.
|
* Copyright (C) 2004, 2007-2011 Free Software Foundation, Inc.
|
||||||
* Copyright (C) 2016 Werner Koch
|
* Copyright (C) 2016 Werner Koch
|
||||||
|
* Copyright (C) 2020, 2021 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -170,10 +171,7 @@ static const struct
|
|||||||
is killed and not just reloaded. */
|
is killed and not just reloaded. */
|
||||||
void (*runtime_change) (int killflag);
|
void (*runtime_change) (int killflag);
|
||||||
|
|
||||||
/* The option name for the configuration filename of this backend.
|
/* The name for the configuration filename of this backend. */
|
||||||
This must be an absolute filename. It can be an option from a
|
|
||||||
different backend (but then ordering of the options might
|
|
||||||
matter). Note: This must be unique among all components. */
|
|
||||||
const char *option_config_filename;
|
const char *option_config_filename;
|
||||||
|
|
||||||
/* If this is a file backend rather than a program backend, then
|
/* If this is a file backend rather than a program backend, then
|
||||||
@ -183,19 +181,19 @@ static const struct
|
|||||||
{
|
{
|
||||||
{ NULL }, /* GC_BACKEND_ANY dummy entry. */
|
{ NULL }, /* GC_BACKEND_ANY dummy entry. */
|
||||||
{ GPG_DISP_NAME, GPGNAME, GNUPG_MODULE_NAME_GPG,
|
{ GPG_DISP_NAME, GPGNAME, GNUPG_MODULE_NAME_GPG,
|
||||||
NULL, GPGCONF_NAME "-" GPG_NAME ".conf" },
|
NULL, GPG_NAME ".conf" },
|
||||||
{ GPGSM_DISP_NAME, GPGSM_NAME, GNUPG_MODULE_NAME_GPGSM,
|
{ GPGSM_DISP_NAME, GPGSM_NAME, GNUPG_MODULE_NAME_GPGSM,
|
||||||
NULL, GPGCONF_NAME "-" GPGSM_NAME ".conf" },
|
NULL, GPGSM_NAME ".conf" },
|
||||||
{ GPG_AGENT_DISP_NAME, GPG_AGENT_NAME, GNUPG_MODULE_NAME_AGENT,
|
{ GPG_AGENT_DISP_NAME, GPG_AGENT_NAME, GNUPG_MODULE_NAME_AGENT,
|
||||||
gpg_agent_runtime_change, GPGCONF_NAME"-" GPG_AGENT_NAME ".conf" },
|
gpg_agent_runtime_change, GPG_AGENT_NAME ".conf" },
|
||||||
{ SCDAEMON_DISP_NAME, SCDAEMON_NAME, GNUPG_MODULE_NAME_SCDAEMON,
|
{ SCDAEMON_DISP_NAME, SCDAEMON_NAME, GNUPG_MODULE_NAME_SCDAEMON,
|
||||||
scdaemon_runtime_change, GPGCONF_NAME"-" SCDAEMON_NAME ".conf" },
|
scdaemon_runtime_change, SCDAEMON_NAME ".conf" },
|
||||||
{ DIRMNGR_DISP_NAME, DIRMNGR_NAME, GNUPG_MODULE_NAME_DIRMNGR,
|
{ DIRMNGR_DISP_NAME, DIRMNGR_NAME, GNUPG_MODULE_NAME_DIRMNGR,
|
||||||
dirmngr_runtime_change, GPGCONF_NAME "-" DIRMNGR_NAME ".conf" },
|
dirmngr_runtime_change, DIRMNGR_NAME ".conf" },
|
||||||
{ DIRMNGR_DISP_NAME " LDAP Server List", NULL, 0,
|
{ DIRMNGR_DISP_NAME " LDAP Server List", NULL, 0,
|
||||||
NULL, "ldapserverlist-file", "LDAP Server" },
|
NULL, "ldapserverlist-file", "LDAP Server" },
|
||||||
{ "Pinentry", "pinentry", GNUPG_MODULE_NAME_PINENTRY,
|
{ "Pinentry", "pinentry", GNUPG_MODULE_NAME_PINENTRY,
|
||||||
NULL, GPGCONF_NAME "-pinentry.conf" },
|
NULL, "pinentry.conf" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -434,6 +432,11 @@ struct gc_option
|
|||||||
of the list so that they can be omitted from the option
|
of the list so that they can be omitted from the option
|
||||||
declarations. */
|
declarations. */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned int ignore:1; /* The ARGPARSE_ATTR_IGNORE. */
|
||||||
|
unsigned int force:1; /* The ARGPARSE_ATTR_FORCE. */
|
||||||
|
} attr;
|
||||||
|
|
||||||
/* This is true if the option is supported by this version of the
|
/* This is true if the option is supported by this version of the
|
||||||
backend. */
|
backend. */
|
||||||
int active;
|
int active;
|
||||||
@ -2101,33 +2104,113 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend,
|
|||||||
estream_t outfp;
|
estream_t outfp;
|
||||||
int exitcode;
|
int exitcode;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
gc_option_t *option;
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
size_t line_len = 0;
|
size_t line_len = 0;
|
||||||
ssize_t length;
|
ssize_t length;
|
||||||
estream_t config;
|
const char *config_name;
|
||||||
char *config_filename;
|
gnupg_argparse_t pargs;
|
||||||
|
int dummy_argc;
|
||||||
|
gnupg_opt_t *opt_table = NULL; /* A malloced option table. */
|
||||||
|
size_t opt_table_used = 0; /* Its current length. */
|
||||||
|
size_t opt_table_size = 0; /* Its allocated length. */
|
||||||
|
char **string_array = NULL; /* An allocated array with
|
||||||
|
* malloced strings. */
|
||||||
|
size_t string_array_used = 0; /* Current number of items in
|
||||||
|
* the array. */
|
||||||
|
size_t string_array_size = 0; /* Allocated number of slots in
|
||||||
|
* the array. */
|
||||||
|
size_t n;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
pgmname = (gc_backend[backend].module_name
|
pgmname = (gc_backend[backend].module_name
|
||||||
? gnupg_module_name (gc_backend[backend].module_name)
|
? gnupg_module_name (gc_backend[backend].module_name)
|
||||||
: gc_backend[backend].program );
|
: gc_backend[backend].program );
|
||||||
i = 0;
|
|
||||||
if (!gnupg_default_homedir_p ()
|
|
||||||
&& backend != GC_BACKEND_ANY
|
|
||||||
&& backend != GC_BACKEND_DIRMNGR_LDAP_SERVER_LIST
|
|
||||||
&& backend != GC_BACKEND_PINENTRY)
|
|
||||||
{
|
|
||||||
argv[i++] = "--homedir";
|
|
||||||
argv[i++] = gnupg_homedir ();
|
|
||||||
}
|
|
||||||
argv[i++] = "--gpgconf-list";
|
|
||||||
argv[i++] = NULL;
|
|
||||||
|
|
||||||
if (only_installed && gnupg_access (pgmname, X_OK))
|
if (only_installed && gnupg_access (pgmname, X_OK))
|
||||||
{
|
{
|
||||||
return; /* The component is not installed. */
|
return; /* The component is not installed. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* First we need to read the option table from the program. */
|
||||||
|
argv[0] = "--dump-option-table";
|
||||||
|
argv[1] = NULL;
|
||||||
|
err = gnupg_spawn_process (pgmname, argv, NULL, NULL, 0,
|
||||||
|
NULL, &outfp, NULL, &pid);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
gc_error (1, 0, "could not gather option table from '%s': %s",
|
||||||
|
pgmname, gpg_strerror (err));
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0)
|
||||||
|
{
|
||||||
|
char *fields[4];
|
||||||
|
char *optname, *optdesc;
|
||||||
|
|
||||||
|
/* Strip newline and carriage return, if present. */
|
||||||
|
while (length > 0
|
||||||
|
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
|
||||||
|
line[--length] = '\0';
|
||||||
|
|
||||||
|
log_debug ("line='%s'\n", line);
|
||||||
|
if (split_fields_colon (line, fields, DIM (fields)) < 4)
|
||||||
|
{
|
||||||
|
gc_error (0,0, "WARNING: invalid line in option table of '%s'\n",
|
||||||
|
pgmname);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The +1 here is to make sure that we will have a zero item at
|
||||||
|
* the end of the table. */
|
||||||
|
if (opt_table_used + 1 >= opt_table_size)
|
||||||
|
{
|
||||||
|
/* Note that this also does the initial allocation. */
|
||||||
|
opt_table_size += 128;
|
||||||
|
opt_table = xreallocarray (opt_table,
|
||||||
|
opt_table_used,
|
||||||
|
opt_table_size,
|
||||||
|
sizeof *opt_table);
|
||||||
|
}
|
||||||
|
/* The +1 here accounts for the two items we add below. */
|
||||||
|
if (string_array_used + 1 >= string_array_size)
|
||||||
|
{
|
||||||
|
string_array_size += 256;
|
||||||
|
string_array = xreallocarray (string_array,
|
||||||
|
string_array_used,
|
||||||
|
string_array_size,
|
||||||
|
sizeof *string_array);
|
||||||
|
}
|
||||||
|
string_array[string_array_used++] = optname = xstrdup (fields[0]);
|
||||||
|
string_array[string_array_used++] = optdesc = xstrdup (fields[3]);
|
||||||
|
|
||||||
|
opt_table[opt_table_used].long_opt = optname;
|
||||||
|
opt_table[opt_table_used].short_opt = atoi (fields[1]);
|
||||||
|
opt_table[opt_table_used].description = optdesc;
|
||||||
|
opt_table[opt_table_used].flags = strtoul (fields[2], NULL, 10);
|
||||||
|
opt_table_used++;
|
||||||
|
|
||||||
|
/* Put the description into our table. */
|
||||||
|
option = find_option (component, optname, backend);
|
||||||
|
if (option && !option->desc)
|
||||||
|
option->desc = xstrdup (optdesc);
|
||||||
|
}
|
||||||
|
if (length < 0 || es_ferror (outfp))
|
||||||
|
gc_error (1, errno, "error reading from %s", pgmname);
|
||||||
|
if (es_fclose (outfp))
|
||||||
|
gc_error (1, errno, "error closing %s", pgmname);
|
||||||
|
|
||||||
|
err = gnupg_wait_process (pgmname, pid, 1, &exitcode);
|
||||||
|
if (err)
|
||||||
|
gc_error (1, 0, "running %s failed (exitcode=%d): %s",
|
||||||
|
pgmname, exitcode, gpg_strerror (err));
|
||||||
|
gnupg_release_process (pid);
|
||||||
|
|
||||||
|
|
||||||
|
/* Now read the default options. */
|
||||||
|
argv[0] = "--gpgconf-list";
|
||||||
|
argv[1] = NULL;
|
||||||
err = gnupg_spawn_process (pgmname, argv, NULL, NULL, 0,
|
err = gnupg_spawn_process (pgmname, argv, NULL, NULL, 0,
|
||||||
NULL, &outfp, NULL, &pid);
|
NULL, &outfp, NULL, &pid);
|
||||||
if (err)
|
if (err)
|
||||||
@ -2138,7 +2221,6 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend,
|
|||||||
|
|
||||||
while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0)
|
while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0)
|
||||||
{
|
{
|
||||||
gc_option_t *option;
|
|
||||||
char *linep;
|
char *linep;
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
char *default_value = NULL;
|
char *default_value = NULL;
|
||||||
@ -2218,104 +2300,95 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend,
|
|||||||
|
|
||||||
|
|
||||||
/* At this point, we can parse the configuration file. */
|
/* At this point, we can parse the configuration file. */
|
||||||
config_filename = get_config_filename (component, backend);
|
config_name = gc_backend[backend].option_config_filename;
|
||||||
|
if (!config_name)
|
||||||
|
gc_error (1, 0, "name of config file for %s is not known\n", pgmname);
|
||||||
|
|
||||||
config = es_fopen (config_filename, "r");
|
memset (&pargs, 0, sizeof pargs);
|
||||||
if (!config)
|
dummy_argc = 0;
|
||||||
{
|
pargs.argc = &dummy_argc;
|
||||||
if (errno != ENOENT)
|
pargs.flags = (ARGPARSE_FLAG_KEEP
|
||||||
gc_error (0, errno, "warning: can not open config file %s",
|
| ARGPARSE_FLAG_SYS
|
||||||
config_filename);
|
| ARGPARSE_FLAG_USER
|
||||||
}
|
| ARGPARSE_FLAG_WITHATTR
|
||||||
else
|
| ARGPARSE_FLAG_VERBOSE);
|
||||||
{
|
|
||||||
while ((length = es_read_line (config, &line, &line_len, NULL)) > 0)
|
|
||||||
{
|
|
||||||
char *name;
|
|
||||||
char *value;
|
|
||||||
gc_option_t *option;
|
|
||||||
|
|
||||||
name = line;
|
while (gnupg_argparser (&pargs, opt_table, config_name))
|
||||||
while (*name == ' ' || *name == '\t')
|
|
||||||
name++;
|
|
||||||
if (!*name || *name == '#' || *name == '\r' || *name == '\n')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
value = name;
|
|
||||||
while (*value && *value != ' ' && *value != '\t'
|
|
||||||
&& *value != '#' && *value != '\r' && *value != '\n')
|
|
||||||
value++;
|
|
||||||
if (*value == ' ' || *value == '\t')
|
|
||||||
{
|
|
||||||
char *end;
|
|
||||||
|
|
||||||
*(value++) = '\0';
|
|
||||||
while (*value == ' ' || *value == '\t')
|
|
||||||
value++;
|
|
||||||
|
|
||||||
end = value;
|
|
||||||
while (*end && *end != '#' && *end != '\r' && *end != '\n')
|
|
||||||
end++;
|
|
||||||
while (end > value && (end[-1] == ' ' || end[-1] == '\t'))
|
|
||||||
end--;
|
|
||||||
*end = '\0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*value = '\0';
|
|
||||||
|
|
||||||
/* Look up the option in the component and install the
|
|
||||||
configuration data. */
|
|
||||||
option = find_option (component, line, backend);
|
|
||||||
if (option)
|
|
||||||
{
|
{
|
||||||
char *opt_value;
|
char *opt_value;
|
||||||
|
|
||||||
if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_NONE)
|
if (pargs.r_type & ARGPARSE_OPT_IGNORE)
|
||||||
{
|
{
|
||||||
if (*value)
|
log_debug ("ignored\n");
|
||||||
gc_error (0, 0,
|
continue;
|
||||||
"warning: ignoring argument %s for option %s",
|
|
||||||
value, name);
|
|
||||||
opt_value = xstrdup ("1");
|
|
||||||
}
|
}
|
||||||
else if (gc_arg_type[option->arg_type].fallback
|
if (pargs.r_opt == ARGPARSE_CONFFILE)
|
||||||
== GC_ARG_TYPE_STRING)
|
|
||||||
opt_value = xasprintf ("\"%s", gc_percent_escape (value));
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
/* FIXME: Verify that the number is sane. */
|
log_debug ("current conffile='%s'\n",
|
||||||
opt_value = xstrdup (value);
|
pargs.r_type? pargs.r.ret_str: "[cmdline]");
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now enter the option into the table. */
|
/* We only have the short option. Search in the option table
|
||||||
|
* for the long option name. */
|
||||||
|
for (i=0; opt_table[i].short_opt; i++)
|
||||||
|
if (opt_table[i].short_opt == pargs.r_opt)
|
||||||
|
break;
|
||||||
|
if (!opt_table[i].short_opt || !opt_table[i].long_opt)
|
||||||
|
continue; /* No or only a short option - ignore. */
|
||||||
|
|
||||||
|
/* Look up the option from the config file in our fixed list of
|
||||||
|
* options which are handled by us. */
|
||||||
|
option = find_option (component, opt_table[i].long_opt, backend);
|
||||||
|
if (!option)
|
||||||
|
continue; /* We don't want to handle this option. */
|
||||||
|
|
||||||
|
option->attr.ignore = !!(pargs.r_type & ARGPARSE_ATTR_IGNORE);
|
||||||
|
option->attr.force = !!(pargs.r_type & ARGPARSE_ATTR_FORCE);
|
||||||
|
|
||||||
|
switch ((pargs.r_type & ARGPARSE_TYPE_MASK))
|
||||||
|
{
|
||||||
|
case ARGPARSE_TYPE_INT:
|
||||||
|
opt_value = xasprintf ("%d", pargs.r.ret_int);
|
||||||
|
break;
|
||||||
|
case ARGPARSE_TYPE_LONG:
|
||||||
|
opt_value = xasprintf ("%ld", pargs.r.ret_long);
|
||||||
|
break;
|
||||||
|
case ARGPARSE_TYPE_ULONG:
|
||||||
|
opt_value = xasprintf ("%lu", pargs.r.ret_ulong);
|
||||||
|
break;
|
||||||
|
case ARGPARSE_TYPE_STRING:
|
||||||
|
opt_value = xasprintf ("\"%s", gc_percent_escape (pargs.r.ret_str));
|
||||||
|
break;
|
||||||
|
default: /* ARGPARSE_TYPE_NONE or any unknown type. */
|
||||||
|
opt_value = xstrdup ("1"); /* Make sure we have some value. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now enter the value read from the config file into the table. */
|
||||||
if (!(option->flags & GC_OPT_FLAG_LIST))
|
if (!(option->flags & GC_OPT_FLAG_LIST))
|
||||||
{
|
{
|
||||||
if (option->value)
|
|
||||||
xfree (option->value);
|
xfree (option->value);
|
||||||
option->value = opt_value;
|
option->value = opt_value;
|
||||||
}
|
}
|
||||||
else
|
else if (!option->value)
|
||||||
{
|
|
||||||
if (!option->value)
|
|
||||||
option->value = opt_value;
|
option->value = opt_value;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *old = option->value;
|
char *old = option->value;
|
||||||
option->value = xasprintf ("%s,%s", old, opt_value);
|
option->value = xstrconcat (old, ",", opt_value, NULL);
|
||||||
xfree (old);
|
xfree (old);
|
||||||
xfree (opt_value);
|
xfree (opt_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length < 0 || es_ferror (config))
|
|
||||||
gc_error (1, errno, "error reading from %s", config_filename);
|
|
||||||
if (es_fclose (config))
|
|
||||||
gc_error (1, errno, "error closing %s", config_filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
xfree (line);
|
xfree (line);
|
||||||
|
xfree (opt_table);
|
||||||
|
/* Note that we release the string array after the option table
|
||||||
|
* because the option table has pointers into the string array. */
|
||||||
|
for (n=0; n < string_array_used; n++)
|
||||||
|
xfree (string_array[n]);
|
||||||
|
xfree (string_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -678,6 +678,12 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
fname = argc ? *argv : NULL;
|
fname = argc ? *argv : NULL;
|
||||||
|
|
||||||
|
/* Set the configuraton directories for use by gpgrt_argparser. We
|
||||||
|
* don't have a configuration file for this program but we have code
|
||||||
|
* which reads the component's config files. */
|
||||||
|
gnupg_set_confdir (GNUPG_CONFDIR_SYS, gnupg_sysconfdir ());
|
||||||
|
gnupg_set_confdir (GNUPG_CONFDIR_USER, gnupg_homedir ());
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
case aListComponents:
|
case aListComponents:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user