agent: Kludge to allow disabling of the extra sockets.
[gnupg.git] / agent / gpg-agent.c
index 8d6ecfc..d3f203b 100644 (file)
@@ -47,6 +47,9 @@
 #ifdef HAVE_SIGNAL_H
 # include <signal.h>
 #endif
+#ifdef HAVE_INOTIFY_INIT
+# include <sys/inotify.h>
+#endif /*HAVE_INOTIFY_INIT*/
 #include <npth.h>
 
 #define GNUPG_COMMON_NEED_AFLOCAL
@@ -764,14 +767,6 @@ main (int argc, char **argv )
 
   npth_init ();
 
-  /* Check that the libraries are suitable.  Do it here because
-     the option parsing may need services of the library. */
-  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
-    {
-      log_fatal( _("%s is too old (need %s, have %s)\n"), "libgcrypt",
-                 NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
-    }
-
   malloc_hooks.malloc = gcry_malloc;
   malloc_hooks.realloc = gcry_realloc;
   malloc_hooks.free = gcry_free;
@@ -779,7 +774,7 @@ main (int argc, char **argv )
   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
   assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
   assuan_sock_init ();
-  setup_libassuan_logging (&opt.debug);
+  setup_libassuan_logging (&opt.debug, NULL);
 
   setup_libgcrypt_logging ();
   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
@@ -1050,6 +1045,34 @@ main (int argc, char **argv )
       agent_exit (0);
     }
 
+  if (! opt.extra_socket)
+    {
+      opt.extra_socket = 1;  /* (1 = points into r/o section)  */
+      socket_name_extra = GPG_AGENT_EXTRA_SOCK_NAME;
+    }
+  else if (socket_name_extra
+           && (!strcmp (socket_name_extra, "none")
+               || !strcmp (socket_name_extra, "/dev/null")))
+    {
+      /* User requested not to create this socket.  */
+      opt.extra_socket = 0;
+      socket_name_extra = NULL;
+    }
+
+  if (! opt.browser_socket)
+    {
+      opt.browser_socket = 1;  /* (1 = points into r/o section)  */
+      socket_name_browser = GPG_AGENT_BROWSER_SOCK_NAME;
+    }
+  else if (socket_name_browser
+           && (!strcmp (socket_name_browser, "none")
+               || !strcmp (socket_name_browser, "/dev/null")))
+    {
+      /* User requested not to create this socket.  */
+      opt.browser_socket = 0;
+      socket_name_browser = NULL;
+    }
+
   set_debug ();
 
   if (atexit (cleanup))
@@ -1246,13 +1269,10 @@ main (int argc, char **argv )
                                              &socket_nonce_browser);
         }
 
-      if (ssh_support)
-        {
-          socket_name_ssh = create_socket_name (GPG_AGENT_SSH_SOCK_NAME, 1);
-          fd_ssh = create_server_socket (socket_name_ssh, 0, 1,
-                                         &redir_socket_name_ssh,
-                                         &socket_nonce_ssh);
-        }
+      socket_name_ssh = create_socket_name (GPG_AGENT_SSH_SOCK_NAME, 1);
+      fd_ssh = create_server_socket (socket_name_ssh, 0, 1,
+                                     &redir_socket_name_ssh,
+                                     &socket_nonce_ssh);
 
       /* If we are going to exec a program in the parent, we record
          the PID, so that the child may check whether the program is
@@ -1318,8 +1338,7 @@ main (int argc, char **argv )
            *socket_name_extra = 0;
          if (opt.browser_socket)
            *socket_name_browser = 0;
-         if (ssh_support)
-           *socket_name_ssh = 0;
+          *socket_name_ssh = 0;
 
           if (argc)
             { /* Run the program given on the commandline.  */
@@ -2311,12 +2330,12 @@ do_start_connection_thread (ctrl_t ctrl)
 {
   active_connections++;
   agent_init_default_ctrl (ctrl);
-  if (opt.verbose)
+  if (opt.verbose && !DBG_IPC)
     log_info (_("handler 0x%lx for fd %d started\n"),
               (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
 
   start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd);
-  if (opt.verbose)
+  if (opt.verbose && !DBG_IPC)
     log_info (_("handler 0x%lx for fd %d terminated\n"),
               (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
 
@@ -2407,6 +2426,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
@@ -2430,6 +2474,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);
@@ -2467,6 +2514,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 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*/
+
   /* 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). */
@@ -2508,6 +2577,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;
@@ -2582,6 +2659,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)
@@ -2628,6 +2714,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);
@@ -2665,6 +2755,7 @@ check_own_socket_thread (void *arg)
       log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
       goto leave;
     }
+  assuan_set_flag (ctx, ASSUAN_NO_LOGGING, 1);
 
   rc = assuan_socket_connect (ctx, sockname, (pid_t)(-1), 0);
   if (rc)