From: Alex Rousskov Date: Fri, 30 Aug 2013 16:24:32 +0000 (-0600) Subject: Allow changing the FTP user name and destination via repeated USER commands. X-Git-Tag: SQUID_3_5_0_1~117^2~38 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fac171a8371b492d5abf64d61a330f29e8ecc464;p=thirdparty%2Fsquid.git Allow changing the FTP user name and destination via repeated USER commands. When the user or destination change, Squid closes client data connection, and server control connection (if any). --- diff --git a/src/FtpGatewayServer.cc b/src/FtpGatewayServer.cc index d570c61167..aa2092fbb7 100644 --- a/src/FtpGatewayServer.cc +++ b/src/FtpGatewayServer.cc @@ -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; diff --git a/src/client_side.cc b/src/client_side.cc index eb72699df7..eb9eb760f5 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -4921,6 +4921,11 @@ FtpAcceptDataConnection(const CommAcceptCbParams ¶ms) 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 subCall = commCbCall(5, 5, "FtpAcceptDataConnection", CommAcceptCbPtrFun(FtpAcceptDataConnection, connState)); Subscription::Pointer sub = new CallSubscription(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 ¶ms 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 ¶ms) // 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); diff --git a/src/client_side.h b/src/client_side.h index c771d1428d..62cdf86915 100644 --- a/src/client_side.h +++ b/src/client_side.h @@ -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;