[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[gftp] Re: gftp does not tolerate ssh2 banner



Hi,
   I improved the login sequence for SSH2 servers in my current CVS tree. I have
a tarball of my latest code online at http://www.gftp.org/gftp-test.tar.bz2. It
will handle login banners without any problems. I also removed the options for
use SSH subsystem, the sftp-server path and use the ssh-askpass utility. My
latest code always uses the SFTP subsystem.

Brian


On Wed, Sep 08, 2004 at 06:01:20PM -0400, Phillip Vandry wrote:
> Hello,
> 
> I took a look at gftp while looking for a GUI SFTP client. It looks
> like gftp is a good match to this need and from what I have seen, it
> works well.
> 
> The problem I had with it is that it was difficult to get it to connect.
> 
> The default mode of operation does not use the ssh subsystem mechanism,
> but instead just tries to launch "sftp-server" as a comment on the remote
> system. I found that this did not work very well because "sftp-server"
> is not in my $PATH. On Debian systems it is in /usr/lib, and on my
> Solaris systems on which I have installed openssh myself it is in
> /opt/openssh/libexec. gftp has a configuration item that lets me specify
> the directory in which "sftp-server" is located so that is how I was able
> to get gftp to work at first but I don't really like that option because
> the user should not really be expected to supply this server specific
> information, and SFTP is supposed to be called an an ssh subsystem anyway.
> 
> gftp supports launching the SFTP server as a subsystem but I had even
> less success with this. The problem in this case was simple: gftp mistook
> my ssh server's login banner for a corrupted SFTP message and closed the
> connection. In other words it cannot detect where a textual message from
> the ssh invocation stops and the SFTP protocol begins. It is possible
> that you only tested this feature of gftp so far against ssh servers
> that do not output a banner. I thought of several solutions to this.
> 
> (1) launch the ssh client with the -q option to suppress messages.
> The disadvantage is that other important messages will be lost as well.
> 
> (2) detect a textual message that precedes the SFTP protocol stream by
> scanning the input for a valid SFTP packet and assuming that everything
> that comes before is a text message.
> 
> (3) Use an enhanced version of the gftp_exec_without_new_pty() function
> that creates seperate pipes for the ssh command's stdout and stderr. Read
> SFTP protocol data from the stdout pipe, and read textual messages which
> should be relayed to the user from the stderr pipe.
> 
> My favorite solution is the third one, but it is the most complicated to
> implement and requires changing or extending the application's design a
> little bit. If this is the solution that is ultimately chosen then I'd
> like to at least hear your opinion of it before implementing it.
> 
> What I implemented is the second solution. This seems to work fine and
> may actually be sufficient.
> 
> Here's what else needs to be done:
> 
> - I changed a message that gets output to the log to reflect that the
> server issued a message rather than assuming it is an error. The new
> message will need to be translated. I have only supplied two translations.
> 
> - Change the type of this message to something other than an error.
> 
> The patch is attached.
> 
> -Phil
> 
> -- 
> Q. Why can /dev/null accept only integers?  A. You can't sink a float

> --- sshv2.c	2004/09/08 20:51:53	1.1
> +++ sshv2.c	2004/09/08 21:58:16	1.2
> @@ -18,7 +18,7 @@
>  /*****************************************************************************/
>  
>  #include "gftp.h"
> -static const char cvsid[] = "$Id: sshv2.c,v 1.1 2004/09/08 20:51:53 vandry Exp $";
> +static const char cvsid[] = "$Id: sshv2.c,v 1.2 2004/09/08 21:58:16 vandry Exp $";
>  
>  #define SSH_MAX_HANDLE_SIZE		256
>  #define SSH_MAX_STRING_SIZE		34000
> @@ -604,9 +604,10 @@
>  sshv2_read_response (gftp_request * request, sshv2_message * message,
>                       int fd)
>  {
> -  char buf[6], error_buffer[255], *pos;
> +  char buf[6], error_buffer[2], *pos;
>    sshv2_params * params;
>    ssize_t numread, rem;
> +  int notok = 0;
>  
>    params = request->protocol_data;
>  
> @@ -633,30 +634,68 @@
>            request->logging_function (gftp_logging_error, request,
>                               _("Error: Message size %d too big from server\n"),
>                               message->length);
> +	  notok = 1;
>          }
>        else
>          {
> +	  /* If the connection is not yet initialized, we might expect to see
> +	     either a harmless message (like a server banner) or an important
> +	     error message either before, or instead of the sftp data */
> +
> +	  /* We got here because the first four bytes of the stream represented
> +	     a ridiculous message length. Almost any ASCII message will trigger
> +	     this, which is good */
> +
> +	  /* What we will do is read one byte at a time until we get something
> +	     that looks valid -and- happens to be a SSH_FXP_VERSION message.
> +	     -pkv */
> +
>            request->logging_function (gftp_logging_error, request,
> -                     _("There was an error initializing a SSH connection with the remote server. The error message from the remote server follows:\n"), buf);
> +                     _("The server reported the following message while initializing a SSH connection:\n"), buf);
>  
> -          request->logging_function (gftp_logging_error, request, "%s", buf);
> +	  error_buffer[0] = buf[0];
> +	  error_buffer[1] = 0;
> +          request->logging_function (gftp_logging_error, request, "%s", error_buffer);
>  
>            if (gftp_fd_set_sockblocking (request, fd, 0) == -1)
>              return (GFTP_EFATAL);
>  
> -          if ((numread = gftp_fd_read (NULL, error_buffer, 
> -                                          sizeof (error_buffer) - 1, 
> -                                          fd)) > 0)
> -            {
> -              error_buffer[numread] = '\0';
> -              request->logging_function (gftp_logging_error, request,
> -                                         "%s", error_buffer);
> -            }
> +	  for (;;) {
> +		/* shift the buffer by one */
> +		buf[0] = buf[1]; buf[1] = buf[2];
> +		buf[2] = buf[3]; buf[3] = buf[4];
> +
> +		/* read only one byte into the end of the buffer */
> +		if ((numread = gftp_fd_read(NULL, buf+4, 1, fd)) > 0) {
> +			/* got one. try again to reinterpret the message. */
> +			memcpy(&message->length, buf, 4);
> +			message->length = ntohl(message->length);
> +			if ((message->length <= 34000) && (buf[4] == SSH_FXP_VERSION))
> +				break;
> +
> +			/* still no good. One more character must be part of
> +			   the text message. */
> +			error_buffer[0] = buf[0];
> +			request->logging_function(gftp_logging_error,
> +				request, "%s", error_buffer);
> +		} else {
> +			/* We ran out of bytes to read or an error occured. */
> +			/* Assume the five bytes we already have are the tail
> +			   end of a text message, so log them */
> +			buf[4] = 0;
> +			request->logging_function(gftp_logging_error,
> +				request, "%s", buf);
> +			notok = 1;
> +		}
> +	  }
> +
>          }
>  
> -      memset (message, 0, sizeof (*message));
> -      gftp_disconnect (request);
> -      return (GFTP_EFATAL);
> +      if (notok) {
> +	memset (message, 0, sizeof (*message));
> +	gftp_disconnect (request);
> +	return (GFTP_EFATAL);
> +      }
>      }
>  
>    message->command = buf[4];
> --- fr.po	2004/09/08 21:48:22	1.1
> +++ fr.po	2004/09/08 21:58:21	1.2
> @@ -1304,11 +1304,9 @@
>  
>  #: lib/sshv2.c:640
>  msgid ""
> -"There was an error initializing a SSH connection with the remote server. The "
> -"error message from the remote server follows:\n"
> +"The server reported the following message while initializing a SSH connection:\n"
>  msgstr ""
> -"Il y a eu une erreur ?? l'initialisation de la connexion SSH avec le serveur "
> -"distant. Le message d'erreur du serveur distant suit??:\n"
> +"Le serveur a ??mis le message suivant au moment de l'initialisation de la connexion SSH:\n"
>  
>  #: lib/sshv2.c:869
>  #, c-format
> --- ja.po	2004/09/08 21:51:24	1.1
> +++ ja.po	2004/09/08 21:58:24	1.2
> @@ -1256,11 +1256,9 @@
>  
>  #: lib/sshv2.c:640
>  msgid ""
> -"There was an error initializing a SSH connection with the remote server. The "
> -"error message from the remote server follows:\n"
> +"The server reported the following message while initializing a SSH connection:\n"
>  msgstr ""
> -"??????????????????????????? SSH ??????????????????????????????????????????????????????????????????????????????"
> -"?????????????????????:\n"
> +"SSH ?????????????????????????????????????????????????????????????????????????????????????????????:\n"
>  
>  #: lib/sshv2.c:869
>  #, c-format