]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Allow changing the FTP user name and destination via repeated USER commands.
authorAlex Rousskov <rousskov@measurement-factory.com>
Fri, 30 Aug 2013 16:24:32 +0000 (10:24 -0600)
committerAlex Rousskov <rousskov@measurement-factory.com>
Fri, 30 Aug 2013 16:24:32 +0000 (10:24 -0600)
When the user or destination change, Squid closes client data connection,
and server control connection (if any).

src/FtpGatewayServer.cc
src/client_side.cc
src/client_side.h

index d570c611674f90fef2b03f009716fd12b9f0a911..aa2092fbb713de7a676b723ea777794b393cfb4d 100644 (file)
@@ -384,11 +384,9 @@ ServerStateData::readGreeting()
         if (clientState() == ConnStateData::FTP_BEGIN)
             clientState(ConnStateData::FTP_CONNECTED);
 
-        // Do not forward server greeting to client as a preliminary
-        // reply because it may confuse web browsers.  Should we
-        // forward greeting as part of the final reply?
-        //ctrl.replycode = 120; // change status for forwarded server greeting
-        //forwardPreliminaryReply(&ServerStateData::start);
+        // Do not forward server greeting to the client because our client
+        // side code has greeted the client already. Also, a greeting may
+        // confuse a client that has changed the gateway destination mid-air.
 
         start();
         break;
index eb72699df7b5d4577fd26b2ad4a6b852469b1ea7..eb9eb760f573ed9f55d97096486cddf04e411c8b 100644 (file)
@@ -4921,6 +4921,11 @@ FtpAcceptDataConnection(const CommAcceptCbParams &params)
 static void
 FtpCloseDataConnection(ConnStateData *conn)
 {
+    if (conn->ftp.listener != NULL) {
+        conn->ftp.listener->cancel("no longer needed");
+        conn->ftp.listener = NULL;
+    }
+
     if (Comm::IsConnOpen(conn->ftp.dataListenConn)) {
         debugs(33, 5, HERE << "FTP closing client data listen socket: " <<
                *conn->ftp.dataListenConn);
@@ -4928,13 +4933,18 @@ FtpCloseDataConnection(ConnStateData *conn)
     }
     conn->ftp.dataListenConn = NULL;
 
+    if (conn->ftp.reader != NULL) {
+        // comm_read_cancel can deal with negative FDs
+        comm_read_cancel(conn->ftp.dataConn->fd, conn->ftp.reader);
+        conn->ftp.reader = NULL;
+    }
+
     if (Comm::IsConnOpen(conn->ftp.dataConn)) {
         debugs(33, 5, HERE << "FTP closing client data connection: " <<
                *conn->ftp.dataConn);
         conn->ftp.dataConn->close();
     }
     conn->ftp.dataConn = NULL;
-    conn->ftp.reader = NULL;
 }
 
 /// Writes FTP [error] response before we fully parsed the FTP request and
@@ -5077,11 +5087,6 @@ FtpParseRequest(ConnStateData *connState, HttpRequestMethod *method_p, Http::Pro
             FtpWriteEarlyReply(connState, 530, "Must login first");
             return NULL;
         }
-
-        if (params.size() == 0) {
-            FtpWriteEarlyReply(connState, 501, "Missing username");
-            return NULL;
-        }
     }
 
     // We need to process USER request now because it sets request URI.
@@ -5245,9 +5250,9 @@ FtpHandlePasvReply(ClientSocketContext *context, const HttpReply *reply, StoreIO
     RefCount<AcceptCall> subCall = commCbCall(5, 5, "FtpAcceptDataConnection",
         CommAcceptCbPtrFun(FtpAcceptDataConnection, connState));
     Subscription::Pointer sub = new CallSubscription<AcceptCall>(subCall);
-    AsyncJob::Start(new Comm::TcpAcceptor(conn, note, sub));
-
+    connState->ftp.listener = subCall.getRaw();
     connState->ftp.dataListenConn = conn;
+    AsyncJob::Start(new Comm::TcpAcceptor(conn, note, sub));
 
     char addr[MAX_IPSTRLEN];
     // remote server in interception setups and local address otherwise
@@ -5635,25 +5640,29 @@ FtpHandleUserRequest(ConnStateData *connState, const String &cmd, String &params
 
     const String::size_type eou = params.rfind('@');
     if (eou == String::npos || eou + 1 >= params.size()) {
-        if (connState->ftp.uri.size() > 0)
-            return true;
         FtpWriteEarlyReply(connState, 501, "Missing host");
         return false;
     }
 
     static const String scheme = "ftp://";
+    const String login = params.substr(0, eou);
     const String host = params.substr(eou + 1, params.size());
+
     String uri = scheme;
     uri.append(host);
     uri.append("/");
 
-    if (connState->ftp.uri.size() == 0)
+    if (!connState->ftp.uri.size()) {
         connState->ftp.uri = uri;
-    else if (uri.caseCmp(connState->ftp.uri) != 0) {
-        debugs(11, 3, "expected " << connState->ftp.uri);
-        debugs(11, 3, " but got " << uri);
-        FtpWriteEarlyReply(connState, 501, "Cannot change host");
-        return false;
+        debugs(11, 3, "set URI to " << connState->ftp.uri);
+    } else if (uri.caseCmp(connState->ftp.uri) == 0) {
+        debugs(11, 5, "keep URI as " << uri);
+    } else {
+        debugs(11, 3, "reset URI from " << connState->ftp.uri << " to " << uri);
+        FtpCloseDataConnection(connState);
+        connState->ftp.readGreeting = false;
+        connState->unpinConnection(); // close control connection to the server
+        FtpChangeState(connState, ConnStateData::FTP_BEGIN, "URI reset");
     }
 
     params.cut(eou);
@@ -5714,7 +5723,7 @@ FtpHandlePortRequest(ClientSocketContext *context, String &cmd, String &params)
     // conn->local.port(20);
 
     context->getConn()->ftp.dataConn = conn;
-    context->getConn()->ftp.uploadAvailSize = 0; // XXX: FtpCloseDataConnection should do that
+    context->getConn()->ftp.uploadAvailSize = 0;
 
     FtpChangeState(context->getConn(), ConnStateData::FTP_HANDLE_PORT, "FtpHandlePortRequest");
 
@@ -5819,7 +5828,6 @@ FtpHandleConnectDone(const Comm::ConnectionPointer &conn, comm_err_t status, int
         assert(context->http && context->http->storeEntry() != NULL);
     } else {
         assert(context->getConn()->ftp.dataConn == conn);
-        context->getConn()->ftp.uploadAvailSize = 0;
         assert(Comm::IsConnOpen(context->getConn()->ftp.dataConn));
     }
     context->getConn()->resumeFtpRequest(context);
index c771d1428d2f6e3c4d21b1562028d820c6b694c1..62cdf8691572b0a2f86b3f378fe36f60962ab0f0 100644 (file)
@@ -356,6 +356,7 @@ public:
         Ip::Address serverDataAddr;
         char uploadBuf[CLIENT_REQ_BUF_SZ];
         size_t uploadAvailSize;
+        AsyncCall::Pointer listener; ///< set when we are passively listening
         AsyncCall::Pointer connector; ///< set when we are actively connecting
         AsyncCall::Pointer reader; ///< set when we are reading FTP data
     } ftp;