Windows NT DGPENSV2LPKMN 10.0 build 14393 (Windows Server 2016) AMD64
Apache/2.4.46 (Win64) OpenSSL/1.1.1h PHP/7.3.25
: 172.16.0.66 | : 172.16.0.254
Cant Read [ /etc/named.conf ]
7.3.25
SYSTEM
www.github.com/MadExploits
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
CPANEL RESET
CREATE WP USER
BLACK DEFEND!
README
+ Create Folder
+ Create File
[ A ]
[ C ]
[ D ]
C: /
xampp7 /
FileZillaFTP /
source /
[ HOME SHELL ]
Name
Size
Permission
Action
hash_algorithms
[ DIR ]
drwxrwxrwx
includes
[ DIR ]
drwxrwxrwx
install
[ DIR ]
drwxrwxrwx
interface
[ DIR ]
drwxrwxrwx
misc
[ DIR ]
drwxrwxrwx
res
[ DIR ]
drwxrwxrwx
tinyxml
[ DIR ]
drwxrwxrwx
Accounts.cpp
12.2
KB
-rw-rw-rw-
Accounts.h
2.12
KB
-rw-rw-rw-
AdminInterface.cpp
3.1
KB
-rw-rw-rw-
AdminInterface.h
1.77
KB
-rw-rw-rw-
AdminListenSocket.cpp
1.64
KB
-rw-rw-rw-
AdminListenSocket.h
1.58
KB
-rw-rw-rw-
AdminSocket.cpp
9.85
KB
-rw-rw-rw-
AdminSocket.h
2.1
KB
-rw-rw-rw-
AsyncGssSocketLayer.cpp
30.35
KB
-rw-rw-rw-
AsyncGssSocketLayer.h
4.76
KB
-rw-rw-rw-
AsyncSocketEx.cpp
51.94
KB
-rw-rw-rw-
AsyncSocketEx.h
11.75
KB
-rw-rw-rw-
AsyncSocketExLayer.cpp
26.22
KB
-rw-rw-rw-
AsyncSocketExLayer.h
7
KB
-rw-rw-rw-
AsyncSslSocketLayer.cpp
60.12
KB
-rw-rw-rw-
AsyncSslSocketLayer.h
8.94
KB
-rw-rw-rw-
ControlSocket.cpp
96.33
KB
-rw-rw-rw-
ControlSocket.h
4.74
KB
-rw-rw-rw-
ExternalIpCheck.cpp
7.82
KB
-rw-rw-rw-
ExternalIpCheck.h
1.85
KB
-rw-rw-rw-
FileLogger.cpp
6.68
KB
-rw-rw-rw-
FileLogger.h
1.35
KB
-rw-rw-rw-
FileZilla server.rc
2.65
KB
-rw-rw-rw-
FileZilla server.sln
2.75
KB
-rw-rw-rw-
FileZilla server.vcproj
39.95
KB
-rw-rw-rw-
ListenSocket.cpp
4.23
KB
-rw-rw-rw-
ListenSocket.h
2.29
KB
-rw-rw-rw-
MFC64bitFix.cpp
2.56
KB
-rw-rw-rw-
MFC64bitFix.h
1.45
KB
-rw-rw-rw-
OptionLimits.h
1022
B
-rw-rw-rw-
OptionTypes.h
6.46
KB
-rw-rw-rw-
Options.cpp
31.81
KB
-rw-rw-rw-
Options.h
2.59
KB
-rw-rw-rw-
Permissions.cpp
61.53
KB
-rw-rw-rw-
Permissions.h
6.82
KB
-rw-rw-rw-
Server.cpp
42.34
KB
-rw-rw-rw-
Server.h
2.05
KB
-rw-rw-rw-
ServerThread.cpp
26.13
KB
-rw-rw-rw-
ServerThread.h
4.21
KB
-rw-rw-rw-
Service.cpp
15.23
KB
-rw-rw-rw-
SpeedLimit.cpp
6.87
KB
-rw-rw-rw-
SpeedLimit.h
1.96
KB
-rw-rw-rw-
StdAfx.cpp
4.41
KB
-rw-rw-rw-
StdAfx.h
4.93
KB
-rw-rw-rw-
Thread.cpp
2.85
KB
-rw-rw-rw-
Thread.h
1.87
KB
-rw-rw-rw-
TransferSocket.cpp
28.72
KB
-rw-rw-rw-
TransferSocket.h
3.62
KB
-rw-rw-rw-
autobanmanager.cpp
3.44
KB
-rw-rw-rw-
autobanmanager.h
1.46
KB
-rw-rw-rw-
config.h
1.52
KB
-rw-rw-rw-
conversion.cpp
1.95
KB
-rw-rw-rw-
conversion.h
435
B
-rw-rw-rw-
defs.h
1.03
KB
-rw-rw-rw-
hash_thread.cpp
4.79
KB
-rw-rw-rw-
hash_thread.h
930
B
-rw-rw-rw-
iputils.cpp
10.87
KB
-rw-rw-rw-
iputils.h
1.32
KB
-rw-rw-rw-
platform.h
1.43
KB
-rw-rw-rw-
resource.h
515
B
-rw-rw-rw-
version.cpp
4.32
KB
-rw-rw-rw-
version.h
881
B
-rw-rw-rw-
xml_utils.cpp
487
B
-rw-rw-rw-
xml_utils.h
236
B
-rw-rw-rw-
Delete
Unzip
Zip
${this.title}
Close
Code Editor : ControlSocket.cpp
// FileZilla Server - a Windows ftp server // Copyright (C) 2002-2004 - 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. // ControlSocket.cpp: Implementierungsdatei // #include "stdafx.h" #include "ControlSocket.h" #include "transfersocket.h" #include "ServerThread.h" #include "Options.h" #include "Permissions.h" #include "AsyncGssSocketLayer.h" #include "AsyncSslSocketLayer.h" #include <math.h> #include "iputils.h" #include "autobanmanager.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CControlSocket std::map<CStdString, int> CControlSocket::m_UserCount; CCriticalSectionWrapper CControlSocket::m_Sync; CControlSocket::CControlSocket(CServerThread *pOwner) : m_hash_algorithm(CHashThread::SHA1) { m_status.loggedon = FALSE; m_status.hammerValue = 0; m_transferstatus.socket = NULL; m_transferstatus.ip = _T(""); m_transferstatus.port = -1; m_transferstatus.pasv = -1; m_transferstatus.rest = 0; m_transferstatus.type = -1; m_transferstatus.family = AF_UNSPEC; m_bWaitGoOffline = FALSE; GetSystemTime(&m_LastTransferTime); GetSystemTime(&m_LastCmdTime); GetSystemTime(&m_LoginTime); m_bQuitCommand = FALSE; ASSERT(pOwner); m_pOwner = pOwner; m_nTelnetSkip = 0; m_nRecvBufferPos = 0; m_pSendBuffer = NULL; m_nSendBufferLen = 0; m_pGssLayer = NULL; m_pSslLayer = NULL; for (int i = 0; i < 2; i++) { m_SlQuotas[i].bContinue = false; m_SlQuotas[i].nBytesAllowedToTransfer = -1; m_SlQuotas[i].nTransferred = 0; m_SlQuotas[i].bBypassed = true; } m_transferMode = mode_stream; m_zlibLevel = 8; m_antiHammeringWaitTime = 0; m_bProtP = false; m_useUTF8 = true; for (int i = 0; i < 3; i++) m_facts[i] = true; m_facts[fact_perm] = false; m_shutdown = false; m_hash_id = 0; } CControlSocket::~CControlSocket() { if (m_status.loggedon) { DecUserCount(m_status.user); m_pOwner->DecIpCount(m_status.ip); m_status.loggedon = FALSE; } t_connop *op = new t_connop; op->data = 0; op->op = USERCONTROL_CONNOP_REMOVE; op->userid = m_userid; m_pOwner->SendNotification(FSM_CONNECTIONDATA, (LPARAM)op); if (m_transferstatus.socket) delete m_transferstatus.socket; m_transferstatus.socket=0; delete [] m_pSendBuffer; m_nSendBufferLen = 0; RemoveAllLayers(); delete m_pGssLayer; delete m_pSslLayer; } ///////////////////////////////////////////////////////////////////////////// // Member-Funktion CControlSocket #define BUFFERSIZE 500 void CControlSocket::OnReceive(int nErrorCode) { if (m_antiHammeringWaitTime) { if (nErrorCode) { //Control connection has been closed Close(); SendStatus(_T("disconnected."), 0); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); } return; } int len = BUFFERSIZE; int nLimit = GetSpeedLimit(upload); if (!nLimit) { ParseCommand(); return; } if (len > nLimit && nLimit != -1) len = nLimit; unsigned char *buffer = new unsigned char[BUFFERSIZE]; int numread = Receive(buffer, len); if (numread != SOCKET_ERROR && numread) { if (nLimit != -1) m_SlQuotas[upload].nTransferred += numread; m_pOwner->IncRecvCount(numread); //Parse all received bytes for (int i = 0; i<numread; i++) { if (!m_nRecvBufferPos) { //Remove telnet characters if (m_nTelnetSkip) { if (buffer[i] < 240) m_nTelnetSkip = 0; else continue; } else if (buffer[i] == 255) { m_nTelnetSkip = 1; continue; } } //Check for line endings if ((buffer[i] == '\r')||(buffer[i] == 0)||(buffer[i] == '\n')) { //If input buffer is not empty... if (m_nRecvBufferPos) { m_RecvBuffer[m_nRecvBufferPos] = 0; m_RecvLineBuffer.push_back(m_RecvBuffer); m_nRecvBufferPos = 0; //Signal that there is a new command waiting to be processed. GetSystemTime(&m_LastCmdTime); } } else //The command may only be 2000 chars long. This ensures that a malicious user can't //send extremely large commands to fill the memory of the server if (m_nRecvBufferPos < 2000) m_RecvBuffer[m_nRecvBufferPos++] = buffer[i]; } } else { if (!numread || GetLastError() != WSAEWOULDBLOCK) { //Control connection has been closed Close(); SendStatus(_T("disconnected."), 0); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); delete [] buffer; return; } } ParseCommand(); delete [] buffer; } BOOL CControlSocket::GetCommand(CStdString &command, CStdString &args) { //Get first command from input buffer CStdStringA str; if (m_RecvLineBuffer.empty()) return FALSE; str = m_RecvLineBuffer.front(); m_RecvLineBuffer.pop_front(); //Output command in status window CStdString str2; if (m_useUTF8) { #ifdef _UNICODE str2 = ConvFromNetwork(str); #else str2 = ConvToLocal(ConvFromNetwork(str)); #endif } else { #ifdef _UNICODE str2 = ConvFromLocal(str); #else str2 = str; #endif } //Hide passwords if the server admin wants to. if (!str2.Left(5).CompareNoCase(_T("PASS "))) { if (m_pOwner->m_pOptions->GetOptionVal(OPTION_LOGSHOWPASS)) SendStatus(str2, 2); else { CStdString msg = str2; for (int i = 5; i < msg.GetLength(); i++) msg[i] = '*'; SendStatus(msg, 2); } } else SendStatus(str2, 2); //Split command and arguments int pos = str2.Find(_T(" ")); if (pos != -1) { command = str2.Left(pos); if (pos == str2.GetLength() - 1) args = _T(""); else { args = str2.Mid(pos + 1); if (args == _T("")) { Send(_T("501 Syntax error, failed to decode string")); return FALSE; } } } else { args = _T(""); command = str2; } if (command == _T("")) return FALSE; command.MakeUpper(); return TRUE; } void CControlSocket::SendStatus(LPCTSTR status, int type) { t_statusmsg *msg = new t_statusmsg; _tcscpy(msg->ip, m_RemoteIP); GetLocalTime(&msg->time); if (!m_status.loggedon) { msg->user = new TCHAR[16]; _tcscpy(msg->user, _T("(not logged in)")); } else { msg->user = new TCHAR[_tcslen(m_status.user) + 1]; _tcscpy(msg->user, m_status.user); } msg->userid = m_userid; msg->type = type; msg->status = new TCHAR[_tcslen(status) + 1]; _tcscpy(msg->status, status); m_pOwner->SendNotification(FSM_STATUSMESSAGE, (LPARAM)msg); } BOOL CControlSocket::Send(LPCTSTR str, bool sendStatus /*=true*/) { if (sendStatus) SendStatus(str, 3); char* buffer; int len; if (m_useUTF8) { char* utf8 = ConvToNetwork(str); if (!utf8) { Close(); SendStatus(_T("Failed to convert reply to UTF-8"), 1); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); return false; } buffer = new char[strlen(utf8) + 3]; strcpy(buffer, utf8); strcat(buffer, "\r\n"); len = strlen(buffer); delete [] utf8; } else { CStdStringA local = ConvToLocal(str); if (local == "") { Close(); SendStatus(_T("Failed to convert reply to local charset"), 1); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); return false; } buffer = new char[strlen(local) + 3]; strcpy(buffer, local); strcat(buffer, "\r\n"); len = strlen(buffer); } //Add line to back of send buffer if it's not empty if (m_pSendBuffer) { char *tmp = m_pSendBuffer; m_pSendBuffer = new char[m_nSendBufferLen + len]; memcpy(m_pSendBuffer, tmp, m_nSendBufferLen); memcpy(m_pSendBuffer+m_nSendBufferLen, buffer, len); delete [] tmp; m_nSendBufferLen += len; delete [] buffer; return TRUE; } int nLimit = GetSpeedLimit(download); if (!nLimit) { if (!m_pSendBuffer) { m_pSendBuffer = buffer; m_nSendBufferLen = len; } else { char *tmp = m_pSendBuffer; m_pSendBuffer = new char[m_nSendBufferLen + len]; memcpy(m_pSendBuffer, tmp, m_nSendBufferLen); memcpy(m_pSendBuffer+m_nSendBufferLen, buffer, len); delete [] tmp; m_nSendBufferLen += len; delete [] buffer; } return TRUE; } int numsend = nLimit; if (numsend == -1 || len < numsend) numsend = len; int res = CAsyncSocketEx::Send(buffer, numsend); if (res==SOCKET_ERROR && GetLastError() == WSAEWOULDBLOCK) { res = 0; } else if (!res || res==SOCKET_ERROR) { delete [] buffer; Close(); SendStatus(_T("could not send reply, disconnected."), 0); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); return FALSE; } if (nLimit != -1) m_SlQuotas[download].nTransferred += res; if (res != len) { if (!m_pSendBuffer) { m_pSendBuffer = new char[len-res]; memcpy(m_pSendBuffer, buffer+res, len-res); m_nSendBufferLen = len-res; } else { char *tmp = m_pSendBuffer; m_pSendBuffer = new char[m_nSendBufferLen + len - res]; memcpy(m_pSendBuffer, tmp, m_nSendBufferLen); memcpy(m_pSendBuffer+m_nSendBufferLen, buffer+res, len-res); delete [] tmp; m_nSendBufferLen += len-res; } TriggerEvent(FD_WRITE); } delete [] buffer; m_pOwner->IncSendCount(res); return TRUE; } void CControlSocket::OnClose(int nErrorCode) { Close(); SendStatus(_T("disconnected."), 0); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); CAsyncSocketEx::OnClose(nErrorCode); } #define COMMAND_USER 0 #define COMMAND_PASS 1 #define COMMAND_QUIT 2 #define COMMAND_CWD 3 #define COMMAND_PWD 4 #define COMMAND_PORT 5 #define COMMAND_PASV 6 #define COMMAND_TYPE 7 #define COMMAND_LIST 8 #define COMMAND_REST 9 #define COMMAND_CDUP 10 #define COMMAND_RETR 11 #define COMMAND_STOR 12 #define COMMAND_SIZE 13 #define COMMAND_DELE 14 #define COMMAND_RMD 15 #define COMMAND_MKD 16 #define COMMAND_RNFR 17 #define COMMAND_RNTO 18 #define COMMAND_ABOR 19 #define COMMAND_SYST 20 #define COMMAND_NOOP 21 #define COMMAND_APPE 22 #define COMMAND_NLST 23 #define COMMAND_MDTM 24 #define COMMAND_XPWD 25 #define COMMAND_XCUP 26 #define COMMAND_XMKD 27 #define COMMAND_XRMD 28 #define COMMAND_NOP 29 #define COMMAND_EPSV 30 #define COMMAND_EPRT 31 #define COMMAND_AUTH 32 #define COMMAND_ADAT 33 #define COMMAND_PBSZ 34 #define COMMAND_PROT 35 #define COMMAND_FEAT 36 #define COMMAND_MODE 37 #define COMMAND_OPTS 38 #define COMMAND_HELP 39 #define COMMAND_ALLO 40 #define COMMAND_MLST 41 #define COMMAND_MLSD 42 #define COMMAND_SITE 43 #define COMMAND_PASVSMC 44 // some bugged SMC routers convert incoming PASV into P@SW #define COMMAND_STRU 45 #define COMMAND_CLNT 46 #define COMMAND_MFMT 47 #define COMMAND_HASH 48 typedef struct { int nID; TCHAR command[5]; BOOL bHasargs; BOOL bValidBeforeLogon; } t_command; static const t_command commands[]={ COMMAND_USER, _T("USER"), TRUE, TRUE, COMMAND_PASS, _T("PASS"), FALSE, TRUE, COMMAND_QUIT, _T("QUIT"), FALSE, TRUE, COMMAND_CWD, _T("CWD"), FALSE, FALSE, COMMAND_PWD, _T("PWD"), FALSE, FALSE, COMMAND_PORT, _T("PORT"), TRUE, FALSE, COMMAND_PASV, _T("PASV"), FALSE, FALSE, COMMAND_TYPE, _T("TYPE"), TRUE, FALSE, COMMAND_LIST, _T("LIST"), FALSE, FALSE, COMMAND_REST, _T("REST"), TRUE, FALSE, COMMAND_CDUP, _T("CDUP"), FALSE, FALSE, COMMAND_RETR, _T("RETR"), TRUE, FALSE, COMMAND_STOR, _T("STOR"), TRUE, FALSE, COMMAND_SIZE, _T("SIZE"), TRUE, FALSE, COMMAND_DELE, _T("DELE"), TRUE, FALSE, COMMAND_RMD, _T("RMD"), TRUE, FALSE, COMMAND_MKD, _T("MKD"), TRUE, FALSE, COMMAND_RNFR, _T("RNFR"), TRUE, FALSE, COMMAND_RNTO, _T("RNTO"), TRUE, FALSE, COMMAND_ABOR, _T("ABOR"), FALSE, FALSE, COMMAND_SYST, _T("SYST"), FALSE, TRUE, COMMAND_NOOP, _T("NOOP"), FALSE, FALSE, COMMAND_APPE, _T("APPE"), TRUE, FALSE, COMMAND_NLST, _T("NLST"), FALSE, FALSE, COMMAND_MDTM, _T("MDTM"), TRUE, FALSE, COMMAND_XPWD, _T("XPWD"), FALSE, FALSE, COMMAND_XCUP, _T("XCUP"), FALSE, FALSE, COMMAND_XMKD, _T("XMKD"), TRUE, FALSE, COMMAND_XRMD, _T("XRMD"), TRUE, FALSE, COMMAND_NOP, _T("NOP"), FALSE, FALSE, COMMAND_EPSV, _T("EPSV"), FALSE, FALSE, COMMAND_EPRT, _T("EPRT"), TRUE, FALSE, COMMAND_AUTH, _T("AUTH"), TRUE, TRUE, COMMAND_ADAT, _T("ADAT"), TRUE, TRUE, COMMAND_PBSZ, _T("PBSZ"), TRUE, TRUE, COMMAND_PROT, _T("PROT"), TRUE, TRUE, COMMAND_FEAT, _T("FEAT"), FALSE, TRUE, COMMAND_MODE, _T("MODE"), TRUE, FALSE, COMMAND_OPTS, _T("OPTS"), TRUE, FALSE, COMMAND_HELP, _T("HELP"), FALSE, TRUE, COMMAND_ALLO, _T("ALLO"), FALSE, FALSE, COMMAND_MLST, _T("MLST"), FALSE, FALSE, COMMAND_MLSD, _T("MLSD"), FALSE, FALSE, COMMAND_SITE, _T("SITE"), TRUE, TRUE, COMMAND_PASVSMC, _T("P@SW"), FALSE, FALSE, COMMAND_STRU, _T("STRU"), TRUE, FALSE, COMMAND_CLNT, _T("CLNT"), TRUE, TRUE, COMMAND_MFMT, _T("MFMT"), TRUE, FALSE, COMMAND_HASH, _T("HASH"), TRUE, FALSE }; void CControlSocket::ParseCommand() { if (m_antiHammeringWaitTime) return; //Get command CStdString command; CStdString args; if (!GetCommand(command, args)) return; //Check if command is valid int nCommandID = -1; for (int i = 0; i < (sizeof(commands)/sizeof(t_command)); i++) { if (command == commands[i].command) { //Does the command needs an argument? if (commands[i].bHasargs && (args == _T(""))) { Send(_T("501 Syntax error")); if (!m_RecvLineBuffer.empty()) m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_COMMAND, m_userid); return; } //Can it be issued before logon? else if (!m_status.loggedon && !commands[i].bValidBeforeLogon) { Send(_T("530 Please log in with USER and PASS first.")); if (!m_RecvLineBuffer.empty()) m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_COMMAND, m_userid); return; } nCommandID = commands[i].nID; break; } } //Command not recognized if (nCommandID == -1) { Send(_T("500 Syntax error, command unrecognized.")); if (!m_RecvLineBuffer.empty()) m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_COMMAND, m_userid); return; } //Now process the commands switch (nCommandID) { case COMMAND_USER: { AntiHammerIncrease(); if (m_status.loggedon) { GetSystemTime(&m_LoginTime); DecUserCount(m_status.user); m_pOwner->DecIpCount(m_status.ip); t_connop *op = new t_connop; op->op = USERCONTROL_CONNOP_CHANGEUSER; t_connectiondata_changeuser *conndata = new t_connectiondata_changeuser; op->data = conndata; op->userid = m_userid; m_pOwner->SendNotification(FSM_CONNECTIONDATA, (LPARAM)op); m_status.loggedon = FALSE; m_CurrentServerDir = _T(""); } if (m_pOwner->m_pOptions->GetOptionVal(OPTION_ENABLESSL) && m_pOwner->m_pOptions->GetOptionVal(OPTION_ALLOWEXPLICITSSL) && m_pOwner->m_pOptions->GetOptionVal(OPTION_SSLFORCEEXPLICIT) && !m_pSslLayer) { Send(_T("530 Have to use explicit SSL/TLS before logging on.")); break; } RenName = _T(""); args.MakeLower(); m_status.user = args; if (m_pGssLayer && m_pGssLayer->AuthSuccessful()) { char sendme[4096]; #ifdef _UNICODE int res = m_pGssLayer->ProcessCommand("USER", ConvToLocal(args), sendme); #else int res = m_pGssLayer->ProcessCommand("USER", args, sendme); #endif if (res != -1) { if (DoUserLogin(0, true)) { #ifdef _UNICODE Send(ConvFromLocal(sendme)); #else Send(sendme); #endif } else m_status.user = _T(""); } break; } if (!m_pSslLayer) { CUser user; if (m_pOwner->m_pPermissions->CheckUserLogin(m_status.user, _T(""), user, true) && user.ForceSsl()) { m_status.user = _T(""); Send(_T("530 SSL required")); break; } } Send(_T("331 Password required for ") + args); } break; case COMMAND_PASS: AntiHammerIncrease(); if (m_status.loggedon) Send(_T("503 Bad sequence of commands.")); else if (m_pGssLayer && m_pGssLayer->AuthSuccessful()) { char sendme[4096]; #ifdef _UNICODE int res = m_pGssLayer->ProcessCommand("PASS", ConvToLocal(m_status.user), ConvToLocal(args), sendme); #else int res = m_pGssLayer->ProcessCommand("PASS", m_status.user, args, sendme); #endif if (res != -1) { if (DoUserLogin(_T(""), true)) #ifdef _UNICODE Send(ConvFromLocal(sendme)); #else Send(sendme); #endif } } else if (DoUserLogin(args)) Send(_T("230 Logged on")); break; case COMMAND_QUIT: m_bQuitCommand = TRUE; if (!m_transferstatus.socket || !m_transferstatus.socket->InitCalled()) { Send(_T("221 Goodbye")); if (m_pSslLayer) { if (ShutDown() || WSAGetLastError() != WSAEWOULDBLOCK) ForceClose(5); } else if (CanQuit()) ForceClose(5); } break; case COMMAND_CWD: { //Unquote args if (!UnquoteArgs(args)) { Send(_T("501 Syntax error")); break; } if (args == _T("")) { CStdString str; str.Format(_T("250 Broken client detected, missing argument to CWD. \"%s\" is current directory."), m_CurrentServerDir); Send(str); break; } int res = m_pOwner->m_pPermissions->ChangeCurrentDir(m_status.user, m_CurrentServerDir, args); if (!res) { CStdString str; str.Format(_T("250 CWD successful. \"%s\" is current directory."), m_CurrentServerDir); Send(str); } else if (res & PERMISSION_DENIED) { CStdString str; str.Format(_T("550 CWD failed. \"%s\": Permission denied."), args); Send(str); } else if (res & PERMISSION_INVALIDNAME) { CStdString str; str.Format(_T("550 CWD failed. \"%s\": Filename invalid."), args); Send(str); } else if (res) { CStdString str; str.Format(_T("550 CWD failed. \"%s\": directory not found."), args); Send(str); } } break; case COMMAND_PWD: case COMMAND_XPWD: { CStdString str; str.Format(_T("257 \"%s\" is current directory."), m_CurrentServerDir); Send(str); } break; case COMMAND_PORT: { if (GetFamily() != AF_INET) { Send(_T("500 You are connected using IPv6. PORT is only for IPv4. You have to use the EPRT command instead.")); break; } if (m_transferstatus.socket) { SendTransferinfoNotification(); delete m_transferstatus.socket; m_transferstatus.socket = 0; } int count = 0; int pos = 0; //Convert commas to dots args.Replace(_T(","), _T(".")); while (1) { pos = args.Find(_T("."), pos); if (pos != -1) count++; else break; pos++; } if (count != 5) { Send(_T("501 Syntax error")); m_transferstatus.pasv = -1; break; } CStdString ip; int port = 0; int i = args.ReverseFind('.'); port = _ttoi(args.Right(args.GetLength() - (i + 1))); //get ls byte of server socket args = args.Left(i); i = args.ReverseFind('.'); port += 256 * _ttoi(args.Right(args.GetLength() - (i + 1))); // add ms byte to server socket ip = args.Left(i); #ifdef _UNICODE int res = inet_addr(ConvToLocal(ip)); #else int res = inet_addr(ip); #endif if (res == INADDR_NONE) { // Fix: Convert IP in PORT command to int and back to string (strips // leading zeros) because some FTP clients prepend zeros to it. // inet_addr() thinks this is an octal number and will return INADDR_NONE // if 8 or 9 are encountered. CStdString decIP; ip += _T("."); int pos = ip.Find('.'); while (pos != -1) { CStdString tmp; tmp.Format(_T("%d."), _ttoi(ip.Left(pos))); decIP += tmp; ip = ip.Mid(pos + 1); pos = ip.Find('.'); } ip = decIP.Left(decIP.GetLength() - 1); #ifdef _UNICODE res = inet_addr(ConvToLocal(ip)); #else res = inet_addr(ip); #endif } if (res == INADDR_NONE || port < 1 || port > 65535) { Send(_T("501 Syntax error")); m_transferstatus.pasv = -1; break; } if (m_pOwner->m_pOptions->GetOptionVal(OPTION_ACTIVE_IGNORELOCAL)) { CStdString peerAddr; UINT peerPort = 0; if (GetPeerName(peerAddr, peerPort)) { if (!IsRoutableAddress(ip) && IsRoutableAddress(peerAddr)) ip = peerAddr; } } m_transferstatus.ip = ip; m_transferstatus.port = port; m_transferstatus.pasv = 0; m_transferstatus.family = AF_INET; Send(_T("200 Port command successful")); break; } case COMMAND_PASV: case COMMAND_PASVSMC: { if (GetFamily() != AF_INET) { Send(_T("500 You are connected using IPv6. PASV is only for IPv4. You have to use the EPSV command instead.")); break; } if (m_transferstatus.socket) { SendTransferinfoNotification(); delete m_transferstatus.socket; } m_transferstatus.family = AF_INET; m_transferstatus.socket = new CTransferSocket(this); unsigned int retries = 3; unsigned int port = 0; CStdString pasvIP = GetPassiveIP(); if (pasvIP == _T("")) { delete m_transferstatus.socket; m_transferstatus.socket = NULL; Send(_T("421 Can't create socket")); m_transferstatus.pasv = -1; break; } while (retries > 0) { if (m_pOwner->m_pOptions->GetOptionVal(OPTION_USECUSTOMPASVPORT)) { static UINT customPort = 0; unsigned int minPort = (unsigned int)m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVMINPORT); unsigned int maxPort = (unsigned int)m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVMAXPORT); if (minPort > maxPort) { unsigned int temp = minPort; minPort = maxPort; maxPort = temp; } if (customPort < minPort || customPort > maxPort) { customPort = minPort; } port = customPort; ++customPort; } else { port = 0; } if (m_transferstatus.socket->Create(port, SOCK_STREAM, FD_ACCEPT)) break; --retries; } if (retries <= 0) { delete m_transferstatus.socket; m_transferstatus.socket = NULL; Send(_T("421 Can't create socket")); m_transferstatus.pasv = -1; break; } if (m_pGssLayer && m_pGssLayer->AuthSuccessful()) m_transferstatus.socket->UseGSS(m_pGssLayer); if (m_pSslLayer && m_bProtP) m_transferstatus.socket->UseSSL(m_pSslLayer->GetContext()); if (!m_transferstatus.socket->Listen()) { delete m_transferstatus.socket; m_transferstatus.socket = NULL; Send(_T("421 Can't create socket")); m_transferstatus.pasv = -1; break; } //Now retrieve the port CStdString dummy; if (m_transferstatus.socket->GetSockName(dummy, port)) { //Reformat the ip pasvIP.Replace(_T("."), _T(",")); //Put the answer together CStdString str; if (nCommandID == COMMAND_PASVSMC) str.Format(_T("227 Warning: Router with P@SW bug detected. Entering Passive Mode (%s,%d,%d)"), pasvIP, port / 256, port % 256); else str.Format(_T("227 Entering Passive Mode (%s,%d,%d)"), pasvIP, port / 256, port % 256); Send(str); m_transferstatus.pasv = 1; } else { delete m_transferstatus.socket; m_transferstatus.socket = NULL; Send(_T("421 Can't create socket")); m_transferstatus.pasv = -1; break; } break; } case COMMAND_TYPE: { args.MakeUpper(); if (args[0] != 'I' && args[0] != 'A' && args != _T("L 8")) { Send(_T("501 Unsupported type. Supported types are I, A and L 8")); break; } m_transferstatus.type = (args[0] == 'A') ? 1 : 0; CStdString str; str.Format(_T("200 Type set to %s"), args); Send(str); } break; case COMMAND_LIST: if (m_transferstatus.pasv == -1) { Send(_T("503 Bad sequence of commands.")); break; } if (!m_transferstatus.pasv && (m_transferstatus.ip == _T("") || m_transferstatus.port == -1)) { Send(_T("503 Bad sequence of commands.")); break; } if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("521 PROT P required")); break; } else { //Check args, currently only supported argument is the directory which will be listed. CStdString dirToList; args.TrimLeft(_T(" ")); args.TrimRight(_T(" ")); if (args != _T("")) { BOOL bBreak = FALSE; while (args[0] == '-') //No parameters supported { if (args.GetLength() < 2) { //Dash without param Send(_T("501 Syntax error")); bBreak = TRUE; break; } int pos = args.Find(' '); CStdString params; if (pos != -1) { params = args.Left(1); params = params.Left(pos - 1); args = args.Mid(pos + 1); args.TrimLeft(_T(" ")); } else args = _T(""); while (params != _T("")) { //Some parameters are not support if (params[0] == 'R') { Send(_T("504 Command not implemented for that parameter")); bBreak = TRUE; break; } //Ignore other parameters params = params.Mid(1); } if (args == _T("")) break; } if (bBreak) break; if (args != _T("")) { //Unquote args if (!UnquoteArgs(args)) { Send(_T("501 Syntax error")); break; } dirToList = args; } } t_dirlisting *pResult; CStdString physicalDir, logicalDir; int error = m_pOwner->m_pPermissions->GetDirectoryListing(m_status.user, m_CurrentServerDir, dirToList, pResult, physicalDir, logicalDir, CPermissions::AddLongListingEntry, m_useUTF8); if (error & PERMISSION_DENIED) { Send(_T("550 Permission denied.")); ResetTransferstatus(); break; } else if (error & PERMISSION_INVALIDNAME) { Send(_T("550 Filename invalid.")); ResetTransferstatus(); break; } else if (error) { Send(_T("550 Directory not found.")); ResetTransferstatus(); break; } if (!m_transferstatus.pasv) { if (m_transferstatus.socket) { SendTransferinfoNotification(); delete m_transferstatus.socket; } CTransferSocket *transfersocket = new CTransferSocket(this); m_transferstatus.socket = transfersocket; transfersocket->Init(pResult, TRANSFERMODE_LIST); if (m_transferMode == mode_zlib) { if (!transfersocket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } if (!CreateTransferSocket(transfersocket)) break; SendTransferinfoNotification(TRANSFERMODE_LIST, ConvToLocal(physicalDir), ConvToLocal(logicalDir)); Send(_T("150 Opening data channel for directory list.")); } else { if (!m_transferstatus.socket) { CPermissions::DestroyDirlisting(pResult); Send(_T("503 Bad sequence of commands.")); break; } m_transferstatus.socket->Init(pResult, TRANSFERMODE_LIST); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } SendTransferinfoNotification(TRANSFERMODE_LIST, ConvToLocal(physicalDir), ConvToLocal(logicalDir)); m_transferstatus.socket->PasvTransfer(); } } break; case COMMAND_REST: { BOOL error = FALSE; for (int i = 0; i < args.GetLength(); i++) if (args[i] < '0' || args[i] > '9') { error = TRUE; break; } if (error) { Send(_T("501 Bad parameter. Numeric value required")); break; } m_transferstatus.rest = _ttoi64(args); CStdString str; str.Format(_T("350 Rest supported. Restarting at %I64d"), m_transferstatus.rest); Send(str); } break; case COMMAND_CDUP: case COMMAND_XCUP: { CStdString dir = _T(".."); int res = m_pOwner->m_pPermissions->ChangeCurrentDir(m_status.user, m_CurrentServerDir, dir); if (!res) { CStdString str; str.Format(_T("200 CDUP successful. \"%s\" is current directory."), m_CurrentServerDir); Send(str); } else if (res & PERMISSION_DENIED) Send(_T("550 CDUP failed, permission denied.")); else if (res & PERMISSION_INVALIDNAME) Send(_T("550 CDUP failed, filename invalid.")); else if (res) Send(_T("550 CDUP failed, directory not found.")); } break; case COMMAND_RETR: { if (m_transferstatus.pasv == -1) { Send(_T("503 Bad sequence of commands.")); break; } if (!m_transferstatus.pasv && (m_transferstatus.ip == _T("") || m_transferstatus.port == -1)) { Send(_T("503 Bad sequence of commands.")); break; } if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("521 PROT P required")); break; } //Much more checks //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckFilePermissions(m_status.user, args, m_CurrentServerDir, FOP_READ, physicalFile, logicalFile); if (error & PERMISSION_DENIED) { Send(_T("550 Permission denied")); ResetTransferstatus(); } else if (error & PERMISSION_INVALIDNAME) { Send(_T("550 Filename invalid.")); ResetTransferstatus(); } else if (error) { Send(_T("550 File not found")); ResetTransferstatus(); } else { if (!m_transferstatus.pasv) { if (m_transferstatus.socket) { SendTransferinfoNotification(); delete m_transferstatus.socket; } CTransferSocket *transfersocket = new CTransferSocket(this); m_transferstatus.socket = transfersocket; transfersocket->Init(physicalFile, TRANSFERMODE_SEND, m_transferstatus.rest); if (m_transferMode == mode_zlib) { if (!transfersocket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } if (!CreateTransferSocket(transfersocket)) break; __int64 totalSize; if (!GetLength64(physicalFile, totalSize)) totalSize = -1; SendTransferinfoNotification(TRANSFERMODE_SEND, physicalFile, logicalFile, m_transferstatus.rest, totalSize); Send(_T("150 Opening data channel for file transfer.")); } else { if (!m_transferstatus.socket) { Send(_T("503 Bad sequence of commands.")); break; } m_transferstatus.socket->Init(physicalFile, TRANSFERMODE_SEND, m_transferstatus.rest); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } __int64 totalSize; if (!GetLength64(physicalFile, totalSize)) totalSize = -1; SendTransferinfoNotification(TRANSFERMODE_SEND, physicalFile, logicalFile, m_transferstatus.rest, totalSize); m_transferstatus.socket->PasvTransfer(); } GetSystemTime(&m_LastTransferTime); } break; } case COMMAND_STOR: { if (m_transferstatus.pasv == -1) { Send(_T("503 Bad sequence of commands.")); break; } if(!m_transferstatus.pasv && (m_transferstatus.ip == _T("") || m_transferstatus.port == -1)) { Send(_T("503 Bad sequence of commands.")); break; } if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("521 PROT P required")); break; } //Much more checks //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckFilePermissions(m_status.user, args, m_CurrentServerDir, m_transferstatus.rest ? FOP_APPEND : FOP_WRITE, physicalFile, logicalFile); if (error & PERMISSION_DENIED) { Send(_T("550 Permission denied")); ResetTransferstatus(); } else if (error & PERMISSION_INVALIDNAME) { Send(_T("550 Filename invalid.")); ResetTransferstatus(); } else if (error) { Send(_T("550 Filename invalid")); ResetTransferstatus(); } else { if (!m_transferstatus.pasv) { CTransferSocket *transfersocket = new CTransferSocket(this); transfersocket->Init(physicalFile, TRANSFERMODE_RECEIVE, m_transferstatus.rest); m_transferstatus.socket = transfersocket; if (m_transferMode == mode_zlib) { if (!transfersocket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } if (!CreateTransferSocket(transfersocket)) break; SendTransferinfoNotification(TRANSFERMODE_RECEIVE, physicalFile, logicalFile, m_transferstatus.rest); Send(_T("150 Opening data channel for file transfer.")); } else { if (!m_transferstatus.socket) { Send(_T("503 Bad sequence of commands.")); break; } m_transferstatus.socket->Init(physicalFile, TRANSFERMODE_RECEIVE, m_transferstatus.rest); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } SendTransferinfoNotification(TRANSFERMODE_RECEIVE, physicalFile, logicalFile, m_transferstatus.rest); m_transferstatus.socket->PasvTransfer(); } GetSystemTime(&m_LastTransferTime); } } break; case COMMAND_SIZE: { //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckFilePermissions(m_status.user, args, m_CurrentServerDir, FOP_LIST, physicalFile, logicalFile); if (error & PERMISSION_DENIED) Send(_T("550 Permission denied")); else if (error & PERMISSION_INVALIDNAME) Send(_T("550 Filename invalid.")); else if (error) Send(_T("550 File not found")); else { CStdString str; _int64 length; if (GetLength64(physicalFile, length)) str.Format(_T("213 %I64d"), length); else str = _T("550 File not found"); Send(str); } } break; case COMMAND_DELE: { //Unquote args if (!UnquoteArgs(args)) { Send(_T("501 Syntax error")); break; } CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckFilePermissions(m_status.user, args, m_CurrentServerDir, FOP_DELETE, physicalFile, logicalFile); if (error & PERMISSION_DENIED) Send(_T("550 Permission denied")); else if (error & PERMISSION_INVALIDNAME) Send(_T("550 Filename invalid.")); else if (error) Send(_T("550 File not found")); else { bool success = DeleteFile(physicalFile) == TRUE; if (!success && GetLastError() == ERROR_ACCESS_DENIED) { DWORD attr = GetFileAttributes(physicalFile); if (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_READONLY) { attr &= ~FILE_ATTRIBUTE_READONLY; SetFileAttributes(physicalFile, attr); success = DeleteFile(physicalFile) == TRUE; } } if (!success) Send(_T("500 Failed to delete the file.")); else Send(_T("250 File deleted successfully")); } } break; case COMMAND_RMD: case COMMAND_XRMD: { //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckDirectoryPermissions(m_status.user, args, m_CurrentServerDir, DOP_DELETE, physicalFile, logicalFile); if (error & PERMISSION_DENIED) Send(_T("550 Permission denied")); else if (error & PERMISSION_INVALIDNAME) Send(_T("550 Filename invalid.")); else if (error) Send(_T("550 Directory not found")); else { if (!RemoveDirectory(physicalFile)) { if (GetLastError() == ERROR_DIR_NOT_EMPTY) Send(_T("550 Directory not empty.")); else Send(_T("450 Internal error deleting the directory.")); } else Send(_T("250 Directory deleted successfully")); } } break; case COMMAND_MKD: case COMMAND_XMKD: { //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckDirectoryPermissions(m_status.user, args, m_CurrentServerDir, DOP_CREATE, physicalFile, logicalFile); if (error & PERMISSION_DENIED) Send(_T("550 Can't create directory. Permission denied")); else if (error & PERMISSION_INVALIDNAME) Send(_T("550 Filename invalid.")); else if (error & PERMISSION_DOESALREADYEXIST && (error & PERMISSION_FILENOTDIR)!=PERMISSION_FILENOTDIR) Send(_T("550 Directory already exists")); else if (error & PERMISSION_FILENOTDIR) Send(_T("550 File with same name already exists")); else if (error) Send(_T("550 Directoryname not valid")); else { CStdString str; BOOL res = FALSE; BOOL bReplySent = FALSE; physicalFile += _T("\\"); while (physicalFile != _T("")) { CStdString piece = physicalFile.Left(physicalFile.Find('\\')+1); if (piece.Right(2) == _T(".\\")) { Send(_T("550 Directoryname not valid")); bReplySent = TRUE; break; } str += piece; physicalFile = physicalFile.Mid(physicalFile.Find('\\') + 1); res = CreateDirectory(str, 0); } if (!bReplySent) if (!res)//CreateDirectory(result+"\\",0)) { int error = GetLastError(); if (error == ERROR_ALREADY_EXISTS) Send(_T("550 Directory already exists")); else Send(_T("450 Internal error creating the directory.")); } else Send(_T("257 \"") + logicalFile + _T("\" created successfully")); } } break; case COMMAND_RNFR: { //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } RenName = _T(""); CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckFilePermissions(m_status.user, args, m_CurrentServerDir, FOP_DELETE, physicalFile, logicalFile); if (!error) { RenName = physicalFile; bRenFile = TRUE; Send(_T("350 File exists, ready for destination name.")); break; } else if (error & PERMISSION_DENIED) Send(_T("550 Permission denied")); else if (error & PERMISSION_INVALIDNAME) Send(_T("550 Filename invalid.")); else { int error2 = m_pOwner->m_pPermissions->CheckDirectoryPermissions(m_status.user, args, m_CurrentServerDir, DOP_DELETE, physicalFile, logicalFile); if (!error2) { RenName = physicalFile; bRenFile = FALSE; Send(_T("350 Directory exists, ready for destination name.")); } else if (error2 & PERMISSION_DENIED) Send(_T("550 Permission denied")); else if (error2 & PERMISSION_INVALIDNAME) Send(_T("550 Filename invalid.")); else Send(_T("550 file/directory not found")); break; } } break; case COMMAND_RNTO: { if (RenName == _T("")) { Send(_T("503 Bad sequence of commands!")); break; } //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } if (bRenFile) { CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckFilePermissions(m_status.user, args, m_CurrentServerDir, FOP_CREATENEW, physicalFile, logicalFile); if (error) RenName = _T(""); if (error & PERMISSION_DENIED) Send(_T("550 Permission denied")); else if (error & PERMISSION_INVALIDNAME) Send(_T("553 Filename invalid.")); else if (error & PERMISSION_DOESALREADYEXIST && (error & PERMISSION_DIRNOTFILE)!=PERMISSION_DIRNOTFILE) Send(_T("553 file exists")); else if (error) Send(_T("553 Filename invalid")); else { if (!MoveFile(RenName, physicalFile)) Send(_T("450 Internal error renaming the file")); else Send(_T("250 file renamed successfully")); } } else { CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckDirectoryPermissions(m_status.user, args, m_CurrentServerDir, DOP_CREATE, physicalFile, logicalFile); if (error) RenName = _T(""); if (error & PERMISSION_DENIED) Send(_T("550 Permission denied")); else if (error & PERMISSION_INVALIDNAME) Send(_T("550 Filename invalid.")); else if (error & PERMISSION_DOESALREADYEXIST && (error & PERMISSION_FILENOTDIR)!=PERMISSION_FILENOTDIR) Send(_T("550 file exists")); else if (error) Send(_T("550 Filename invalid")); else { if (!MoveFile(RenName, physicalFile)) Send(_T("450 Internal error renaming the file")); else Send(_T("250 file renamed successfully")); } } } break; case COMMAND_ABOR: { if (m_transferstatus.socket) { if (m_transferstatus.socket->Started()) Send(_T("426 Connection closed; transfer aborted.")); } Send(_T("226 ABOR command successful")); ResetTransferstatus(); break; } case COMMAND_SYST: Send(_T("215 UNIX emulated by FileZilla")); break; case COMMAND_NOOP: case COMMAND_NOP: Send(_T("200 OK")); break; case COMMAND_APPE: { if (m_transferstatus.pasv == -1) { Send(_T("503 Bad sequence of commands.")); break; } if (!m_transferstatus.pasv && (m_transferstatus.ip == _T("") || m_transferstatus.port == -1)) { Send(_T("503 Bad sequence of commands.")); break; } if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("521 PROT P required")); break; } //Much more checks //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckFilePermissions(m_status.user, args, m_CurrentServerDir, FOP_APPEND, physicalFile, logicalFile); if (error & PERMISSION_DENIED) { Send(_T("550 Permission denied")); ResetTransferstatus(); } else if (error & PERMISSION_INVALIDNAME) { Send(_T("550 Filename invalid.")); ResetTransferstatus(); } else if (error) { Send(_T("550 Filename invalid")); ResetTransferstatus(); } else { _int64 size = 0; if (!GetLength64(physicalFile, size)) size = 0; m_transferstatus.rest = size; if (!m_transferstatus.pasv) { CTransferSocket *transfersocket = new CTransferSocket(this); transfersocket->Init(physicalFile, TRANSFERMODE_RECEIVE, m_transferstatus.rest); m_transferstatus.socket = transfersocket; if (m_transferMode == mode_zlib) { if (!transfersocket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } if (!CreateTransferSocket(transfersocket)) break; SendTransferinfoNotification(TRANSFERMODE_RECEIVE, physicalFile, logicalFile, m_transferstatus.rest); CStdString str; str.Format(_T("150 Opening data channel for file transfer, restarting at offset %I64d"), size); Send(str); } else { if (!m_transferstatus.socket) { Send(_T("503 Bad sequence of commands.")); break; } m_transferstatus.socket->Init(physicalFile, TRANSFERMODE_RECEIVE, m_transferstatus.rest); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } SendTransferinfoNotification(TRANSFERMODE_RECEIVE, physicalFile, logicalFile, m_transferstatus.rest); m_transferstatus.socket->PasvTransfer(); } GetSystemTime(&m_LastTransferTime); } } break; case COMMAND_NLST: if (m_transferstatus.pasv == -1) { Send(_T("503 Bad sequence of commands.")); break; } if (!m_transferstatus.pasv && (m_transferstatus.ip == _T("") || m_transferstatus.port == -1)) { Send(_T("503 Bad sequence of commands.")); break; } if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("521 PROT P required")); break; } //Much more checks else { //Check args, currently only supported argument is the directory which will be listed. if (args != _T("")) { BOOL bBreak = FALSE; while (args[0] == '-') //No parameters supported { if (args.GetLength() < 2) { //Dash without param Send(_T("501 Syntax error")); bBreak = TRUE; break; } int pos = args.Find(' '); CStdString params; if (pos != -1) { params = args.Left(1); params = params.Left(pos-1); args = args.Mid(pos+1); args.TrimLeft(_T(" ")); } else args = _T(""); while (params != _T("")) { //Some parameters are not support if (params[0] == 'R') { Send(_T("504 Command not implemented for that parameter")); bBreak = TRUE; break; } //Ignore other parameters params = params.Mid(1); } if (args == _T("")) break; } if (bBreak) break; if (args != _T("")) { //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } } } t_dirlisting *pResult; CStdString physicalDir, logicalDir; int error = m_pOwner->m_pPermissions->GetDirectoryListing(m_status.user, m_CurrentServerDir, args, pResult, physicalDir, logicalDir, CPermissions::AddShortListingEntry, m_useUTF8); if (error & PERMISSION_DENIED) { Send(_T("550 Permission denied")); ResetTransferstatus(); } else if (error & PERMISSION_INVALIDNAME) { Send(_T("550 Filename invalid.")); ResetTransferstatus(); } else if (error) { Send(_T("550 Directory not found")); ResetTransferstatus(); } else { if (!m_transferstatus.pasv) { CTransferSocket *transfersocket = new CTransferSocket(this); m_transferstatus.socket = transfersocket; transfersocket->Init(pResult, TRANSFERMODE_NLST); if (m_transferMode == mode_zlib) { if (!transfersocket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } if (!CreateTransferSocket(transfersocket)) break; SendTransferinfoNotification(TRANSFERMODE_LIST, physicalDir, logicalDir); // Use TRANSFERMODE_LIST instead of TRANSFERMODE_NLST. Send(_T("150 Opening data channel for directory list.")); } else { if (!m_transferstatus.socket) { CPermissions::DestroyDirlisting(pResult); Send(_T("503 Bad sequence of commands.")); break; } m_transferstatus.socket->Init(pResult, TRANSFERMODE_NLST ); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } SendTransferinfoNotification(TRANSFERMODE_LIST, physicalDir, logicalDir); // Use TRANSFERMODE_LIST instead of TRANSFERMODE_NLST. m_transferstatus.socket->PasvTransfer(); } } } break; case COMMAND_MDTM: { //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckFilePermissions(m_status.user, args, m_CurrentServerDir, FOP_LIST, physicalFile, logicalFile); if (error & PERMISSION_DENIED) Send(_T("550 Permission denied")); else if (error & PERMISSION_INVALIDNAME) Send(_T("550 Filename invalid.")); else if (error & 2) Send(_T("550 File not found")); else { CFileStatus64 status; GetStatus64(physicalFile, status); CStdString str; SYSTEMTIME time; FileTimeToSystemTime(&status.m_mtime, &time); str.Format(_T("213 %04d%02d%02d%02d%02d%02d"), time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond); Send(str); } } break; case COMMAND_EPSV: { if (m_transferstatus.socket) { SendTransferinfoNotification(); delete m_transferstatus.socket; } m_transferstatus.family = (GetFamily() == AF_INET) ? 1 : 2; m_transferstatus.socket = new CTransferSocket(this); unsigned int port = 0; unsigned int retries = 3; while (retries > 0) { if (m_pOwner->m_pOptions->GetOptionVal(OPTION_USECUSTOMPASVPORT)) { static UINT customPort = 0; unsigned int minPort = (unsigned int)m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVMINPORT); unsigned int maxPort = (unsigned int)m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVMAXPORT); if (minPort > maxPort) { unsigned int temp = minPort; minPort = maxPort; maxPort = temp; } if (customPort < minPort || customPort > maxPort) { customPort = minPort; } port = customPort; ++customPort; } if (m_transferstatus.socket->Create(port, SOCK_STREAM, FD_ACCEPT, 0, GetFamily())) { break; } --retries; } if (retries <= 0) { delete m_transferstatus.socket; m_transferstatus.socket=0; Send(_T("421 Can't create socket")); break; } if (m_pGssLayer && m_pGssLayer->AuthSuccessful()) m_transferstatus.socket->UseGSS(m_pGssLayer); if (m_pSslLayer && m_bProtP) m_transferstatus.socket->UseSSL(m_pSslLayer->GetContext()); if (!m_transferstatus.socket->Listen()) { delete m_transferstatus.socket; m_transferstatus.socket=0; Send(_T("421 Can't create socket")); m_transferstatus.pasv = -1; break; } //Now retrieve the port CStdString dummy; if (m_transferstatus.socket->GetSockName(dummy, port)) { //Put the answer together CStdString str; str.Format(_T("229 Entering Extended Passive Mode (|||%d|)"), port); Send(str); m_transferstatus.pasv=1; } else { delete m_transferstatus.socket; m_transferstatus.socket=0; Send(_T("421 Can't create socket")); m_transferstatus.pasv = -1; } break; } case COMMAND_EPRT: { if (m_transferstatus.socket) { SendTransferinfoNotification(); delete m_transferstatus.socket; m_transferstatus.socket=0; } if (args[0] != '|') { Send(_T("501 Syntax error")); m_transferstatus.pasv = -1; break; } args = args.Mid(1); int pos = args.Find('|'); if (pos < 1 || (pos>=(args.GetLength()-1))) { Send(_T("501 Syntax error")); m_transferstatus.pasv = -1; break; } int protocol = _ttoi(args.Left(pos)); bool ipv6Allowed = m_pOwner->m_pOptions->GetOptionVal(OPTION_DISABLE_IPV6) == 0; if (protocol != 1 && (protocol != 2 || !ipv6Allowed)) { if (ipv6Allowed) Send(_T("522 Extended Port Failure - unknown network protocol. Supported protocols: (1,2)")); else Send(_T("522 Extended Port Failure - unknown network protocol. Supported protocols: (1)")); m_transferstatus.pasv = -1; break; } args = args.Mid(pos + 1); pos = args.Find('|'); if (pos < 1 || (pos>=(args.GetLength()-1))) { Send(_T("501 Syntax error")); m_transferstatus.pasv = -1; break; } CStdString ip = args.Left(pos); if (protocol == 1) { #ifdef _UNICODE if (inet_addr(ConvToLocal(ip)) == INADDR_NONE) #else if (inet_addr(ip) == INADDR_NONE) #endif { Send(_T("501 Syntax error, not a valid IPv4 address")); m_transferstatus.pasv = -1; break; } } else { ip = GetIPV6LongForm(ip); if (ip.IsEmpty()) { Send(_T("501 Syntax error, not a valid IPv6 address")); m_transferstatus.pasv = -1; break; } } args = args.Mid(pos + 1); pos = args.Find('|'); if (pos < 1) { Send(_T("501 Syntax error")); m_transferstatus.pasv = -1; break; } int port = _ttoi(args.Left(pos)); if (port < 1 || port > 65535) { Send(_T("501 Syntax error")); m_transferstatus.pasv = -1; break; } m_transferstatus.port = port; m_transferstatus.ip = ip; m_transferstatus.family = (protocol == 1) ? AF_INET : AF_INET6; m_transferstatus.pasv = 0; Send(_T("200 Port command successful")); break; } case COMMAND_AUTH: { if (m_nRecvBufferPos || m_RecvLineBuffer.size() ) { Send(_T("503 Bad sequence of commands. Received additional data after the AUTH command before this reply could be sent.")); ForceClose(-1); break; } if (m_pGssLayer) { Send(_T("534 Authentication type already set to GSSAPI")); break; } else if (m_pSslLayer) { Send(_T("534 Authentication type already set to SSL")); break; } args.MakeUpper(); if (args == _T("GSSAPI")) { if (!m_pOwner->m_pOptions->GetOptionVal(OPTION_USEGSS)) { Send(_T("502 GSSAPI authentication not implemented")); break; } m_pGssLayer = new CAsyncGssSocketLayer; BOOL res = AddLayer(m_pGssLayer); if (res) { res = m_pGssLayer->InitGSS(FALSE, (BOOL)m_pOwner->m_pOptions->GetOptionVal(OPTION_GSSPROMPTPASSWORD)); if (!res) SendStatus(_T("Unable to init GSS"), 1); } if (!res) { RemoveAllLayers(); delete m_pGssLayer; m_pGssLayer = NULL; Send(_T("431 Could not initialize GSSAPI libraries")); break; } Send(_T("334 Using authentication type GSSAPI; ADAT must follow")); } else if (args == _T("SSL") || args == _T("TLS")) { if (m_pSslLayer) { Send(_T("503 Already using SSL/TLS")); break; } if (!m_pOwner->m_pOptions->GetOptionVal(OPTION_ENABLESSL) || !m_pOwner->m_pOptions->GetOptionVal(OPTION_ALLOWEXPLICITSSL)) { Send(_T("502 SSL/TLS authentication not allowed")); break; } m_pSslLayer = new CAsyncSslSocketLayer; BOOL res = AddLayer(m_pSslLayer); if (res) { CString error; #ifdef _UNICODE int res = m_pSslLayer->SetCertKeyFile(ConvToLocal(m_pOwner->m_pOptions->GetOption(OPTION_SSLCERTFILE)), ConvToLocal(m_pOwner->m_pOptions->GetOption(OPTION_SSLKEYFILE)), ConvToLocal(m_pOwner->m_pOptions->GetOption(OPTION_SSLKEYPASS)), &error); #else int res = m_pSslLayer->SetCertKeyFile(m_pOwner->m_pOptions->GetOption(OPTION_SSLCERTFILE), m_pOwner->m_pOptions->GetOption(OPTION_SSLKEYFILE), m_pOwner->m_pOptions->GetOption(OPTION_SSLKEYPASS), &error); #endif if (res == SSL_FAILURE_LOADDLLS) SendStatus(_T("Failed to load SSL libraries"), 1); else if (res == SSL_FAILURE_INITSSL) SendStatus(_T("Failed to initialize SSL libraries"), 1); else if (res == SSL_FAILURE_VERIFYCERT) { if (error != _T("")) SendStatus(error, 1); else SendStatus(_T("Failed to set certificate and private key"), 1); } if (res) { RemoveAllLayers(); delete m_pSslLayer; m_pSslLayer = NULL; Send(_T("431 Could not initialize SSL connection")); break; } } if (res) { int code = m_pSslLayer->InitSSLConnection(false); if (code == SSL_FAILURE_LOADDLLS) SendStatus(_T("Failed to load SSL libraries"), 1); else if (code == SSL_FAILURE_INITSSL) SendStatus(_T("Failed to initialize SSL library"), 1); res = (code == 0); } if (res) { if (args == _T("SSL")) { SendStatus(_T("234 Using authentication type SSL"), 3); static const char* reply = "234 Using authentication type SSL\r\n"; const int len = strlen(reply); res = (m_pSslLayer->SendRaw(reply, len) == len); } else // TLS { SendStatus(_T("234 Using authentication type TLS"), 3); static const char* reply = "234 Using authentication type TLS\r\n"; const int len = strlen(reply); res = (m_pSslLayer->SendRaw(reply, len) == len); } } if (!res) { RemoveAllLayers(); delete m_pSslLayer; m_pSslLayer = NULL; Send(_T("431 Could not initialize SSL connection")); break; } } else { Send(_T("504 Auth type not supported")); break; } break; } case COMMAND_ADAT: if (m_pGssLayer) { char sendme[4096]; #ifdef _UNICODE m_pGssLayer->ProcessCommand("ADAT", ConvToLocal(args), sendme); Send(ConvFromLocal(sendme)); #else m_pGssLayer->ProcessCommand("ADAT", args, sendme); Send(sendme); #endif } else Send(_T("502 Command not implemented for this authentication type")); break; case COMMAND_PBSZ: if (m_pGssLayer) { char sendme[4096]; #ifdef _UNICODE m_pGssLayer->ProcessCommand("PBSZ", ConvToLocal(args), sendme); Send(ConvFromLocal(sendme)); #else m_pGssLayer->ProcessCommand("PBSZ", args, sendme); Send(sendme); #endif } else if (m_pSslLayer) Send(_T("200 PBSZ=0")); else Send(_T("502 Command not implemented for this authentication type")); break; case COMMAND_PROT: if (m_pGssLayer) { char sendme[4096]; #ifdef _UNICODE m_pGssLayer->ProcessCommand("PROT", ConvToLocal(args), sendme); Send(ConvFromLocal(sendme)); #else m_pGssLayer->ProcessCommand("PROT", args, sendme); Send(sendme); #endif } else if (m_pSslLayer) { args.MakeUpper(); if (args == _T("C")) { if (m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP)) Send(_T("534 This server requires an encrypted data connection with PROT P")); else { if (m_transferstatus.socket) m_transferstatus.socket->UseSSL(0); Send(_T("200 Protection level set to C")); m_bProtP = false; } } else if (args == _T("P")) { if (m_transferstatus.socket) m_transferstatus.socket->UseSSL(m_pSslLayer->GetContext()); Send(_T("200 Protection level set to P")); m_bProtP = true; } else if (args == _T("S") || args == _T("E")) Send(_T("504 Protection level ") + args + _T(" not supported")); else Send(_T("504 Protection level ") + args + _T(" not recognized")); } else Send(_T("502 Command not implemented for this authentication type")); break; case COMMAND_FEAT: { if (!Send(_T("211-Features:"))) break; if (!Send(_T(" MDTM"))) break; if (!Send(_T(" REST STREAM"))) break; if (!Send(_T(" SIZE"))) break; if (m_pOwner->m_pOptions->GetOptionVal(OPTION_MODEZ_USE)) { if (!Send(_T(" MODE Z"))) break; } if (!Send(_T(" MLST type*;size*;modify*;"))) break; if (!Send(_T(" MLSD"))) break; if (m_pOwner->m_pOptions->GetOptionVal(OPTION_ENABLESSL) && (m_pOwner->m_pOptions->GetOptionVal(OPTION_ALLOWEXPLICITSSL) || m_pSslLayer)) { if (!Send(_T(" AUTH SSL"))) break; if (!Send(_T(" AUTH TLS"))) break; if (!Send(_T(" PROT"))) break; if (!Send(_T(" PBSZ"))) break; } if (!Send(_T(" UTF8"))) break; if (!Send(_T(" CLNT"))) break; if (!Send(_T(" MFMT"))) break; if (m_pOwner->m_pOptions->GetOptionVal(OPTION_ENABLE_HASH)) { CStdString hash = _T(" HASH "); hash += _T("SHA-1"); if (m_hash_algorithm == CHashThread::SHA1) hash += _T("*"); hash += _T(";SHA-512"); if (m_hash_algorithm == CHashThread::SHA512) hash += _T("*"); hash += _T(";MD5"); if (m_hash_algorithm == CHashThread::MD5) hash += _T("*"); if (!Send(hash)) break; } if (!Send(_T("211 End"))) break; break; } case COMMAND_MODE: if (args == _T("S") || args == _T("s")) { m_transferMode = mode_stream; Send(_T("200 MODE set to S.")); } else if (args == _T("Z") || args == _T("z")) { if (m_pOwner->m_pOptions->GetOptionVal(OPTION_MODEZ_USE) || m_transferMode == mode_zlib) { if (m_transferMode == mode_zlib || CheckIpForZlib()) { m_transferMode = mode_zlib; Send(_T("200 MODE set to Z.")); } else Send(_T("504 MODE Z not allowed from your IP")); } else Send(_T("504 MODE Z not enabled")); } else if (args == _T("C") || args == _T("c") || args == _T("B") || args == _T("b")) Send(_T("502 Unimplemented MODE type")); else Send(_T("504 Unknown MODE type")); break; case COMMAND_OPTS: args.MakeUpper(); if (args.Left(13) == _T("MODE Z LEVEL ")) { int level = _ttoi(args.Mid(13)); if (m_zlibLevel == level || (level >= m_pOwner->m_pOptions->GetOptionVal(OPTION_MODEZ_LEVELMIN) && level <= m_pOwner->m_pOptions->GetOptionVal(OPTION_MODEZ_LEVELMAX))) { m_zlibLevel = level; CString str; str.Format(_T("200 MODE Z LEVEL set to %d"), level); Send(str); } else Send(_T("501 can't change MODE Z LEVEL do desired value")); } else if (args == _T("UTF8 ON")) { m_useUTF8 = true; Send(_T("200 UTF8 mode enabled")); } else if (args == _T("UTF8 OFF")) { m_useUTF8 = false; Send(_T("200 UTF8 mode disabled")); } else if (args.Left(4) == _T("MLST")) ParseMlstOpts(args.Mid(4)); else if (args.Left(4) == _T("HASH")) ParseHashOpts(args.Mid(4)); else Send(_T("501 Option not understood")); break; case COMMAND_HELP: if (args == _T("")) { Send(_T("214-The following commands are recognized:")); CString str; for (int i = 0; i < (sizeof(commands)/sizeof(t_command)); i++) { CString cmd = commands[i].command; while (cmd.GetLength() < 4) cmd += _T(" "); str += _T(" ") + cmd; if (!((i + 1) % 8)) { Send(str); str = _T(""); } } if (str != _T("")) Send(str); Send(_T("214 Have a nice day.")); } else { args.MakeUpper(); int i; for (i = 0; i < (sizeof(commands)/sizeof(t_command)); i++) { if (args == commands[i].command) { CStdString str; str.Format(_T("214 Command %s is supported by FileZilla Server"), args); Send(str); break; } } if (i == (sizeof(commands)/sizeof(t_command))) { CStdString str; str.Format(_T("502 Command %s is not recognized or supported by FileZilla Server"), args); Send(str); } } break; case COMMAND_ALLO: Send(_T("202 No storage allocation neccessary.")); break; case COMMAND_MLST: { CStdString fact; CStdString logicalName; int res = m_pOwner->m_pPermissions->GetFact(m_status.user, m_CurrentServerDir, args, fact, logicalName, m_facts); if (res & PERMISSION_DENIED) { Send(_T("550 Permission denied.")); break; } else if (res & PERMISSION_INVALIDNAME) { Send(_T("550 Filename invalid.")); break; } else if (res) { Send(_T("550 File or directory not found.")); break; } CStdString str; str.Format(_T("250-Listing %s"), logicalName); if (!Send(str)) break; fact = _T(" ") + fact; if (!Send(fact)) break; Send(_T("250 End")); } break; case COMMAND_MLSD: if (m_transferstatus.pasv == -1) { Send(_T("503 Bad sequence of commands.")); break; } if (!m_transferstatus.pasv && (m_transferstatus.ip == _T("") || m_transferstatus.port == -1)) Send(_T("503 Bad sequence of commands.")); //Much more checks else { if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("521 PROT P required")); break; } if (args != _T("")) { //Unquote args if (!UnquoteArgs(args)) { Send(_T("501 Syntax error")); break; } } t_dirlisting *pResult; CStdString physicalDir, logicalDir; int error = m_pOwner->m_pPermissions->GetDirectoryListing(m_status.user, m_CurrentServerDir, args, pResult, physicalDir, logicalDir, CPermissions::AddFactsListingEntry, m_useUTF8, m_facts); if (error & PERMISSION_DENIED) { Send(_T("550 Permission denied")); ResetTransferstatus(); } else if (error & PERMISSION_INVALIDNAME) { Send(_T("550 Filename invalid.")); ResetTransferstatus(); } else if (error) { Send(_T("550 Directory not found")); ResetTransferstatus(); } else { if (!m_transferstatus.pasv) { if (m_transferstatus.socket) { SendTransferinfoNotification(); delete m_transferstatus.socket; } CTransferSocket *transfersocket = new CTransferSocket(this); m_transferstatus.socket = transfersocket; transfersocket->Init(pResult, TRANSFERMODE_LIST); if (m_transferMode == mode_zlib) { if (!transfersocket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } if (!CreateTransferSocket(transfersocket)) break; SendTransferinfoNotification(TRANSFERMODE_LIST, physicalDir, logicalDir); Send(_T("150 Opening data channel for directory list.")); } else { if (!m_transferstatus.socket) { CPermissions::DestroyDirlisting(pResult); Send(_T("503 Bad sequence of commands.")); break; } m_transferstatus.socket->Init(pResult, TRANSFERMODE_LIST ); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send(_T("550 could not initialize zlib, please use MODE S instead")); ResetTransferstatus(); break; } } SendTransferinfoNotification(TRANSFERMODE_LIST, physicalDir, logicalDir); m_transferstatus.socket->PasvTransfer(); } } } break; case COMMAND_SITE: { CStdString cmd; args.MakeUpper(); int pos = args.Find(' '); if (pos != -1) { cmd = args.Left(pos); args = args.Mid(pos + 1); args.TrimLeft(_T(" ")); } else { cmd = args; args = _T(""); } if (cmd == _T("NAMEFMT")) { if (args == _T("") || args == _T("1")) Send(_T("200 Now using naming format \"1\"")); else Send(_T("504 Naming format not implemented")); break; } else { Send(_T("504 Command not implemented for that parameter")); break; } break; } case COMMAND_STRU: args.MakeUpper(); if (args == _T("F")) Send(_T("200 Using file structure 'File'")); else Send(_T("504 Command not implemented for that parameter")); break; case COMMAND_CLNT: Send(_T("200 Don't care")); break; case COMMAND_MFMT: { int pos = args.find(' '); if (pos < 1) { Send(_T("501 Syntax error")); break; } CStdString timeval = args.Left(pos); args = args.Mid(pos + 1); if (timeval.GetLength() < 14) { Send( _T("501 Syntax error") ); break; } bool numbersOnly = true; for (int i = 0; i < 14; i++) { if (timeval[i] < '0' || timeval[i] > '9') { numbersOnly = false; break; } } if (!numbersOnly) { Send( _T("501 Syntax error") ); break; } int year = (timeval[0] - '0') * 1000 + (timeval[1] - '0') * 100 + (timeval[2] - '0') * 10 + timeval[3] - '0'; int month = (timeval[4] - '0') * 10 + timeval[5] - '0'; int day = (timeval[6] - '0') * 10 + timeval[7] - '0'; int hour = (timeval[8] - '0') * 10 + timeval[9] - '0'; int minute = (timeval[10] - '0') * 10 + timeval[11] - '0'; int second = (timeval[12] - '0') * 10 + timeval[13] - '0'; if (year < 1000 || month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59) { Send( _T("501 Not a valid date") ); break; } SYSTEMTIME st = {0}; st.wYear = year; st.wMonth = month; st.wDay = day; st.wHour = hour; st.wMinute = minute; st.wSecond = second; FILETIME ft; if (!SystemTimeToFileTime(&st, &ft)) { Send( _T("501 Not a valid date") ); break; } //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } if (args == _T("")) { Send( _T("501 Syntax error") ); break; } CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckFilePermissions(m_status.user, args, m_CurrentServerDir, FOP_LIST, physicalFile, logicalFile); if (error & PERMISSION_DENIED) Send(_T("550 Permission denied")); else if (error & PERMISSION_INVALIDNAME) Send(_T("550 Filename invalid.")); else if (error & 2) Send(_T("550 File not found")); else { HANDLE hFile = CreateFile(physicalFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); if (hFile == INVALID_HANDLE_VALUE) Send(_T("550 Cannot access file")); else { if (!SetFileTime(hFile, 0, 0, &ft)) Send(_T("550 Failed to set file modification time")); else Send(_T("213 modify=") + timeval.Left(14) + _T("; ") + logicalFile); CloseHandle(hFile); } } } break; case COMMAND_HASH: { if (!m_pOwner->m_pOptions->GetOptionVal(OPTION_ENABLE_HASH)) { Send(_T("500 Syntax error, command unrecognized.")); break; } //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } CStdString physicalFile, logicalFile; int error = m_pOwner->m_pPermissions->CheckFilePermissions(m_status.user, args, m_CurrentServerDir, FOP_READ, physicalFile, logicalFile); if (error & PERMISSION_DENIED) { Send(_T("550 Permission denied")); ResetTransferstatus(); } else if (error & PERMISSION_INVALIDNAME) { Send(_T("550 Filename invalid.")); ResetTransferstatus(); } else if (error) { Send(_T("550 File not found")); ResetTransferstatus(); } else { int hash_res = m_pOwner->GetHashThread().Hash(physicalFile, m_hash_algorithm, m_hash_id, m_pOwner); if (hash_res == CHashThread::BUSY) Send(_T("450 Another hash operation is already in progress.")); else if (hash_res != CHashThread::PENDING) Send(_T("550 Failed to hash file")); } } break; default: Send(_T("502 Command not implemented.")); } if (!m_RecvLineBuffer.empty()) m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_COMMAND, m_userid); return; } void CControlSocket::ProcessTransferMsg() { if (!m_transferstatus.socket) return; int status = m_transferstatus.socket->GetStatus(); GetSystemTime(&m_LastCmdTime); if (m_transferstatus.socket) if (m_transferstatus.socket->GetMode()==TRANSFERMODE_SEND || m_transferstatus.socket->GetMode()==TRANSFERMODE_RECEIVE) GetSystemTime(&m_LastTransferTime); if (status == 2 && m_transferstatus.pasv && m_transferstatus.usedResolvedIP) m_pOwner->ExternalIPFailed(); int mode = m_transferstatus.socket->GetMode(); _int64 zlibBytesIn = 0; _int64 zlibBytesOut = 0; if (m_transferMode == mode_zlib) m_transferstatus.socket->GetZlibStats(zlibBytesIn, zlibBytesOut); ResetTransferstatus(); if (!status) { if ((mode == TRANSFERMODE_LIST || mode == TRANSFERMODE_NLST || mode == TRANSFERMODE_SEND) && zlibBytesIn && zlibBytesOut) { if (zlibBytesIn >= zlibBytesOut) { CString str; _int64 percent = 10000 - (zlibBytesOut * 10000 / zlibBytesIn); str.Format(_T("226 Transfer OK, compression saved %I64d of %I64d bytes (%I64d.%02I64d%%)"), zlibBytesIn - zlibBytesOut, zlibBytesIn, percent / 100, percent % 100); Send(str); } else { CString str; _int64 percent = (zlibBytesOut * 10000 / zlibBytesIn) - 10000; str.Format(_T("226 Transfer OK, unfortunately compression did increase the transfer size by %I64d bytes to %I64d bytes (%I64d.%02I64d%%)"), zlibBytesOut - zlibBytesIn, zlibBytesOut, percent / 100, percent % 100); Send(str); } } else if (mode == TRANSFERMODE_RECEIVE && zlibBytesIn && zlibBytesOut) { if (zlibBytesOut >= zlibBytesIn) { CString str; _int64 percent = 10000 - (zlibBytesIn * 10000 / zlibBytesOut); str.Format(_T("226 Transfer OK, compression saved %I64d of %I64d bytes (%I64d.%02I64d%%)"), zlibBytesOut - zlibBytesIn, zlibBytesOut, percent / 100, percent % 100); Send(str); } else { CString str; _int64 percent = (zlibBytesIn * 10000 / zlibBytesOut) - 10000; str.Format(_T("226 Transfer OK, unfortunately compression did increase the transfer size by %I64d bytes to %I64d bytes (%I64d.%02I64d%%)"), zlibBytesIn - zlibBytesOut, zlibBytesIn, percent / 100, percent % 100); Send(str); } } else Send(_T("226 Transfer OK")); } else if (status==1) Send(_T("426 Connection closed; transfer aborted.")); else if (status==2) Send(_T("425 Can't open data connection.")); else if (status==3) Send(_T("550 can't access file.")); else if (status==4) { Send(_T("426 Connection timed out, aborting transfer")); ForceClose(1); return; } else if (status==5) Send(_T("425 Can't open data connection")); else if (status==6) Send(_T("450 zlib error")); if (status>=0 && m_bWaitGoOffline) ForceClose(0); else if (m_bQuitCommand) { Send(_T("221 Goodbye")); if (CanQuit()) ForceClose(5); } } CTransferSocket* CControlSocket::GetTransferSocket() { return m_transferstatus.socket; } void CControlSocket::ForceClose(int nReason) { if (m_transferstatus.socket) { // Don't call SendTransferInfoNotification, since connection // does get removed real soon. m_transferstatus.socket->Close(); delete m_transferstatus.socket; m_transferstatus.socket = 0; } if (m_shutdown && nReason == 1) { Close(); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); return; } if (!nReason) Send(_T("421 Server is going offline")); else if (nReason == 1) Send(_T("421 Connection timed out.")); else if (nReason == 2) Send(_T("421 No-transfer-time exceeded. Closing control connection.")); else if (nReason == 3) Send(_T("421 Login time exceeded. Closing control connection.")); else if (nReason == 4) Send(_T("421 Kicked by Administrator")); else if (nReason == 5) { // 221 Goodbye } SendStatus(_T("disconnected."), 0); m_shutdown = true; int res = ShutDown(); if (m_pSslLayer) { if (!res && GetLastError() == WSAEWOULDBLOCK) return; } Close(); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); } void CControlSocket::IncUserCount(const CStdString &user) { int curcount=GetUserCount(user)+1; EnterCritSection(m_Sync); m_UserCount[user]=curcount; LeaveCritSection(m_Sync); } void CControlSocket::DecUserCount(const CStdString &user) { int curcount=GetUserCount(user)-1; if (curcount<0) return; EnterCritSection(m_Sync); m_UserCount[user]=curcount; LeaveCritSection(m_Sync); } int CControlSocket::GetUserCount(const CStdString &user) { EnterCritSection(m_Sync); int count=0; std::map<CStdString, int>::iterator iter = m_UserCount.find(user); if (iter!=m_UserCount.end()) count = iter->second; LeaveCritSection(m_Sync); return count; } void CControlSocket::CheckForTimeout() { if (m_antiHammeringWaitTime) { m_antiHammeringWaitTime -= 1000; if (m_antiHammeringWaitTime <= 0) { m_antiHammeringWaitTime = 0; TriggerEvent(FD_FORCEREAD); } } if (m_status.hammerValue > 0) m_status.hammerValue--; if (m_transferstatus.socket) { if (m_transferstatus.socket->CheckForTimeout()) return; } _int64 timeout; if (m_shutdown) timeout = 3; else timeout = m_pOwner->m_pOptions->GetOptionVal(OPTION_TIMEOUT); if (!timeout) return; SYSTEMTIME sCurrentTime; GetSystemTime(&sCurrentTime); FILETIME fCurrentTime; SystemTimeToFileTime(&sCurrentTime, &fCurrentTime); FILETIME fLastTime; SystemTimeToFileTime(&m_LastCmdTime, &fLastTime); _int64 elapsed = ((_int64)(fCurrentTime.dwHighDateTime - fLastTime.dwHighDateTime) << 32) + fCurrentTime.dwLowDateTime - fLastTime.dwLowDateTime; if (elapsed > (timeout*10000000)) { ForceClose(1); return; } if (m_status.loggedon) { //Transfer timeout _int64 nNoTransferTimeout=m_pOwner->m_pOptions->GetOptionVal(OPTION_NOTRANSFERTIMEOUT); if (!nNoTransferTimeout) return; SystemTimeToFileTime(&m_LastTransferTime, &fLastTime); elapsed = ((_int64)(fCurrentTime.dwHighDateTime - fLastTime.dwHighDateTime) << 32) + fCurrentTime.dwLowDateTime - fLastTime.dwLowDateTime; if (elapsed>(nNoTransferTimeout*10000000)) { ForceClose(2); return; } } else { //Login timeout _int64 nLoginTimeout=m_pOwner->m_pOptions->GetOptionVal(OPTION_LOGINTIMEOUT); if (!nLoginTimeout) return; SystemTimeToFileTime(&m_LoginTime, &fLastTime); elapsed = ((_int64)(fCurrentTime.dwHighDateTime - fLastTime.dwHighDateTime) << 32) + fCurrentTime.dwLowDateTime - fLastTime.dwLowDateTime; if (elapsed>(nLoginTimeout*10000000)) { ForceClose(3); return; } } } void CControlSocket::WaitGoOffline(bool wait /*=true*/) { if (!wait) { m_bWaitGoOffline = FALSE; return; } if (m_transferstatus.socket) { if (!m_transferstatus.socket->Started()) ForceClose(0); else m_bWaitGoOffline=TRUE; } else ForceClose(0); } void CControlSocket::ResetTransferstatus() { if (m_transferstatus.socket) { SendTransferinfoNotification(); delete m_transferstatus.socket; } m_transferstatus.socket = 0; m_transferstatus.ip = _T(""); m_transferstatus.port = -1; m_transferstatus.pasv = -1; m_transferstatus.rest = 0; } BOOL CControlSocket::UnquoteArgs(CStdString &args) { args.TrimLeft( _T(" ") ); args.TrimRight( _T(" ") ); int pos1 = args.Find('"'); int pos2 = args.ReverseFind('"'); if (pos1 == -1 && pos2 == -1) return TRUE; if (pos1 || pos2 != (args.GetLength()-1) || pos1 >= (pos2-1)) return FALSE; args = args.Mid(1, args.GetLength() - 2); return TRUE; } void CControlSocket::OnSend(int nErrorCode) { if (m_nSendBufferLen && m_pSendBuffer) { int nLimit = GetSpeedLimit(download); if (!nLimit) return; int numsend = nLimit; if (nLimit == -1 || nLimit > m_nSendBufferLen) numsend = m_nSendBufferLen; int numsent = CAsyncSocketEx::Send(m_pSendBuffer, numsend); if (numsent==SOCKET_ERROR && GetLastError() == WSAEWOULDBLOCK) return; if (!numsent || numsent == SOCKET_ERROR) { Close(); SendStatus(_T("could not send reply, disconnected."), 0); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); delete [] m_pSendBuffer; m_pSendBuffer = NULL; m_nSendBufferLen = 0; return; } if (nLimit != -1) m_SlQuotas[download].nTransferred += numsent; if (numsent == m_nSendBufferLen) { delete [] m_pSendBuffer; m_pSendBuffer = NULL; m_nSendBufferLen = 0; } else { char *tmp = m_pSendBuffer; m_pSendBuffer = new char[m_nSendBufferLen-numsent]; memcpy(m_pSendBuffer, tmp+numsent, m_nSendBufferLen-numsent); delete [] tmp; m_nSendBufferLen -= numsent; TriggerEvent(FD_WRITE); } } } BOOL CControlSocket::DoUserLogin(LPCTSTR password, bool skipPass /*=false*/) { CUser user; if (!m_pOwner->m_pPermissions->CheckUserLogin(m_status.user, password, user, skipPass)) { AntiHammerIncrease(2); m_pOwner->AntiHammerIncrease(m_RemoteIP); if (m_pOwner->m_pAutoBanManager->RegisterAttempt(m_RemoteIP)) { Send(_T("421 Temporarily banned for too many failed login attempts")); ForceClose(-1); return FALSE; } Send(_T("530 Login or password incorrect!")); return FALSE; } if (!user.IsEnabled()) { Send(_T("530 Not logged in, user account has been disabled")); ForceClose(-1); return FALSE; } if (!user.BypassUserLimit()) { int nMaxUsers = (int)m_pOwner->m_pOptions->GetOptionVal(OPTION_MAXUSERS); if (m_pOwner->GetGlobalNumConnections()>nMaxUsers&&nMaxUsers) { SendStatus(_T("Refusing connection. Reason: Max. connection count reached."), 1); Send(_T("421 Too many users are connected, please try again later.")); ForceClose(-1); return FALSE; } } if (user.GetUserLimit() && GetUserCount(m_status.user)>=user.GetUserLimit()) { CStdString str; str.Format(_T("Refusing connection. Reason: Max. connection count reached for the user \"%s\"."), m_status.user); SendStatus(str,1); Send(_T("421 Too many users logged in for this account. Try again later.")); ForceClose(-1); return FALSE; } CStdString peerIP; UINT port = 0; BOOL bResult = GetPeerName(peerIP, port); if (bResult) { if (!user.AccessAllowed(peerIP)) { Send(_T("521 This user is not allowed to connect from this IP")); ForceClose(-1); return FALSE; } } else { SendStatus(_T("Could not get peer name"), 1); Send(_T("421 Refusing connection. Could not get peer name.")); ForceClose(-1); return FALSE; } int count = m_pOwner->GetIpCount(peerIP); if (user.GetIpLimit() && count >= user.GetIpLimit()) { CStdString str; if (count==1) str.Format(_T("Refusing connection. Reason: No more connections allowed from this IP. (%s already connected once)"), peerIP.c_str()); else str.Format(_T("Refusing connection. Reason: No more connections allowed from this IP. (%s already connected %d times)"), peerIP.c_str(), count); SendStatus(str, 1); Send(_T("421 Refusing connection. No more connections allowed from your IP.")); ForceClose(-1); return FALSE; } m_CurrentServerDir = m_pOwner->m_pPermissions->GetHomeDir(m_status.user); if (m_CurrentServerDir == _T("")) { Send(_T("550 Could not get home dir!")); ForceClose(-1); return FALSE; } m_status.ip = peerIP; count = GetUserCount(user.user); if (user.GetUserLimit() && count >= user.GetUserLimit()) { CStdString str; str.Format(_T("Refusing connection. Reason: Maximum connection count (%d) reached for this user"), user.GetUserLimit()); SendStatus(str, 1); str.Format(_T("421 Refusing connection. Maximum connection count reached for the user '%s'"), user.user); Send(str); ForceClose(-1); return FALSE; } m_pOwner->IncIpCount(peerIP); IncUserCount(m_status.user); m_status.loggedon = TRUE; GetSystemTime(&m_LastTransferTime); m_pOwner->m_pPermissions->AutoCreateDirs(m_status.user); t_connectiondata_changeuser *conndata = new t_connectiondata_changeuser; t_connop *op = new t_connop; op->data = conndata; op->op = USERCONTROL_CONNOP_CHANGEUSER; op->userid = m_userid; conndata->user = m_status.user; m_pOwner->SendNotification(FSM_CONNECTIONDATA, (LPARAM)op); return TRUE; } void CControlSocket::Continue() { if (m_SlQuotas[download].bContinue) { TriggerEvent(FD_WRITE); if (m_transferstatus.socket && m_transferstatus.socket->Started()) m_transferstatus.socket->TriggerEvent(FD_WRITE); m_SlQuotas[download].bContinue = false; } if (m_SlQuotas[upload].bContinue) { TriggerEvent(FD_READ); if (m_transferstatus.socket && m_transferstatus.socket->Started()) m_transferstatus.socket->TriggerEvent(FD_READ); m_SlQuotas[upload].bContinue = false; } } int CControlSocket::GetSpeedLimit(sltype mode) { CUser user; int nLimit = -1; if (m_status.loggedon && m_pOwner->m_pPermissions->GetUser(m_status.user, user)) { nLimit = user.GetCurrentSpeedLimit(mode); } if (nLimit > 0) { nLimit *= 100; if (m_SlQuotas[mode].nTransferred >= nLimit) { m_SlQuotas[mode].bContinue = TRUE; return 0; } else nLimit -= m_SlQuotas[mode].nTransferred; } else nLimit = -1; if (user.BypassServerSpeedLimit(mode)) m_SlQuotas[mode].bBypassed = TRUE; else if (m_SlQuotas[mode].nBytesAllowedToTransfer != -1) { if (nLimit == -1 || nLimit > (m_SlQuotas[mode].nBytesAllowedToTransfer - m_SlQuotas[mode].nTransferred)) nLimit = m_SlQuotas[mode].nBytesAllowedToTransfer - m_SlQuotas[mode].nTransferred; } if (!nLimit) m_SlQuotas[mode].bContinue = TRUE; return nLimit; } BOOL CControlSocket::CreateTransferSocket(CTransferSocket *pTransferSocket) { /* Create socket * First try control connection port - 1, if that fails try * control connection port + 1. If that fails as well, let * the OS decide. */ bool bFallback = false; BOOL bCreated = FALSE; // Fix: Formerly, the data connection would always be opened using the server's default (primary) IP. // This would cause Windows Firewall to freak out if control connection was opened on a secondary IP. // When using Active FTP behind Windows Firewall, no connection could be made. This fix ensures the data // socket is on the same IP as the control socket. CStdString controlIP; UINT controlPort = 0; BOOL bResult = this->GetSockName(controlIP, controlPort); if (bResult) { // Try create control conn. port - 1 if (controlPort > 1) if (pTransferSocket->Create(controlPort - 1, SOCK_STREAM, FD_CONNECT, controlIP, m_transferstatus.family, true)) bCreated = TRUE; } if (!bCreated) { creation_fallback: bFallback = true; // Let the OS find a valid port if (!pTransferSocket->Create(0, SOCK_STREAM, FD_CONNECT, controlIP, m_transferstatus.family, true)) { // Give up Send(_T("421 Can't create socket")); ResetTransferstatus(); return FALSE; } } if (m_pGssLayer && m_pGssLayer->AuthSuccessful()) m_transferstatus.socket->UseGSS(m_pGssLayer); if (pTransferSocket->Connect(m_transferstatus.ip, m_transferstatus.port) == 0) { if (!bFallback && GetLastError() == WSAEADDRINUSE) { pTransferSocket->Close(); goto creation_fallback; } if (GetLastError() != WSAEWOULDBLOCK) { Send(_T("425 Can't open data connection")); ResetTransferstatus(); return FALSE; } } if (m_pSslLayer && m_bProtP) pTransferSocket->UseSSL(m_pSslLayer->GetContext()); return TRUE; } bool CControlSocket::CheckIpForZlib() { CStdString peerIP; UINT port = 0; BOOL bResult = GetPeerName(peerIP, port); if (!bResult) return false; if (!m_pOwner->m_pOptions->GetOptionVal(OPTION_MODEZ_ALLOWLOCAL) && !IsRoutableAddress(peerIP)) return false; CStdString ips = m_pOwner->m_pOptions->GetOption(OPTION_MODEZ_DISALLOWED_IPS); ips += " "; int pos = ips.Find(' '); while (pos != -1) { CStdString blockedIP = ips.Left(pos); ips = ips.Mid(pos + 1); pos = ips.Find(' '); if (MatchesFilter(blockedIP, peerIP)) return false; } return true; } void CControlSocket::AntiHammerIncrease(int amount /*=1*/) { if (m_status.hammerValue < 8000) m_status.hammerValue += amount * 200; if (m_status.hammerValue > 2000) m_antiHammeringWaitTime += 1000 * (int)pow(1.3, (m_status.hammerValue / 400) - 5); } void CControlSocket::SendTransferinfoNotification(const char transfermode, const CStdString& physicalFile, const CStdString& logicalFile, __int64 startOffset, __int64 totalSize) { t_connop *op = new t_connop; op->op = USERCONTROL_CONNOP_TRANSFERINIT; op->userid = m_userid; t_connectiondata_transferinfo *conndata = new t_connectiondata_transferinfo; conndata->transferMode = transfermode; conndata->physicalFile = physicalFile; conndata->logicalFile = logicalFile; conndata->startOffset = startOffset; conndata->totalSize = totalSize; op->data = conndata; m_pOwner->SendNotification(FSM_CONNECTIONDATA, (LPARAM)op); } int CControlSocket::OnLayerCallback(std::list<t_callbackMsg>& callbacks) { for (std::list<t_callbackMsg>::iterator iter = callbacks.begin(); iter != callbacks.end(); iter++) { if (m_pSslLayer && iter->pLayer == m_pSslLayer) { if (iter->nType == LAYERCALLBACK_LAYERSPECIFIC && iter->nParam1 == SSL_INFO && iter->nParam2 == SSL_INFO_ESTABLISHED) SendStatus(_T("SSL connection established"), 0); else if (iter->nType == LAYERCALLBACK_LAYERSPECIFIC && iter->nParam1 == SSL_INFO && iter->nParam2 == SSL_INFO_SHUTDOWNCOMPLETE) { if (m_shutdown) { delete [] iter->str; Close(); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); return 0; } if (!m_bQuitCommand) { delete [] iter->str; continue; } do { delete [] iter->str; iter++; } while (iter != callbacks.end()); ForceClose(5); return 0; } } else if (iter->nType == LAYERCALLBACK_LAYERSPECIFIC && iter->nParam1 == SSL_VERBOSE_WARNING) { if (iter->str) { CStdString str = "SSL warning: "; str += iter->str; SendStatus(str, 1); } } delete [] iter->str; } return 0;//CAsyncSocketEx::OnLayerCallback(pLayer, nType, nParam1, nParam2); } bool CControlSocket::InitImplicitSsl() { m_pSslLayer = new CAsyncSslSocketLayer; int res = AddLayer(m_pSslLayer) ? 1 : 0; if (!res) { delete m_pSslLayer; m_pSslLayer = 0; return false; } CString error; #ifdef _UNICODE res = m_pSslLayer->SetCertKeyFile(ConvToLocal(m_pOwner->m_pOptions->GetOption(OPTION_SSLCERTFILE)), ConvToLocal(m_pOwner->m_pOptions->GetOption(OPTION_SSLKEYFILE)), ConvToLocal(m_pOwner->m_pOptions->GetOption(OPTION_SSLKEYPASS)), &error); #else res = m_pSslLayer->SetCertKeyFile(m_pOwner->m_pOptions->GetOption(OPTION_SSLCERTFILE), m_pOwner->m_pOptions->GetOption(OPTION_SSLKEYFILE), m_pOwner->m_pOptions->GetOption(OPTION_SSLKEYPASS), &error); #endif if (res == SSL_FAILURE_LOADDLLS) SendStatus(_T("Failed to load SSL libraries"), 1); else if (res == SSL_FAILURE_INITSSL) SendStatus(_T("Failed to initialize SSL libraries"), 1); else if (res == SSL_FAILURE_VERIFYCERT) { if (error != _T("")) SendStatus(error, 1); else SendStatus(_T("Failed to set certificate and private key"), 1); } if (res) { RemoveAllLayers(); delete m_pSslLayer; m_pSslLayer = NULL; Send(_T("431 Could not initialize SSL connection"), 1); return false; } int code = m_pSslLayer->InitSSLConnection(false); if (code == SSL_FAILURE_LOADDLLS) SendStatus(_T("Failed to load SSL libraries"), 1); else if (code == SSL_FAILURE_INITSSL) SendStatus(_T("Failed to initialize SSL library"), 1); if (!code) return true; RemoveAllLayers(); delete m_pSslLayer; m_pSslLayer = NULL; Send(_T("431 Could not initialize SSL connection")); //Close socket Close(); SendStatus(_T("disconnected."), 0); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); return false; } bool CControlSocket::CanQuit() { if (m_pSslLayer) return false; return true; } CStdString CControlSocket::GetPassiveIP() { //Get the ip of the control socket CStdString localIP; UINT localPort; BOOL bValidSockAddr = GetSockName(localIP, localPort); //Get peer ip CStdString peerIP; UINT peerPort = 0; BOOL bResult = GetPeerName(peerIP, peerPort); if (bResult) { if (m_pOwner->m_pOptions->GetOptionVal(OPTION_NOEXTERNALIPONLOCAL) && !IsRoutableAddress(peerIP)) { // Remote IP address from an unroutable subnet // Inside a NAT-in-NAT environment, two different unroutable address ranges are used. // If remote address comes from a different unroutable subnet, don't use local // address. // Note that in a NAT-in-NAT environment, the external IP address specified will either // be the worldwide one or the NAT one. Either external or single-NATed users won't be able // to use passive mode. m_transferstatus.usedResolvedIP = false; if (!bValidSockAddr) return _T(""); return localIP; } } if (m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVIPTYPE)) { CStdString pasvIP = m_pOwner->GetExternalIP(localIP); if (pasvIP != _T("") && pasvIP != localIP) { m_transferstatus.usedResolvedIP = true; return pasvIP; } } m_transferstatus.usedResolvedIP = false; if (!bValidSockAddr) return _T(""); return localIP; } void CControlSocket::ParseMlstOpts(CStdString args) { if (args == _T("")) { for (int i = 0; i < 4; i++) m_facts[i] = false; Send(_T("200 MLST OPTS")); return; } if (args[0] != ' ') { Send(_T("501 Invalid MLST options")); return; } args = args.Mid(1); if (args.Find(' ') != -1) { Send(_T("501 Invalid MLST options")); return; } bool facts[4] = {0}; while (args != _T("")) { int pos = args.Find(';'); if (pos < 1) { Send(_T("501 Invalid MLST options")); return; } CStdString fact = args.Left(pos); args = args.Mid(pos + 1); if (fact == _T("TYPE")) facts[fact_type] = true; else if (fact == _T("SIZE")) facts[fact_size] = true; else if (fact == _T("MODIFY")) facts[fact_modify] = true; //else if (fact == _T("PERM")) // facts[fact_perm] = true; } for (int i = 0; i < 4; i++) m_facts[i] = facts[i]; CStdString factstr; if (facts[fact_type]) factstr += _T("type;"); if (facts[fact_size]) factstr += _T("size;"); if (facts[fact_modify]) factstr += _T("modify;"); if (facts[fact_perm]) factstr += _T("perm;"); CStdString result = _T("200 MLST OPTS"); if (factstr != _T("")) result += _T(" ") + factstr; Send(result); } void CControlSocket::ParseHashOpts(CStdString args) { if (args == _T("")) { switch (m_hash_algorithm) { case CHashThread::MD5: Send(_T("200 MD5")); break; case CHashThread::SHA512: Send(_T("200 SHA-512")); break; default: Send(_T("200 SHA-1")); break; } return; } if (args[0] != ' ') { Send(_T("501 Invalid HASH options")); return; } args = args.Mid(1); if (args.Find(' ') != -1) { Send(_T("501 Invalid HASH options")); return; } if (args == _T("SHA-1")) { m_hash_algorithm = CHashThread::SHA1; Send(_T("200 Hash algorithm set to SHA-1")); } else if (args == _T("SHA-512")) { m_hash_algorithm = CHashThread::SHA512; Send(_T("200 Hash algorithm set to SHA-512")); } else if (args == _T("MD5")) { m_hash_algorithm = CHashThread::MD5; Send(_T("200 Hash algorithm set to MD5")); } else Send(_T("501 Unknown algorithm")); } void CControlSocket::ProcessHashResult(int hash_id, int res, CHashThread::_algorithm alg, const CStdString& hash, const CStdString& file) { if (hash_id != m_hash_id) return; m_hash_id = 0; if (res == CHashThread::BUSY) Send(_T("450 Another hash operation is already in progress.")); else if (res == CHashThread::FAILURE_OPEN) Send(_T("550 Failed to open file")); else if (res == CHashThread::FAILURE_READ) Send(_T("550 Could not read from file")); else { CStdString algname; switch (alg) { case CHashThread::SHA1: algname = "SHA-1"; break; case CHashThread::SHA512: algname = "SHA-512"; break; case CHashThread::MD5: algname = "MD5"; break; } Send(_T("213 ") + algname + _T(" ") + hash + _T(" ") + file); } }
Close