From ddbd54ef881bd2c3481d62b89bef7241667b64ee Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 12:34:49 +0200 Subject: [PATCH] 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 --- src/engine-gpgsm.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 3a837577..ac6c5fc6 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -564,7 +564,7 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, engine_status_handler_t status_fnc, void *status_fnc_value) { - gpg_error_t err; + gpg_error_t err, cb_err; char *line; size_t linelen; @@ -572,6 +572,7 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, if (err) return err; + cb_err = 0; do { err = assuan_read_line (ctx, &line, &linelen); @@ -584,32 +585,45 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, if (linelen >= 2 && line[0] == 'O' && line[1] == 'K' && (line[2] == '\0' || line[2] == ' ')) - return 0; + return cb_err; else if (linelen >= 4 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' && 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 && line[0] == 'S' && line[1] == ' ') { - char *rest; - gpgme_status_code_t r; + /* After an error from a status callback we skip all further + status lines. */ + if (!cb_err) + { + char *rest; + gpgme_status_code_t r; - rest = strchr (line + 2, ' '); - if (!rest) - rest = line + linelen; /* set to an empty string */ - else - *(rest++) = 0; + rest = strchr (line + 2, ' '); + if (!rest) + rest = line + linelen; /* set to an empty string */ + else + *(rest++) = 0; - r = _gpgme_parse_status (line + 2); + r = _gpgme_parse_status (line + 2); - if (r >= 0 && status_fnc) - err = status_fnc (status_fnc_value, r, rest); - else - err = gpg_error (GPG_ERR_GENERAL); + if (r >= 0 && status_fnc) + cb_err = status_fnc (status_fnc_value, r, rest); + } } 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);