diff options
Diffstat (limited to 'agent/call-pinentry.c')
-rw-r--r-- | agent/call-pinentry.c | 156 |
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"); |