From 650356148af43ea619bec12e599a4981b147d5f8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 6 Sep 2016 10:53:45 +0200 Subject: [PATCH] agent: Terminate on deletion of the socket file (Linux only). * configure.ac (AC_CHECK_FUNCS): Chec for inotify_init. * agent/gpg-agent.c [HAVE_INOTIFY_INIT]: Include sys/inotify.h. (my_inotify_is_name) [HAVE_INOTIFY_INIT]: New. (handle_connections) [HAVE_INOTIFY_INIT]: New. Signed-off-by: Werner Koch --- agent/gpg-agent.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 8 +++++ 2 files changed, 82 insertions(+) diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index e119975ea..75a9283f4 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -47,6 +47,9 @@ #ifdef HAVE_SIGNAL_H # include #endif +#ifdef HAVE_INOTIFY_INIT +# include +#endif /*HAVE_INOTIFY_INIT*/ #include #define GNUPG_COMMON_NEED_AFLOCAL @@ -2399,6 +2402,31 @@ start_connection_thread_ssh (void *arg) } +#ifdef HAVE_INOTIFY_INIT +/* Read an inotify event and return true if it matches NAME. */ +static int +my_inotify_is_name (int fd, const char *name) +{ + union { + struct inotify_event ev; + char _buf[sizeof (struct inotify_event) + 100 + 1]; + } buf; + int n; + + n = npth_read (fd, &buf, sizeof buf); + if (n < sizeof (struct inotify_event)) + return 0; + if (buf.ev.len < strlen (name)+1) + return 0; + if (strcmp (buf.ev.name, name)) + return 0; /* Not the desired file. */ + + return 1; /* Found. */ +} +#endif /*HAVE_INOTIFY_INIT*/ + + + /* Connection handler loop. Wait for connection requests and spawn a thread after accepting a connection. */ static void @@ -2422,6 +2450,9 @@ handle_connections (gnupg_fd_t listen_fd, HANDLE events[2]; unsigned int events_set; #endif +#ifdef HAVE_INOTIFY_INIT + int my_inotify_fd; +#endif /*HAVE_INOTIFY_INIT*/ struct { const char *name; void *(*func) (void *arg); @@ -2459,6 +2490,28 @@ handle_connections (gnupg_fd_t listen_fd, # endif #endif +#ifdef HAVE_INOTIFY_INIT + if (disable_check_own_socket) + my_inotify_fd = -1; + else if ((my_inotify_fd = inotify_init ()) == -1) + log_info ("error enabling fast daemon termination: %s\n", + strerror (errno)); + else + { + /* We need to watch the directory for the file becuase there + * won't be an IN_DELETE_SELF for a socket file. */ + char *slash = strrchr (socket_name, '/'); + log_assert (slash && slash[1]); + *slash = 0; + if (inotify_add_watch (my_inotify_fd, socket_name, IN_DELETE) == -1) + { + close (my_inotify_fd); + my_inotify_fd = -1; + } + *slash = '/'; + } +#endif /*HAVE_INOTIFY_INIT*/ + /* On Windows we need to fire up a separate thread to listen for requests from Putty (an SSH client), so we can replace Putty's Pageant (its ssh-agent implementation). */ @@ -2500,6 +2553,14 @@ handle_connections (gnupg_fd_t listen_fd, if (FD2INT (listen_fd_ssh) > nfd) nfd = FD2INT (listen_fd_ssh); } +#ifdef HAVE_INOTIFY_INIT + if (my_inotify_fd != -1) + { + FD_SET (my_inotify_fd, &fdset); + if (my_inotify_fd > nfd) + nfd = my_inotify_fd; + } +#endif /*HAVE_INOTIFY_INIT*/ listentbl[0].l_fd = listen_fd; listentbl[1].l_fd = listen_fd_extra; @@ -2574,6 +2635,15 @@ handle_connections (gnupg_fd_t listen_fd, ctrl_t ctrl; npth_t thread; +#ifdef HAVE_INOTIFY_INIT + if (my_inotify_fd != -1 && FD_ISSET (my_inotify_fd, &read_fdset) + && my_inotify_is_name (my_inotify_fd, GPG_AGENT_SOCK_NAME)) + { + shutdown_pending = 1; + log_info ("socket file has been removed - shutting down\n"); + } +#endif /*HAVE_INOTIFY_INIT*/ + for (idx=0; idx < DIM(listentbl); idx++) { if (listentbl[idx].l_fd == GNUPG_INVALID_FD) @@ -2620,6 +2690,10 @@ handle_connections (gnupg_fd_t listen_fd, } } +#ifdef HAVE_INOTIFY_INIT + if (my_inotify_fd != -1) + close (my_inotify_fd); +#endif /*HAVE_INOTIFY_INIT*/ cleanup (); log_info (_("%s %s stopped\n"), strusage(11), strusage(13)); npth_attr_destroy (&tattr); diff --git a/configure.ac b/configure.ac index bd24ea441..b16f83746 100644 --- a/configure.ac +++ b/configure.ac @@ -1388,6 +1388,14 @@ AC_CHECK_FUNCS([memicmp stpcpy strsep strlwr strtoul memmove stricmp strtol \ flockfile funlockfile getpwnam getpwuid \ getenv inet_pton strpbrk]) +# See whether libc supports the Linux inotify interface +case "${host}" in + *-*-linux*) + AC_CHECK_FUNCS([inotify_init]) + ;; +esac + + if test "$have_android_system" = yes; then # On Android ttyname is a stub but prints an error message. AC_DEFINE(HAVE_BROKEN_TTYNAME,1,