diff --git a/agent/agent.h b/agent/agent.h index 7342475e7..b80c6a05c 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -220,6 +220,8 @@ struct pin_entry_info_s int max_tries; /* max. number of allowed tries. */ int failed_tries; /* Number of tries so far failed. */ int with_qualitybar; /* Set if the quality bar should be displayed. */ + int with_repeat; /* Request repetition of the passphrase. */ + int repeat_okay; /* Repetition worked. */ int (*check_cb)(struct pin_entry_info_s *); /* CB used to check the PIN */ void *check_cb_arg; /* optional argument which might be of use in the CB */ const char *cb_errtext; /* used by the cb to display a specific error */ diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 126d6968b..e5977ad6a 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -682,23 +682,23 @@ setup_qualitybar (void) } -/* Check the button_info line for a close action. */ +/* Check the button_info line for a close action. Also check for the + PIN_REPEATED flag. */ static gpg_error_t close_button_status_cb (void *opaque, const char *line) { - int *flag = opaque; - const char *keyword = line; - int keywordlen; + unsigned int *flag = opaque; + const char *args; - for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) - ; - while (spacep (line)) - line++; - if (keywordlen == 11 && !memcmp (keyword, "BUTTON_INFO", keywordlen)) + if ((args = has_leading_keyword (line, "BUTTON_INFO"))) { - if ( !strcmp (line, "close") ) + if (!strcmp (args, "close")) *flag = 1; } + else if (has_leading_keyword (line, "PIN_REPEATED")) + { + *flag |= 256; + } return 0; } @@ -721,7 +721,7 @@ agent_askpin (ctrl_t ctrl, const char *errtext = NULL; int is_pin = 0; int saveflag; - int close_button; + unsigned int close_button; if (opt.batch) return 0; /* fixme: we should return BAD PIN */ @@ -806,6 +806,18 @@ agent_askpin (ctrl_t ctrl, return unlock_pinentry (rc); } + if (pininfo->with_repeat) + { + snprintf (line, DIM(line)-1, "SETREPEATERROR %s", + _("does not match - try again")); + line[DIM(line)-1] = 0; + rc = assuan_transact (entry_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + if (rc) + pininfo->with_repeat = 0; /* Pinentry does not support it. */ + } + pininfo->repeat_okay = 0; + for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++) { memset (&parm, 0, sizeof parm); @@ -828,6 +840,16 @@ agent_askpin (ctrl_t ctrl, errtext = NULL; } + if (pininfo->with_repeat) + { + snprintf (line, DIM(line)-1, "SETREPEAT %s", _("Repeat:")); + line[DIM(line)-1] = 0; + rc = assuan_transact (entry_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + if (rc) + return unlock_pinentry (rc); + } + saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); assuan_begin_confidential (entry_ctx); close_button = 0; @@ -842,9 +864,10 @@ agent_askpin (ctrl_t ctrl, && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); + /* Change error code in case the window close button was clicked to cancel the operation. */ - if (close_button && gpg_err_code (rc) == GPG_ERR_CANCELED) + if ((close_button & 1) && gpg_err_code (rc) == GPG_ERR_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA) @@ -881,7 +904,11 @@ agent_askpin (ctrl_t ctrl, } if (!errtext) - return unlock_pinentry (0); /* okay, got a PIN or passphrase */ + { + if (pininfo->with_repeat && (close_button & 256)) + pininfo->repeat_okay = 1; + return unlock_pinentry (0); /* okay, got a PIN or passphrase */ + } } return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN @@ -902,7 +929,7 @@ agent_get_passphrase (ctrl_t ctrl, char line[ASSUAN_LINELENGTH]; struct entry_parm_s parm; int saveflag; - int close_button; + unsigned int close_button; *retpass = NULL; if (opt.batch) @@ -991,7 +1018,7 @@ agent_get_passphrase (ctrl_t ctrl, rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); /* Change error code in case the window close button was clicked to cancel the operation. */ - if (close_button && gpg_err_code (rc) == GPG_ERR_CANCELED) + if ((close_button & 1) && gpg_err_code (rc) == GPG_ERR_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); if (rc) diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 54273239f..f3ef30c15 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -3104,6 +3104,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec, pi2 = pi + (sizeof *pi + 100 + 1); pi->max_length = 100; pi->max_tries = 1; + pi->with_repeat = 1; pi2->max_length = 100; pi2->max_tries = 1; pi2->check_cb = reenter_compare_cb; @@ -3115,8 +3116,9 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec, if (err) goto out; - /* Unless the passphrase is empty, ask to confirm it. */ - if (pi->pin && *pi->pin) + /* Unless the passphrase is empty or the pinentry told us that + it already did the repetition check, ask to confirm it. */ + if (pi->pin && *pi->pin && !pi->repeat_okay) { err = agent_askpin (ctrl, description2, NULL, NULL, pi2); if (err == -1) diff --git a/agent/genkey.c b/agent/genkey.c index 9918c12e7..91917f77b 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -363,6 +363,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, pi->max_length = 100; pi->max_tries = 3; pi->with_qualitybar = 1; + pi->with_repeat = 1; pi2->max_length = 100; pi2->max_tries = 3; pi2->check_cb = reenter_compare_cb; @@ -379,8 +380,9 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, pi2->failed_tries = 0; goto next_try; } - /* Unless the passphrase is empty, ask to confirm it. */ - if (pi->pin && *pi->pin) + /* Unless the passphrase is empty or the pinentry told us that + it already did the repetition check, ask to confirm it. */ + if (pi->pin && *pi->pin && !pi->repeat_okay) { err = agent_askpin (ctrl, text2, NULL, NULL, pi2); if (err == -1)