summaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2023-08-24 09:07:26 +0200
committerNIIBE Yutaka <gniibe@fsij.org>2023-08-24 09:07:26 +0200
commit716e59b0b62888776706472e69ee595e00a2e010 (patch)
treedf2d0463594886ba335feb38390723c03e948a5d /agent
parenttpm2d: Fix call to assuan_control. (diff)
downloadgnupg2-716e59b0b62888776706472e69ee595e00a2e010.tar.xz
gnupg2-716e59b0b62888776706472e69ee595e00a2e010.zip
agent: Add agent_kick_the_loop function.
* agent/agent.h (agent_kick_the_loop): New. * agent/gpg-agent.c [HAVE_W32_SYSTEM] (the_event2): New. [HAVE_PSELECT_NO_EINTR] (event_pipe_fd): New. [!HAVE_PSELECT_NO_EINTR] (main_thread_pid): New. (create_an_event): New, factored out. (get_agent_daemon_notify_event): Use create_an_event. (handle_signal): Add a case for SIGCONT. (agent_kick_the_loop): New. (handle_connections): Call pselect possibly with the pipe. Call eselect with THE_EVENT2. -- GnuPG-bug-id: 6682 Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
Diffstat (limited to 'agent')
-rw-r--r--agent/agent.h1
-rw-r--r--agent/gpg-agent.c150
2 files changed, 117 insertions, 34 deletions
diff --git a/agent/agent.h b/agent/agent.h
index 531fad210..69a1d5ff5 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -411,6 +411,7 @@ void *get_agent_daemon_notify_event (void);
#endif
void agent_sighup_action (void);
int map_pk_openpgp_to_gcry (int openpgp_algo);
+void agent_kick_the_loop (void);
/*-- command.c --*/
gpg_error_t agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid,
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 9df0facbe..dd38528bb 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -432,6 +432,17 @@ static assuan_sock_nonce_t socket_nonce_ssh;
* Let's try this as default. Change at runtime with --listen-backlog. */
static int listen_backlog = 64;
+#ifdef HAVE_W32_SYSTEM
+/* The event to break the select call. */
+static HANDLE the_event2;
+#elif defined(HAVE_PSELECT_NO_EINTR)
+/* An FD to break the select call. */
+static int event_pipe_fd;
+#else
+/* PID of the main thread. */
+static pid_t main_thread_pid;
+#endif
+
/* Default values for options passed to the pinentry. */
static char *default_display;
static char *default_ttyname;
@@ -2130,39 +2141,45 @@ get_agent_active_connection_count (void)
notification event. Calling it the first time creates that
event. */
#if defined(HAVE_W32_SYSTEM)
+static void *
+create_an_event (void)
+{
+ HANDLE h, h2;
+ SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
+
+ /* We need to use a manual reset event object due to the way our
+ w32-pth wait function works: If we would use an automatic
+ reset event we are not able to figure out which handle has
+ been signaled because at the time we single out the signaled
+ handles using WFSO the event has already been reset due to
+ the WFMO. */
+ h = CreateEvent (&sa, TRUE, FALSE, NULL);
+ if (!h)
+ log_error ("can't create an event: %s\n", w32_strerror (-1) );
+ else if (!DuplicateHandle (GetCurrentProcess(), h,
+ GetCurrentProcess(), &h2,
+ EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
+ {
+ log_error ("setting synchronize for an event failed: %s\n",
+ w32_strerror (-1) );
+ CloseHandle (h);
+ }
+ else
+ {
+ CloseHandle (h);
+ return h2;
+ }
+
+ return INVALID_HANDLE_VALUE;
+}
+
void *
get_agent_daemon_notify_event (void)
{
static HANDLE the_event = INVALID_HANDLE_VALUE;
if (the_event == INVALID_HANDLE_VALUE)
- {
- HANDLE h, h2;
- SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
-
- /* We need to use a manual reset event object due to the way our
- w32-pth wait function works: If we would use an automatic
- reset event we are not able to figure out which handle has
- been signaled because at the time we single out the signaled
- handles using WFSO the event has already been reset due to
- the WFMO. */
- h = CreateEvent (&sa, TRUE, FALSE, NULL);
- if (!h)
- log_error ("can't create scd notify event: %s\n", w32_strerror (-1) );
- else if (!DuplicateHandle (GetCurrentProcess(), h,
- GetCurrentProcess(), &h2,
- EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
- {
- log_error ("setting synchronize for scd notify event failed: %s\n",
- w32_strerror (-1) );
- CloseHandle (h);
- }
- else
- {
- CloseHandle (h);
- the_event = h2;
- }
- }
+ the_event = create_an_event ();
return the_event;
}
@@ -2528,6 +2545,11 @@ handle_signal (int signo)
agent_sigusr2_action ();
break;
+ case SIGCONT:
+ /* Do nothing, but break the syscall. */
+ log_debug ("SIGCONT received - breaking select\n");
+ break;
+
case SIGTERM:
if (!shutdown_pending)
log_info ("SIGTERM received - shutting down ...\n");
@@ -2959,6 +2981,28 @@ start_connection_thread_ssh (void *arg)
}
+void
+agent_kick_the_loop (void)
+{
+ /* Kick the select loop. */
+#ifdef HAVE_W32_SYSTEM
+ int ret = SetEvent (the_event2);
+ if (ret == 0)
+ log_error ("SetEvent for agent_kick_the_loop failed: %s\n",
+ w32_strerror (-1));
+#else
+# ifdef HAVE_PSELECT_NO_EINTR
+ write (event_pipe_fd, "", 1);
+# else
+ int ret = kill (main_thread_pid, SIGCONT);
+ if (ret < 0)
+ log_error ("sending signal for agent_kick_the_loop failed: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+# endif
+#endif
+}
+
+
/* Connection handler loop. Wait for connection requests and spawn a
thread after accepting a connection. */
static void
@@ -2980,8 +3024,13 @@ handle_connections (gnupg_fd_t listen_fd,
struct timespec curtime;
struct timespec timeout;
#ifdef HAVE_W32_SYSTEM
- HANDLE events[2];
+ HANDLE events[3];
unsigned int events_set;
+#else
+ int signo;
+# ifdef HAVE_PSELECT_NO_EINTR
+ int pipe_fd[2];
+# endif
#endif
int sock_inotify_fd = -1;
int home_inotify_fd = -1;
@@ -3009,11 +3058,24 @@ handle_connections (gnupg_fd_t listen_fd,
npth_sigev_add (SIGUSR1);
npth_sigev_add (SIGUSR2);
npth_sigev_add (SIGINT);
+ npth_sigev_add (SIGCONT);
npth_sigev_add (SIGTERM);
npth_sigev_fini ();
+# ifdef HAVE_PSELECT_NO_EINTR
+ ret = gnupg_create_pipe (pipe_fd);
+ if (ret)
+ {
+ log_error ("pipe creation failed: %s\n", gpg_strerror (ret));
+ return;
+ }
+ event_pipe_fd = pipe_fd[1];
+# else
+ main_thread_pid = getpid ();
+# endif
#else
events[0] = get_agent_daemon_notify_event ();
- events[1] = INVALID_HANDLE_VALUE;
+ events[1] = the_event2 = create_an_event ();
+ events[2] = INVALID_HANDLE_VALUE;
#endif
if (disable_check_own_socket)
@@ -3140,6 +3202,12 @@ handle_connections (gnupg_fd_t listen_fd,
thus a simple assignment is fine to copy the entire set. */
read_fdset = fdset;
+#ifdef HAVE_PSELECT_NO_EINTR
+ FD_SET (pipe_fd[0], &read_fdset);
+ if (nfd < pipe_fd[0])
+ nfd = pipe_fd[0];
+#endif
+
npth_clock_gettime (&curtime);
if (!(npth_timercmp (&curtime, &abstime, <)))
{
@@ -3155,11 +3223,8 @@ handle_connections (gnupg_fd_t listen_fd,
npth_sigev_sigmask ());
saved_errno = errno;
- {
- int signo;
- while (npth_sigev_get_pending (&signo))
- handle_signal (signo);
- }
+ while (npth_sigev_get_pending (&signo))
+ handle_signal (signo);
#else
ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
events, &events_set);
@@ -3182,6 +3247,15 @@ handle_connections (gnupg_fd_t listen_fd,
next timeout. */
continue;
+#ifdef HAVE_PSELECT_NO_EINTR
+ if (FD_ISSET (pipe_fd[0], &read_fdset))
+ {
+ char buf[256];
+
+ read (pipe_fd[0], buf, sizeof buf);
+ }
+#endif
+
/* The inotify fds are set even when a shutdown is pending (see
* above). So we must handle them in any case. To avoid that
* they trigger a second time we close them immediately. */
@@ -3259,6 +3333,14 @@ handle_connections (gnupg_fd_t listen_fd,
close (sock_inotify_fd);
if (home_inotify_fd != -1)
close (home_inotify_fd);
+#ifdef HAVE_W32_SYSTEM
+ if (the_event2 != INVALID_HANDLE_VALUE)
+ CloseHandle (the_event2);
+#endif
+#ifdef HAVE_PSELECT_NO_EINTR
+ close (pipe_fd[0]);
+ close (pipe_fd[1]);
+#endif
cleanup ();
log_info (_("%s %s stopped\n"), gpgrt_strusage(11), gpgrt_strusage(13));
npth_attr_destroy (&tattr);