diff options
author | Werner Koch <[email protected]> | 2020-07-08 12:20:01 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2020-07-08 14:13:43 +0000 |
commit | d9e2dfa4c585de7c261fde13c18bd0f82415d6c3 (patch) | |
tree | c7280b9374eace0fdaff992ac3760370829f0b9b | |
parent | gpg: Fix flaw in symmetric algorithm selection in mixed mode. (diff) | |
download | gnupg-d9e2dfa4c585de7c261fde13c18bd0f82415d6c3.tar.gz gnupg-d9e2dfa4c585de7c261fde13c18bd0f82415d6c3.zip |
agent: New option --newsymkey for GET_PASSPHRASE
* agent/call-pinentry.c (do_getpin): New.
(agent_askpin): Use do_getpin.
(agent_get_passphrase): Add arg pininfo. Use do_getpin.
* agent/genkey.c (check_passphrase_constraints): New arg no_empty.
* agent/command.c (reenter_passphrase_cmp_cb): New.
(cmd_get_passphrase): Add option --newsymkey.
--
This new option allows to present a passphrase with the usual repeat
box as it is used by gpg-agent's internal key generation.
Signed-off-by: Werner Koch <[email protected]>
Backported-from-master: eace4bbe1ded8b01f9ad52ebc1871f2fd13c3a08
-rw-r--r-- | agent/agent.h | 5 | ||||
-rw-r--r-- | agent/call-pinentry.c | 268 | ||||
-rw-r--r-- | agent/command.c | 170 | ||||
-rw-r--r-- | agent/genkey.c | 8 |
4 files changed, 354 insertions, 97 deletions
diff --git a/agent/agent.h b/agent/agent.h index e10e02b8c..8b5ae6083 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -447,7 +447,8 @@ gpg_error_t agent_askpin (ctrl_t ctrl, int agent_get_passphrase (ctrl_t ctrl, char **retpass, const char *desc, const char *prompt, const char *errtext, int with_qualitybar, - const char *keyinfo, cache_mode_t cache_mode); + const char *keyinfo, cache_mode_t cache_mode, + struct pin_entry_info_s *pininfo); int agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok, const char *notokay, int with_cancel); int agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn); @@ -484,7 +485,7 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, membuf_t *outbuf, int *r_padding); /*-- genkey.c --*/ -int check_passphrase_constraints (ctrl_t ctrl, const char *pw, +int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty, char **failed_constraint); gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, char **r_passphrase); diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index b0b5bcb92..2af94c9cd 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -85,6 +85,7 @@ struct entry_parm_s int lines; size_t size; unsigned char *buffer; + int status; }; @@ -836,7 +837,7 @@ inq_quality (void *opaque, const char *line) else { percent = estimate_passphrase_quality (pin); - if (check_passphrase_constraints (NULL, pin, NULL)) + if (check_passphrase_constraints (NULL, pin, 0, NULL)) percent = -percent; snprintf (numbuf, sizeof numbuf, "%d", percent); rc = assuan_send_data (ctx, numbuf, strlen (numbuf)); @@ -953,6 +954,36 @@ build_cmd_setdesc (char *line, size_t linelen, const char *desc) } +/* Ask pinentry to get a pin by "GETPIN" command, spawning a thread + * detecting the socket's EOF. */ +static gpg_error_t +do_getpin (ctrl_t ctrl, struct entry_parm_s *parm) +{ + gpg_error_t rc; + int saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); + + (void)ctrl; + + assuan_begin_confidential (entry_ctx); + rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, parm, + inq_quality, entry_ctx, + pinentry_status_cb, &parm->status); + assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); + /* Most pinentries out in the wild return the old Assuan error code + for canceled which gets translated to an assuan Cancel error and + not to the code for a user cancel. Fix this here. */ + if (rc && gpg_err_source (rc) && 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 ((parm->status & PINENTRY_STATUS_CLOSE_BUTTON) + && gpg_err_code (rc) == GPG_ERR_CANCELED) + rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); + + return rc; +} + + /* Call the Entry and ask for the PIN. We do check for a valid PIN number here and repeat it as long as we have invalid formed @@ -970,7 +1001,6 @@ agent_askpin (ctrl_t ctrl, struct entry_parm_s parm; const char *errtext = NULL; int is_pin = 0; - int saveflag; if (opt.batch) return 0; /* fixme: we should return BAD PIN */ @@ -1114,25 +1144,8 @@ agent_askpin (ctrl_t ctrl, return unlock_pinentry (ctrl, rc); } - saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); - assuan_begin_confidential (entry_ctx); - rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, - inq_quality, entry_ctx, - pinentry_status_cb, &pininfo->status); - assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); - /* Most pinentries out in the wild return the old Assuan error code - for canceled which gets translated to an assuan Cancel error and - not to the code for a user cancel. Fix this here. */ - if (rc && gpg_err_source (rc) - && 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 ((pininfo->status & PINENTRY_STATUS_CLOSE_BUTTON) - && gpg_err_code (rc) == GPG_ERR_CANCELED) - rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); + rc = do_getpin (ctrl, &parm); + pininfo->status = parm.status; if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA) errtext = is_pin? L_("PIN too long") @@ -1183,9 +1196,11 @@ agent_askpin (ctrl_t ctrl, } if ((pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE)) - /* The password was read from the cache. Don't count this - against the retry count. */ - pininfo->failed_tries --; + { + /* The password was read from the cache. Don't count this + against the retry count. */ + pininfo->failed_tries --; + } } return unlock_pinentry (ctrl, gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN @@ -1195,19 +1210,22 @@ agent_askpin (ctrl_t ctrl, /* Ask for the passphrase using the supplied arguments. The returned - passphrase needs to be freed by the caller. */ + passphrase needs to be freed by the caller. PININFO is optional + and can be used to have constraints checinkg while the pinentry + dialog is open (like what we do in agent_askpin). This is very + similar to agent_akpin and we should eventually merge the two + functions. */ int agent_get_passphrase (ctrl_t ctrl, char **retpass, const char *desc, const char *prompt, const char *errtext, int with_qualitybar, - const char *keyinfo, cache_mode_t cache_mode) + const char *keyinfo, cache_mode_t cache_mode, + struct pin_entry_info_s *pininfo) { - int rc; + int is_pin; char line[ASSUAN_LINELENGTH]; struct entry_parm_s parm; - int saveflag; - unsigned int pinentry_status; *retpass = NULL; if (opt.batch) @@ -1215,17 +1233,42 @@ agent_get_passphrase (ctrl_t ctrl, if (ctrl->pinentry_mode != PINENTRY_MODE_ASK) { + unsigned char *passphrase; + size_t size; + if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL) return gpg_error (GPG_ERR_CANCELED); - if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) + if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK && pininfo) { - size_t size; + *pininfo->pin = 0; /* Reset the PIN. */ + rc = pinentry_loopback (ctrl, "PASSPHRASE", + &passphrase, &size, + pininfo->max_length - 1); + if (rc) + return rc; + memcpy (&pininfo->pin, passphrase, size); + wipememory (passphrase, size); + xfree (passphrase); + pininfo->pin[size] = 0; + if (pininfo->check_cb) + { + /* More checks by utilizing the optional callback. */ + pininfo->cb_errtext = NULL; + rc = pininfo->check_cb (pininfo); + } + return rc; + + } + else if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) + { + /* Legacy variant w/o PININFO. */ return pinentry_loopback (ctrl, "PASSPHRASE", (unsigned char **)retpass, &size, MAX_PASSPHRASE_LEN); } + return gpg_error (GPG_ERR_NO_PIN_ENTRY); } @@ -1233,9 +1276,14 @@ agent_get_passphrase (ctrl_t ctrl, if (rc) return rc; - if (!prompt) - prompt = desc && strstr (desc, "PIN")? L_("PIN:"): L_("Passphrase:"); - + /* Set IS_PIN and if needed a default prompt. */ + if (prompt) + is_pin = !!strstr (prompt, "PIN"); + else + { + is_pin = desc && strstr (desc, "PIN"); + prompt = is_pin? L_("PIN:"): L_("Passphrase:"); + } /* If we have a KEYINFO string and are normal, user, or ssh cache mode, we tell that the Pinentry so it may use it for own caching @@ -1256,7 +1304,6 @@ agent_get_passphrase (ctrl_t ctrl, if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD) return unlock_pinentry (ctrl, rc); - if (desc) build_cmd_setdesc (line, DIM(line), desc); else @@ -1270,7 +1317,8 @@ agent_get_passphrase (ctrl_t ctrl, if (rc) return unlock_pinentry (ctrl, rc); - if (with_qualitybar && opt.min_passphrase_len) + if ((with_qualitybar || (pininfo && pininfo->with_qualitybar)) + && opt.min_passphrase_len) { rc = setup_qualitybar (ctrl); if (rc) @@ -1280,40 +1328,132 @@ agent_get_passphrase (ctrl_t ctrl, if (errtext) { snprintf (line, DIM(line), "SETERROR %s", errtext); - rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); + rc = assuan_transact (entry_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (ctrl, rc); } - memset (&parm, 0, sizeof parm); - parm.size = ASSUAN_LINELENGTH/2 - 5; - parm.buffer = gcry_malloc_secure (parm.size+10); - if (!parm.buffer) - return unlock_pinentry (ctrl, out_of_core ()); + if (!pininfo) + { + /* Legacy method without PININFO. */ + memset (&parm, 0, sizeof parm); + parm.size = ASSUAN_LINELENGTH/2 - 5; + parm.buffer = gcry_malloc_secure (parm.size+10); + if (!parm.buffer) + return unlock_pinentry (ctrl, out_of_core ()); - saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); - assuan_begin_confidential (entry_ctx); - pinentry_status = 0; - rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, - inq_quality, entry_ctx, - pinentry_status_cb, &pinentry_status); - assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); - /* Most pinentries out in the wild return the old Assuan error code - for canceled which gets translated to an assuan Cancel error and - not to the code for a user cancel. Fix this here. */ - if (rc && gpg_err_source (rc) && 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 ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON) - && gpg_err_code (rc) == GPG_ERR_CANCELED) - rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); + rc = do_getpin (ctrl, &parm); + if (rc) + xfree (parm.buffer); + else + *retpass = parm.buffer; + return unlock_pinentry (ctrl, rc); + } - if (rc) - xfree (parm.buffer); - else - *retpass = parm.buffer; - return unlock_pinentry (ctrl, rc); + /* We got PININFO. */ + + if (pininfo->with_repeat) + { + snprintf (line, DIM(line), "SETREPEATERROR %s", + L_("does not match - try again")); + 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; + pininfo->status = 0; + + for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++) + { + memset (&parm, 0, sizeof parm); + parm.size = pininfo->max_length; + parm.buffer = (unsigned char*)pininfo->pin; + *pininfo->pin = 0; /* Reset the PIN. */ + + if (errtext) + { + /* TRANSLATORS: The string is appended to an error message in + the pinentry. The %s is the actual error message, the + two %d give the current and maximum number of tries. */ + snprintf (line, DIM(line), L_("SETERROR %s (try %d of %d)"), + errtext, pininfo->failed_tries+1, pininfo->max_tries); + rc = assuan_transact (entry_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + if (rc) + return unlock_pinentry (ctrl, rc); + errtext = NULL; + } + + if (pininfo->with_repeat) + { + snprintf (line, DIM(line), "SETREPEAT %s", L_("Repeat:")); + rc = assuan_transact (entry_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + if (rc) + return unlock_pinentry (ctrl, rc); + } + + rc = do_getpin (ctrl, &parm); + pininfo->status = parm.status; + if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA) + errtext = is_pin? L_("PIN too long") + : L_("Passphrase too long"); + else if (rc) + return unlock_pinentry (ctrl, rc); + + if (!errtext && pininfo->min_digits) + { + /* do some basic checks on the entered PIN. */ + if (!all_digitsp (pininfo->pin)) + errtext = L_("Invalid characters in PIN"); + else if (pininfo->max_digits + && strlen (pininfo->pin) > pininfo->max_digits) + errtext = L_("PIN too long"); + else if (strlen (pininfo->pin) < pininfo->min_digits) + errtext = L_("PIN too short"); + } + + if (!errtext && pininfo->check_cb) + { + /* More checks by utilizing the optional callback. */ + pininfo->cb_errtext = NULL; + rc = pininfo->check_cb (pininfo); + /* When pinentry cache causes an error, return now. */ + if (rc && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE)) + return unlock_pinentry (ctrl, rc); + + 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) + return unlock_pinentry (ctrl, rc); + } + + if (!errtext) + { + if (pininfo->with_repeat + && (pininfo->status & PINENTRY_STATUS_PIN_REPEATED)) + pininfo->repeat_okay = 1; + return unlock_pinentry (ctrl, 0); /* okay, got a PIN or passphrase */ + } + + if ((pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE)) + { + /* The password was read from the Pinentry's own cache. + Don't count this against the retry count. */ + pininfo->failed_tries--; + } + } + + return unlock_pinentry (ctrl, gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN + : GPG_ERR_BAD_PASSPHRASE)); } diff --git a/agent/command.c b/agent/command.c index c24fc80fd..ebbb42cb7 100644 --- a/agent/command.c +++ b/agent/command.c @@ -1400,9 +1400,22 @@ send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw) } +/* Callback function to compare the first entered PIN with the one + currently being entered. */ +static gpg_error_t +reenter_passphrase_cmp_cb (struct pin_entry_info_s *pi) +{ + const char *pin1 = pi->check_cb_arg; + + if (!strcmp (pin1, pi->pin)) + return 0; /* okay */ + return gpg_error (GPG_ERR_BAD_PASSPHRASE); +} + + static const char hlp_get_passphrase[] = "GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]]\n" - " [--qualitybar] <cache_id>\n" + " [--qualitybar] [--newsymkey] <cache_id>\n" " [<error_message> <prompt> <description>]\n" "\n" "This function is usually used to ask for a passphrase to be used\n" @@ -1424,6 +1437,9 @@ static const char hlp_get_passphrase[] = "cache the user will not be asked to enter a passphrase but the error\n" "code GPG_ERR_NO_DATA is returned. \n" "\n" + "If the option\"--newsymkey\" is used the agent asks for a new passphrase\n" + "to be used in symmetric-only encryption. This must not be empty.\n" + "\n" "If the option \"--qualitybar\" is used a visual indication of the\n" "entered passphrase quality is shown. (Unless no minimum passphrase\n" "length has been configured.)"; @@ -1433,13 +1449,19 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) ctrl_t ctrl = assuan_get_pointer (ctx); int rc; char *pw; - char *response; - char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL; + char *response = NULL; + char *response2 = NULL; + char *cacheid = NULL; /* May point into LINE. */ + char *desc = NULL; /* Ditto */ + char *prompt = NULL; /* Ditto */ + char *errtext = NULL; /* Ditto */ const char *desc2 = _("Please re-enter this passphrase"); char *p; - int opt_data, opt_check, opt_no_ask, opt_qualbar; + int opt_data, opt_check, opt_no_ask, opt_qualbar, opt_newsymkey; int opt_repeat = 0; char *entry_errtext = NULL; + struct pin_entry_info_s *pi = NULL; + struct pin_entry_info_s *pi2 = NULL; if (ctrl->restricted) return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); @@ -1456,6 +1478,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) opt_repeat = 1; } opt_qualbar = has_option (line, "--qualitybar"); + opt_newsymkey = has_option (line, "--newsymkey"); line = skip_options (line); cacheid = line; @@ -1505,26 +1528,116 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) { rc = send_back_passphrase (ctx, opt_data, pw); xfree (pw); + goto leave; } else if (opt_no_ask) - rc = gpg_error (GPG_ERR_NO_DATA); - else { - /* Note, that we only need to replace the + characters and - should leave the other escaping in place because the escaped - string is send verbatim to the pinentry which does the - unescaping (but not the + replacing) */ - if (errtext) - plus_to_blank (errtext); - if (prompt) - plus_to_blank (prompt); - if (desc) - plus_to_blank (desc); + rc = gpg_error (GPG_ERR_NO_DATA); + goto leave; + } + + /* Note, that we only need to replace the + characters and should + * leave the other escaping in place because the escaped string is + * send verbatim to the pinentry which does the unescaping (but not + * the + replacing) */ + if (errtext) + plus_to_blank (errtext); + if (prompt) + plus_to_blank (prompt); + if (desc) + plus_to_blank (desc); + if (opt_newsymkey) + { + /* We do not want to break any existing usage of this command + * and thus we introduced the option --newsymkey to make this + * command more useful to query the passphrase for symmetric + * encryption. */ + pi = gcry_calloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1); + if (!pi) + { + rc = gpg_error_from_syserror (); + goto leave; + } + pi2 = gcry_calloc_secure (1, sizeof (*pi2) + MAX_PASSPHRASE_LEN + 1); + if (!pi2) + { + rc = gpg_error_from_syserror (); + goto leave; + } + pi->max_length = MAX_PASSPHRASE_LEN + 1; + pi->max_tries = 3; + pi->with_qualitybar = opt_qualbar; + pi->with_repeat = opt_repeat; + pi2->max_length = MAX_PASSPHRASE_LEN + 1; + pi2->max_tries = 3; + pi2->check_cb = reenter_passphrase_cmp_cb; + pi2->check_cb_arg = pi->pin; + + for (;;) /* (degenerated for-loop) */ + { + xfree (response); + response = NULL; + rc = agent_get_passphrase (ctrl, &response, + desc, + prompt, + entry_errtext? entry_errtext:errtext, + opt_qualbar, cacheid, CACHE_MODE_USER, + pi); + if (rc) + goto leave; + xfree (entry_errtext); + entry_errtext = NULL; + /* We don't allow an empty passpharse in this mode. */ + if (check_passphrase_constraints (ctrl, pi->pin, 1, &entry_errtext)) + { + pi->failed_tries = 0; + pi2->failed_tries = 0; + continue; + } + if (*pi->pin && !pi->repeat_okay) + { + /* The passphrase is empty and the pinentry did not + * already run the repetition check, do it here. This + * is only called when using an old and simple pinentry. */ + xfree (response); + response = NULL; + rc = agent_get_passphrase (ctrl, &response, + L_("Please re-enter this passphrase"), + prompt, + entry_errtext? entry_errtext:errtext, + opt_qualbar, cacheid, CACHE_MODE_USER, + pi2); + if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE) + { /* The re-entered passphrase one did not match and + * the user did not hit cancel. */ + entry_errtext = xtrystrdup (L_("does not match - try again")); + if (!entry_errtext) + { + rc = gpg_error_from_syserror (); + goto leave; + } + continue; + } + } + break; + } + if (!rc && *pi->pin) + { + /* Return the passphrase. */ + if (cacheid) + agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, pi->pin, 0); + rc = send_back_passphrase (ctx, opt_data, pi->pin); + } + } + else + { next_try: + xfree (response); + response = NULL; rc = agent_get_passphrase (ctrl, &response, desc, prompt, entry_errtext? entry_errtext:errtext, - opt_qualbar, cacheid, CACHE_MODE_USER); + opt_qualbar, cacheid, CACHE_MODE_USER, NULL); xfree (entry_errtext); entry_errtext = NULL; if (!rc) @@ -1532,27 +1645,24 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) int i; if (opt_check - && check_passphrase_constraints (ctrl, response, &entry_errtext)) + && check_passphrase_constraints (ctrl, response,0,&entry_errtext)) { - xfree (response); goto next_try; } for (i = 0; i < opt_repeat; i++) { - char *response2; - if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) break; + xfree (response2); + response2 = NULL; rc = agent_get_passphrase (ctrl, &response2, desc2, prompt, errtext, 0, - cacheid, CACHE_MODE_USER); + cacheid, CACHE_MODE_USER, NULL); if (rc) break; if (strcmp (response2, response)) { - xfree (response2); - xfree (response); entry_errtext = try_percent_escape (_("does not match - try again"), NULL); if (!entry_errtext) @@ -1562,7 +1672,6 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) } goto next_try; } - xfree (response2); } if (!rc) { @@ -1570,10 +1679,15 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, response, 0); rc = send_back_passphrase (ctx, opt_data, response); } - xfree (response); } } + leave: + xfree (response); + xfree (response2); + xfree (entry_errtext); + xfree (pi2); + xfree (pi); return leave_cmd (ctx, rc); } @@ -3233,7 +3347,9 @@ command_has_option (const char *cmd, const char *cmdopt) if (!strcmp (cmd, "GET_PASSPHRASE")) { if (!strcmp (cmdopt, "repeat")) - return 1; + return 1; + if (!strcmp (cmdopt, "newsymkey")) + return 1; } return 0; diff --git a/agent/genkey.c b/agent/genkey.c index d5c80d0aa..b0aa47582 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -179,7 +179,7 @@ take_this_one_anyway (ctrl_t ctrl, const char *desc) message describing the problem is returned in *FAILED_CONSTRAINT. */ int -check_passphrase_constraints (ctrl_t ctrl, const char *pw, +check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty, char **failed_constraint) { gpg_error_t err = 0; @@ -198,7 +198,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, /* The first check is to warn about an empty passphrase. */ if (!*pw) { - const char *desc = (opt.enforce_passphrase_constraints? + const char *desc = (opt.enforce_passphrase_constraints || no_empty? L_("You have not entered a passphrase!%0A" "An empty passphrase is not allowed.") : L_("You have not entered a passphrase - " @@ -209,7 +209,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, err = 1; if (failed_constraint) { - if (opt.enforce_passphrase_constraints) + if (opt.enforce_passphrase_constraints || no_empty) *failed_constraint = xstrdup (desc); else err = take_this_one_anyway2 (ctrl, desc, @@ -399,7 +399,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, initial_errtext = NULL; if (!err) { - if (check_passphrase_constraints (ctrl, pi->pin, &initial_errtext)) + if (check_passphrase_constraints (ctrl, pi->pin, 0, &initial_errtext)) { pi->failed_tries = 0; pi2->failed_tries = 0; |