agent: Make digest algorithms for ssh fingerprints configurable.
[gnupg.git] / agent / gpg-agent.c
index dcc9bb6..77b811c 100644 (file)
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #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
 #include "agent.h"
 #include <assuan.h> /* Malloc hooks  and socket wrappers. */
 
-#include "i18n.h"
-#include "sysutils.h"
-#include "gc-opt-flags.h"
-#include "exechelp.h"
-#include "asshelp.h"
+#include "../common/i18n.h"
+#include "../common/sysutils.h"
+#include "../common/gc-opt-flags.h"
+#include "../common/exechelp.h"
+#include "../common/asshelp.h"
 #include "../common/init.h"
 
 
@@ -114,6 +111,7 @@ enum cmd_and_opt_values
   oCheckPassphrasePattern,
   oMaxPassphraseDays,
   oEnablePassphraseHistory,
+  oEnableExtendedKeyFormat,
   oUseStandardSocket,
   oNoUseStandardSocket,
   oExtraSocket,
@@ -131,6 +129,7 @@ enum cmd_and_opt_values
   oKeepTTY,
   oKeepDISPLAY,
   oSSHSupport,
+  oSSHFingerprintDigest,
   oPuttySupport,
   oDisableScdaemon,
   oDisableCheckOwnSocket,
@@ -234,6 +233,8 @@ static ARGPARSE_OPTS opts[] = {
                 /* */    N_("allow passphrase to be prompted through Emacs")),
 
   ARGPARSE_s_n (oSSHSupport,   "enable-ssh-support", N_("enable ssh support")),
+  ARGPARSE_s_s (oSSHFingerprintDigest, "ssh-fingerprint-digest",
+                N_("digest to use when communicating ssh fingerprints")),
   ARGPARSE_s_n (oPuttySupport, "enable-putty-support",
 #ifdef HAVE_W32_SYSTEM
                 /* */           N_("enable putty support")
@@ -241,6 +242,7 @@ static ARGPARSE_OPTS opts[] = {
                 /* */           "@"
 #endif
                 ),
+  ARGPARSE_s_n (oEnableExtendedKeyFormat, "enable-extended-key-format", "@"),
 
   /* Dummy options for backward compatibility.  */
   ARGPARSE_o_s (oWriteEnvFile, "write-env-file", "@"),
@@ -254,7 +256,6 @@ static ARGPARSE_OPTS opts[] = {
 /* The list of supported debug flags.  */
 static struct debug_flags_s debug_flags [] =
   {
-    { DBG_COMMAND_VALUE, "command"  },
     { DBG_MPI_VALUE    , "mpi"     },
     { DBG_CRYPTO_VALUE , "crypto"  },
     { DBG_MEMORY_VALUE , "memory"  },
@@ -307,8 +308,10 @@ static int putty_support;
 #endif /*HAVE_W32_SYSTEM*/
 
 /* The list of open file descriptors at startup.  Note that this list
-   has been allocated using the standard malloc.  */
+ * has been allocated using the standard malloc.  */
+#ifndef HAVE_W32_SYSTEM
 static int *startup_fd_list;
+#endif
 
 /* The signal mask at startup and a flag telling whether it is valid.  */
 #ifdef HAVE_SIGPROCMASK
@@ -348,7 +351,7 @@ static char *redir_socket_name_extra;
 static char *socket_name_browser;
 static char *redir_socket_name_browser;
 
-/* Name of the communication socket used for ssh-agent-emulation.  */
+/* Name of the communication socket used for ssh-agent protocol.  */
 static char *socket_name_ssh;
 static char *redir_socket_name_ssh;
 
@@ -387,9 +390,9 @@ static pid_t parent_pid = (pid_t)(-1);
 static int active_connections;
 
 /* This object is used to dispatch progress messages from Libgcrypt to
- * the right thread.  Given that we won't have at max a few dozen
- * connections at the same time using a linked list is the easiest way
- * to handle this. */
+ * the right thread.  Given that we will have at max only a few dozen
+ * connections at a time, using a linked list is the easiest way to
+ * handle this. */
 struct progress_dispatch_s
 {
   struct progress_dispatch_s *next;
@@ -523,10 +526,9 @@ set_debug (void)
   else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
     opt.debug = DBG_IPC_VALUE;
   else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
-    opt.debug = DBG_IPC_VALUE|DBG_COMMAND_VALUE;
+    opt.debug = DBG_IPC_VALUE;
   else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
-    opt.debug = (DBG_IPC_VALUE|DBG_COMMAND_VALUE
-                 |DBG_CACHE_VALUE);
+    opt.debug = (DBG_IPC_VALUE | DBG_CACHE_VALUE);
   else if (!strcmp (debug_level, "guru") || numok)
     {
       opt.debug = ~0;
@@ -576,50 +578,6 @@ remove_socket (char *name, char *redir_name)
 }
 
 
-/* Return a malloc'ed string that is the path to the passed
- * unix-domain socket (or return NULL if this is not a valid
- * unix-domain socket).  We use a plain int here because it is only
- * used on Linux.
- *
- * FIXME: This function needs to be moved to libassuan.  */
-#ifndef HAVE_W32_SYSTEM
-static char *
-get_socket_name (int fd)
-{
-  struct sockaddr_un un;
-  socklen_t len = sizeof(un);
-  char *name = NULL;
-
-  if (getsockname (fd, (struct sockaddr*)&un, &len) != 0)
-    log_error ("could not getsockname(%d): %s\n", fd,
-               gpg_strerror (gpg_error_from_syserror ()));
-  else if (un.sun_family != AF_UNIX)
-    log_error ("file descriptor %d is not a unix-domain socket\n", fd);
-  else if (len <= offsetof (struct sockaddr_un, sun_path))
-    log_error ("socket name not present for file descriptor %d\n", fd);
-  else if (len > sizeof(un))
-    log_error ("socket name for file descriptor %d was truncated "
-               "(passed %lu bytes, wanted %u)\n", fd, sizeof(un), len);
-  else
-    {
-      log_debug ("file descriptor %d has path %s (%lu octets)\n", fd,
-                 un.sun_path, len - offsetof (struct sockaddr_un, sun_path));
-      name = xtrymalloc (len - offsetof (struct sockaddr_un, sun_path) + 1);
-      if (!name)
-        log_error ("failed to allocate memory for name of fd %d: %s\n",
-                   fd, gpg_strerror (gpg_error_from_syserror ()));
-      else
-        {
-          memcpy (name, un.sun_path, len);
-          name[len] = 0;
-        }
-    }
-
-  return name;
-}
-#endif /*!HAVE_W32_SYSTEM*/
-
-
 /* Discover which inherited file descriptors correspond to which
  * services/sockets offered by gpg-agent, using the LISTEN_FDS and
  * LISTEN_FDNAMES convention.  The understood labels are "ssh",
@@ -717,12 +675,18 @@ map_supervised_sockets (gnupg_fd_t *r_fd,
   /* Assign the descriptors to the return values.  */
   if (!fdnames)
     {
+      struct stat statbuf;
+
       if (fd_count != 1)
         log_error ("no LISTEN_FDNAMES and LISTEN_FDS (%d) != 1"
                    " in --supervised mode."
                    " (ignoring all sockets but the first one)\n",
                    fd_count);
+      if (fstat (3, &statbuf) == -1 && errno ==EBADF)
+        log_fatal ("file descriptor 3 must be valid in --supervised mode"
+                   " if LISTEN_FDNAMES is not set\n");
       *r_fd = 3;
+      socket_name = gnupg_get_socket_name (3);
     }
   else if (fd_count != nfdnames)
     {
@@ -739,14 +703,12 @@ map_supervised_sockets (gnupg_fd_t *r_fd,
         {
           for (j = 0; j < DIM (tbl); j++)
             {
-              log_debug ("i=%d j=%d fdname=%s check=%s\n", i, j,
-                         fdnames[i], tbl[j].label);
               if (!strcmp (fdnames[i], tbl[j].label) || j == DIM(tbl)-1)
                 {
+                  fd = 3 + i;
                   if (**tbl[j].fdaddr == -1)
                     {
-                      fd = 3 + i;
-                      name = get_socket_name (fd);
+                      name = gnupg_get_socket_name (fd);
                       if (name)
                         {
                           **tbl[j].fdaddr = fd;
@@ -832,7 +794,8 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       opt.min_passphrase_nonalpha = MIN_PASSPHRASE_NONALPHA;
       opt.check_passphrase_pattern = NULL;
       opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
-      opt.enable_passhrase_history = 0;
+      opt.enable_passphrase_history = 0;
+      opt.enable_extended_key_format = 0;
       opt.ignore_cache_for_signing = 0;
       opt.allow_mark_trusted = 1;
       opt.allow_external_cache = 1;
@@ -840,6 +803,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       opt.allow_emacs_pinentry = 0;
       opt.disable_scdaemon = 0;
       disable_check_own_socket = 0;
+      opt.ssh_fingerprint_digest = GCRY_MD_MD5;
       return 1;
     }
 
@@ -899,7 +863,11 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       opt.max_passphrase_days = pargs->r.ret_ulong;
       break;
     case oEnablePassphraseHistory:
-      opt.enable_passhrase_history = 1;
+      opt.enable_passphrase_history = 1;
+      break;
+
+    case oEnableExtendedKeyFormat:
+      opt.enable_extended_key_format = 1;
       break;
 
     case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
@@ -943,6 +911,15 @@ thread_init_once (void)
       npth_initialized++;
       npth_init ();
     }
+  gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
+  /* Now that we have set the syscall clamp we need to tell Libgcrypt
+   * that it should get them from libgpg-error.  Note that Libgcrypt
+   * has already been initialized but at that point nPth was not
+   * initialized and thus Libgcrypt could not set its system call
+   * clamp.  */
+#if GCRYPT_VERSION_NUMBER >= 0x010800 /* 1.8.0 */
+  gcry_control (GCRYCTL_REINIT_SYSCALL_CLAMP, 0, 0);
+#endif
 }
 
 
@@ -985,8 +962,10 @@ main (int argc, char **argv )
 
   /* Before we do anything else we save the list of currently open
      file descriptors and the signal mask.  This info is required to
-     do the exec call properly. */
+     do the exec call properly.  We don't need it on Windows.  */
+#ifndef HAVE_W32_SYSTEM
   startup_fd_list = get_all_open_fds ();
+#endif /*!HAVE_W32_SYSTEM*/
 #ifdef HAVE_SIGPROCMASK
   if (!sigprocmask (SIG_UNBLOCK, NULL, &startup_signal_mask))
     startup_signal_mask_valid = 1;
@@ -1089,7 +1068,7 @@ main (int argc, char **argv )
     }
 
   /* Initialize the secure memory. */
-  gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
+  gcry_control (GCRYCTL_INIT_SECMEM, SECMEM_BUFFER_SIZE, 0);
   maybe_setuid = 0;
 
   /*
@@ -1201,6 +1180,11 @@ main (int argc, char **argv )
        case oSSHSupport:
           ssh_support = 1;
           break;
+       case oSSHFingerprintDigest:
+          opt.ssh_fingerprint_digest = gcry_md_map_name (pargs.r.ret_str);
+          if (opt.ssh_fingerprint_digest == 0)
+            log_error ("Unknown digest algorithm: %s\n", pargs.r.ret_str);
+          break;
         case oPuttySupport:
 #        ifdef HAVE_W32_SYSTEM
           putty_support = 1;
@@ -1403,6 +1387,8 @@ main (int argc, char **argv )
                  GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       es_printf ("pinentry-timeout:%lu:0:\n",
                  GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME);
+      es_printf ("enable-extended-key-format:%lu:\n",
+                 GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
 
       agent_exit (0);
     }
@@ -1507,8 +1493,6 @@ main (int argc, char **argv )
       pid_t pid;
 #endif
 
-      initialize_modules ();
-
       /* Remove the DISPLAY variable so that a pinentry does not
          default to a specific display.  There is still a default
          display when gpg-agent was started using --display or a
@@ -1568,10 +1552,15 @@ main (int argc, char **argv )
         parent_pid = getpid ();
 
       fflush (NULL);
+
 #ifdef HAVE_W32_SYSTEM
+
       (void)csh_style;
       (void)nodetach;
+      initialize_modules ();
+
 #else /*!HAVE_W32_SYSTEM*/
+
       pid = fork ();
       if (pid == (pid_t)-1)
         {
@@ -1789,6 +1778,23 @@ agent_libgcrypt_progress_cb (void *data, const char *what, int printchar,
       break;
   if (dispatch && dispatch->cb)
     dispatch->cb (dispatch->ctrl, what, printchar, current, total);
+
+  /* Libgcrypt < 1.8 does not know about nPth and thus when it reads
+   * from /dev/random this will block the process.  To mitigate this
+   * problem we yield the thread when Libgcrypt tells us that it needs
+   * more entropy.  This way other threads have chance to run.  */
+#if GCRYPT_VERSION_NUMBER < 0x010800 /* 1.8.0 */
+  if (what && !strcmp (what, "need_entropy"))
+    {
+#if GPGRT_VERSION_NUMBER < 0x011900 /* 1.25 */
+      /* In older gpg-error versions gpgrt_yield is buggy for use with
+       * nPth and thus we need to resort to a sleep call.  */
+      npth_usleep (1000); /* 1ms */
+#else
+      gpgrt_yield ();
+#endif
+    }
+#endif
 }
 
 
@@ -1914,7 +1920,7 @@ agent_copy_startup_env (ctrl_t ctrl)
   const char *value;
 
   for (idx=0; !err && names[idx]; idx++)
-      if ((value = session_env_getenv (opt.startup_env, names[idx])))
+    if ((value = session_env_getenv (opt.startup_env, names[idx])))
       err = session_env_setenv (ctrl->session_env, names[idx], value);
 
   if (!err && !ctrl->lc_ctype && opt.startup_lc_ctype)
@@ -2406,7 +2412,7 @@ handle_signal (int signo)
 }
 #endif
 
-/* Check the nonce on a new connection.  This is a NOP unless we we
+/* Check the nonce on a new connection.  This is a NOP unless we
    are using our Unix domain socket emulation under Windows.  */
 static int
 check_nonce (ctrl_t ctrl, assuan_sock_nonce_t *nonce)
@@ -2715,31 +2721,6 @@ 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
@@ -2748,6 +2729,7 @@ handle_connections (gnupg_fd_t listen_fd,
                     gnupg_fd_t listen_fd_browser,
                     gnupg_fd_t listen_fd_ssh)
 {
+  gpg_error_t err;
   npth_attr_t tattr;
   struct sockaddr_un paddr;
   socklen_t plen;
@@ -2763,9 +2745,7 @@ 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*/
+  int my_inotify_fd = -1;
   struct {
     const char *name;
     void *(*func) (void *arg);
@@ -2803,27 +2783,14 @@ 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
+  else if ((err = gnupg_inotify_watch_socket (&my_inotify_fd, socket_name)))
     {
-      /* 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 = '/';
+      if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED)
+        log_info ("error enabling fast daemon termination: %s\n",
+                  gpg_strerror (err));
     }
-#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
@@ -2866,14 +2833,12 @@ 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;
@@ -2892,8 +2857,19 @@ handle_connections (gnupg_fd_t listen_fd,
             break; /* ready */
 
           /* Do not accept new connections but keep on running the
-             loop to cope with the timer events.  */
+           * loop to cope with the timer events.
+           *
+           * Note that we do not close the listening socket because a
+           * client trying to connect to that socket would instead
+           * restart a new dirmngr instance - which is unlikely the
+           * intention of a shutdown. */
           FD_ZERO (&fdset);
+          nfd = -1;
+          if (my_inotify_fd != -1)
+            {
+              FD_SET (my_inotify_fd, &fdset);
+              nfd = my_inotify_fd;
+            }
        }
 
       /* POSIX says that fd_set should be implemented as a structure,
@@ -2948,14 +2924,13 @@ 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))
+          if (my_inotify_fd != -1
+              && FD_ISSET (my_inotify_fd, &read_fdset)
+              && gnupg_inotify_has_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++)
             {
@@ -2998,15 +2973,12 @@ handle_connections (gnupg_fd_t listen_fd,
                       xfree (ctrl);
                     }
                 }
-              fd = GNUPG_INVALID_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);