I'm re-writing a client that downloads some data from a 3rd party
using SFTP.  The old client was written using Paramiko but I'd like to
rewrite it using Twisted and Conch.  Right now I'm running into an
issue trying to get a directory listing from the remote server:

2011-08-22 13:35:03-0500 [SSHChannel session (0) on SSHService
ssh-connection on _WrappingProtocol,client] Unhandled Error
        Traceback (most recent call last):
          File "/usr/lib64/python2.7/site-packages/twisted/python/log.py",
line 84, in callWithLogger
            return callWithContext({"system": lp}, func, *args, **kw)
          File "/usr/lib64/python2.7/site-packages/twisted/python/log.py",
line 69, in callWithContext
            return context.call({ILogContext: newCtx}, func, *args, **kw)
          File "/usr/lib64/python2.7/site-packages/twisted/python/context.py",
line 118, in callWithContext
            return self.currentContext().callWithContext(ctx, func, *args, **kw)
          File "/usr/lib64/python2.7/site-packages/twisted/python/context.py",
line 81, in callWithContext
            return func(*args,**kw)
        --- <exception caught here> ---
          File 
"/usr/lib64/python2.7/site-packages/twisted/conch/ssh/filetransfer.py",
line 53, in dataReceived
            f(data)
          File 
"/usr/lib64/python2.7/site-packages/twisted/conch/ssh/filetransfer.py",
line 711, in packet_STATUS
            msg, data = getNS(data)
          File "/usr/lib64/python2.7/site-packages/twisted/conch/ssh/common.py",
line 36, in getNS
            l, = struct.unpack('!L',s[c:c+4])
        struct.error: unpack requires a string argument of length 4

The problem seems to be that the remote SFTP implementation isn't
returning complete status response message - it doesn't include the
error message and the language identifier.  I made a quite ugly
workaround:

diff --git a/twisted/conch/ssh/filetransfer.py b/twisted/conch/ssh/filetransfer.
index 81a86fd..ed55b27 100644
--- a/twisted/conch/ssh/filetransfer.py
+++ b/twisted/conch/ssh/filetransfer.py
@@ -708,8 +708,15 @@ class FileTransferClient(FileTransferBase):
         d, data = self._parseRequest(data)
         code, = struct.unpack('!L', data[:4])
         data = data[4:]
-        msg, data = getNS(data)
-        lang = getNS(data)
+        if len(data) >= 4:
+            msg, data = getNS(data)
+            if len(data) >= 4:
+                lang = getNS(data)
+            else:
+                lang = ''
+        else:
+            msg = ''
+            lang = ''
         if code == FX_OK:
             d.callback((msg, lang))
         elif code == FX_EOF:

Looking through the Paramiko code[1] it looks like it pads SFTP
messages that are shorter than expected with null bytes.  From what I
saw in the  SFTP I-D[2], a status message that doesn't include the
error message and language code could be construed as legal even
though they are not specifically marked as optional.


[1] https://github.com/robey/paramiko/blob/master/paramiko/message.py#L103
[2] http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-4

-- 
Jeff Ollie

_______________________________________________
Twisted-Python mailing list
Twisted-Python@twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

Reply via email to