aboutsummaryrefslogtreecommitdiffstats
path: root/agent/call-pinentry.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/call-pinentry.c')
-rw-r--r--agent/call-pinentry.c156
1 files changed, 84 insertions, 72 deletions
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index 34dde3744..a895a8b8f 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -24,7 +24,6 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
-#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#ifndef HAVE_W32_SYSTEM
@@ -424,7 +423,17 @@ start_pinentry (ctrl_t ctrl)
opt.no_grab? "OPTION no-grab":"OPTION grab",
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
- return unlock_pinentry (ctrl, rc);
+ {
+ if (gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED
+ || gpg_err_code (rc) == GPG_ERR_UNKNOWN_OPTION)
+ {
+ if (opt.verbose)
+ log_info ("Option no-grab/grab is ignored by pinentry.\n");
+ /* Keep going even if the feature is not supported. */
+ }
+ else
+ return unlock_pinentry (ctrl, rc);
+ }
value = session_env_getenv (ctrl->session_env, "GPG_TTY");
if (value)
@@ -439,7 +448,7 @@ start_pinentry (ctrl_t ctrl)
return unlock_pinentry (ctrl, rc);
}
value = session_env_getenv (ctrl->session_env, "TERM");
- if (value)
+ if (value && *value)
{
char *optstr;
if (asprintf (&optstr, "OPTION ttytype=%s", value) < 0 )
@@ -949,15 +958,14 @@ build_cmd_setdesc (char *line, size_t linelen, const char *desc)
static void *
watch_sock (void *arg)
{
- gnupg_fd_t *p = (gnupg_fd_t *)arg;
pid_t pid = assuan_get_pid (entry_ctx);
while (1)
{
int err;
- gnupg_fd_t sock = *p;
fd_set fdset;
struct timeval timeout = { 0, 500000 };
+ gnupg_fd_t sock = *(gnupg_fd_t *)arg;
if (sock == GNUPG_INVALID_FD)
return NULL;
@@ -995,18 +1003,11 @@ watch_sock (void *arg)
}
-/* Ask pinentry to get a pin by "GETPIN" command, spawning a thread
- detecting the socket's EOF.
- */
static gpg_error_t
-do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
+watch_sock_start (gnupg_fd_t *sock_p, npth_t *thread_p)
{
npth_attr_t tattr;
- gpg_error_t rc;
int err;
- npth_t thread;
- int saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
- gnupg_fd_t sock_watched = ctrl->thread_startup.fd;
err = npth_attr_init (&tattr);
if (err)
@@ -1016,7 +1017,7 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
}
npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
- err = npth_create (&thread, &tattr, watch_sock, (void *)&sock_watched);
+ err = npth_create (thread_p, &tattr, watch_sock, sock_p);
npth_attr_destroy (&tattr);
if (err)
{
@@ -1024,6 +1025,36 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
return gpg_error_from_errno (err);
}
+ return 0;
+}
+
+static void
+watch_sock_end (gnupg_fd_t *sock_p, npth_t *thread_p)
+{
+ int err;
+
+ *sock_p = GNUPG_INVALID_FD;
+ err = npth_join (*thread_p, NULL);
+ if (err)
+ log_error ("watch_sock_end: error joining thread: %s\n", strerror (err));
+}
+
+
+/* Ask pinentry to get a pin by "GETPIN" command, spawning a thread
+ detecting the socket's EOF.
+ */
+static gpg_error_t
+do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
+{
+ gpg_error_t rc;
+ int saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
+ gnupg_fd_t sock_watched = ctrl->thread_startup.fd;
+ npth_t thread;
+
+ rc = watch_sock_start (&sock_watched, &thread);
+ if (rc)
+ return rc;
+
assuan_begin_confidential (entry_ctx);
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, parm,
inq_quality, entry_ctx,
@@ -1040,10 +1071,7 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
&& gpg_err_code (rc) == GPG_ERR_CANCELED)
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
- sock_watched = GNUPG_INVALID_FD;
- err = npth_join (thread, NULL);
- if (err)
- log_error ("do_getpin: error joining thread: %s\n", strerror (err));
+ watch_sock_end (&sock_watched, &thread);
return rc;
}
@@ -1392,6 +1420,9 @@ agent_get_confirmation (ctrl_t ctrl,
if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
return gpg_error (GPG_ERR_CANCELED);
+ if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
+ return pinentry_loopback_confirm (ctrl, desc, 1, ok, notok);
+
return gpg_error (GPG_ERR_NO_PIN_ENTRY);
}
@@ -1445,70 +1476,38 @@ agent_get_confirmation (ctrl_t ctrl,
return unlock_pinentry (ctrl, rc);
}
- rc = assuan_transact (entry_ctx, "CONFIRM",
- NULL, NULL, NULL, NULL, NULL, NULL);
- 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 (ctrl, rc);
-}
-
-
-
-/* Pop up the PINentry, display the text DESC and a button with the
- text OK_BTN (which may be NULL to use the default of "OK") and wait
- for the user to hit this button. The return value is not
- relevant. */
-int
-agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
-{
- int rc;
- char line[ASSUAN_LINELENGTH];
+ {
+ gnupg_fd_t sock_watched = ctrl->thread_startup.fd;
+ npth_t thread;
- if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
- return gpg_error (GPG_ERR_CANCELED);
+ rc = watch_sock_start (&sock_watched, &thread);
+ if (rc)
+ return rc;
- rc = start_pinentry (ctrl);
- if (rc)
- return rc;
+ rc = assuan_transact (entry_ctx, "CONFIRM",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ 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);
- if (desc)
- build_cmd_setdesc (line, DIM(line), desc);
- else
- snprintf (line, DIM(line), "RESET");
- rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- /* Most pinentries out in the wild return the old Assuan error code
- for canceled which gets translated to an assuan Cancel error and
- not to the code for a user cancel. Fix this here. */
- 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);
+ watch_sock_end (&sock_watched, &thread);
- if (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 (ctrl, rc);
- }
-
- rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL,
- NULL, NULL, NULL);
- 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 (ctrl, rc);
+ }
}
+
/* The thread running the popup message. */
static void *
popup_message_thread (void *arg)
{
- (void)arg;
+ gpg_error_t rc;
+ gnupg_fd_t sock_watched = *(gnupg_fd_t *)arg;
+ npth_t thread;
+
+ rc = watch_sock_start (&sock_watched, &thread);
+ if (rc)
+ return NULL;
/* We use the --one-button hack instead of the MESSAGE command to
allow the use of old Pinentries. Those old Pinentries will then
@@ -1516,6 +1515,7 @@ popup_message_thread (void *arg)
annoyance. */
assuan_transact (entry_ctx, "CONFIRM --one-button",
NULL, NULL, NULL, NULL, NULL, NULL);
+ watch_sock_end (&sock_watched, &thread);
popup_finished = 1;
return NULL;
}
@@ -1536,7 +1536,15 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
int err;
if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
- return gpg_error (GPG_ERR_CANCELED);
+ {
+ if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
+ return gpg_error (GPG_ERR_CANCELED);
+
+ if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
+ return pinentry_loopback_confirm (ctrl, desc, 0, ok_btn, NULL);
+
+ return gpg_error (GPG_ERR_NO_PIN_ENTRY);
+ }
rc = start_pinentry (ctrl);
if (rc)
@@ -1564,7 +1572,8 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
popup_finished = 0;
- err = npth_create (&popup_tid, &tattr, popup_message_thread, NULL);
+ err = npth_create (&popup_tid, &tattr, popup_message_thread,
+ &ctrl->thread_startup.fd);
npth_attr_destroy (&tattr);
if (err)
{
@@ -1587,6 +1596,9 @@ agent_popup_message_stop (ctrl_t ctrl)
(void)ctrl;
+ if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
+ return;
+
if (!popup_tid || !entry_ctx)
{
log_debug ("agent_popup_message_stop called with no active popup\n");