📄 ftpcontrolsocket.cpp
字号:
// FileZilla - a Windows ftp client
// Copyright (C) 2002 - Tim Kosse <tim.kosse@gmx.de>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// CFtpControlSocket.cpp: Implementierungsdatei
//
#include "stdafx.h"
#include "FtpControlSocket.h"
#include "mainthread.h"
#include "transfersocket.h"
#include "fileexistsdlg.h"
#include "pathfunctions.h"
#include "asyncproxysocketlayer.h"
#include "AsyncSslSocketLayer.h"
#include "AsyncGssSocketLayer.h"
#include "filezillaapi.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
class CFtpControlSocket::CFileTransferData : public CFtpControlSocket::t_operation::COpData
{
public:
CFileTransferData()
{
pDirectoryListing=0;
nGotTransferEndReply=0;
nWaitNextOpState=0;
bSentStor=FALSE;
nMKDOpState=-1;
pFileTime=0;
pFileSize=0;
bUseAbsolutePaths = FALSE;
bTriedPortPasvOnce = FALSE;
};
~CFileTransferData()
{
if (pDirectoryListing)
delete pDirectoryListing;
pDirectoryListing=0;
delete pFileSize;
delete pFileTime;
};
CString rawpwd;
t_transferfile transferfile;
t_transferdata transferdata;
CString host;
int port;
BOOL bPasv;
int nGotTransferEndReply;
t_directory *pDirectoryListing;
int nWaitNextOpState;
BOOL bSentStor;
CServerPath MKDCurrent;
std::list<CString> MKDSegments;
int nMKDOpState;
CTime ListStartTime;
CTime *pFileTime; //Used when downloading and OPTION_PRESERVEDOWNLOADFILETIME is set or when LIST fails
_int64 *pFileSize; //Used when LIST failes
BOOL bUseAbsolutePaths;
BOOL bTriedPortPasvOnce;
};
class CFtpControlSocket::CListData:public CFtpControlSocket::t_operation::COpData
{
public:
CListData()
{
pDirectoryListing = 0;
bTriedPortPasvOnce = FALSE;
}
virtual ~CListData()
{
if (pDirectoryListing)
delete pDirectoryListing;
}
CString rawpwd;
CServerPath path;
CString subdir;
CServerPath realpath;
int nListMode;
BOOL bPasv;
CString host;
UINT port;
int nFinish;
t_directory *pDirectoryListing;
CTime ListStartTime;
BOOL bTriedPortPasvOnce;
};
class CFtpControlSocket::CMakeDirData : public CFtpControlSocket::t_operation::COpData
{
public:
CMakeDirData() {}
virtual ~CMakeDirData() {}
CServerPath path;
CServerPath Current;
std::list<CString> Segments;
};
#define MKD_INIT -1
#define MKD_FINDPARENT 0
#define MKD_MAKESUBDIRS 1
#define MKD_CHANGETOSUBDIR 2
/////////////////////////////////////////////////////////////////////////////
// CFtpControlSocket
CFtpControlSocket::CFtpControlSocket(CMainThread *pMainThread) : CControlSocket(pMainThread)
{
ASSERT(pMainThread);
m_Operation.nOpMode=0;
m_Operation.nOpState=-1;
m_Operation.pData=0;
m_pTransferSocket=0;
m_pDataFile=0;
m_pDirectoryListing=0;
m_pOwner=pMainThread;
srand( (unsigned)time( NULL ) );
m_bKeepAliveActive=FALSE;
m_bCheckForTimeout=TRUE;
}
CFtpControlSocket::~CFtpControlSocket()
{
LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("~CFtpControlSocket()"));
DoClose();
if (m_pTransferSocket)
{
m_pTransferSocket->Close();
delete m_pTransferSocket;
m_pTransferSocket=0;
}
if (m_pDataFile)
{
delete m_pDataFile;
m_pDataFile=0;
}
}
/////////////////////////////////////////////////////////////////////////////
// Member-Funktion CFtpControlSocket
#define CONNECT_INIT -1
#define CONNECT_GSS_INIT -2
#define CONNECT_GSS_AUTHDONE -3
#define CONNECT_GSS_CWD -4
#define CONNECT_GSS_FAILED -5
#define CONNECT_GSS_NEEDPASS -6
#define CONNECT_GSS_NEEDUSER -7
#define CONNECT_SSL_INIT -8
#define CONNECT_SSL_NEGOTIATE -9
#define CONNECT_SSL_WAITDONE -10
void CFtpControlSocket::Connect(t_server &server)
{
USES_CONVERSION;
ASSERT(!m_pOwner->IsConnected());
ASSERT(!m_Operation.nOpMode);
ASSERT(!m_pSslLayer);
if (server.nServerType&FZ_SERVERTYPE_LAYER_SSL_IMPLICIT ||
server.nServerType&FZ_SERVERTYPE_LAYER_SSL_EXPLICIT)
{
m_pSslLayer = new CAsyncSslSocketLayer;
AddLayer(m_pSslLayer);
}
ASSERT(!m_pProxyLayer);
if (!server.fwbypass)
{
int nProxyType=COptions::GetOptionVal(OPTION_PROXYTYPE);
if (nProxyType!=PROXYTYPE_NOPROXY)
{
m_pProxyLayer=new CAsyncProxySocketLayer;
if (nProxyType==PROXYTYPE_SOCKS4)
m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS4, T2CA(COptions::GetOption(OPTION_PROXYHOST)), COptions::GetOptionVal(OPTION_PROXYPORT));
else if (nProxyType==PROXYTYPE_SOCKS4A)
m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS4A, T2CA(COptions::GetOption(OPTION_PROXYHOST)),COptions::GetOptionVal(OPTION_PROXYPORT));
else if (nProxyType==PROXYTYPE_SOCKS5)
if (COptions::GetOptionVal(OPTION_PROXYUSELOGON))
m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS5, T2CA(COptions::GetOption(OPTION_PROXYHOST)),
COptions::GetOptionVal(OPTION_PROXYPORT),
T2CA(COptions::GetOption(OPTION_PROXYUSER)),
T2CA(CCrypt::decrypt(COptions::GetOption(OPTION_PROXYPASS))));
else
m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS5, T2CA(COptions::GetOption(OPTION_PROXYHOST)),
COptions::GetOptionVal(OPTION_PROXYPORT));
else if (nProxyType==PROXYTYPE_HTTP11)
if (COptions::GetOptionVal(OPTION_PROXYUSELOGON))
m_pProxyLayer->SetProxy(PROXYTYPE_HTTP11, T2CA(COptions::GetOption(OPTION_PROXYHOST)),
COptions::GetOptionVal(OPTION_PROXYPORT),
T2CA(COptions::GetOption(OPTION_PROXYUSER)),
T2CA(CCrypt::decrypt(COptions::GetOption(OPTION_PROXYPASS))));
else
m_pProxyLayer->SetProxy(PROXYTYPE_HTTP11, T2CA(COptions::GetOption(OPTION_PROXYHOST)) ,COptions::GetOptionVal(OPTION_PROXYPORT));
else
ASSERT(FALSE);
AddLayer(m_pProxyLayer);
}
}
m_Operation.nOpMode=CSMODE_CONNECT;
BOOL bUseGSS = FALSE;
if (COptions::GetOptionVal(OPTION_USEGSS) && !m_pSslLayer)
{
CString GssServers=COptions::GetOption(OPTION_GSSSERVERS);
LPCSTR lpszAscii=T2CA(server.host);
hostent *fullname=gethostbyname(lpszAscii);
CString host;
if (fullname)
host=fullname->h_name;
else
host=server.host;
host.MakeLower();
int i;
while ((i=GssServers.Find(_T(";")))!=-1)
{
if (("."+GssServers.Left(i))==host.Right(GssServers.Left(i).GetLength()+1) || GssServers.Left(i)==host)
{
bUseGSS=TRUE;
break;
}
GssServers=GssServers.Mid(i+1);
}
}
if (bUseGSS)
{
m_pGssLayer = new CAsyncGssSocketLayer;
AddLayer(m_pGssLayer);
if (!m_pGssLayer->InitGSS())
{
ShowStatus("Unable to initialize GSS api", 1);
DoClose(FZ_REPLY_CRITICALERROR);
return;
}
}
m_Operation.nOpState = m_pGssLayer?CONNECT_GSS_INIT:CONNECT_INIT;
m_Operation.nOpMode = CSMODE_CONNECT;
if (!Create())
{
DoClose();
return;
}
AsyncSelect();
if (server.nServerType&FZ_SERVERTYPE_LAYER_SSL_IMPLICIT)
{
ASSERT(m_pSslLayer);
if (m_pSslLayer->InitClientSSL())
PostMessage(m_pOwner->m_hOwnerWnd, m_pOwner->m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_SECURESERVER, 1), 0);
else
{
DoClose();
return;
}
}
int logontype = COptions::GetOptionVal(OPTION_LOGONTYPE);
int port;
CString buf,temp;
if (server.fwbypass)
logontype=0;
// are we connecting directly to the host (logon type 0) or via a firewall? (logon type>0)
CString fwhost;
int fwport;
if(!logontype)
{
temp=server.host;
port=server.port;
}
else
{
fwhost=COptions::GetOption(OPTION_FWHOST);
fwport=COptions::GetOptionVal(OPTION_FWPORT);
temp=fwhost;
port=fwport;
if(fwport!=21)
fwhost.Format( _T("%s:%d"), fwhost, fwport); // add port to fwhost (only if port is not 21)
}
m_CurrentServer = server;
CString hostname = server.host;
if(server.port!=21)
hostname.Format( _T("%s:%d"), hostname, server.port); // add port to hostname (only if port is not 21)
CString str;
str.Format(IDS_STATUSMSG_CONNECTING,hostname);
ShowStatus(str,0);
if ((server.nServerType&FZ_SERVERTYPE_LAYERMASK)==FZ_SERVERTYPE_LAYER_SSL_EXPLICIT)
m_Operation.nOpState=CONNECT_SSL_INIT;
if (!CControlSocket::Connect(temp, port))
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
DoClose();
return;
}
}
m_ServerName = logontype?fwhost:hostname;
m_LastRecvTime = m_LastSendTime = CTime::GetCurrentTime();
}
void CFtpControlSocket::LogOnToServer(BOOL bSkipReply /*=FALSE*/)
{
int logontype = m_pGssLayer ? 0 : COptions::GetOptionVal(OPTION_LOGONTYPE);
const int LO = -2, ER = -1;
CString buf, temp;
const int NUMLOGIN = 9; // currently supports 9 different login sequences
int logonseq[NUMLOGIN][20] = {
// this array stores all of the logon sequences for the various firewalls
// in blocks of 3 nums. 1st num is command to send, 2nd num is next point in logon sequence array
// if 200 series response is rec'd from server as the result of the command, 3rd num is next
// point in logon sequence if 300 series rec'd
{0,LO,3, 1,LO,ER}, // no firewall
{3,6,3, 4,6,ER, 5,9,9, 0,LO,12, 1,LO,ER}, // SITE hostname
{3,6,3, 4,6,ER, 6,LO,9, 1,LO,ER}, // USER after logon
{7,3,3, 0,LO,6, 1,LO,ER}, //proxy OPEN
{3,6,3, 4,6,ER, 0,LO,9, 1,LO,ER}, // Transparent
{6,LO,3, 1,LO,ER}, // USER remoteID@remotehost
{8,6,3, 4,6,ER, 0,LO,9, 1,LO,ER}, //USER fireID@remotehost
{9,ER,3, 1,LO,6, 2,LO,ER}, //USER remoteID@remotehost fireID
{10,LO,3,11,LO,6,2,LO,ER} // USER remoteID@fireID@remotehost
};
if (m_CurrentServer.fwbypass)
logontype=0;
if (m_Operation.nOpState==CONNECT_SSL_INIT)
{
if (!Send("AUTH SSL"))
return;
m_Operation.nOpState=CONNECT_SSL_NEGOTIATE;
return;
}
else if (m_Operation.nOpState==CONNECT_SSL_NEGOTIATE)
{
int res=GetReplyCode();
if (res!=2 && res!=3)
{
DoClose();
return;
}
else
{
ASSERT(m_pSslLayer);
if (!m_pSslLayer->InitClientSSL())
{
DoClose();
return;
}
}
m_Operation.nOpState=CONNECT_SSL_WAITDONE;
return;
}
else if (m_Operation.nOpState==CONNECT_SSL_WAITDONE)
m_Operation.nOpState=CONNECT_INIT;
else if (m_Operation.nOpState==CONNECT_GSS_FAILED ||
m_Operation.nOpState == CONNECT_GSS_NEEDPASS ||
m_Operation.nOpState == CONNECT_GSS_NEEDUSER)
{
if (!m_RecvBuffer.empty() && m_RecvBuffer.front() != _T(""))
{
//Incoming reply from server during async is not allowed
DoClose();
return;
}
}
else if (!bSkipReply)
{
int res=GetReplyCode();
if(res!=2 && res!=3 && m_Operation.nOpState>=0) // get initial connect msg off server
{
int nError=FZ_REPLY_ERROR;
if (res==5 && logonseq[logontype][m_Operation.nOpState]==1)
nError|=FZ_REPLY_CRITICALERROR;
DoClose(nError);
return;
}
}
CString hostname=m_CurrentServer.host;
if(m_CurrentServer.port!=21) hostname.Format(hostname+":%d",m_CurrentServer.port); // add port to hostname (only if port is not 21)
USES_CONVERSION;
//**** GSS Authentication ****
if (m_Operation.nOpState==CONNECT_GSS_INIT) //authenticate
{
int i = m_pGssLayer->GetClientAuth(T2CA(m_CurrentServer.host));
if (i==-1)
m_Operation.nOpState = CONNECT_GSS_AUTHDONE;
else if (i != GSSAPI_AUTHENTICATION_SUCCEEDED)
{
m_Operation.nOpState = CONNECT_GSS_FAILED;
CAsyncRequestData *pData=new CAsyncRequestData;
pData->nRequestType=FZ_ASYNCREQUEST_GSS_AUTHFAILED;
pData->nRequestID=m_pOwner->GetNextAsyncRequestID();
if (!PostMessage(m_pOwner->m_hOwnerWnd, m_pOwner->m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_ASYNCREQUEST, FZ_ASYNCREQUEST_GSS_AUTHFAILED), (LPARAM)pData))
delete pData;
}
else
{
// we got authentication, we need to check whether we have forwardable tickets
//ShowStatus(IDS_STATUSMSG_GSSAUTH, 0);
PostMessage(m_pOwner->m_hOwnerWnd,m_pOwner->m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_SECURESERVER, TRUE), 0);
if (Send("CWD ."))
m_Operation.nOpState = CONNECT_GSS_CWD;
}
return;
}
else if (m_Operation.nOpState == CONNECT_GSS_AUTHDONE)
{
if (!m_pGssLayer->AuthSuccessful())
{
m_Operation.nOpState = CONNECT_GSS_FAILED;
CAsyncRequestData *pData=new CAsyncRequestData;
pData->nRequestType = FZ_ASYNCREQUEST_GSS_AUTHFAILED;
pData->nRequestID = m_pOwner->GetNextAsyncRequestID();
if (!PostMessage(m_pOwner->m_hOwnerWnd, m_pOwner->m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_ASYNCREQUEST, FZ_ASYNCREQUEST_GSS_AUTHFAILED), (LPARAM)pData))
delete pData;
return;
}
else
{
// we got authentication, we need to check whether we have forwardable tickets
//ShowStatus(IDS_STATUSMSG_GSSAUTH, 0);
PostMessage(m_pOwner->m_hOwnerWnd,m_pOwner->m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_SECURESERVER, TRUE), 0);
if (Send("CWD ."))
m_Operation.nOpState = CONNECT_GSS_CWD;
return;
}
}
else if (m_Operation.nOpState == CONNECT_GSS_CWD)
{ // authentication succeeded, we're now get the response to the CWD command
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -