[PINENTRY PATCH 8/8] gnome3: Honor timeout.
Daniel Kahn Gillmor
dkg at fifthhorseman.net
Fri Nov 4 23:57:52 CET 2016
* gnome3/pinentry-gnome3.c (create_prompt): Use timeout to determine
how long to wait for Gcr to provide a system prompt before giving up.
(_gcr_timeout_done): New. Record that a timeout has elapsed.
(gnome3_cmd_handler): Set up a timeout before launching the prompt,
and tear it down afterward.
(_gcr_prompt_password_done): Report timeout differently from normal
cancellation.
(_gcr_prompt_confirm_done): Report timeout differently from normal
cancellation.
--
Without this change, pinentry-gnome3 does not respect the timeout
parameter at all, and can hang indefinitely in the event that the
system prompter is locked or the user is ignoring the session.
Signed-off-by: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
---
gnome3/pinentry-gnome3.c | 75 +++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 65 insertions(+), 10 deletions(-)
diff --git a/gnome3/pinentry-gnome3.c b/gnome3/pinentry-gnome3.c
index 06c2076..148ef65 100644
--- a/gnome3/pinentry-gnome3.c
+++ b/gnome3/pinentry-gnome3.c
@@ -74,6 +74,8 @@ struct _gnome3_run {
GcrPrompt *prompt;
GMainLoop *main_loop;
int ret;
+ guint timeout_id;
+ int timed_out;
};
static void
@@ -82,6 +84,9 @@ _gcr_prompt_password_done (GObject *source_object, GAsyncResult *res, gpointer u
static void
_gcr_prompt_confirm_done (GObject *source_object, GAsyncResult *res, gpointer user_data);
+static gboolean
+_gcr_timeout_done (gpointer user_data);
+
static void
_propagate_g_error_to_pinentry (pinentry_t pe, GError *error, gpg_err_code_t code, const char *loc)
{
@@ -102,11 +107,25 @@ create_prompt (pinentry_t pe, int confirm)
char window_id[32];
/* Create the prompt. */
- prompt = GCR_PROMPT (gcr_system_prompt_open (-1, NULL, &error));
+ prompt = GCR_PROMPT (gcr_system_prompt_open (pe->timeout ? pe->timeout : -1, NULL, &error));
if (! prompt)
{
- _propagate_g_error_to_pinentry (pe, error, GPG_ERR_CONFIGURATION,
- "gcr_system_prompt_open");
+ /* this means the timeout elapsed, but no prompt was ever shown. */
+ if (error->code == GCR_SYSTEM_PROMPT_IN_PROGRESS)
+ {
+ fprintf (stderr, "Timeout: the Gcr system prompter was already in use.\n");
+ pe->specific_err_info = strdup ("Timeout: the Gcr system prompter was already in use.");
+ /* not using GPG_ERR_TIMEOUT here because the user never saw
+ a prompt: */
+ pe->specific_err = gpg_error (GPG_ERR_PIN_ENTRY);
+ }
+ else
+ {
+ fprintf (stderr, "couldn't create prompt for gnupg passphrase: %s\n",
+ error->message);
+ _propagate_g_error_to_pinentry (pe, error, GPG_ERR_CONFIGURATION,
+ "gcr_system_prompt_open");
+ }
g_error_free (error);
return NULL;
}
@@ -207,6 +226,8 @@ gnome3_cmd_handler (pinentry_t pe)
}
state.pinentry = pe;
state.ret = 0;
+ state.timeout_id = 0;
+ state.timed_out = 0;
state.prompt = create_prompt (pe, !!(pe->pin));
if (!state.prompt)
{
@@ -218,9 +239,13 @@ gnome3_cmd_handler (pinentry_t pe)
else
gcr_prompt_confirm_async (state.prompt, NULL, _gcr_prompt_confirm_done, &state);
+ if (pe->timeout)
+ state.timeout_id = g_timeout_add_seconds (pe->timeout, _gcr_timeout_done, &state);
g_main_loop_run (state.main_loop);
/* clean up state: */
+ if (state.timeout_id && !state.timed_out)
+ g_source_destroy (g_main_context_find_source_by_id (NULL, state.timeout_id));
g_clear_object (&state.prompt);
g_main_loop_unref (state.main_loop);
return state.ret;
@@ -243,17 +268,23 @@ _gcr_prompt_password_done (GObject *source_object, GAsyncResult *res, gpointer u
/* "The returned password is valid until the next time a method
is called to display another prompt." */
password = gcr_prompt_password_finish (prompt, res, &error);
- if (error)
- /* Error. */
+ if ((! password && ! error) ||
+ (error && error->code == G_IO_ERROR_CANCELLED))
+ {
+ /* operation was cancelled or timed out. */
+ ret = -1;
+ if (state->timed_out)
+ state->pinentry->specific_err = gpg_error (GPG_ERR_TIMEOUT);
+ if (error)
+ g_error_free (error);
+ }
+ else if (error)
{
_propagate_g_error_to_pinentry (state->pinentry, error, GPG_ERR_PIN_ENTRY,
"gcr_system_password_finish");
g_error_free (error);
ret = -1;
}
- else if (! password && ! error)
- /* User cancelled the operation. */
- ret = -1;
else
{
pinentry_setbufferlen (pe, strlen (password) + 1);
@@ -295,8 +326,16 @@ _gcr_prompt_confirm_done (GObject *source_object, GAsyncResult *res, gpointer us
reply = gcr_prompt_confirm_finish (prompt, res, &error);
if (error)
{
- _propagate_g_error_to_pinentry (state->pinentry, error, GPG_ERR_PIN_ENTRY,
- "gcr_system_confirm_finish");
+ if (error->code == G_IO_ERROR_CANCELLED)
+ {
+ pe->canceled = 1;
+ if (state->timed_out)
+ state->pinentry->specific_err = gpg_error (GPG_ERR_TIMEOUT);
+ }
+ else
+ _propagate_g_error_to_pinentry (state->pinentry, error, GPG_ERR_PIN_ENTRY,
+ "gcr_system_confirm_finish");
+ g_error_free (error);
ret = 0;
}
else if (reply == GCR_PROMPT_REPLY_CONTINUE
@@ -309,6 +348,8 @@ _gcr_prompt_confirm_done (GObject *source_object, GAsyncResult *res, gpointer us
/* GCR_PROMPT_REPLY_CANCEL */
{
pe->canceled = 1;
+ if (state->timed_out)
+ state->pinentry->specific_err = gpg_error (GPG_ERR_TIMEOUT);
ret = 0;
}
state->ret = ret;
@@ -318,6 +359,20 @@ _gcr_prompt_confirm_done (GObject *source_object, GAsyncResult *res, gpointer us
g_main_loop_quit (state->main_loop);
}
+static gboolean
+_gcr_timeout_done (gpointer user_data)
+{
+ struct _gnome3_run *state = (struct _gnome3_run *) user_data;
+
+ if (!state)
+ return FALSE;
+
+ state->timed_out = 1;
+ gcr_prompt_close (state->prompt);
+
+ return FALSE;
+}
+
pinentry_cmd_handler_t pinentry_cmd_handler = gnome3_cmd_handler;
int
--
2.10.1
More information about the Gnupg-devel
mailing list