aboutsummaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
Diffstat (limited to 'agent')
-rw-r--r--agent/ChangeLog6
-rw-r--r--agent/agent.h1
-rw-r--r--agent/call-pinentry.c34
-rw-r--r--agent/findkey.c27
4 files changed, 67 insertions, 1 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog
index 1289ff33e..9a4a07fb7 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -1,3 +1,9 @@
+2006-10-19 Werner Koch <[email protected]>
+
+ * findkey.c (unprotect): Use it to avoid unnecessary calls to
+ agent_askpin.
+ * call-pinentry.c (pinentry_active_p): New.
+
2006-10-17 Werner Koch <[email protected]>
* Makefile.am (gpg_agent_LDADD): Link to libcommonpth.
diff --git a/agent/agent.h b/agent/agent.h
index cd5120721..6e02276b6 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -205,6 +205,7 @@ int agent_key_available (const unsigned char *grip);
void initialize_module_query (void);
void agent_query_dump_state (void);
void agent_reset_query (ctrl_t ctrl);
+int pinentry_active_p (ctrl_t ctrl, int waitseconds);
int agent_askpin (ctrl_t ctrl,
const char *desc_text, const char *prompt_text,
const char *inital_errtext,
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index cf0112833..7193db799 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -300,6 +300,40 @@ start_pinentry (ctrl_t ctrl)
return 0;
}
+/* Returns True is the pinentry is currently active. If WAITSECONDS is
+ greater than zero the function will wait for this many seconds
+ before returning. */
+int
+pinentry_active_p (ctrl_t ctrl, int waitseconds)
+{
+ if (waitseconds > 0)
+ {
+ pth_event_t evt;
+ int rc;
+
+ evt = pth_event (PTH_EVENT_TIME, pth_timeout (waitseconds, 0));
+ if (!pth_mutex_acquire (&entry_lock, 0, evt))
+ {
+ if (pth_event_occurred (evt))
+ rc = gpg_error (GPG_ERR_TIMEOUT);
+ else
+ rc = gpg_error (GPG_ERR_INTERNAL);
+ pth_event_free (evt, PTH_FREE_THIS);
+ return rc;
+ }
+ pth_event_free (evt, PTH_FREE_THIS);
+ }
+ else
+ {
+ if (!pth_mutex_acquire (&entry_lock, 1, NULL))
+ return gpg_error (GPG_ERR_LOCKED);
+ }
+
+ if (!pth_mutex_release (&entry_lock))
+ log_error ("failed to release the entry lock at %d\n", __LINE__);
+ return 0;
+}
+
static int
getpin_cb (void *opaque, const void *buffer, size_t length)
diff --git a/agent/findkey.c b/agent/findkey.c
index b32b22eda..2e9c2b957 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -30,6 +30,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>
+#include <pth.h> /* (we use pth_sleep) */
#include "agent.h"
@@ -41,7 +42,7 @@ struct try_unprotect_arg_s {
/* Write an S-expression formatted key to our key storage. With FORCE
- pased as true an existsing key with the given GRIP will get
+ pased as true an existing key with the given GRIP will get
overwritten. */
int
agent_write_private_key (const unsigned char *grip,
@@ -253,6 +254,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
void *cache_marker;
const char *pw;
+ retry:
pw = agent_get_cache (hexgrip, cache_mode, &cache_marker);
if (pw)
{
@@ -266,6 +268,29 @@ unprotect (ctrl_t ctrl, const char *desc_text,
}
rc = 0;
}
+
+ /* If the pinentry is currently in use, we wait up to 60 seconds
+ for it close and check the cache again. This solves a common
+ situation where several requests for unprotecting a key have
+ been made but the user is still entering the passphrase for
+ the first request. Because all requests to agent_askpin are
+ serialized they would then pop up one after the other to
+ request the passphrase - despite that the user has already
+ entered it and is then available in the cache. This
+ implementation is not race free but in the worst case the
+ user has to enter the passphrase only once more. */
+ if (pinentry_active_p (ctrl, 0))
+ {
+ /* Active - wait */
+ if (!pinentry_active_p (ctrl, 60))
+ {
+ /* We need to give the other thread a chance to actually put
+ it into the cache. */
+ pth_sleep (1);
+ goto retry;
+ }
+ /* Timeout - better call pinentry now the plain way. */
+ }
}
pi = gcry_calloc_secure (1, sizeof (*pi) + 100);