1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00

Backport of the new option parser from 2.3

* configure.ac (GPGRT_ENABLE_ARGPARSE_MACROS): Define.
* common/argparse.c, common/argparse.h: Rewrite.
* tests/gpgscm/main.c: Switch to the new option parser.

* g10/gpg.c: Switch to the new option parser and enable a global conf
file.
* g10/gpgv.c: Ditto.
* agent/gpg-agent.c: Ditto.
* agent/preset-passphrase.c: Ditto.
* agent/protect-tool.c: Ditto.
* scd/scdaemon.c: Ditto.
* dirmngr/dirmngr.c: Ditto.
* dirmngr/dirmngr_ldap.c: Ditto
* dirmngr/dirmngr-client.c: Ditto.
* kbx/kbxutil.c: Ditto.
* tools/gpg-card.c: Ditto.
* tools/gpg-check-pattern.c: Ditto.
* tools/gpg-connect-agent.c: Ditto.
* tools/gpg-pair-tool.c: Ditto.
* tools/gpg-wks-client.c: Ditto.
* tools/gpg-wks-server.c: Ditto.
* tools/gpgconf.c: Ditto.
* tools/gpgsplit.c: Ditto.
* tools/gpgtar.c: Ditto.
* g13/g13.c: Ditto.
* g13/g13-syshelp.c: Ditto.  Do not force verbose mode.
* sm/gpgsm.c: Ditto. Add option --no-options.
--

This is backport from master

commit cdbe10b762
commit ba463128ce
commit 3bc004decd
commit 2c823bd878
commit 0e8f6e2aa9

but without changing all functions names to gpgrt.  Instead we use
wrapper functions which, when building against old Libgpg-error
versions, are implemented in argparse.c using code from the current
libgpg-error.  This allows to keep the dependency requirement at
libgpg-error 1.27 to support older distributions.  Tested builds
against 1.27 and 1.40-beta.

Note that g13-syshelp does not anymore default to --verbose because
that can now be enabled in /etc/gnupg/g13-syshelp.conf.

GnuPG-bug-id: 4788
Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2020-12-04 11:51:48 +01:00
parent 7d7a50ba72
commit a028f24136
No known key found for this signature in database
GPG key ID: E3FDFF218E45B72B
25 changed files with 2590 additions and 1463 deletions

280
g10/gpg.c
View file

@ -1,7 +1,7 @@
/* gpg.c - The GnuPG utility (main for gpg)
* Copyright (C) 1998-2019 Free Software Foundation, Inc.
* Copyright (C) 1998-2020 Free Software Foundation, Inc.
* Copyright (C) 1997-2019 Werner Koch
* Copyright (C) 2015-2019 g10 Code GmbH
* Copyright (C) 2015-2020 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -17,6 +17,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <config.h>
@ -634,7 +635,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oDisplayCharset, "display-charset", "@"),
ARGPARSE_s_s (oDisplayCharset, "charset", "@"),
ARGPARSE_s_s (oOptions, "options", "@"),
ARGPARSE_conffile (oOptions, "options", "@"),
ARGPARSE_s_s (oDebug, "debug", "@"),
ARGPARSE_s_s (oDebugLevel, "debug-level", "@"),
@ -737,7 +738,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oNoDefKeyring, "no-default-keyring", "@"),
ARGPARSE_s_n (oNoKeyring, "no-keyring", "@"),
ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
ARGPARSE_s_n (oNoOptions, "no-options", "@"),
ARGPARSE_noconffile (oNoOptions, "no-options", "@"),
ARGPARSE_s_s (oHomedir, "homedir", "@"),
ARGPARSE_s_n (oNoBatch, "no-batch", "@"),
ARGPARSE_s_n (oWithColons, "with-colons", "@"),
@ -1058,10 +1059,13 @@ my_strusage( int level )
static char *digests, *pubkeys, *ciphers, *zips, *ver_gcry;
const char *p;
switch( level ) {
switch (level)
{
case 9: p = "GPL-3.0-or-later"; break;
case 11: p = "@GPG@ (@GNUPG@)";
break;
case 13: p = VERSION; break;
case 14: p = GNUPG_DEF_COPYRIGHT_LINE; break;
case 17: p = PRINTABLE_OS_NAME; break;
case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
@ -2301,13 +2305,11 @@ main (int argc, char **argv)
strlist_t nrings = NULL;
armor_filter_context_t *afx = NULL;
int detached_sig = 0;
FILE *configfp = NULL;
char *configname = NULL;
char *save_configname = NULL;
char *default_configname = NULL;
unsigned configlineno;
int parse_debug = 0;
int default_config = 1;
char *last_configname = NULL;
const char *configname = NULL; /* NULL or points to last_configname.
* NULL also indicates that we are
* processing options from the cmdline. */
int debug_argparser = 0;
int default_keyring = 1;
int greeting = 0;
int nogreeting = 0;
@ -2430,41 +2432,42 @@ main (int argc, char **argv)
opt.emit_version = 0;
opt.weak_digests = NULL;
/* Check whether we have a config file on the command line. */
/* Check special options given on the command line. */
orig_argc = argc;
orig_argv = argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
while( arg_parse( &pargs, opts) ) {
if( pargs.r_opt == oDebug || pargs.r_opt == oDebugAll )
parse_debug++;
else if (pargs.r_opt == oDebugIOLBF)
es_setvbuf (es_stdout, NULL, _IOLBF, 0);
else if( pargs.r_opt == oOptions ) {
/* yes there is one, so we do not try the default one, but
* read the option file when it is encountered at the commandline
*/
default_config = 0;
}
else if( pargs.r_opt == oNoOptions )
while (gnupg_argparse (NULL, &pargs, opts))
{
switch (pargs.r_opt)
{
default_config = 0; /* --no-options */
case oDebug:
case oDebugAll:
debug_argparser++;
break;
case oDebugIOLBF:
es_setvbuf (es_stdout, NULL, _IOLBF, 0);
break;
case oNoOptions:
/* Set here here because the homedir would otherwise be
* created before main option parsing starts. */
opt.no_homedir_creation = 1;
break;
case oHomedir:
gnupg_set_homedir (pargs.r.ret_str);
break;
case oNoPermissionWarn:
opt.no_perm_warn = 1;
break;
}
else if( pargs.r_opt == oHomedir )
gnupg_set_homedir (pargs.r.ret_str);
else if( pargs.r_opt == oNoPermissionWarn )
opt.no_perm_warn=1;
else if (pargs.r_opt == oStrict )
{
/* Not used */
}
else if (pargs.r_opt == oNoStrict )
{
/* Not used */
}
}
}
/* Reset the flags. */
pargs.flags &= ~(ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
#ifdef HAVE_DOSISH_SYSTEM
if ( strchr (gnupg_homedir (), '\\') ) {
@ -2508,64 +2511,67 @@ main (int argc, char **argv)
additional_weak_digest ("MD5");
parse_auto_key_locate (DEFAULT_AKL_LIST);
/* Try for a version specific config file first */
default_configname = get_default_configname ();
if (default_config)
configname = xstrdup (default_configname);
argc = orig_argc;
argv = orig_argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= ARGPARSE_FLAG_KEEP;
/* We are re-using the struct, thus the reset flag. We OR the
* flags so that the internal intialized flag won't be cleared. */
pargs.flags |= (ARGPARSE_FLAG_RESET
| ARGPARSE_FLAG_KEEP
| ARGPARSE_FLAG_SYS
| ARGPARSE_FLAG_USER
| ARGPARSE_FLAG_USERVERS);
/* By this point we have a homedir, and cannot change it. */
check_permissions (gnupg_homedir (), 0);
next_pass:
if( configname ) {
if(check_permissions(configname,1))
{
/* If any options file is unsafe, then disable any external
programs for keyserver calls or photo IDs. Since the
external program to call is set in the options file, a
unsafe options file can lead to an arbitrary program
being run. */
/* The configuraton directories for use by gpgrt_argparser. */
gnupg_set_confdir (GNUPG_CONFDIR_SYS, gnupg_sysconfdir ());
gnupg_set_confdir (GNUPG_CONFDIR_USER, gnupg_homedir ());
opt.exec_disable=1;
}
configlineno = 0;
configfp = gnupg_fopen( configname, "r" );
if (configfp && is_secured_file (fileno (configfp)))
{
fclose (configfp);
configfp = NULL;
gpg_err_set_errno (EPERM);
}
if( !configfp ) {
if( default_config ) {
if( parse_debug )
log_info(_("Note: no default option file '%s'\n"),
configname );
}
else {
log_error(_("option file '%s': %s\n"),
configname, strerror(errno) );
g10_exit(2);
}
xfree(configname); configname = NULL;
}
if( parse_debug && configname )
log_info(_("reading options from '%s'\n"), configname );
default_config = 0;
}
while( optfile_parse( configfp, configname, &configlineno,
&pargs, opts) )
while (gnupg_argparser (&pargs, opts, GPG_NAME EXTSEP_S "conf"))
{
switch( pargs.r_opt )
switch (pargs.r_opt)
{
case ARGPARSE_CONFFILE:
if (debug_argparser)
log_info (_("reading options from '%s'\n"),
pargs.r_type? pargs.r.ret_str: "[cmdline]");
if (pargs.r_type)
{
xfree (last_configname);
last_configname = xstrdup (pargs.r.ret_str);
configname = last_configname;
if (is_secured_filename (configname))
{
pargs.r_opt = ARGPARSE_PERMISSION_ERROR;
pargs.err = ARGPARSE_PRINT_ERROR;
}
else if (strncmp (configname, gnupg_sysconfdir (),
strlen (gnupg_sysconfdir ())))
{
/* This is not the global config file and thus we
* need to check the permissions: If the file is
* unsafe, then disable any external programs for
* keyserver calls or photo IDs. Since the
* external program to call is set in the options
* file, a unsafe options file can lead to an
* arbitrary program being run. */
if (check_permissions (configname, 1))
opt.exec_disable=1;
}
}
else
configname = NULL;
break;
/* case oOptions:
* case oNoOptions:
* We will never see these options here because
* gpgrt_argparse handles them for us.
*/
case aListConfig:
case aListGcryptConfig:
case aGPGConfList:
@ -2702,25 +2708,25 @@ main (int argc, char **argv)
break;
case oNoUseAgent:
obsolete_option (configname, configlineno, "no-use-agent");
obsolete_option (configname, pargs.lineno, "no-use-agent");
break;
case oGpgAgentInfo:
obsolete_option (configname, configlineno, "gpg-agent-info");
obsolete_option (configname, pargs.lineno, "gpg-agent-info");
break;
case oReaderPort:
obsolete_scdaemon_option (configname, configlineno, "reader-port");
obsolete_scdaemon_option (configname, pargs.lineno, "reader-port");
break;
case octapiDriver:
obsolete_scdaemon_option (configname, configlineno, "ctapi-driver");
obsolete_scdaemon_option (configname, pargs.lineno, "ctapi-driver");
break;
case opcscDriver:
obsolete_scdaemon_option (configname, configlineno, "pcsc-driver");
obsolete_scdaemon_option (configname, pargs.lineno, "pcsc-driver");
break;
case oDisableCCID:
obsolete_scdaemon_option (configname, configlineno, "disable-ccid");
obsolete_scdaemon_option (configname, pargs.lineno, "disable-ccid");
break;
case oHonorHttpProxy:
obsolete_option (configname, configlineno, "honor-http-proxy");
obsolete_option (configname, pargs.lineno, "honor-http-proxy");
break;
case oAnswerYes: opt.answer_yes = 1; break;
@ -2731,7 +2737,7 @@ main (int argc, char **argv)
sl->flags = KEYDB_RESOURCE_FLAG_PRIMARY;
break;
case oShowKeyring:
deprecated_warning(configname,configlineno,"--show-keyring",
deprecated_warning(configname,pargs.lineno,"--show-keyring",
"--list-options ","show-keyring");
opt.list_options|=LIST_SHOW_KEYRING;
break;
@ -2803,14 +2809,6 @@ main (int argc, char **argv)
/* Ignore this old option. */
break;
case oOptions:
/* config files may not be nested (silently ignore them) */
if( !configfp ) {
xfree(configname);
configname = xstrdup(pargs.r.ret_str);
goto next_pass;
}
break;
case oNoArmor: opt.no_armor=1; opt.armor=0; break;
case oNoDefKeyring:
@ -2843,7 +2841,7 @@ main (int argc, char **argv)
case oDefaultKey:
sl = add_to_strlist (&opt.def_secret_key, pargs.r.ret_str);
sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
if (configfp)
if (configname)
sl->flags |= PK_LIST_CONFIG;
break;
case oDefRecipient:
@ -2861,7 +2859,6 @@ main (int argc, char **argv)
xfree(opt.def_recipient); opt.def_recipient = NULL;
opt.def_recipient_self = 0;
break;
case oNoOptions: opt.no_homedir_creation = 1; break; /* no-options */
case oHomedir: break;
case oNoBatch: opt.batch = 0; break;
@ -2893,7 +2890,7 @@ main (int argc, char **argv)
opt.tofu_default_policy = parse_tofu_policy (pargs.r.ret_str);
break;
case oTOFUDBFormat:
obsolete_option (configname, configlineno, "tofu-db-format");
obsolete_option (configname, pargs.lineno, "tofu-db-format");
break;
case oForceOwnertrust:
@ -2951,17 +2948,17 @@ main (int argc, char **argv)
case oSigPolicyURL: add_policy_url(pargs.r.ret_str,0); break;
case oCertPolicyURL: add_policy_url(pargs.r.ret_str,1); break;
case oShowPolicyURL:
deprecated_warning(configname,configlineno,"--show-policy-url",
deprecated_warning(configname,pargs.lineno,"--show-policy-url",
"--list-options ","show-policy-urls");
deprecated_warning(configname,configlineno,"--show-policy-url",
deprecated_warning(configname,pargs.lineno,"--show-policy-url",
"--verify-options ","show-policy-urls");
opt.list_options|=LIST_SHOW_POLICY_URLS;
opt.verify_options|=VERIFY_SHOW_POLICY_URLS;
break;
case oNoShowPolicyURL:
deprecated_warning(configname,configlineno,"--no-show-policy-url",
deprecated_warning(configname,pargs.lineno,"--no-show-policy-url",
"--list-options ","no-show-policy-urls");
deprecated_warning(configname,configlineno,"--no-show-policy-url",
deprecated_warning(configname,pargs.lineno,"--no-show-policy-url",
"--verify-options ","no-show-policy-urls");
opt.list_options&=~LIST_SHOW_POLICY_URLS;
opt.verify_options&=~VERIFY_SHOW_POLICY_URLS;
@ -2978,7 +2975,7 @@ main (int argc, char **argv)
append_to_strlist(&opt.comments,pargs.r.ret_str);
break;
case oDefaultComment:
deprecated_warning(configname,configlineno,
deprecated_warning(configname,pargs.lineno,
"--default-comment","--no-comments","");
/* fall through */
case oNoComments:
@ -2988,17 +2985,17 @@ main (int argc, char **argv)
case oThrowKeyids: opt.throw_keyids = 1; break;
case oNoThrowKeyids: opt.throw_keyids = 0; break;
case oShowPhotos:
deprecated_warning(configname,configlineno,"--show-photos",
deprecated_warning(configname,pargs.lineno,"--show-photos",
"--list-options ","show-photos");
deprecated_warning(configname,configlineno,"--show-photos",
deprecated_warning(configname,pargs.lineno,"--show-photos",
"--verify-options ","show-photos");
opt.list_options|=LIST_SHOW_PHOTOS;
opt.verify_options|=VERIFY_SHOW_PHOTOS;
break;
case oNoShowPhotos:
deprecated_warning(configname,configlineno,"--no-show-photos",
deprecated_warning(configname,pargs.lineno,"--no-show-photos",
"--list-options ","no-show-photos");
deprecated_warning(configname,configlineno,"--no-show-photos",
deprecated_warning(configname,pargs.lineno,"--no-show-photos",
"--verify-options ","no-show-photos");
opt.list_options&=~LIST_SHOW_PHOTOS;
opt.verify_options&=~VERIFY_SHOW_PHOTOS;
@ -3029,7 +3026,7 @@ main (int argc, char **argv)
* enough space for the flags. */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
if (configfp)
if (configname)
sl->flags |= PK_LIST_CONFIG;
if (pargs.r_opt == oHiddenRecipient
|| pargs.r_opt == oHiddenRecipientFile)
@ -3045,7 +3042,7 @@ main (int argc, char **argv)
/* Store an additional recipient. */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
if (configfp)
if (configname)
sl->flags |= PK_LIST_CONFIG;
if (pargs.r_opt == oHiddenEncryptTo)
sl->flags |= PK_LIST_HIDDEN;
@ -3055,7 +3052,7 @@ main (int argc, char **argv)
opt.no_encrypt_to = 1;
break;
case oEncryptToDefaultKey:
opt.encrypt_to_default_key = configfp ? 2 : 1;
opt.encrypt_to_default_key = configname ? 2 : 1;
break;
case oTrySecretKey:
@ -3101,7 +3098,7 @@ main (int argc, char **argv)
case oLocalUser: /* store the local users */
sl = add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings );
sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
if (configfp)
if (configname)
sl->flags |= PK_LIST_CONFIG;
break;
case oSender:
@ -3241,7 +3238,7 @@ main (int argc, char **argv)
{
if(configname)
log_error(_("%s:%d: invalid keyserver options\n"),
configname,configlineno);
configname,pargs.lineno);
else
log_error(_("invalid keyserver options\n"));
}
@ -3251,7 +3248,7 @@ main (int argc, char **argv)
{
if(configname)
log_error(_("%s:%d: invalid import options\n"),
configname,configlineno);
configname,pargs.lineno);
else
log_error(_("invalid import options\n"));
}
@ -3266,7 +3263,7 @@ main (int argc, char **argv)
{
if(configname)
log_error(_("%s:%d: invalid export options\n"),
configname,configlineno);
configname,pargs.lineno);
else
log_error(_("invalid export options\n"));
}
@ -3281,7 +3278,7 @@ main (int argc, char **argv)
{
if(configname)
log_error(_("%s:%d: invalid list options\n"),
configname,configlineno);
configname,pargs.lineno);
else
log_error(_("invalid list options\n"));
}
@ -3321,7 +3318,7 @@ main (int argc, char **argv)
{
if(configname)
log_error(_("%s:%d: invalid verify options\n"),
configname,configlineno);
configname,pargs.lineno);
else
log_error(_("invalid verify options\n"));
}
@ -3342,17 +3339,17 @@ main (int argc, char **argv)
case oCertNotation: add_notation_data( pargs.r.ret_str, 1 ); break;
case oKnownNotation: register_known_notation (pargs.r.ret_str); break;
case oShowNotation:
deprecated_warning(configname,configlineno,"--show-notation",
deprecated_warning(configname,pargs.lineno,"--show-notation",
"--list-options ","show-notations");
deprecated_warning(configname,configlineno,"--show-notation",
deprecated_warning(configname,pargs.lineno,"--show-notation",
"--verify-options ","show-notations");
opt.list_options|=LIST_SHOW_NOTATIONS;
opt.verify_options|=VERIFY_SHOW_NOTATIONS;
break;
case oNoShowNotation:
deprecated_warning(configname,configlineno,"--no-show-notation",
deprecated_warning(configname,pargs.lineno,"--no-show-notation",
"--list-options ","no-show-notations");
deprecated_warning(configname,configlineno,"--no-show-notation",
deprecated_warning(configname,pargs.lineno,"--no-show-notation",
"--verify-options ","no-show-notations");
opt.list_options&=~LIST_SHOW_NOTATIONS;
opt.verify_options&=~VERIFY_SHOW_NOTATIONS;
@ -3408,7 +3405,7 @@ main (int argc, char **argv)
ovrseskeyfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
break;
case oMergeOnly:
deprecated_warning(configname,configlineno,"--merge-only",
deprecated_warning(configname,pargs.lineno,"--merge-only",
"--import-options ","merge-only");
opt.import_options|=IMPORT_MERGE_ONLY;
break;
@ -3536,7 +3533,7 @@ main (int argc, char **argv)
{
if(configname)
log_error(_("%s:%d: invalid auto-key-locate list\n"),
configname,configlineno);
configname,pargs.lineno);
else
log_error(_("invalid auto-key-locate list\n"));
}
@ -3558,7 +3555,7 @@ main (int argc, char **argv)
if (configname)
log_info("%s:%d: WARNING: gpg not built with large secure "
"memory buffer. Ignoring enable-large-rsa\n",
configname,configlineno);
configname,pargs.lineno);
else
log_info("WARNING: gpg not built with large secure "
"memory buffer. Ignoring --enable-large-rsa\n");
@ -3620,7 +3617,7 @@ main (int argc, char **argv)
case oNoop: break;
default:
if (configfp)
if (configname)
pargs.err = ARGPARSE_PRINT_WARNING;
else
{
@ -3634,19 +3631,8 @@ main (int argc, char **argv)
}
}
if (configfp)
{
fclose( configfp );
configfp = NULL;
/* Remember the first config file name. */
if (!save_configname)
save_configname = configname;
else
xfree(configname);
configname = NULL;
goto next_pass;
}
xfree(configname); configname = NULL;
gnupg_argparse (NULL, &pargs, NULL); /* Release internal state. */
if (log_get_errorcount (0))
{
write_status_failure ("option-parser", gpg_error(GPG_ERR_GENERAL));
@ -3657,11 +3643,11 @@ main (int argc, char **argv)
directly after the option parsing. */
if (cmd == aGPGConfList)
{
gpgconf_list (save_configname ? save_configname : default_configname);
gpgconf_list (last_configname ? last_configname : "UNKNOWN");
g10_exit (0);
}
xfree (save_configname);
xfree (default_configname);
xfree (last_configname);
last_configname = NULL;
if (print_dane_records)
log_error ("invalid option \"%s\"; use \"%s\" instead\n",