diff options
Diffstat (limited to 'agent')
-rw-r--r-- | agent/ChangeLog | 6 | ||||
-rw-r--r-- | agent/agent.h | 1 | ||||
-rw-r--r-- | agent/call-pinentry.c | 34 | ||||
-rw-r--r-- | agent/findkey.c | 27 |
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); |