changeset 458:656a0b3d1403

2004-4-10 Brian Masney <masneyb@gftp.org> * lib/gftp.h lib/pty.c lib/sshv2.c - added gftp_exec() that will always open a pseudo terminal and a separate socket pair for the stdin/stdout file descriptors. The banner and password request will come through the pseudo terminal while the sftp protocol specific data will always come through the socket pair. This allows for a much cleaner SSH login sequence that does not require echo xsftp to capture a login banner. Removed option ssh_use_askpass since it is no longer needed. This code is based off of a suggestion from Gertjan Halkes * src/text/gftp-text.c - removed setting the options ssh_use_askpass and sshv2_use_sftp_subsys
author masneyb
date Sat, 10 Apr 2004 15:14:46 +0000
parents afa37403af96
children b4abf70c6425
files ChangeLog lib/gftp.h lib/pty.c lib/sshv2.c src/text/gftp-text.c
diffstat 5 files changed, 133 insertions(+), 134 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Apr 10 00:28:31 2004 +0000
+++ b/ChangeLog	Sat Apr 10 15:14:46 2004 +0000
@@ -1,3 +1,16 @@
+2004-4-10 Brian Masney <masneyb@gftp.org>
+	* lib/gftp.h lib/pty.c lib/sshv2.c - added gftp_exec() that will always
+	open a pseudo terminal and a separate socket pair for the stdin/stdout
+	file descriptors. The banner and password request will come through the
+	pseudo terminal while the sftp protocol specific data will always come
+	through the socket pair. This allows for a much cleaner SSH login
+	sequence that does not require echo xsftp to capture a login banner. 
+	Removed option ssh_use_askpass since it is no longer needed.
+	This code is based off of a suggestion from Gertjan Halkes
+
+	* src/text/gftp-text.c - removed setting the options ssh_use_askpass
+	and sshv2_use_sftp_subsys
+
 2004-03-30  Gareth Owen  <gowen72@yahoo,com>
 
 	* configure.in: Added en_GB to ALL_LINGUAS
@@ -2406,7 +2419,7 @@
 
 	* cvsclean - added this script
 
-	* *.[ch] - added $Id: ChangeLog,v 1.256 2004/03/31 04:14:33 gowen Exp $ tags
+	* *.[ch] - added $Id: ChangeLog,v 1.257 2004/04/10 15:14:45 masneyb Exp $ tags
 
 	* debian/* - updated files from Debian maintainer
 
--- a/lib/gftp.h	Sat Apr 10 00:28:31 2004 +0000
+++ b/lib/gftp.h	Sat Apr 10 15:14:46 2004 +0000
@@ -1007,12 +1007,9 @@
 /* pty.c */
 char * gftp_get_pty_impl 		( void );
 
-pid_t gftp_exec_with_new_pty 		( gftp_request * request, 
-					  int *fdm, 
-					  char **args );
-
-pid_t gftp_exec_without_new_pty 	( gftp_request * request, 
-					  int *fdm, 
+pid_t gftp_exec 			( gftp_request * request,
+					  int *fdm,
+					  int *ptymfd,
 					  char **args );
 
 #ifdef USE_SSL
--- a/lib/pty.c	Sat Apr 10 00:28:31 2004 +0000
+++ b/lib/pty.c	Sat Apr 10 15:14:46 2004 +0000
@@ -259,7 +259,7 @@
 
 
 static void
-_gftp_close_all_fds (void)
+_gftp_close_all_fds (int ptysfd)
 {
   int i, maxfds;
 
@@ -272,16 +272,32 @@
 #endif
 
   for (i=3; i<maxfds; i++)
-    close (i);
+    {
+      if (i == ptysfd)
+        continue;
+
+      close (i);
+    }
 }
 
 
 pid_t
-gftp_exec_without_new_pty (gftp_request * request, int *fdm, char **args)
+gftp_exec (gftp_request * request, int *fdm, int *ptymfd, char **args)
 {
+  char pts_name[64];
   pid_t child;
+  int ptysfd;
   int s[2];
 
+  *pts_name = '\0';
+  if ((*ptymfd = _gftp_ptym_open (pts_name, sizeof (pts_name), &ptysfd)) < 0)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                _("Cannot open master pty %s: %s\n"), pts_name,
+                                g_strerror (errno));
+      return (-1);
+    }
+
   if (socketpair (AF_LOCAL, SOCK_STREAM, 0, s) < 0)
     {
       request->logging_function (gftp_logging_error, request,
@@ -294,24 +310,36 @@
     {
       setsid ();
 
+      if ((ptysfd = _gftp_ptys_open (*ptymfd, ptysfd, pts_name)) < 0)
+        {
+          printf ("Cannot open slave pts %s: %s\n", pts_name,
+                  g_strerror (errno));
+          return (-1);
+        }
+
       close (s[0]);
+      close (*ptymfd);
 
       _gftp_tty_raw (s[1]);
+      _gftp_tty_raw (ptysfd);
+
       dup2 (s[1], 0);
       dup2 (s[1], 1);
-      dup2 (s[1], 2);
-      _gftp_close_all_fds ();
+      _gftp_close_all_fds (ptysfd);
 
       execvp (args[0], args);
 
       printf (_("Error: Cannot execute ssh: %s\n"), g_strerror (errno));
-      exit (1);
+      _exit (1);
     }
   else if (child > 0)
     {
       close (s[1]);
+
+      *fdm = s[0];
       _gftp_tty_raw (s[0]);
-      *fdm = s[0];
+      _gftp_tty_raw (*ptymfd);
+
       return (child);
     }
   else
@@ -323,58 +351,3 @@
     }
 }
 
-
-pid_t
-gftp_exec_with_new_pty (gftp_request * request, int *fdm, char **args)
-{
-  char pts_name[64];
-  pid_t child;
-  int fds;
-
-  *pts_name = '\0';
-  if ((*fdm = _gftp_ptym_open (pts_name, sizeof (pts_name), &fds)) < 0)
-    {
-      request->logging_function (gftp_logging_error, request->user_data,
-                                _("Cannot open master pty %s: %s\n"), pts_name,
-                                g_strerror (errno));
-      return (-1);
-    }
-
-  if ((child = fork ()) == 0)
-    {
-      setsid ();
-
-      if ((fds = _gftp_ptys_open (*fdm, fds, pts_name)) < 0)
-        {
-          printf ("Cannot open slave pts %s: %s\n", pts_name, 
-                  g_strerror (errno));
-          return (-1);
-        }
-
-      close (*fdm);
-
-      _gftp_tty_raw (fds);
-      dup2 (fds, 0);
-      dup2 (fds, 1);
-      dup2 (fds, 2);
-      _gftp_close_all_fds ();
-
-      execvp (args[0], args);
-
-      printf (_("Error: Cannot execute ssh: %s\n"), g_strerror (errno));
-      exit (1);
-    }
-  else if (child > 0)
-    {
-      _gftp_tty_raw (*fdm);
-      return (child);
-    }
-  else
-    {
-      request->logging_function (gftp_logging_error, request->user_data,
-                                 _("Cannot fork another process: %s\n"),
-                                 g_strerror (errno));
-      return (-1);
-    }
-}
-
--- a/lib/sshv2.c	Sat Apr 10 00:28:31 2004 +0000
+++ b/lib/sshv2.c	Sat Apr 10 15:14:46 2004 +0000
@@ -42,11 +42,6 @@
    gftp_option_type_checkbox, GINT_TO_POINTER(1), NULL, 
    GFTP_CVARS_FLAGS_SHOW_BOOKMARK,
    N_("Require a username/password for SSH connections"), GFTP_PORT_ALL, NULL},
-  {"ssh_use_askpass", N_("Use ssh-askpass utility"),
-   gftp_option_type_checkbox, GINT_TO_POINTER(0), NULL, 
-   GFTP_CVARS_FLAGS_SHOW_BOOKMARK,
-   N_("Use the ssh-askpass utility to supply the remote password"), GFTP_PORT_GTK,
-        NULL},
   {"sshv2_use_sftp_subsys", N_("Use SSH2 SFTP subsys"), 
    gftp_option_type_checkbox, GINT_TO_POINTER(0), NULL, 
    GFTP_CVARS_FLAGS_SHOW_BOOKMARK,
@@ -253,7 +248,7 @@
                          " %s -s sftp", request->hostname);
   else
     sshv2_add_exec_args (&logstr, &logstr_len, &args, &args_len, &args_cur,
-                         " %s \"%s\"", request->hostname, execname);
+                         " %s %s", request->hostname, execname);
 
   request->logging_function (gftp_logging_misc, request, 
                              _("Running program %s\n"), logstr);
@@ -262,33 +257,81 @@
 }
 
 
-static char *
-sshv2_start_login_sequence (gftp_request * request, int fd)
+static int
+sshv2_start_login_sequence (gftp_request * request, int fdm, int ptymfd)
 {
+  size_t rem, len, diff, lastdiff;
   char *tempstr, *pwstr, *tmppos;
-  size_t rem, len, diff, lastdiff, key_pos;
-  int wrotepw, ok;
+  int wrotepw, ok, maxfd, ret;
+  fd_set rset, eset;
   ssize_t rd;
 
   rem = len = SSH_LOGIN_BUFSIZE;
   tempstr = g_malloc0 (len + 1);
-  key_pos = diff = lastdiff = 0;
+  diff = lastdiff = 0;
   wrotepw = 0;
   ok = 1;
 
-  if (gftp_fd_set_sockblocking (request, fd, 1) == -1)
-    return (NULL);
+  if (gftp_fd_set_sockblocking (request, fdm, 1) == -1)
+    return (GFTP_ERETRYABLE);
+
+  if (gftp_fd_set_sockblocking (request, ptymfd, 1) == -1)
+    return (GFTP_ERETRYABLE);
 
-  pwstr = g_strconcat (request->password, "\n", NULL);
+  if (request->password == NULL)
+    pwstr = g_strdup ("\n");
+  else
+    pwstr = g_strconcat (request->password, "\n", NULL);
+
+  FD_ZERO (&rset);
+  FD_ZERO (&eset);
+  maxfd = fdm > ptymfd ? fdm : ptymfd;
 
   errno = 0;
   while (1)
     {
-      if ((rd = gftp_fd_read (request, tempstr + diff, rem - 1, fd)) <= 0)
+      FD_SET (fdm, &rset);
+      FD_SET (ptymfd, &rset);
+
+      FD_SET (fdm, &eset);
+      FD_SET (ptymfd, &eset);
+
+      ret = select (maxfd + 1, &rset, NULL, &eset, NULL);
+      if (ret < 0 && errno == EINTR)
+        continue;
+
+      if (ret < 0)
         {
-          ok = 0;
+          request->logging_function (gftp_logging_error, request,
+                                     _("Connection to %s timed out\n"),
+                                     request->hostname);
+          gftp_disconnect (request);
+          return (GFTP_ERETRYABLE);
+        }
+
+      if (FD_ISSET (fdm, &eset) || FD_ISSET (ptymfd, &eset))
+        {
+          request->logging_function (gftp_logging_error, request,
+                               _("Error: Could not read from socket: %s\n"),
+                                g_strerror (errno));
+          gftp_disconnect (request);
+          return (GFTP_ERETRYABLE);
+        }
+        
+      if (FD_ISSET (fdm, &rset))
+        {
+          ok = 1;
           break;
         }
+      else if (!FD_ISSET (ptymfd, &rset))
+        continue;
+
+      rd = gftp_fd_read (request, tempstr + diff, rem - 1, ptymfd);
+      if (rd < 0)
+        return (rd);
+      else if (rd == 0)
+        continue;
+
       rem -= rd;
       diff += rd;
       tempstr[diff] = '\0'; 
@@ -310,17 +353,16 @@
             }
               
           wrotepw = 1;
-          if (gftp_fd_write (request, pwstr, strlen (pwstr), fd) < 0)
+          if (gftp_fd_write (request, pwstr, strlen (pwstr), ptymfd) < 0)
             {
               ok = 0;
               break;
             }
         }
       else if (diff > 2 && strcmp (tempstr + diff - 2, ": ") == 0 &&
-               ((tmppos = strstr (tempstr + key_pos, "Enter passphrase for RSA key")) != NULL ||
-                ((tmppos = strstr (tempstr + key_pos, "Enter passphrase for key '")) != NULL)))
+               ((tmppos = strstr (tempstr, "Enter passphrase for RSA key")) != NULL ||
+                ((tmppos = strstr (tempstr, "Enter passphrase for key '")) != NULL)))
         {
-          key_pos = diff;
           if (wrotepw)
             {
               ok = SSH_ERROR_BADPASS;
@@ -335,7 +377,7 @@
             }
 
           wrotepw = 1;
-          if (gftp_fd_write (request, pwstr, strlen (pwstr), fd) < 0)
+          if (gftp_fd_write (request, pwstr, strlen (pwstr), ptymfd) < 0)
             {
               ok = 0;
               break;
@@ -346,8 +388,6 @@
           ok = SSH_ERROR_QUESTION;
           break;
         }
-      else if (diff >= 5 && strcmp (tempstr + diff - 5, "xsftp") == 0)
-        break;
       else if (rem <= 1)
         {
           request->logging_function (gftp_logging_recv, request,
@@ -366,6 +406,8 @@
     request->logging_function (gftp_logging_recv, request,
                                "%s\n", tempstr + lastdiff);
 
+  g_free (tempstr);
+
   if (ok <= 0)
     {
       if (ok == SSH_ERROR_BADPASS)
@@ -378,11 +420,10 @@
         request->logging_function (gftp_logging_error, request,
                                    _("Please correct the above warning to connect to this host.\n"));
 
-      g_free (tempstr);
-      return (NULL);
+      return (GFTP_EFATAL);
     }
  
-  return (tempstr);
+  return (0);
 }
 
 
@@ -585,7 +626,7 @@
   buf[len + 5] = '\0';
 
 #ifdef DEBUG
-  printf ("\rSending: ");
+  printf ("\rSending to FD %d: ", request->datafd);
   for (clen=0; clen<len + 5; clen++)
     printf ("%x ", buf[clen] & 0xff);
   printf ("\n");
@@ -848,9 +889,9 @@
 static int
 sshv2_connect (gftp_request * request)
 {
-  int version, ret, fdm;
-  intptr_t ssh_use_askpass, sshv2_use_sftp_subsys;
-  char **args, *tempstr, *p1, p2, *exepath, *ssh2_sftp_path;
+  char **args, *p1, p2, *exepath, *ssh2_sftp_path;
+  intptr_t sshv2_use_sftp_subsys;
+  int version, ret, fdm, ptymfd;
   struct servent serv_struct;
   sshv2_params * params;
   sshv2_message message;
@@ -869,13 +910,7 @@
 			     _("Opening SSH connection to %s\n"),
                              request->hostname);
 
-  /* Ugh!! We don't get a login banner from sftp-server, and if we are
-     using ssh-agent to cache a users password, then we won't receive
-     any initial text from the server, and we'll block. So I just send a 
-     xsftp server banner over. I hope this works on most Unices */
-
   gftp_lookup_request_option (request, "ssh2_sftp_path", &ssh2_sftp_path);
-  gftp_lookup_request_option (request, "ssh_use_askpass", &ssh_use_askpass);
   gftp_lookup_request_option (request, "sshv2_use_sftp_subsys", 
                               &sshv2_use_sftp_subsys);
 
@@ -902,35 +937,20 @@
         request->port = ntohs (serv_struct.s_port);
     }
 
-  exepath = g_strdup_printf ("echo -n xsftp ; %s%csftp-server", p1, p2);
+  exepath = g_strdup_printf ("%s%csftp-server", p1, p2);
   args = sshv2_gen_exec_args (request, exepath, sshv2_use_sftp_subsys);
 
-  if (ssh_use_askpass || sshv2_use_sftp_subsys)
-    child = gftp_exec_without_new_pty (request, &fdm, args);
-  else
-    child = gftp_exec_with_new_pty (request, &fdm, args);
+  child = gftp_exec (request, &fdm, &ptymfd, args);
 
   if (child == 0)
     exit (0);
-  else if (child < 0)
-    return (GFTP_ERETRYABLE);
-
-  if (!sshv2_use_sftp_subsys)
-    {
-      tempstr = sshv2_start_login_sequence (request, fdm);
-      if (!tempstr || !(strlen (tempstr) > 4 && strcmp (tempstr + strlen (tempstr) - 5,
-                                                        "xsftp") == 0))
-        {
-          sshv2_free_args (args);
-          g_free (exepath);
-          return (GFTP_EFATAL);
-        }
-      g_free (tempstr);
-    }
 
   sshv2_free_args (args);
   g_free (exepath);
 
+  if (child < 0)
+    return (GFTP_ERETRYABLE);
+
   request->datafd = fdm;
 
   version = htonl (SSH_MY_VERSION);
@@ -938,6 +958,10 @@
                                  &version, 4)) < 0)
     return (ret);
 
+  ret = sshv2_start_login_sequence (request, fdm, ptymfd);
+  if (ret < 0)
+    return (ret);
+
   memset (&message, 0, sizeof (message));
   ret = sshv2_read_response (request, &message, -1);
   if (ret < 0)
--- a/src/text/gftp-text.c	Sat Apr 10 00:28:31 2004 +0000
+++ b/src/text/gftp-text.c	Sat Apr 10 15:14:46 2004 +0000
@@ -238,20 +238,12 @@
 
   gftp_text_remreq = gftp_request_new ();
   remuidata = gftp_text_remreq;
-  gftp_set_request_option (gftp_text_remreq, "ssh_use_askpass", 
-                           GINT_TO_POINTER(0));
-  gftp_set_request_option (gftp_text_remreq, "sshv2_use_sftp_subsys", 
-                           GINT_TO_POINTER(0));
   gftp_text_remreq->logging_function = gftp_text_log;
 
   gftp_text_locreq = gftp_request_new ();
   locuidata = gftp_text_locreq;
-  gftp_set_request_option (gftp_text_locreq, "ssh_use_askpass", 
-                           GINT_TO_POINTER(0));
-  gftp_set_request_option (gftp_text_locreq, "sshv2_use_sftp_subsys", 
-                           GINT_TO_POINTER(0));
+  gftp_text_locreq->logging_function = gftp_text_log;
 
-  gftp_text_locreq->logging_function = gftp_text_log;
   if (gftp_protocols[GFTP_LOCAL_NUM].init (gftp_text_locreq) == 0)
     {
       gftp_setup_startup_directory (gftp_text_locreq);