diff --git a/g10/gpg.c b/g10/gpg.c index 5947e63f5..88e8f6646 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -1912,31 +1912,8 @@ gpgconf_list (const char *configfile) { char *configfile_esc = percent_escape (configfile, NULL); - es_printf ("%s-%s.conf:%lu:\"%s\n", - GPGCONF_NAME, GPG_NAME, - GC_OPT_FLAG_DEFAULT, - configfile_esc ? configfile_esc : "/dev/null"); - es_printf ("verbose:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("quiet:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("keyserver:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("default-key:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("try-secret-key:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("auto-key-locate:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("auto-key-import:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("include-key-block:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("auto-key-retrieve:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT); - es_printf ("group:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("compliance:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, "gnupg"); - es_printf ("default-new-key-algo:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("trust-model:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("disable-dirmngr:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("max-cert-depth:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("completes-needed:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("marginals-needed:%lu:\n", GC_OPT_FLAG_NONE); /* The next one is an info only item and should match the macros at the top of keygen.c */ diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 8aee3bb4c..b64324706 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -1715,39 +1715,20 @@ main ( int argc, char **argv) { case aGPGConfList: { /* List options and default values in the GPG Conf format. */ - char *config_filename_esc = percent_escape (opt.config_filename, NULL); - es_printf ("%s-%s.conf:%lu:\"%s\n", - GPGCONF_NAME, GPGSM_NAME, - GC_OPT_FLAG_DEFAULT, config_filename_esc); - xfree (config_filename_esc); - - es_printf ("verbose:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("quiet:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT); - es_printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("disable-crl-checks:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("enable-crl-checks:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("disable-trusted-cert-crl-check:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("enable-ocsp:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("include-certs:%lu:%d:\n", GC_OPT_FLAG_DEFAULT, DEFAULT_INCLUDE_CERTS); - es_printf ("disable-policy-checks:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("auto-issuer-key-retrieve:%lu:\n", GC_OPT_FLAG_NONE); - es_printf ("disable-dirmngr:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("cipher-algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, DEFAULT_CIPHER_ALGO); es_printf ("p12-charset:%lu:\n", GC_OPT_FLAG_DEFAULT); es_printf ("default-key:%lu:\n", GC_OPT_FLAG_DEFAULT); es_printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_DEFAULT); - es_printf ("keyserver:%lu:\n", GC_OPT_FLAG_NONE); /* The next one is an info only item and should match what proc_parameters actually implements. */ es_printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, "RSA-3072"); - es_printf ("compliance:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, "gnupg"); - } break; case aGPGConfTest: diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index 015b08900..7d5c4924c 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -1,7 +1,7 @@ /* gpgconf-comp.c - Configuration utility for GnuPG. * Copyright (C) 2004, 2007-2011 Free Software Foundation, Inc. * Copyright (C) 2016 Werner Koch - * Copyright (C) 2020, 2021 g10 Code GmbH + * Copyright (C) 2020-2022 g10 Code GmbH * * This file is part of GnuPG. * @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -396,14 +395,13 @@ static known_option_t known_options_gpg[] = { "encrypt-to", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC }, { "group", GC_OPT_FLAG_LIST, GC_LEVEL_ADVANCED, GC_ARG_TYPE_ALIAS_LIST}, - { "options", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE, - GC_ARG_TYPE_FILENAME }, { "compliance", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT }, { "default-new-key-algo", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE }, { "trust-model", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE }, { "debug-level", GC_OPT_FLAG_ARG_OPT, GC_LEVEL_ADVANCED }, { "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED, GC_ARG_TYPE_FILENAME }, + { "keyserver", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE }, { "auto-key-locate", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED }, { "auto-key-retrieve", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT }, { "no-auto-key-retrieve", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE }, @@ -412,12 +410,17 @@ static known_option_t known_options_gpg[] = { "completes-needed", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE }, { "marginals-needed", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE }, - /* The next is a pseudo option which we read via --gpgconf-list */ - { "default_pubkey_algo", - (GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_NO_CHANGE), GC_LEVEL_INVISIBLE }, + /* The next is a pseudo option which we read via --gpgconf-list. + * The meta information is taken from the table below. */ + { "default_pubkey_algo", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE }, { NULL } }; +static const char *known_pseudo_options_gpg[] = + {/* v-- ARGPARSE_TYPE_STRING */ + "default_pubkey_algo:0:2:@:", + NULL + }; /* The known options of the GC_COMPONENT_GPGSM component. */ @@ -448,12 +451,18 @@ static known_option_t known_options_gpgsm[] = { "cipher-algo", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED }, { "disable-trusted-cert-crl-check", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT }, - /* Pseudo option follows. */ { "default_pubkey_algo", (GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_NO_CHANGE), GC_LEVEL_INVISIBLE }, + /* Pseudo option follows. See also table below. */ + { "default_pubkey_algo", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE }, { NULL } }; +static const char *known_pseudo_options_gpgsm[] = + {/* v-- ARGPARSE_TYPE_STRING */ + "default_pubkey_algo:0:2:@:", + NULL + }; /* The known options of the GC_COMPONENT_DIRMNGR component. */ @@ -516,7 +525,7 @@ struct gc_option_s unsigned int opt_arg:1; /* The option's argument is optional. */ unsigned int runtime:1; /* The option is runtime changeable. */ - unsigned int active:1; /* Has been announced in gpgconf-list. */ + unsigned int gpgconf_list:1; /* Has been announced in gpgconf-list. */ unsigned int has_default:1; /* The option has a default value. */ unsigned int def_in_desc:1; /* The default is in the descrition. */ @@ -584,6 +593,9 @@ static struct /* The static table of known options for this component. */ known_option_t *known_options; + /* The static table of known pseudo options for this component or NULL. */ + const char **known_pseudo_options; + /* The runtime change callback. If KILLFLAG is true the component is killed and not just reloaded. */ void (*runtime_change) (int killflag); @@ -605,23 +617,23 @@ static struct { GPG_NAME, GPG_DISP_NAME, "gnupg", N_("OpenPGP"), GNUPG_MODULE_NAME_GPG, GPG_NAME ".conf", - known_options_gpg }, + known_options_gpg, known_pseudo_options_gpg }, { GPGSM_NAME, GPGSM_DISP_NAME, "gnupg", N_("S/MIME"), GNUPG_MODULE_NAME_GPGSM, GPGSM_NAME ".conf", - known_options_gpgsm }, + known_options_gpgsm, known_pseudo_options_gpgsm }, { GPG_AGENT_NAME, GPG_AGENT_DISP_NAME, "gnupg", N_("Private Keys"), GNUPG_MODULE_NAME_AGENT, GPG_AGENT_NAME ".conf", - known_options_gpg_agent, gpg_agent_runtime_change }, + known_options_gpg_agent, NULL, gpg_agent_runtime_change }, { SCDAEMON_NAME, SCDAEMON_DISP_NAME, "gnupg", N_("Smartcards"), GNUPG_MODULE_NAME_SCDAEMON, SCDAEMON_NAME ".conf", - known_options_scdaemon, scdaemon_runtime_change}, + known_options_scdaemon, NULL, scdaemon_runtime_change}, { DIRMNGR_NAME, DIRMNGR_DISP_NAME, "gnupg", N_("Network"), GNUPG_MODULE_NAME_DIRMNGR, DIRMNGR_NAME ".conf", - known_options_dirmngr, dirmngr_runtime_change }, + known_options_dirmngr, NULL, dirmngr_runtime_change }, { "pinentry", "Pinentry", "gnupg", N_("Passphrase Entry"), GNUPG_MODULE_NAME_PINENTRY, NULL, @@ -1441,7 +1453,7 @@ gc_component_list_options (int component, estream_t out) { /* Do not output unknown or internal options. */ if (!option->is_header - && (!option->active || option->level == GC_LEVEL_INTERNAL)) + && option->level == GC_LEVEL_INTERNAL) continue; if (option->is_header) @@ -1517,6 +1529,47 @@ find_option (gc_component_id_t component, const char *name) +struct read_line_wrapper_parm_s +{ + const char *pgmname; + estream_t fp; + char *line; + size_t line_len; + const char **extra_lines; + int extra_lines_idx; + char *extra_line_buffer; +}; + + +/* Helper for retrieve_options_from_program. */ +static ssize_t +read_line_wrapper (struct read_line_wrapper_parm_s *parm) +{ + ssize_t length; + const char *extra_line; + + if (parm->fp) + { + length = es_read_line (parm->fp, &parm->line, &parm->line_len, NULL); + if (length > 0) + return length; + if (length < 0 || es_ferror (parm->fp)) + gc_error (1, errno, "error reading from %s", parm->pgmname); + if (es_fclose (parm->fp)) + gc_error (1, errno, "error closing %s", parm->pgmname); + /* EOF seen. */ + parm->fp = NULL; + } + /* Return the made up lines. */ + if (!parm->extra_lines + || !(extra_line = parm->extra_lines[parm->extra_lines_idx])) + return -1; /* This is really the EOF. */ + parm->extra_lines_idx++; + xfree (parm->extra_line_buffer); + parm->extra_line_buffer = xstrdup (extra_line); + return strlen (parm->extra_line_buffer); +} + /* Retrieve the options for the component COMPONENT. With * ONLY_INSTALLED set components which are not installed are silently * ignored. */ @@ -1532,7 +1585,7 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed) known_option_t *known_option; gc_option_t *option; char *line = NULL; - size_t line_len = 0; + size_t line_len; ssize_t length; const char *config_name; gnupg_argparse_t pargs; @@ -1545,6 +1598,8 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed) size_t opt_info_used = 0; /* Its current length. */ size_t opt_info_size = 0; /* Its allocated length. */ int i; + struct read_line_wrapper_parm_s read_line_parm; + int pseudo_count; pgmname = (gc_component[component].module_name ? gnupg_module_name (gc_component[component].module_name) @@ -1567,13 +1622,31 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed) pgmname, gpg_strerror (err)); } - while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0) + read_line_parm.pgmname = pgmname; + read_line_parm.fp = outfp; + read_line_parm.line = line; + read_line_parm.line_len = line_len = 0; + read_line_parm.extra_line_buffer = NULL; + read_line_parm.extra_lines = gc_component[component].known_pseudo_options; + read_line_parm.extra_lines_idx = 0; + pseudo_count = 0; + while ((length = read_line_wrapper (&read_line_parm)) > 0) { char *fields[4]; char *optname, *optdesc; unsigned int optflags; int short_opt; gc_arg_type_t arg_type; + int pseudo = 0; + + if (read_line_parm.extra_line_buffer) + { + line = read_line_parm.extra_line_buffer; + pseudo = 1; + pseudo_count++; + } + else + line = read_line_parm.line; /* Strip newline and carriage return, if present. */ while (length > 0 @@ -1589,14 +1662,13 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed) optname = fields[0]; short_opt = atoi (fields[1]); - if (short_opt < 1) + if (short_opt < 1 && !pseudo) { gc_error (0,0, "WARNING: bad short option in option table of '%s'\n", pgmname); continue; } - optflags = strtoul (fields[2], NULL, 10); if ((optflags & ARGPARSE_OPT_HEADER)) known_option = NULL; /* We want all header-only options. */ @@ -1628,7 +1700,7 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed) sizeof *opt_info); } /* The +1 here accounts for the two items we are going to add to - * the global string table. */ + * the global string table. */ if (string_array_used + 1 >= string_array_size) { string_array_size += 256; @@ -1649,11 +1721,14 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed) * known_option_s for this because that one does not carry * header lines and it might also be problematic to use such * static tables for caching options and default values. */ - opt_table[opt_table_used].long_opt = optname; - opt_table[opt_table_used].short_opt = short_opt; - opt_table[opt_table_used].description = optdesc; - opt_table[opt_table_used].flags = optflags; - opt_table_used++; + if (!pseudo) + { + opt_table[opt_table_used].long_opt = optname; + opt_table[opt_table_used].short_opt = short_opt; + opt_table[opt_table_used].description = optdesc; + opt_table[opt_table_used].flags = optflags; + opt_table_used++; + } /* Note that as per argparser specs the opt_table uses "@" to * specifify an empty description. In the DESC script of @@ -1674,6 +1749,8 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed) default: arg_type = GC_ARG_TYPE_NONE; break; } opt_info[opt_info_used].arg_type = arg_type; + if (pseudo) /* Pseudo options are always no_change. */ + opt_info[opt_info_used].no_change = 1; if ((optflags & ARGPARSE_OPT_HEADER)) opt_info[opt_info_used].is_header = 1; @@ -1696,11 +1773,10 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed) } opt_info_used++; } - 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); - log_assert (opt_table_used == opt_info_used); + xfree (read_line_parm.extra_line_buffer); + line = read_line_parm.line; + line_len = read_line_parm.line_len; + log_assert (opt_table_used + pseudo_count == opt_info_used); err = gnupg_wait_process (pgmname, pid, 1, &exitcode); if (err) @@ -1782,18 +1858,20 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed) option = find_option (component, line); if (option) { - if (option->active) + if (option->gpgconf_list) gc_error (1, errno, "option %s returned twice from \"%s --gpgconf-list\"", line, pgmname); - option->active = 1; + option->gpgconf_list = 1; - /* Runtime is duplicated - see above. */ - option->runtime = !!(flags & GC_OPT_FLAG_RUNTIME); - option->has_default = !!(flags & GC_OPT_FLAG_DEFAULT); - option->def_in_desc = !!(flags & GC_OPT_FLAG_DEF_DESC); - option->no_arg_desc = !!(flags & GC_OPT_FLAG_NO_ARG_DESC); - option->no_change = !!(flags & GC_OPT_FLAG_NO_CHANGE); + if ((flags & GC_OPT_FLAG_DEFAULT)) + option->has_default = 1; + if ((flags & GC_OPT_FLAG_DEF_DESC)) + option->def_in_desc = 1; + if ((flags & GC_OPT_FLAG_NO_ARG_DESC)) + option->no_arg_desc = 1; + if ((flags & GC_OPT_FLAG_NO_CHANGE)) + option->no_change = 1; if (default_value && *default_value) option->default_value = xstrdup (default_value); @@ -1846,6 +1924,8 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed) /* pargs.r_type? pargs.r.ret_str: "[cmdline]"); */ continue; } + if ((pargs.r_type & ARGPARSE_OPT_IGNORE)) + continue; /* We only have the short option. Search in the option table * for the long option name. */ @@ -1886,7 +1966,10 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed) opt_value = xasprintf ("%lu", pargs.r.ret_ulong); break; case ARGPARSE_TYPE_STRING: - opt_value = xasprintf ("\"%s", gc_percent_escape (pargs.r.ret_str)); + if (!pargs.r.ret_str) + opt_value = xstrdup ("\"(none)"); /* We should not see this. */ + else + 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. */ @@ -1955,9 +2038,7 @@ option_check_validity (gc_component_id_t component, { char *arg; - if (!option->active) - gc_error (1, 0, "option %s not supported by component %s", - option->name, gc_component[component].name); + (void)component; if (option->new_flags || option->new_value) gc_error (1, 0, "option %s already changed", option->name); @@ -2329,7 +2410,7 @@ change_options_program (gc_component_id_t component, else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_NONE) { - assert (*arg == '1'); + log_assert (*arg == '1'); gpgrt_fprintf (src_file, "%s\n", option->name); if (gpgrt_ferror (src_file)) goto change_one_err; @@ -2379,7 +2460,7 @@ change_options_program (gc_component_id_t component, arg = end; } - assert (arg == NULL || *arg == '\0' || *arg == ','); + log_assert (arg == NULL || *arg == '\0' || *arg == ','); if (arg && *arg == ',') arg++; } @@ -2479,7 +2560,7 @@ change_one_value (gc_component_id_t component, /* We convert the number to a list of 1's for convenient list handling. */ - assert (new_value_nr > 0); + log_assert (new_value_nr > 0); option->new_value = xmalloc ((2 * (new_value_nr - 1) + 1) + 1); str = option->new_value; *(str++) = '1';