agent: Clear bogus pinentry cache, when it causes an error.

* agent/agent.h (PINENTRY_STATUS_*): Expose to public.
(struct pin_entry_info_s): Add status.
* agent/call-pinentry.c (agent_askpin): Clearing the ->status
before the loop, let the assuan_transact set ->status.  When
failure with PINENTRY_STATUS_PASSWORD_FROM_CACHE, it returns
soon.
* agent/findkey.c (unprotect): Clear the pinentry cache,
when it causes an error.

--

GnuPG-bug-id: 4348
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2019-01-28 12:58:13 +09:00
parent 1c92510045
commit 02a2633a7f
3 changed files with 39 additions and 21 deletions

View File

@ -266,6 +266,14 @@ struct server_control_s
}; };
/* Status of pinentry. */
enum
{
PINENTRY_STATUS_CLOSE_BUTTON = 1 << 0,
PINENTRY_STATUS_PIN_REPEATED = 1 << 8,
PINENTRY_STATUS_PASSWORD_FROM_CACHE = 1 << 9
};
/* Information pertaining to pinentry requests. */ /* Information pertaining to pinentry requests. */
struct pin_entry_info_s struct pin_entry_info_s
{ {
@ -275,7 +283,8 @@ struct pin_entry_info_s
int failed_tries; /* Number of tries so far failed. */ int failed_tries; /* Number of tries so far failed. */
int with_qualitybar; /* Set if the quality bar should be displayed. */ int with_qualitybar; /* Set if the quality bar should be displayed. */
int with_repeat; /* Request repetition of the passphrase. */ int with_repeat; /* Request repetition of the passphrase. */
int repeat_okay; /* Repetition worked. */ int repeat_okay; /* Repetition worked. */
unsigned int status; /* Status. */
gpg_error_t (*check_cb)(struct pin_entry_info_s *); /* CB used to check gpg_error_t (*check_cb)(struct pin_entry_info_s *); /* CB used to check
the PIN */ the PIN */
void *check_cb_arg; /* optional argument which might be of use in the CB */ void *check_cb_arg; /* optional argument which might be of use in the CB */

View File

@ -894,13 +894,6 @@ setup_qualitybar (ctrl_t ctrl)
return 0; return 0;
} }
enum
{
PINENTRY_STATUS_CLOSE_BUTTON = 1 << 0,
PINENTRY_STATUS_PIN_REPEATED = 1 << 8,
PINENTRY_STATUS_PASSWORD_FROM_CACHE = 1 << 9
};
/* Check the button_info line for a close action. Also check for the /* Check the button_info line for a close action. Also check for the
PIN_REPEATED flag. */ PIN_REPEATED flag. */
static gpg_error_t static gpg_error_t
@ -965,7 +958,6 @@ agent_askpin (ctrl_t ctrl,
const char *errtext = NULL; const char *errtext = NULL;
int is_pin = 0; int is_pin = 0;
int saveflag; int saveflag;
unsigned int pinentry_status;
if (opt.batch) if (opt.batch)
return 0; /* fixme: we should return BAD PIN */ return 0; /* fixme: we should return BAD PIN */
@ -1076,6 +1068,7 @@ agent_askpin (ctrl_t ctrl,
pininfo->with_repeat = 0; /* Pinentry does not support it. */ pininfo->with_repeat = 0; /* Pinentry does not support it. */
} }
pininfo->repeat_okay = 0; pininfo->repeat_okay = 0;
pininfo->status = 0;
for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++) for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
{ {
@ -1109,10 +1102,9 @@ agent_askpin (ctrl_t ctrl,
saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
assuan_begin_confidential (entry_ctx); assuan_begin_confidential (entry_ctx);
pinentry_status = 0;
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
inq_quality, entry_ctx, inq_quality, entry_ctx,
pinentry_status_cb, &pinentry_status); pinentry_status_cb, &pininfo->status);
assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
/* Most pinentries out in the wild return the old Assuan error code /* Most pinentries out in the wild return the old Assuan error code
for canceled which gets translated to an assuan Cancel error and for canceled which gets translated to an assuan Cancel error and
@ -1124,7 +1116,7 @@ agent_askpin (ctrl_t ctrl,
/* Change error code in case the window close button was clicked /* Change error code in case the window close button was clicked
to cancel the operation. */ to cancel the operation. */
if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON) if ((pininfo->status & PINENTRY_STATUS_CLOSE_BUTTON)
&& gpg_err_code (rc) == GPG_ERR_CANCELED) && gpg_err_code (rc) == GPG_ERR_CANCELED)
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
@ -1151,12 +1143,19 @@ agent_askpin (ctrl_t ctrl,
/* More checks by utilizing the optional callback. */ /* More checks by utilizing the optional callback. */
pininfo->cb_errtext = NULL; pininfo->cb_errtext = NULL;
rc = pininfo->check_cb (pininfo); rc = pininfo->check_cb (pininfo);
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE /* When pinentry cache causes an error, return now. */
&& pininfo->cb_errtext) if (rc
errtext = pininfo->cb_errtext; && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE return unlock_pinentry (ctrl, rc);
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase")); if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
{
if (pininfo->cb_errtext)
errtext = pininfo->cb_errtext;
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
}
else if (rc) else if (rc)
return unlock_pinentry (ctrl, rc); return unlock_pinentry (ctrl, rc);
} }
@ -1164,12 +1163,12 @@ agent_askpin (ctrl_t ctrl,
if (!errtext) if (!errtext)
{ {
if (pininfo->with_repeat if (pininfo->with_repeat
&& (pinentry_status & PINENTRY_STATUS_PIN_REPEATED)) && (pininfo->status & PINENTRY_STATUS_PIN_REPEATED))
pininfo->repeat_okay = 1; pininfo->repeat_okay = 1;
return unlock_pinentry (ctrl, 0); /* okay, got a PIN or passphrase */ return unlock_pinentry (ctrl, 0); /* okay, got a PIN or passphrase */
} }
if ((pinentry_status & PINENTRY_STATUS_PASSWORD_FROM_CACHE)) if ((pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
/* The password was read from the cache. Don't count this /* The password was read from the cache. Don't count this
against the retry count. */ against the retry count. */
pininfo->failed_tries --; pininfo->failed_tries --;

View File

@ -632,7 +632,17 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
pi->check_cb_arg = &arg; pi->check_cb_arg = &arg;
rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi, hexgrip, cache_mode); rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi, hexgrip, cache_mode);
if (!rc) if (rc)
{
if ((pi->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
{
log_error ("Clearing pinentry cache which caused error %s\n",
gpg_strerror (rc));
agent_clear_passphrase (ctrl, hexgrip, cache_mode);
}
}
else
{ {
assert (arg.unprotected_key); assert (arg.unprotected_key);
if (arg.change_required) if (arg.change_required)