diff options
Diffstat (limited to 'agent/call-pinentry.c')
-rw-r--r-- | agent/call-pinentry.c | 149 |
1 files changed, 77 insertions, 72 deletions
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 6a5c1fe1e..af4eb06f2 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -67,12 +67,6 @@ static struct } entry_features; -/* The control variable of the connection owning the current pinentry. - This is only valid if ENTRY_CTX is not NULL. Note, that we care - only about the value of the pointer and that it should never be - dereferenced. */ -static ctrl_t entry_owner; - /* A mutex used to serialize access to the pinentry. */ static npth_mutex_t entry_lock; @@ -128,7 +122,7 @@ agent_query_dump_state (void) void agent_reset_query (ctrl_t ctrl) { - if (entry_ctx && popup_tid && entry_owner == ctrl) + if (entry_ctx && popup_tid && ctrl->pinentry_active) { agent_popup_message_stop (ctrl); } @@ -140,7 +134,7 @@ agent_reset_query (ctrl_t ctrl) stalled pinentry does not block other threads. Fixme: We should have a timeout in Assuan for the disconnect operation. */ static gpg_error_t -unlock_pinentry (gpg_error_t rc) +unlock_pinentry (ctrl_t ctrl, gpg_error_t rc) { assuan_context_t ctx = entry_ctx; int err; @@ -177,15 +171,18 @@ unlock_pinentry (gpg_error_t rc) } } - entry_ctx = NULL; - err = npth_mutex_unlock (&entry_lock); - if (err) + if (--ctrl->pinentry_active == 0) { - log_error ("failed to release the entry lock: %s\n", strerror (err)); - if (!rc) - rc = gpg_error_from_errno (err); + entry_ctx = NULL; + err = npth_mutex_unlock (&entry_lock); + if (err) + { + log_error ("failed to release the entry lock: %s\n", strerror (err)); + if (!rc) + rc = gpg_error_from_errno (err); + } + assuan_release (ctx); } - assuan_release (ctx); return rc; } @@ -288,6 +285,14 @@ start_pinentry (ctrl_t ctrl) char *flavor_version; int err; + if (ctrl->pinentry_active) + { + /* It's trying to use pinentry recursively. In this situation, + the thread holds ENTRY_LOCK already. */ + ctrl->pinentry_active++; + return 0; + } + npth_clock_gettime (&abstime); abstime.tv_sec += LOCK_TIMEOUT; err = npth_mutex_timedlock (&entry_lock, &abstime); @@ -302,8 +307,6 @@ start_pinentry (ctrl_t ctrl) return rc; } - entry_owner = ctrl; - if (entry_ctx) return 0; @@ -325,7 +328,7 @@ start_pinentry (ctrl_t ctrl) the Wine implementation does not flush stdin,stdout and stderr - see above. Let's try to ignore the error. */ #ifndef HAVE_W32_SYSTEM - return unlock_pinentry (tmperr); + return unlock_pinentry (ctrl, tmperr); #endif } @@ -371,6 +374,10 @@ start_pinentry (ctrl_t ctrl) log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc)); return rc; } + + ctrl->pinentry_active = 1; + entry_ctx = ctx; + /* We don't want to log the pinentry communication to make the logs easier to read. We might want to add a new debug option to enable pinentry logging. */ @@ -382,17 +389,15 @@ start_pinentry (ctrl_t ctrl) that atfork is used to change the environment for pinentry. We start the server in detached mode to suppress the console window under Windows. */ - rc = assuan_pipe_connect (ctx, full_pgmname, argv, + rc = assuan_pipe_connect (entry_ctx, full_pgmname, argv, no_close_list, atfork_cb, ctrl, ASSUAN_PIPE_CONNECT_DETACHED); if (rc) { log_error ("can't connect to the PIN entry module '%s': %s\n", full_pgmname, gpg_strerror (rc)); - assuan_release (ctx); - return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY)); + return unlock_pinentry (ctrl, gpg_error (GPG_ERR_NO_PIN_ENTRY)); } - entry_ctx = ctx; if (DBG_IPC) log_debug ("connection to PIN entry established\n"); @@ -402,65 +407,65 @@ start_pinentry (ctrl_t ctrl) { char *optstr; if (asprintf (&optstr, "OPTION pinentry-user-data=%s", value) < 0 ) - return unlock_pinentry (out_of_core ()); + return unlock_pinentry (ctrl, out_of_core ()); rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); xfree (optstr); if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } rc = assuan_transact (entry_ctx, opt.no_grab? "OPTION no-grab":"OPTION grab", NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); value = session_env_getenv (ctrl->session_env, "GPG_TTY"); if (value) { char *optstr; if (asprintf (&optstr, "OPTION ttyname=%s", value) < 0 ) - return unlock_pinentry (out_of_core ()); + return unlock_pinentry (ctrl, out_of_core ()); rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); xfree (optstr); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } value = session_env_getenv (ctrl->session_env, "TERM"); if (value) { char *optstr; if (asprintf (&optstr, "OPTION ttytype=%s", value) < 0 ) - return unlock_pinentry (out_of_core ()); + return unlock_pinentry (ctrl, out_of_core ()); rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); xfree (optstr); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } if (ctrl->lc_ctype) { char *optstr; if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 ) - return unlock_pinentry (out_of_core ()); + return unlock_pinentry (ctrl, out_of_core ()); rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); xfree (optstr); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } if (ctrl->lc_messages) { char *optstr; if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 ) - return unlock_pinentry (out_of_core ()); + return unlock_pinentry (ctrl, out_of_core ()); rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); xfree (optstr); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } @@ -476,7 +481,7 @@ start_pinentry (ctrl_t ctrl) rc = assuan_transact (entry_ctx, "OPTION allow-external-password-cache", NULL, NULL, NULL, NULL, NULL, NULL); if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } if (opt.allow_emacs_pinentry) @@ -486,7 +491,7 @@ start_pinentry (ctrl_t ctrl) rc = assuan_transact (entry_ctx, "OPTION allow-emacs-prompt", NULL, NULL, NULL, NULL, NULL, NULL); if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } @@ -524,7 +529,7 @@ start_pinentry (ctrl_t ctrl) if (*s == '|' && (s2=strchr (s+1,'|'))) s = s2+1; if (asprintf (&optstr, "OPTION default-%s=%s", tbl[idx].key, s) < 0 ) - return unlock_pinentry (out_of_core ()); + return unlock_pinentry (ctrl, out_of_core ()); assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); xfree (optstr); @@ -593,8 +598,9 @@ start_pinentry (ctrl_t ctrl) nodename = utsbuf.nodename; #endif /*!HAVE_W32_SYSTEM*/ - if ((optstr = xtryasprintf ("OPTION owner=%lu %s", - ctrl->client_pid, nodename))) + if ((optstr = xtryasprintf ("OPTION owner=%lu/%d %s", + ctrl->client_pid, ctrl->client_uid, + nodename))) { assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); @@ -651,8 +657,8 @@ start_pinentry (ctrl_t ctrl) rc = agent_inq_pinentry_launched (ctrl, pinentry_pid, flavor_version); if (gpg_err_code (rc) == GPG_ERR_CANCELED || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) - return unlock_pinentry (gpg_err_make (GPG_ERR_SOURCE_DEFAULT, - gpg_err_code (rc))); + return unlock_pinentry (ctrl, gpg_err_make (GPG_ERR_SOURCE_DEFAULT, + gpg_err_code (rc))); rc = 0; } @@ -1022,18 +1028,18 @@ agent_askpin (ctrl_t ctrl, rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); build_cmd_setdesc (line, DIM(line), desc_text); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); snprintf (line, DIM(line), "SETPROMPT %s", prompt_text? prompt_text : is_pin? L_("PIN:") : L_("Passphrase:")); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); /* If a passphrase quality indicator has been requested and a minimum passphrase length has not been disabled, send the command @@ -1042,7 +1048,7 @@ agent_askpin (ctrl_t ctrl, { rc = setup_qualitybar (ctrl); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } if (initial_errtext) @@ -1051,7 +1057,7 @@ agent_askpin (ctrl_t ctrl, rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } if (pininfo->with_repeat) @@ -1082,7 +1088,7 @@ agent_askpin (ctrl_t ctrl, rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); errtext = NULL; } @@ -1092,7 +1098,7 @@ agent_askpin (ctrl_t ctrl, rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); @@ -1120,7 +1126,7 @@ agent_askpin (ctrl_t ctrl, errtext = is_pin? L_("PIN too long") : L_("Passphrase too long"); else if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); if (!errtext && pininfo->min_digits) { @@ -1146,7 +1152,7 @@ agent_askpin (ctrl_t ctrl, || gpg_err_code (rc) == GPG_ERR_BAD_PIN) errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase")); else if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } if (!errtext) @@ -1154,7 +1160,7 @@ agent_askpin (ctrl_t ctrl, if (pininfo->with_repeat && (pinentry_status & PINENTRY_STATUS_PIN_REPEATED)) pininfo->repeat_okay = 1; - return unlock_pinentry (0); /* okay, got a PIN or passphrase */ + return unlock_pinentry (ctrl, 0); /* okay, got a PIN or passphrase */ } if ((pinentry_status & PINENTRY_STATUS_PASSWORD_FROM_CACHE)) @@ -1163,7 +1169,7 @@ agent_askpin (ctrl_t ctrl, pininfo->failed_tries --; } - return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN + return unlock_pinentry (ctrl, gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN : GPG_ERR_BAD_PASSPHRASE)); } @@ -1229,7 +1235,7 @@ agent_get_passphrase (ctrl_t ctrl, rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); if (desc) @@ -1238,18 +1244,18 @@ agent_get_passphrase (ctrl_t ctrl, snprintf (line, DIM(line), "RESET"); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); snprintf (line, DIM(line), "SETPROMPT %s", prompt); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); if (with_qualitybar && opt.min_passphrase_len) { rc = setup_qualitybar (ctrl); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } if (errtext) @@ -1257,14 +1263,14 @@ agent_get_passphrase (ctrl_t ctrl, snprintf (line, DIM(line), "SETERROR %s", errtext); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } memset (&parm, 0, sizeof parm); parm.size = ASSUAN_LINELENGTH/2 - 5; parm.buffer = gcry_malloc_secure (parm.size+10); if (!parm.buffer) - return unlock_pinentry (out_of_core ()); + return unlock_pinentry (ctrl, out_of_core ()); saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); assuan_begin_confidential (entry_ctx); @@ -1288,7 +1294,7 @@ agent_get_passphrase (ctrl_t ctrl, xfree (parm.buffer); else *retpass = parm.buffer; - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } @@ -1332,7 +1338,7 @@ agent_get_confirmation (ctrl_t ctrl, rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); if (ok) { @@ -1340,7 +1346,7 @@ agent_get_confirmation (ctrl_t ctrl, rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } if (notok) { @@ -1363,7 +1369,7 @@ agent_get_confirmation (ctrl_t ctrl, NULL, NULL, NULL, NULL, NULL, NULL); } if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } rc = assuan_transact (entry_ctx, "CONFIRM", @@ -1371,7 +1377,7 @@ agent_get_confirmation (ctrl_t ctrl, if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } @@ -1405,7 +1411,7 @@ agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); if (ok_btn) { @@ -1413,7 +1419,7 @@ agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn) rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL, @@ -1421,7 +1427,7 @@ agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn) if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } @@ -1469,19 +1475,19 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn) snprintf (line, DIM(line), "RESET"); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); if (ok_btn) { snprintf (line, DIM(line), "SETOK %s", ok_btn); rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL); if (rc) - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } err = npth_attr_init (&tattr); if (err) - return unlock_pinentry (gpg_error_from_errno (err)); + return unlock_pinentry (ctrl, gpg_error_from_errno (err)); npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE); popup_finished = 0; @@ -1492,7 +1498,7 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn) rc = gpg_error_from_errno (err); log_error ("error spawning popup message handler: %s\n", strerror (err) ); - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } npth_setname_np (popup_tid, "popup-message"); @@ -1551,10 +1557,9 @@ agent_popup_message_stop (ctrl_t ctrl) /* Thread IDs are opaque, but we try our best here by resetting it to the same content that a static global variable has. */ memset (&popup_tid, '\0', sizeof (popup_tid)); - entry_owner = NULL; /* Now we can close the connection. */ - unlock_pinentry (0); + unlock_pinentry (ctrl, 0); } int @@ -1580,5 +1585,5 @@ agent_clear_passphrase (ctrl_t ctrl, rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); - return unlock_pinentry (rc); + return unlock_pinentry (ctrl, rc); } |