From 6308c300196ae85fd82ed383217219e0206640a4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 7 Sep 2016 12:36:48 +0200 Subject: [PATCH] dirmngr: Terminate on deletion of the socket file (Linux only). * dirmngr/dirmngr.c [HAVE_INOTIFY_INIT]: Include sys/inotify.h. (oDisableCheckOwnSocket): New. (opts): Add --disable-check-own-socket. (disable_check_own_socket): New var. (parse_rereadable_options): Set that var. (my_inotify_is_name) [HAVE_INOTIFY_INIT]: New. (handle_connections) [HAVE_INOTIFY_INIT]: New. Signed-off-by: Werner Koch --- dirmngr/dirmngr.c | 103 ++++++++++++++++++++++++++++++++++++++++++++-- doc/dirmngr.texi | 6 +++ 2 files changed, 105 insertions(+), 4 deletions(-) diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 7f989a55f..499115f65 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -39,6 +39,9 @@ #ifdef HAVE_SIGNAL_H # include #endif +#ifdef HAVE_INOTIFY_INIT +# include +#endif /*HAVE_INOTIFY_INIT*/ #include #include "dirmngr-err.h" @@ -134,6 +137,7 @@ enum cmd_and_opt_values { oUseTor, oKeyServer, oNameServer, + oDisableCheckOwnSocket, aTest }; @@ -218,6 +222,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_i (oGnutlsDebug, "gnutls-debug", "@"), ARGPARSE_s_i (oGnutlsDebug, "tls-debug", "@"), ARGPARSE_s_i (oDebugWait, "debug-wait", "@"), + ARGPARSE_s_n (oDisableCheckOwnSocket, "disable-check-own-socket", "@"), ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"), ARGPARSE_s_s (oHomedir, "homedir", "@"), ARGPARSE_s_s (oLDAPWrapperProgram, "ldap-wrapper-program", "@"), @@ -274,6 +279,9 @@ static int opt_gnutls_debug = -1; /* Flag indicating that a shutdown has been requested. */ static volatile int shutdown_pending; +/* Flags to indicate that we shall not watch our own socket. */ +static int disable_check_own_socket; + /* Counter for the active connections. */ static int active_connections; @@ -528,6 +536,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) http_register_tls_ca (NULL); FREE_STRLIST (opt.keyserver); /* Note: We do not allow resetting of opt.use_tor at runtime. */ + disable_check_own_socket = 0; return 1; } @@ -554,6 +563,8 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) } break; + case oDisableCheckOwnSocket: disable_check_own_socket = 1; break; + case oLDAPWrapperProgram: opt.ldap_wrapper_program = pargs->r.ret_str; break; @@ -1840,6 +1851,35 @@ start_connection_thread (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; + const char *s; + + s = strrchr (name, '/'); + if (s && s[1]) + name = s + 1; + + 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*/ + + /* Main loop in daemon mode. */ static void handle_connections (assuan_fd_t listen_fd) @@ -1857,6 +1897,9 @@ handle_connections (assuan_fd_t listen_fd) struct timespec curtime; struct timespec timeout; int saved_errno; +#ifdef HAVE_INOTIFY_INIT + int my_inotify_fd; +#endif /*HAVE_INOTIFY_INIT*/ npth_attr_init (&tattr); npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED); @@ -1871,12 +1914,43 @@ handle_connections (assuan_fd_t listen_fd) npth_sigev_fini (); #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 because 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*/ + + /* Setup the fdset. It has only one member. This is because we use pth_select instead of pth_accept to properly sync timeouts with to full second. */ FD_ZERO (&fdset); FD_SET (FD2INT (listen_fd), &fdset); nfd = FD2INT (listen_fd); +#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*/ npth_clock_gettime (&abstime); abstime.tv_sec += TIMERTICK_INTERVAL; @@ -1928,11 +2002,28 @@ handle_connections (assuan_fd_t listen_fd) } if (ret <= 0) - /* Interrupt or timeout. Will be handled when calculating the - next timeout. */ - continue; + { + /* Interrupt or timeout. Will be handled when calculating the + next timeout. */ + continue; + } - if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset)) + if (shutdown_pending) + { + /* Do not anymore accept connections. */ + continue; + } + +#ifdef HAVE_INOTIFY_INIT + if (my_inotify_fd != -1 && FD_ISSET (my_inotify_fd, &read_fdset) + && my_inotify_is_name (my_inotify_fd, socket_name)) + { + shutdown_pending = 1; + log_info ("socket file has been removed - shutting down\n"); + } +#endif /*HAVE_INOTIFY_INIT*/ + + if (FD_ISSET (FD2INT (listen_fd), &read_fdset)) { plen = sizeof paddr; fd = INT2FD (npth_accept (FD2INT(listen_fd), @@ -1967,6 +2058,10 @@ handle_connections (assuan_fd_t listen_fd) } } +#ifdef HAVE_INOTIFY_INIT + if (my_inotify_fd != -1) + close (my_inotify_fd); +#endif /*HAVE_INOTIFY_INIT*/ npth_attr_destroy (&tattr); cleanup (); log_info ("%s %s stopped\n", strusage(11), strusage(13)); diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi index b6b70eaf5..d442103a3 100644 --- a/doc/dirmngr.texi +++ b/doc/dirmngr.texi @@ -214,6 +214,12 @@ When running in server mode, wait @var{n} seconds before entering the actual processing loop and print the pid. This gives time to attach a debugger. +@item --disable-check-own-socket +@opindex disable-check-own-socket +On some platforms @command{dirmngr} is able to detect the removal of +its socket file and shutdown itself. This option disable this +self-test for debugging purposes. + @item -s @itemx --sh @itemx -c