common: Fix the "ignore" meta command in argparse.c

* src/argparse.c (gnupg_argparse): Factor some code out to ...
(prepare_arg_return): new.
(gnupg_argparse): No missing arg error in ignore sections.
* common/sysutils.c: Include pwd.h.
(gnupg_getusername): New.
--

Options in an [ignore] section do not anymore lead to an error if an
argument is missing.  However, if the option is also in a force
section the error is thrown.

This is a port of the fix from libgpg-error.  Also fixes the
username fixme.
This commit is contained in:
Werner Koch 2020-12-21 17:23:52 +01:00
parent 8a2e5025eb
commit 09dc59f6d4
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 123 additions and 37 deletions

View File

@ -722,7 +722,7 @@ assure_username (gnupg_argparse_t *arg)
{
if (!arg->internal->username)
{
arg->internal->username = "dummyuser"; /*FIXMEgpgrt_getusername ();*/
arg->internal->username = gnupg_getusername ();
if (!arg->internal->username)
{
log_error ("%s:%u: error getting current user's name: %s\n",
@ -963,6 +963,34 @@ handle_metacmd (gnupg_argparse_t *arg, char *keyword)
}
/* Helper for gnupg_argparse. */
static void
prepare_arg_return (gnupg_argparse_t *arg, opttable_t *opts,
int idx, int in_alias, int set_ignore)
{
/* No argument found at the end of the line. */
if (in_alias)
arg->r_opt = ARGPARSE_MISSING_ARG;
else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
arg->r_type = ARGPARSE_TYPE_NONE; /* Does not take an arg. */
else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
arg->r_type = ARGPARSE_TYPE_NONE; /* No optional argument. */
else if (!(opts[idx].ignore && !opts[idx].forced) && !set_ignore)
arg->r_opt = ARGPARSE_MISSING_ARG;
/* If the caller wants us to return the attributes or
* ignored options, or these flags in. */
if ((arg->flags & ARGPARSE_FLAG_WITHATTR))
{
if (opts[idx].ignore)
arg->r_type |= ARGPARSE_ATTR_IGNORE;
if (opts[idx].forced)
arg->r_type |= ARGPARSE_ATTR_FORCE;
if (set_ignore)
arg->r_type |= ARGPARSE_OPT_IGNORE;
}
}
/****************
* Get options from a file.
* Lines starting with '#' are comment lines.
@ -1008,6 +1036,7 @@ gnupg_argparse (estream_t fp, gnupg_argparse_t *arg, gnupg_opt_t *opts_orig)
char *buffer = NULL;
size_t buflen = 0;
int in_alias=0;
int set_ignore = 0;
int unread_buf[3]; /* We use an int so that we can store EOF. */
int unread_buf_count = 0;
@ -1105,12 +1134,8 @@ gnupg_argparse (estream_t fp, gnupg_argparse_t *arg, gnupg_opt_t *opts_orig)
goto leave;
}
}
else if (state == Akeyword_spc)
{
/* Known option but need to scan for args. */
state = Awaitarg;
}
else if (arg->internal->in_sysconf
else if (state != Akeyword_spc
&& arg->internal->in_sysconf
&& arg->internal->user_seen
&& !arg->internal->user_active)
{
@ -1119,7 +1144,8 @@ gnupg_argparse (estream_t fp, gnupg_argparse_t *arg, gnupg_opt_t *opts_orig)
state = state == Akeyword_eol? Ainit : Acomment;
i = 0;
}
else if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
else if (state != Akeyword_spc
&& (opts[idx].flags & ARGPARSE_OPT_IGNORE))
{
/* Known option is configured to be ignored. Start from
* scratch (new line) or process like a comment. */
@ -1128,7 +1154,7 @@ gnupg_argparse (estream_t fp, gnupg_argparse_t *arg, gnupg_opt_t *opts_orig)
}
else /* Known option */
{
int set_ignore = 0;
set_ignore = 0;
if (arg->internal->in_sysconf)
{
@ -1139,6 +1165,23 @@ gnupg_argparse (estream_t fp, gnupg_argparse_t *arg, gnupg_opt_t *opts_orig)
opts[idx].ignore = 1;
if (arg->internal->explicit_ignore)
opts[idx].explicit_ignore = 1;
if (opts[idx].ignore && !opts[idx].forced)
{
if (arg->internal->verbose)
log_info ("%s:%u: ignoring option \"--%s\"\n",
arg->internal->confname,
arg->lineno,
opts[idx].long_opt);
if ((arg->flags & ARGPARSE_FLAG_WITHATTR))
set_ignore = 1;
else
{
state = state == Akeyword_eol? Ainit : Acomment;
i = 0;
goto nextstate; /* Ignore this one. */
}
}
}
else /* Non-sysconf file */
{ /* Act upon the forced and ignored attributes. */
@ -1156,34 +1199,34 @@ gnupg_argparse (estream_t fp, gnupg_argparse_t *arg, gnupg_opt_t *opts_orig)
set_ignore = 1;
else
{
state = Ainit;
state = state == Akeyword_eol? Ainit : Acomment;
i = 0;
goto nextstate; /* Ignore this one. */
}
}
}
arg->r_opt = opts[idx].short_opt;
if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
arg->r_type = ARGPARSE_TYPE_NONE; /* Does not take an arg. */
else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) )
arg->r_type = ARGPARSE_TYPE_NONE; /* Arg is optional. */
else
arg->r_opt = ARGPARSE_MISSING_ARG;
/* If the caller wants us to return the attributes or
* ignored options, or the flags in. */
if ((arg->flags & ARGPARSE_FLAG_WITHATTR))
if (state == Akeyword_spc)
{
if (opts[idx].ignore)
arg->r_type |= ARGPARSE_ATTR_IGNORE;
if (opts[idx].forced)
arg->r_type |= ARGPARSE_ATTR_FORCE;
if (set_ignore)
arg->r_type |= ARGPARSE_OPT_IGNORE;
/* If we shall ignore but not set the option we skip
* the argument. Otherwise we would need to use a
* made-up but not used args in the conf file. */
if (set_ignore || (opts[idx].ignore && !opts[idx].forced))
{
prepare_arg_return (arg, opts, idx, 0, set_ignore);
set_ignore = 0;
state = Askipandleave;
}
else
state = Awaitarg;
}
else
{
prepare_arg_return (arg, opts, idx, 0, set_ignore);
set_ignore = 0;
goto leave;
}
goto leave;
}
} /* (end state Akeyword_eol/Akeyword_spc) */
else if (state == Ametacmd)
@ -1237,15 +1280,8 @@ gnupg_argparse (estream_t fp, gnupg_argparse_t *arg, gnupg_opt_t *opts_orig)
else if (state == Awaitarg)
{
/* No argument found at the end of the line. */
if (in_alias)
arg->r_opt = ARGPARSE_MISSING_ARG;
else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
arg->r_type = ARGPARSE_TYPE_NONE; /* Does not take an arg. */
else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
arg->r_type = ARGPARSE_TYPE_NONE; /* No optional argument. */
else
arg->r_opt = ARGPARSE_MISSING_ARG;
prepare_arg_return (arg, opts, idx, in_alias, set_ignore);
set_ignore = 0;
goto leave;
}
else if (state == Acopyarg)

View File

@ -40,6 +40,9 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
#include <unistd.h>
#include <errno.h>
#ifdef HAVE_STAT
@ -1741,3 +1744,49 @@ gnupg_fd_valid (int fd)
close (d);
return 1;
}
/* Return a malloced copy of the current user's account name; this may
* return NULL on memory failure. Note that this should eventually be
* replaced by a gpgrt function. */
char *
gnupg_getusername (void)
{
char *result = NULL;
#ifdef HAVE_W32_SYSTEM
wchar_t wtmp[1];
wchar_t *wbuf;
DWORD wsize = 1;
GetUserNameW (wtmp, &wsize);
wbuf = xtrymalloc (wsize * sizeof *wbuf);
if (!wbuf)
{
gpg_err_set_errno (ENOMEM);
return NULL;
}
if (!GetUserNameW (wbuf, &wsize))
{
gpg_err_set_errno (EINVAL);
xfree (wbuf);
return NULL;
}
result= wchar_to_utf8 (wbuf);
xfree (wbuf);
#else /* !HAVE_W32_SYSTEM */
# if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
struct passwd *pwd;
pwd = getpwuid (getuid());
if (pwd)
result = xtrystrdup (pwd->pw_name);
# endif /*HAVE_PWD_H*/
#endif /* !HAVE_W32_SYSTEM */
return result;
}

View File

@ -98,6 +98,7 @@ gnupg_dirent_t gnupg_readdir (gnupg_dir_t gdir);
int gnupg_closedir (gnupg_dir_t gdir);
char *gnupg_get_socket_name (int fd);
int gnupg_fd_valid (int fd);
char *gnupg_getusername (void);
gpg_error_t gnupg_inotify_watch_delete_self (int *r_fd, const char *fname);
gpg_error_t gnupg_inotify_watch_socket (int *r_fd, const char *socket_name);