GNUPG-1-9-BRANCH gnupg/agent (ChangeLog Makefile.am agent.h findkey.c gpg-agent.c)

cvs user mo cvs at cvs.gnupg.org
Wed Jan 26 23:11:46 CET 2005


    Date: Wednesday, January 26, 2005 @ 23:20:21
  Author: mo
    Path: /cvs/gnupg/gnupg/agent
     Tag: GNUPG-1-9-BRANCH

Modified: ChangeLog Makefile.am agent.h findkey.c gpg-agent.c

2005-01-26  Moritz Schulte  <moritz at g10code.com>

	* command-ssh.c: New file.
	* Makefile.am (gpg_agent_SOURCES): New source file: command-ssh.c.

	* findkey.c (modify_description): New function.
	(agent_key_from_file): Support comment field in key s-expressions.

	* gpg-agent.c (enum cmd_and_opt_values): New item: oSSHSupport.
	(opts) New entry for oSSHSupport.
	New variable: socket_name_ssh.
	(cleanup_do): New function based on cleanup().
	(cleanup): Use cleanup_do() for socket_name and socket_name_ssh.
	(main): New switch case for oSSHSupport.
	(main): Move socket name creation code to ...
	(create_socket_name): ... this new function.
	(main): Use create_socket_name() for creating socket names for
	socket_name and for socket_name_ssh in case ssh support is
	enabled.
	Move socket creation code to ...
	(create_server_socket): ... this new function.
	(main): Use create_server_socket() for creating sockets.
	In case standard_socket is set, do not only store a socket name in
	socket_name, but also in socket_name_ssh.
	Generate additional environment info strings for ssh support.
	Pass additional ssh socket argument to handle_connections.
	(start_connection_thread_ssh): New function.
	(handle_connections): Use select to multiplex between gpg-agent
	and ssh-agent protocol.

	* agent.h (struct opt): New member: ssh_support.
	Declare function: start_command_handler_ssh.


-------------+
 ChangeLog   |   33 ++++
 Makefile.am |    4 
 agent.h     |    6 
 findkey.c   |  144 ++++++++++++++++++++
 gpg-agent.c |  399 +++++++++++++++++++++++++++++++++++++++++-----------------
 5 files changed, 464 insertions(+), 122 deletions(-)


Index: gnupg/agent/ChangeLog
diff -u gnupg/agent/ChangeLog:1.59.2.56 gnupg/agent/ChangeLog:1.59.2.57
--- gnupg/agent/ChangeLog:1.59.2.56	Thu Jan 13 19:00:46 2005
+++ gnupg/agent/ChangeLog	Wed Jan 26 23:20:21 2005
@@ -1,3 +1,36 @@
+2005-01-26  Moritz Schulte  <moritz at g10code.com>
+
+	* command-ssh.c: New file.
+	* Makefile.am (gpg_agent_SOURCES): New source file: command-ssh.c.
+
+	* findkey.c (modify_description): New function.
+	(agent_key_from_file): Support comment field in key s-expressions.
+
+	* gpg-agent.c (enum cmd_and_opt_values): New item: oSSHSupport.
+	(opts) New entry for oSSHSupport.
+	New variable: socket_name_ssh.
+	(cleanup_do): New function based on cleanup().
+	(cleanup): Use cleanup_do() for socket_name and socket_name_ssh.
+	(main): New switch case for oSSHSupport.
+	(main): Move socket name creation code to ...
+	(create_socket_name): ... this new function.
+	(main): Use create_socket_name() for creating socket names for
+	socket_name and for socket_name_ssh in case ssh support is
+	enabled.
+	Move socket creation code to ...
+	(create_server_socket): ... this new function.
+	(main): Use create_server_socket() for creating sockets.
+	In case standard_socket is set, do not only store a socket name in
+	socket_name, but also in socket_name_ssh.
+	Generate additional environment info strings for ssh support.
+	Pass additional ssh socket argument to handle_connections.
+	(start_connection_thread_ssh): New function.
+	(handle_connections): Use select to multiplex between gpg-agent
+	and ssh-agent protocol.
+
+	* agent.h (struct opt): New member: ssh_support.
+	Declare function: start_command_handler_ssh.
+
 2005-01-04  Werner Koch  <wk at g10code.com>
 
 	* trustlist.c (agent_marktrusted): Use "Cancel" for the first
Index: gnupg/agent/Makefile.am
diff -u gnupg/agent/Makefile.am:1.22.2.5 gnupg/agent/Makefile.am:1.22.2.6
--- gnupg/agent/Makefile.am:1.22.2.5	Tue Dec 21 20:05:15 2004
+++ gnupg/agent/Makefile.am	Wed Jan 26 23:20:21 2005
@@ -1,4 +1,4 @@
-# Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
 #
 # This file is part of GnuPG.
 #
@@ -29,7 +29,7 @@
 
 gpg_agent_SOURCES = \
 	gpg-agent.c agent.h \
-	command.c \
+	command.c command-ssh.c \
 	query.c \
 	cache.c \
 	trans.c \
Index: gnupg/agent/agent.h
diff -u gnupg/agent/agent.h:1.32.2.12 gnupg/agent/agent.h:1.32.2.13
--- gnupg/agent/agent.h:1.32.2.12	Tue Dec 21 20:05:15 2004
+++ gnupg/agent/agent.h	Wed Jan 26 23:20:21 2005
@@ -1,5 +1,5 @@
 /* agent.h - Global definitions for the agent
- *	Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+ *	Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -66,6 +66,7 @@
   int allow_preset_passphrase;
   int keep_tty;  /* don't switch the TTY (for pinentry) on request */
   int keep_display;  /* don't switch the DISPLAY (for pinentry) on request */
+  int ssh_support;		/* Enable ssh-agent emulation.  */
 } opt;
 
 
@@ -136,6 +137,9 @@
 /*-- command.c --*/
 void start_command_handler (int, int);
 
+/*-- command-ssh.c --*/
+void start_command_handler_ssh (int);
+
 /*-- findkey.c --*/
 int agent_write_private_key (const unsigned char *grip,
                              const void *buffer, size_t length, int force);
Index: gnupg/agent/findkey.c
diff -u gnupg/agent/findkey.c:1.17.2.5 gnupg/agent/findkey.c:1.17.2.6
--- gnupg/agent/findkey.c:1.17.2.5	Mon Dec 13 16:49:56 2004
+++ gnupg/agent/findkey.c	Wed Jan 26 23:20:21 2005
@@ -1,5 +1,5 @@
 /* findkey.c - locate the secret key
- * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -140,6 +140,108 @@
 }
 
 
+/* Modify a Key description, replacing certain special format
+   characters.  List of currently supported replacements:
+
+   %% -> %
+   %c -> <COMMENT>. */
+static int
+modify_description (const char *description,
+		    const char *comment, size_t comment_length,
+		    char **description_modified)
+{
+  size_t description_length;
+  size_t description_new_length;
+  gpg_error_t err;
+  char *description_new;
+  unsigned int i, j;
+  unsigned int special;
+
+  description_length  = strlen (description);
+  description_new_length = description_length;
+  description_new = NULL;
+
+  /* Calculate length.  */
+  special = 0;
+  for (i = 0; i < description_length; i++)
+    {
+      if (description[i] == '%')
+	special = 1;
+      else
+	{
+	  if (special)
+	    {
+	      description_new_length -= 2;
+	      switch (description[i])
+		{
+		case 'c':
+		  /* Comment.  */
+		  description_new_length += comment_length;
+		  break;
+		  
+		case '%':
+		  description_new_length += 1;
+		  break;
+		}
+	      special = 0;
+	    }
+	}
+    }
+
+  /* Allocate.  */
+  description_new = xtrymalloc (description_new_length + 1);
+  if (! description_new)
+    {
+      err = gpg_error_from_errno (errno);
+      goto out;
+    }
+
+  /* Fill.  */
+  for (i = j = 0; i < description_length; i++)
+    {
+      if (description[i] == '%')
+	special = 1;
+      else
+	{
+	  if (special)
+	    {
+	      switch (description[i])
+		{
+		case 'c':
+		  /* Comment.  */
+		  if (comment)
+		    {
+		      strncpy (description_new + j, comment, comment_length);
+		      j += comment_length;
+		    }
+		  break;
+		  
+		case '%':
+		  description_new[j] = '%';
+		  j++;
+		  break;
+		}
+	      special = 0;
+	    }
+	  else
+	    {
+	      description_new[j] = description[i];
+	      j++;
+	    }
+	}
+    }
+
+  description_new[j] = 0;
+  *description_modified = description_new;
+  err = 0;
+
+ out:
+
+  return err;
+}
+
+  
+
 /* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
    should be the hex encoded keygrip of that key to be used with the
    caching mechanism. DESC_TEXT may be set to override the default
@@ -292,10 +394,42 @@
     case PRIVATE_KEY_CLEAR:
       break; /* no unprotection needed */
     case PRIVATE_KEY_PROTECTED:
-      rc = unprotect (ctrl, desc_text, &buf, grip, ignore_cache);
-      if (rc)
-        log_error ("failed to unprotect the secret key: %s\n",
-                   gpg_strerror (rc));
+      {
+	gcry_sexp_t comment_sexp;
+	size_t comment_length;
+	char *desc_text_final;
+	const char *comment;
+	
+	comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
+	if (comment_sexp)
+	  comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
+	else
+	  {
+	    comment = NULL;
+	    comment_length = 0;
+	  }
+
+	if (desc_text)
+	  {
+	    rc = modify_description (desc_text,
+				     comment, comment_length, &desc_text_final);
+	    if (rc)
+	      log_error ("failed to modify description: %s\n", gpg_strerror (rc));
+	  }
+	else
+	  desc_text_final = NULL;
+
+	if (! rc)
+	  {
+	    rc = unprotect (ctrl, desc_text_final, &buf, grip, ignore_cache);
+	    if (rc)
+	      log_error ("failed to unprotect the secret key: %s\n",
+			 gpg_strerror (rc));
+	  }
+
+	gcry_sexp_release (comment_sexp);
+	xfree (desc_text_final);
+      }
       break;
     case PRIVATE_KEY_SHADOWED:
       if (shadow_info)
Index: gnupg/agent/gpg-agent.c
diff -u gnupg/agent/gpg-agent.c:1.31.2.30 gnupg/agent/gpg-agent.c:1.31.2.31
--- gnupg/agent/gpg-agent.c:1.31.2.30	Tue Dec 21 20:05:15 2004
+++ gnupg/agent/gpg-agent.c	Wed Jan 26 23:20:21 2005
@@ -1,5 +1,6 @@
 /* gpg-agent.c  -  The GnuPG Agent
- *	Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ *	Copyright (C) 2000, 2001, 2002, 2003,
+ *                    2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -91,7 +92,8 @@
   oAllowMarkTrusted,
   oAllowPresetPassphrase,
   oKeepTTY,
-  oKeepDISPLAY
+  oKeepDISPLAY,
+  oSSHSupport
 };
 
 
@@ -144,6 +146,7 @@
                              N_("allow clients to mark keys as \"trusted\"")},
   { oAllowPresetPassphrase, "allow-preset-passphrase", 0,
                              N_("allow presetting passphrase")},
+  { oSSHSupport, "ssh-support", 0, "Enable SSH-Agent emulation" },
   {0}
 };
 
@@ -163,6 +166,9 @@
 /* Name of the communication socket */
 static char *socket_name;
 
+/* Name of the communication socket used for ssh-agent-emulation.  */
+static char *socket_name_ssh;
+
 /* Default values for options passed to the pinentry. */
 static char *default_display;
 static char *default_ttyname;
@@ -183,7 +189,7 @@
 /* Local prototypes. */
 static void create_directories (void);
 #ifdef USE_GNU_PTH
-static void handle_connections (int listen_fd);
+static void handle_connections (int listen_fd, int listen_fd_ssh);
 /* Pth wrapper function definitions. */
 GCRY_THREAD_OPTION_PTH_IMPL;
 #endif /*USE_GNU_PTH*/
@@ -297,22 +303,29 @@
  
 
 static void
-cleanup (void)
+cleanup_do (char *name)
 {
-  if (socket_name && *socket_name)
+  if (name && *name)
     {
       char *p;
 
-      remove (socket_name);
-      p = strrchr (socket_name, '/');
+      remove (name);
+      p = strrchr (name, '/');
       if (p)
-        {
-          *p = 0;
-          rmdir (socket_name);
-          *p = '/';
-        }
-      *socket_name = 0;
+	{
+	  *p = 0;
+	  rmdir (name);
+	  *p = '/';
+	}
+      *name = 0;
     }
+}  
+
+static void
+cleanup (void)
+{
+  cleanup_do (socket_name);
+  cleanup_do (socket_name_ssh);
 }
 
 
@@ -404,6 +417,105 @@
 }
 
 
+static void
+create_socket_name (char **name, int standard_socket,
+		    struct sockaddr_un *serv_addr,
+		    char *standard_identifier, char *identifier)
+{
+  char *p;
+
+  if (standard_socket)
+    *name = make_filename (opt.homedir, standard_identifier, NULL);
+  else
+    {
+      *name = xstrdup (identifier);
+      p = strrchr (*name, '/');
+      if (! p)
+	BUG ();
+      *p = 0;
+      if (!mkdtemp (*name))
+	{
+	  log_error (_("can't create directory `%s': %s\n"),
+		     *name, strerror (errno));
+	  exit (1);
+	}
+      *p = '/';
+    }
+
+  if (strchr (*name, PATHSEP_C))
+    {
+      log_error ("`%s' are not allowed in the socket name\n", PATHSEP_S);
+      exit (1);
+    }
+  if (strlen (*name) + 1 >= sizeof serv_addr->sun_path)
+    {
+      log_error ("name of socket too long\n");
+      exit (1);
+    }
+}
+
+static int
+create_server_socket (struct sockaddr_un *serv_addr,
+		      int standard_socket, const char *name)
+{
+  socklen_t len;
+  int fd;
+  int rc;
+
+#ifdef HAVE_W32_SYSTEM
+  fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
+#else
+  fd = socket (AF_UNIX, SOCK_STREAM, 0);
+#endif
+  if (fd == -1)
+    {
+      log_error ("can't create socket: %s\n", strerror (errno));
+      exit (1);
+    }
+
+  memset (serv_addr, 0, sizeof *serv_addr);
+  serv_addr->sun_family = AF_UNIX;
+  strcpy (serv_addr->sun_path, name);
+  len = (offsetof (struct sockaddr_un, sun_path)
+	 + strlen (serv_addr->sun_path) + 1);
+
+#ifdef HAVE_W32_SYSTEM
+  rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len);
+  if ((rc == -1) && standard_socket)
+    {
+      remove (name);
+      rc = bind (fd, (struct sockaddr*) serv_addr, len);
+    }
+#else
+  rc = bind (fd, (struct sockaddr*) serv_addr, len);
+  if ((rc == -1) && standard_socket && (errno == EADDRINUSE))
+    {
+      remove (name);
+      rc = bind (fd, (struct sockaddr*) serv_addr, len);
+    }
+#endif
+  if (rc == -1)
+    {
+      log_error ("error binding socket to `%s': %s\n",
+		 serv_addr->sun_path, strerror (errno));
+      close (fd);
+      exit (1);
+    }
+
+  if (listen (fd, 5 ) == -1)
+    {
+      log_error ("listen() failed: %s\n", strerror (errno));
+      close (fd);
+      exit (1);
+    }
+
+  if (opt.verbose)
+    log_info ("listening on socket `%s'\n", socket_name);
+
+  return fd;
+}
+
+
 int
 main (int argc, char **argv )
 {
@@ -596,6 +708,12 @@
         case oKeepTTY: opt.keep_tty = 1; break;
         case oKeepDISPLAY: opt.keep_display = 1; break;
 
+	case oSSHSupport:
+	  opt.ssh_support = 1;
+	  opt.keep_tty  = 1;
+	  opt.keep_display = 1;
+	  break;
+
         default : pargs.err = configfp? 1:2; break;
 	}
     }
@@ -745,11 +863,10 @@
   else
     { /* Regular server mode */
       int fd;
-      int rc;
+      int fd_ssh;
       pid_t pid;
-      int len;
       struct sockaddr_un serv_addr;
-      char *p;
+      struct sockaddr_un serv_addr_ssh;
 
       /* Remove the DISPLAY variable so that a pinentry does not
          default to a specific display.  There is still a default
@@ -761,90 +878,26 @@
 #endif
 
       /* Create the socket name . */
-      if (standard_socket)
-        socket_name = make_filename (opt.homedir, "S.gpg-agent", NULL);
+      create_socket_name (&socket_name, standard_socket, &serv_addr,
+			  "S.gpg-agent", "/tmp/gpg-XXXXXX/S.gpg-agent");
+      if (opt.ssh_support)
+	create_socket_name (&socket_name_ssh, standard_socket, &serv_addr_ssh,
+			    "S.gpg-agent.ssh", "/tmp/gpg-XXXXXX/S.gpg-agent.ssh");
+
+      fd = create_server_socket (&serv_addr,
+				 standard_socket, socket_name);
+      if (opt.ssh_support)
+	fd_ssh = create_server_socket (&serv_addr_ssh,
+				       standard_socket, socket_name_ssh);
       else
-        {
-          socket_name = xstrdup ("/tmp/gpg-XXXXXX/S.gpg-agent");
-          p = strrchr (socket_name, '/');
-          if (!p)
-            BUG ();
-          *p = 0;;
-          if (!mkdtemp(socket_name))
-            {
-              log_error (_("can't create directory `%s': %s\n"),
-                         socket_name, strerror(errno) );
-              exit (1);
-            }
-          *p = '/';
-        }
-
-      if (strchr (socket_name, PATHSEP_C) )
-        {
-          log_error ("`%s' are not allowed in the socket name\n", PATHSEP_S);
-          exit (1);
-        }
-      if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path ) 
-        {
-          log_error ("name of socket too long\n");
-          exit (1);
-        }
-   
-#ifdef HAVE_W32_SYSTEM
-      fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
-#else
-      fd = socket (AF_UNIX, SOCK_STREAM, 0);
-#endif
-      if (fd == -1)
-        {
-          log_error ("can't create socket: %s\n", strerror(errno) );
-          exit (1);
-        }
-
-      memset (&serv_addr, 0, sizeof serv_addr);
-      serv_addr.sun_family = AF_UNIX;
-      strcpy (serv_addr.sun_path, socket_name);
-      len = (offsetof (struct sockaddr_un, sun_path)
-             + strlen(serv_addr.sun_path) + 1);
-
-#ifdef HAVE_W32_SYSTEM
-      rc = _w32_sock_bind (fd, (struct sockaddr*)&serv_addr, len);
-      if (rc == -1 && standard_socket)
-        {
-          remove (socket_name);
-          rc = bind (fd, (struct sockaddr*)&serv_addr, len);
-        }
-#else
-      rc = bind (fd, (struct sockaddr*)&serv_addr, len);
-      if (rc == -1 && standard_socket && errno == EADDRINUSE)
-        {
-          remove (socket_name);
-          rc = bind (fd, (struct sockaddr*)&serv_addr, len);
-        }
-#endif
-      if (rc == -1)
-        {
-          log_error ("error binding socket to `%s': %s\n",
-                     serv_addr.sun_path, strerror (errno) );
-          close (fd);
-          exit (1);
-        }
-  
-      if (listen (fd, 5 ) == -1)
-        {
-          log_error ("listen() failed: %s\n", strerror (errno));
-          close (fd);
-          exit (1);
-        }
-
-      if (opt.verbose)
-        log_info ("listening on socket `%s'\n", socket_name );
-
+	/* Make the compiler happy.  */
+	fd_ssh = -1;
 
       fflush (NULL);
 #ifdef HAVE_W32_SYSTEM
       pid = getpid ();
       printf ("set GPG_AGENT_INFO=%s;%lu;1\n", socket_name, (ulong)pid);
+      printf ("set GPG_AGENT_INFO=%s;%lu;1\n", socket_name, (ulong)pid);
 #else /*!HAVE_W32_SYSTEM*/
       pid = fork ();
       if (pid == (pid_t)-1) 
@@ -854,7 +907,7 @@
         }
       else if (pid) 
         { /* We are the parent */
-          char *infostr;
+          char *infostr, *infostr_ssh_sock, *infostr_ssh_pid;
           
           close (fd);
           
@@ -866,8 +919,29 @@
               kill (pid, SIGTERM);
               exit (1);
             }
+	  if (opt.ssh_support)
+	    {
+	      if (asprintf (&infostr_ssh_sock, "SSH_AUTH_SOCK=%s",
+			    socket_name_ssh) < 0)
+		{
+		  log_error ("out of core\n");
+		  kill (pid, SIGTERM);
+		  exit (1);
+		}
+	      if (asprintf (&infostr_ssh_pid, "SSH_AGENT_PID=%u",
+			    pid) < 0)
+		{
+		  log_error ("out of core\n");
+		  kill (pid, SIGTERM);
+		  exit (1);
+		}
+	    }
+
           *socket_name = 0; /* don't let cleanup() remove the socket -
                                the child should do this from now on */
+	  if (opt.ssh_support)
+	    *socket_name_ssh = 0;
+
           if (argc) 
             { /* run the program given on the commandline */
               if (putenv (infostr))
@@ -877,6 +951,20 @@
                   kill (pid, SIGTERM );
                   exit (1);
                 }
+              if (putenv (infostr_ssh_sock))
+                {
+                  log_error ("failed to set environment: %s\n",
+                             strerror (errno) );
+                  kill (pid, SIGTERM );
+                  exit (1);
+                }
+              if (putenv (infostr_ssh_pid))
+                {
+                  log_error ("failed to set environment: %s\n",
+                             strerror (errno) );
+                  kill (pid, SIGTERM );
+                  exit (1);
+                }
               execvp (argv[0], argv);
               log_error ("failed to run the command: %s\n", strerror (errno));
               kill (pid, SIGTERM);
@@ -890,12 +978,29 @@
                 {
                   *strchr (infostr, '=') = ' ';
                   printf ( "setenv %s\n", infostr);
+		  if (opt.ssh_support)
+		    {
+		      *strchr (infostr_ssh_sock, '=') = ' ';
+		      printf ( "setenv %s\n", infostr_ssh_sock);
+		      *strchr (infostr_ssh_pid, '=') = ' ';
+		      printf ( "setenv %s\n", infostr_ssh_pid);
+		    }
                 }
               else
                 {
                   printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
+		  if (opt.ssh_support)
+		    {
+		      printf ( "%s; export SSH_AUTH_SOCK;\n", infostr_ssh_sock);
+		      printf ( "%s; export SSH_AGENT_PID;\n", infostr_ssh_pid);
+		    }
                 }
               free (infostr);
+	      if (opt.ssh_support)
+		{
+		  free (infostr_ssh_sock);
+		  free (infostr_ssh_pid);
+		}
               exit (0); 
             }
           /*NEVER REACHED*/
@@ -949,7 +1054,7 @@
 	  sa.sa_flags = 0;
 	  sigaction (SIGPIPE, &sa, NULL);
 #endif
-          handle_connections (fd);
+          handle_connections (fd, opt.ssh_support ? fd_ssh : -1);
         }
       else
 #endif /*!USE_GNU_PTH*/
@@ -1230,16 +1335,37 @@
   return NULL;
 }
 
+static void *
+start_connection_thread_ssh (void *arg)
+{
+  int fd = (int)arg;
+
+  if (opt.verbose)
+    log_info ("ssh handler for fd %d started\n", fd);
+
+  /* FIXME: Move this housekeeping into a ticker function.  Calling it
+     for each connection should work but won't work anymore if our
+     cleints start to keep connections. */
+  agent_trustlist_housekeeping ();
+
+  start_command_handler_ssh (fd);
+  if (opt.verbose)
+    log_info ("ssh handler for fd %d terminated\n", fd);
+  
+  return NULL;
+}
 
 static void
-handle_connections (int listen_fd)
+handle_connections (int listen_fd, int listen_fd_ssh)
 {
   pth_attr_t tattr;
   pth_event_t ev;
   sigset_t sigs;
   int signo;
   struct sockaddr_un paddr;
-  socklen_t plen = sizeof( paddr );
+  socklen_t plen = sizeof ( paddr );
+  fd_set fdset, read_fdset;
+  int ret;
   int fd;
 
   tattr = pth_attr_new();
@@ -1259,6 +1385,11 @@
   ev = NULL;
 #endif
 
+  FD_ZERO (&fdset);
+  FD_SET (listen_fd, &fdset);
+  if (listen_fd_ssh != -1)
+    FD_SET (listen_fd_ssh, &fdset);
+
   for (;;)
     {
       if (shutdown_pending)
@@ -1275,28 +1406,68 @@
           continue;
 	}
 
-      fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev);
-      if (fd == -1)
-        {
+      read_fdset = fdset;
+      ret = pth_select (FD_SETSIZE, &read_fdset, NULL, NULL, NULL);
+      if (ret == -1)
+	{
+	  log_error ("pth_select failed: %s - waiting 1s\n",
+		     strerror (errno));
+	  pth_sleep (1);
+	  continue;
+	}
+      
+
+      if (FD_ISSET (listen_fd, &read_fdset))
+	{
+	  fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev);
+	  if (fd == -1)
+	    {
 #ifdef PTH_STATUS_OCCURRED     /* This is Pth 2 */
-          if (pth_event_status (ev) == PTH_STATUS_OCCURRED)
+	      if (pth_event_status (ev) == PTH_STATUS_OCCURRED)
 #else
-          if (pth_event_occurred (ev))
+		if (pth_event_occurred (ev))
 #endif
-            {
-              handle_signal (signo);
-              continue;
+		  {
+		    handle_signal (signo);
+		    continue;
+		  }
+	      log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
+	      pth_sleep(1);
+	      continue;
+	    }
+
+	  if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
+	    {
+	      log_error ("error spawning connection handler: %s\n",
+			 strerror (errno) );
+	      close (fd);
 	    }
-          log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
-          pth_sleep(1);
-          continue;
 	}
+      else if ((listen_fd_ssh != -1) && FD_ISSET (listen_fd_ssh, &read_fdset))
+	{
+	  fd = pth_accept_ev (listen_fd_ssh, (struct sockaddr *)&paddr, &plen, ev);
+	  if (fd == -1)
+	    {
+#ifdef PTH_STATUS_OCCURRED     /* This is Pth 2 */
+	      if (pth_event_status (ev) == PTH_STATUS_OCCURRED)
+#else
+		if (pth_event_occurred (ev))
+#endif
+		  {
+		    handle_signal (signo);
+		    continue;
+		  }
+	      log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
+	      pth_sleep(1);
+	      continue;
+	    }
 
-      if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
-        {
-          log_error ("error spawning connection handler: %s\n",
-                     strerror (errno) );
-          close (fd);
+	  if (!pth_spawn (tattr, start_connection_thread_ssh, (void*)fd))
+	    {
+	      log_error ("error spawning connection handler: %s\n",
+			 strerror (errno) );
+	      close (fd);
+	    }
 	}
     }
 




More information about the Gnupg-commits mailing list