Fix regression with gpgsm 2.0 due to "OPTION with-secret".

* src/engine-gpgsm.c (gpgsm_assuan_simple_command): Do not terminate
on a status lines.
--

This bug has been with us since the support for gpgsm: If there is no
status line handler but a status line is received anyway the command
handling loop terminates and thus the command/answer order gets out of
sync.  In the case of the bug report this is triggered by sending an
option which starts the agent and that starting emits a "PROGRESS"
status line.

The solution is not to stop reading after a status line but record a
possible error code and return that only after OK or ERR.

GnuPG-bug-id: 1795
Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2015-06-08 12:34:49 +02:00
parent 7addffc082
commit ddbd54ef88
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B

View File

@ -564,7 +564,7 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd,
engine_status_handler_t status_fnc, engine_status_handler_t status_fnc,
void *status_fnc_value) void *status_fnc_value)
{ {
gpg_error_t err; gpg_error_t err, cb_err;
char *line; char *line;
size_t linelen; size_t linelen;
@ -572,6 +572,7 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd,
if (err) if (err)
return err; return err;
cb_err = 0;
do do
{ {
err = assuan_read_line (ctx, &line, &linelen); err = assuan_read_line (ctx, &line, &linelen);
@ -584,32 +585,45 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd,
if (linelen >= 2 if (linelen >= 2
&& line[0] == 'O' && line[1] == 'K' && line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\0' || line[2] == ' ')) && (line[2] == '\0' || line[2] == ' '))
return 0; return cb_err;
else if (linelen >= 4 else if (linelen >= 4
&& line[0] == 'E' && line[1] == 'R' && line[2] == 'R' && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
&& line[3] == ' ') && line[3] == ' ')
err = atoi (&line[4]); {
/* We prefer a callback generated error because that one is
more related to gpgme and thus probably more important
than the error returned by the engine. */
err = cb_err? cb_err : atoi (&line[4]);
}
else if (linelen >= 2 else if (linelen >= 2
&& line[0] == 'S' && line[1] == ' ') && line[0] == 'S' && line[1] == ' ')
{ {
char *rest; /* After an error from a status callback we skip all further
gpgme_status_code_t r; status lines. */
if (!cb_err)
{
char *rest;
gpgme_status_code_t r;
rest = strchr (line + 2, ' '); rest = strchr (line + 2, ' ');
if (!rest) if (!rest)
rest = line + linelen; /* set to an empty string */ rest = line + linelen; /* set to an empty string */
else else
*(rest++) = 0; *(rest++) = 0;
r = _gpgme_parse_status (line + 2); r = _gpgme_parse_status (line + 2);
if (r >= 0 && status_fnc) if (r >= 0 && status_fnc)
err = status_fnc (status_fnc_value, r, rest); cb_err = status_fnc (status_fnc_value, r, rest);
else }
err = gpg_error (GPG_ERR_GENERAL);
} }
else else
err = gpg_error (GPG_ERR_GENERAL); {
/* Invalid line or INQUIRY. We can't do anything else than
to stop. As with ERR we prefer a status callback
generated error code, though. */
err = cb_err ? cb_err : gpg_error (GPG_ERR_GENERAL);
}
} }
while (!err); while (!err);