mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
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 <wk@gnupg.org> Backported-from-master: eace4bbe1ded8b01f9ad52ebc1871f2fd13c3a08
This commit is contained in:
parent
7b6071a45f
commit
d9e2dfa4c5
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
170
agent/command.c
170
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);
|
||||
{
|
||||
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
|
||||
{
|
||||
/* 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);
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user