]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
FEAT response with excessive whitespace
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Thu, 23 Jan 2014 18:10:31 +0000 (20:10 +0200)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Thu, 23 Jan 2014 18:10:31 +0000 (20:10 +0200)
Some broken Microsoft FTP servers seem to be sending the following
response to the FEAT command:

211-FEAT
....SIZE
....MDTM
211 END

A single dot above represents a single space character, so instead of
one space character they send 4 (four) space characters at the beginning
of the internal FEAT lines.

When this happens, the FTP client who sent the FEAT request to Squid
gets nothing; its connection hangs.

The problem is inside FtpHandleFeatReply function while parses the commands
list. Arguments corresponding to an emty string passes to String::substr call
(e->value.substr(beg-raw, end-raw) call) causing failure to a Must clause.

This patch:
 - fixes and adds checks to avoid processing lines which does not include a
   command.
 - try to detect extra spaces before commands
 - try to add the same number of spaces before commands inserted by squid
   to FEAT commands list (EPSV and EPRT commands)

src/client_side.cc

index c4187e60d09c575ca8889f756e726baff3fe3365..77b58f30a84fc367aee1546f3a1c52fc20842bef 100644 (file)
@@ -5339,18 +5339,27 @@ FtpHandleFeatReply(ClientSocketContext *context, const HttpReply *reply, StoreIO
     HttpHeaderPos pos = HttpHeaderInitPos;
     bool hasEPRT = false;
     bool hasEPSV = false;
+    int prependSpaces = 1;
     while (const HttpHeaderEntry *e = filteredHeader.getEntry(&pos)) {
         if (e->id == HDR_FTP_PRE) {
             // assume RFC 2389 FEAT response format, quoted by Squid:
             // <"> SP NAME [SP PARAMS] <">
+            // but accommodate MS servers sending four SPs before NAME
             if (e->value.size() < 4)
                 continue;
             const char *raw = e->value.termedBuf();
-            if (raw[0] != '"' && raw[1] != ' ')
+            if (raw[0] != '"' || raw[1] != ' ')
                 continue;
-            const char *beg = raw + 2; // after quote and space
+            const char *beg = raw + 1 + strspn(raw + 1, " "); // after quote and spaces
             // command name ends with (SP parameter) or quote
             const char *end = beg + strcspn(beg, " \"");
+
+            if (end <= beg)
+                continue;
+
+            // compute the number of spaces before the command
+            prependSpaces = beg - raw - 1;
+
             const String cmd = e->value.substr(beg-raw, end-raw);
 
             if (!FtpSupportedCommand(cmd))
@@ -5363,13 +5372,16 @@ FtpHandleFeatReply(ClientSocketContext *context, const HttpReply *reply, StoreIO
         }
     }
 
+    char buf[256];
     int insertedCount = 0;
     if (!hasEPRT) {
-        filteredHeader.putStr(HDR_FTP_PRE, "\" EPRT\"");
+        snprintf(buf, sizeof(buf), "\"%*s\"", prependSpaces + 4, "EPRT");
+        filteredHeader.putStr(HDR_FTP_PRE, buf);
         ++insertedCount;
     }
     if (!hasEPSV) {
-        filteredHeader.putStr(HDR_FTP_PRE, "\" EPSV\"");
+        snprintf(buf, sizeof(buf), "\"%*s\"", prependSpaces + 4, "EPSV");
+        filteredHeader.putStr(HDR_FTP_PRE, buf);
         ++insertedCount;
     }