home *** CD-ROM | disk | FTP | other *** search
Wrap
// 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" #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_status.loggedon = FALSE; m_status.hammerValue = 0; m_transferstatus.socket = NULL; m_transferstatus.ip = ""; m_transferstatus.port = -1; m_transferstatus.pasv = -1; m_transferstatus.rest = 0; m_transferstatus.type = -1; 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; } 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("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 (m_nTelnetSkip == 2) { if (buffer[i]<251 || buffer[i]>254) m_nTelnetSkip--; } m_nTelnetSkip--; } else if (buffer[i] == 255) m_nTelnetSkip = 2; if (m_nTelnetSkip) 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("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 CStdString str; if (m_RecvLineBuffer.empty()) return FALSE; str = m_RecvLineBuffer.front(); m_RecvLineBuffer.pop_front(); //Output command in status window CStdString str2=str; str2.MakeUpper(); //Hide passwords if the server admin wants to. if (str2.Left(5)=="PASS ") { if (m_pOwner->m_pOptions->GetOptionVal(OPTION_LOGSHOWPASS)) SendStatus(str,2); else { str2=str.Left(5); for (int i=0;i<str.GetLength()-5;i++) str2+="*"; SendStatus(str2,2); } } else SendStatus(str,2); //Split command and arguments int pos = str.Find(" "); if (pos!=-1) { command = str.Left(pos); args = str.Mid(pos+1); args.TrimLeft(" "); args.TrimRight(" "); } else command = str; if (command == "") return FALSE; command.MakeUpper(); return TRUE; } void CControlSocket::SendStatus(LPCTSTR status, int type) { t_statusmsg *msg=new t_statusmsg; strcpy(msg->ip, m_RemoteIP); GetLocalTime(&msg->time); if (!m_status.loggedon) { msg->user = new char[16]; strcpy(msg->user, "(not logged in)"); } else { msg->user = new char[strlen(m_status.user)+1]; strcpy(msg->user, m_status.user); } msg->userid=m_userid; msg->type=type; msg->status = new char[strlen(status)+1]; strcpy(msg->status, status); m_pOwner->SendNotification(FSM_STATUSMESSAGE, (LPARAM)msg); } BOOL CControlSocket::Send(LPCTSTR str, bool sendStatus /*=true*/) { char *buffer = new char[strlen(str) + 3]; strcpy(buffer, str); strcat(buffer, "\r\n"); int len = strlen(buffer); if (sendStatus) SendStatus(str, 3); else if (strlen(str) > 3 && str[3] != '-') { char buffer[4]; memcpy(buffer, str, 3); buffer[3] = 0; SendStatus(buffer, 3); } //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 = new char[len]; memcpy(m_pSendBuffer, buffer, len); 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("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("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 typedef struct { int nID; char command[5]; BOOL bHasargs; BOOL bValidBeforeLogon; } t_command; static const t_command commands[]={ COMMAND_USER, "USER", TRUE, TRUE, COMMAND_PASS, "PASS", FALSE, TRUE, COMMAND_QUIT, "QUIT", FALSE, TRUE, COMMAND_CWD, "CWD", TRUE, FALSE, COMMAND_PWD, "PWD", FALSE, FALSE, COMMAND_PORT, "PORT", TRUE, FALSE, COMMAND_PASV, "PASV", FALSE, FALSE, COMMAND_TYPE, "TYPE", TRUE, FALSE, COMMAND_LIST, "LIST", FALSE, FALSE, COMMAND_REST, "REST", TRUE, FALSE, COMMAND_CDUP, "CDUP", FALSE, FALSE, COMMAND_RETR, "RETR", TRUE, FALSE, COMMAND_STOR, "STOR", TRUE, FALSE, COMMAND_SIZE, "SIZE", TRUE, FALSE, COMMAND_DELE, "DELE", TRUE, FALSE, COMMAND_RMD, "RMD", TRUE, FALSE, COMMAND_MKD, "MKD", TRUE, FALSE, COMMAND_RNFR, "RNFR", TRUE, FALSE, COMMAND_RNTO, "RNTO", TRUE, FALSE, COMMAND_ABOR, "ABOR", FALSE, FALSE, COMMAND_SYST, "SYST", FALSE, TRUE, COMMAND_NOOP, "NOOP", FALSE, FALSE, COMMAND_APPE, "APPE", TRUE, FALSE, COMMAND_NLST, "NLST", FALSE, FALSE, COMMAND_MDTM, "MDTM", TRUE, FALSE, COMMAND_XPWD, "XPWD", FALSE, FALSE, COMMAND_XCUP, "XCUP", FALSE, FALSE, COMMAND_XMKD, "XMKD", TRUE, FALSE, COMMAND_XRMD, "XRMD", TRUE, FALSE, COMMAND_NOP, "NOP", FALSE, FALSE, COMMAND_EPSV, "EPSV", FALSE, FALSE, COMMAND_EPRT, "EPRT", TRUE, FALSE, COMMAND_AUTH, "AUTH", TRUE, TRUE, COMMAND_ADAT, "ADAT", TRUE, TRUE, COMMAND_PBSZ, "PBSZ", TRUE, TRUE, COMMAND_PROT, "PROT", TRUE, TRUE, COMMAND_FEAT, "FEAT", FALSE, TRUE, COMMAND_MODE, "MODE", TRUE, FALSE, COMMAND_OPTS, "OPTS", TRUE, FALSE, COMMAND_HELP, "HELP", FALSE, TRUE, COMMAND_ALLO, "ALLO", FALSE, FALSE, COMMAND_MLST, "MLST", FALSE, FALSE, COMMAND_MLSD, "MLSD", FALSE, FALSE }; void CControlSocket::ParseCommand() { if (m_antiHammeringWaitTime) return; //Get command CStdString command, 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=="")) { Send("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("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("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 = ""; } 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("530 Have to use explicit SSL/TLS before logging on."); break; } RenName = ""; args.MakeLower(); m_status.user = args; if (m_pGssLayer && m_pGssLayer->AuthSuccessful()) { char sendme[4096]; int res = m_pGssLayer->ProcessCommand("USER", args, sendme); if (res != -1) { if (DoUserLogin("", true)) Send(sendme); } break; } if (!m_pSslLayer) { CUser user; if (m_pOwner->m_pPermissions->CheckUserLogin(m_status.user, "", user, true) && user.ForceSsl()) { Send("530 SSL required"); break; } } Send("331 Password required for "+args); } break; case COMMAND_PASS: AntiHammerIncrease(); if (m_status.loggedon) Send("503 Bad sequence of commands."); else if (m_pGssLayer && m_pGssLayer->AuthSuccessful()) { char sendme[4096]; int res = m_pGssLayer->ProcessCommand("PASS", m_status.user, args, sendme); if (res != -1) { if (DoUserLogin("", true)) Send(sendme); } } else if (DoUserLogin(args)) Send("230 Logged on"); break; case COMMAND_QUIT: m_bQuitCommand = TRUE; if (!m_transferstatus.socket) { 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; } int res = m_pOwner->m_pPermissions->ChangeCurrentDir(m_status.user, m_CurrentServerDir, args); if (!res) { CStdString str; str.Format("250 CWD successful. \"%s\" is current directory.", m_CurrentServerDir); Send(str); } else if (res & PERMISSION_DENIED) { CStdString str; str.Format("550 CWD failed. \"%s\": Permission denied.", args); Send(str); } else if (res & PERMISSION_INVALIDNAME) { CStdString str; str.Format("550 CWD failed. \"%s\": Filename invalid.", args); Send(str); } else if (res) { CStdString str; str.Format("550 CWD failed. \"%s\": directory not found.", args); Send(str); } } break; case COMMAND_PWD: case COMMAND_XPWD: { CStdString str; str.Format("257 \"%s\" is current directory.", m_CurrentServerDir); Send(str); } break; case COMMAND_PORT: { 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(",","."); while(1) { pos=args.Find(".",pos); if (pos!=-1) count++; else break; pos++; } if (count!=5) { Send("501 Syntax error"); break; } CStdString ip; int port = 0; int i=args.ReverseFind('.'); port=atoi(args.Right(args.GetLength()-(i+1))); //get ls byte of server socket args=args.Left(i); i=args.ReverseFind('.'); port+=256*atoi(args.Right(args.GetLength()-(i+1))); // add ms byte to server socket ip=args.Left(i); int res = inet_addr(ip); 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 += "."; int pos = ip.Find('.'); while (pos != -1) { CStdString tmp; tmp.Format("%d.", atoi(ip.Left(pos))); decIP += tmp; ip = ip.Mid(pos + 1); pos = ip.Find('.'); } ip = decIP.Left(decIP.GetLength() - 1); res = inet_addr(ip); } if (res == INADDR_NONE || port < 1 || port > 65535) { Send("501 Syntax error"); break; } m_transferstatus.ip = ip; m_transferstatus.port = port; m_transferstatus.pasv=0; Send("200 Port command successful"); break; } case COMMAND_PASV: { if (m_transferstatus.socket) { SendTransferinfoNotification(); delete m_transferstatus.socket; } m_transferstatus.socket = new CTransferSocket(this); unsigned int port = 0; CStdString ip; unsigned int retries = 3; if (m_pOwner->m_pOptions->GetOptionVal(OPTION_CUSTOMPASVIPTYPE)) ip = m_pOwner->GetExternalIP(); if (ip == "") { //Get the ip of the control socket SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); BOOL bResult = GetSockName((SOCKADDR*)&sockAddr, &nSockAddrLen); if (bResult) ip = inet_ntoa(sockAddr.sin_addr); } 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("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(new CAsyncSslSocketLayer(), m_pSslLayer->GetContext()); if (!m_transferstatus.socket->Listen()) { delete m_transferstatus.socket; m_transferstatus.socket = NULL; Send("421 Can't create socket"); break; } //Now retrieve the port SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); BOOL bResult = m_transferstatus.socket->GetSockName((SOCKADDR*)&sockAddr, &nSockAddrLen); if (bResult) port = ntohs(sockAddr.sin_port); //Reformat the ip ip.Replace(".",","); //Put the answer together CStdString str; str.Format("227 Entering Passive Mode (%s,%d,%d)",ip,port/256,port%256); Send(str); m_transferstatus.pasv=1; break; } case COMMAND_TYPE: { args.MakeUpper(); if (args[0] != 'I' && args[0] != 'A') { Send("501 Parameters invalid. Must be I for binary and A for ASCII type."); break; } m_transferstatus.type=(args[0]=='I')?0:1; Send(CStdString("200 Type set to ") + (m_transferstatus.type ? "A" : "I")); } break; case COMMAND_LIST: if (m_transferstatus.pasv == -1) { Send("503 Bad sequence of commands."); break; } if (!m_transferstatus.pasv && (m_transferstatus.ip == "" || m_transferstatus.port == -1)) { Send("503 Bad sequence of commands."); break; } if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("550 PROT P required")); break; } else { //Check args, currently only supported argument is the directory which will be listed. CStdString dirToList; args.TrimLeft(" "); args.TrimRight(" "); if (args!="") { BOOL bBreak = FALSE; while (args[0] == '-') //No parameters supported { if (args.GetLength() < 2) { //Dash without param Send("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(" "); } else args = ""; while (params != "") { //Some parameters are not support if (params[0]=='R') { Send("504 Command not implemented for that parameter"); bBreak = TRUE; break; } //Ignore other parameters params=params.Mid(1); } if (args=="") break; } if (bBreak) break; if (args != "") { //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); if (error & PERMISSION_DENIED) { Send("550 Permission denied."); ResetTransferstatus(); break; } else if (error & PERMISSION_INVALIDNAME) { Send("550 Filename invalid."); ResetTransferstatus(); break; } else if (error) { Send("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("550 could not initialize zlib, please use MODE S instead"); ResetTransferstatus(); break; } } if (!CreateTransferSocket(transfersocket)) break; SendTransferinfoNotification(TRANSFERMODE_LIST, physicalDir, logicalDir); Send("150 Opening data channel for directory list."); } else { m_transferstatus.socket->Init(pResult, TRANSFERMODE_LIST); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send("550 could not initialize zlib, please use MODE S instead"); ResetTransferstatus(); break; } } SendTransferinfoNotification(TRANSFERMODE_LIST, physicalDir, logicalDir); m_transferstatus.socket->PasvTransfer(); } } break; case COMMAND_REST: { BOOL error=FALSE; for (int i=0;i<args.GetLength();i++) if (!isdigit(args[i])) error=TRUE; if (error) { Send("501 Bad parameter. Numeric value required"); break; } m_transferstatus.rest=_atoi64(args); CStdString str; str.Format("350 Rest supported. Restarting at %I64d",m_transferstatus.rest); Send(str); } break; case COMMAND_CDUP: case COMMAND_XCUP: { CStdString dir = ".."; int res = m_pOwner->m_pPermissions->ChangeCurrentDir(m_status.user, m_CurrentServerDir, dir); if (!res) { CStdString str; str.Format("200 CDUP successful. \"%s\" is current directory.", m_CurrentServerDir); Send(str); } else if (res & PERMISSION_DENIED) Send("550 CDUP failed, permission denied."); else if (res & PERMISSION_INVALIDNAME) Send("550 CDUP failed, filename invalid."); else if (res) Send("550 CDUP failed, directory not found."); } break; case COMMAND_RETR: { if (m_transferstatus.pasv == -1) { Send("503 Bad sequence of commands."); break; } if (!m_transferstatus.pasv && (m_transferstatus.ip == "" || m_transferstatus.port == -1)) { Send("503 Bad sequence of commands."); break; } if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("550 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("550 Permission denied"); ResetTransferstatus(); } else if (error & PERMISSION_INVALIDNAME) { Send("550 Filename invalid."); ResetTransferstatus(); } else if (error) { Send("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("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("150 Opening data channel for file transfer."); } else { m_transferstatus.socket->Init(physicalFile, TRANSFERMODE_SEND, m_transferstatus.rest); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send("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("503 Bad sequence of commands."); break; } if(!m_transferstatus.pasv && (m_transferstatus.ip=="" || m_transferstatus.port==-1)) { Send("503 Bad sequence of commands."); break; } if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("550 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("550 Permission denied"); ResetTransferstatus(); } else if (error & PERMISSION_INVALIDNAME) { Send("550 Filename invalid."); ResetTransferstatus(); } else if (error) { Send("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("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("150 Opening data channel for file transfer."); } else { m_transferstatus.socket->Init(physicalFile, TRANSFERMODE_RECEIVE, m_transferstatus.rest); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send("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_READ, physicalFile, logicalFile); if (error & PERMISSION_DENIED) Send("550 Permission denied"); else if (error & PERMISSION_INVALIDNAME) Send("550 Filename invalid."); else if (error) Send("550 File not found"); else { CStdString str; _int64 length; if (GetLength64(physicalFile, length)) str.Format("213 %I64d", length); else str = "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("550 Permission denied"); else if (error & PERMISSION_INVALIDNAME) Send("550 Filename invalid."); else if (error) Send("550 File not found"); else { if (!DeleteFile(physicalFile)) Send(_T("450 Internal error deleting 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("550 Permission denied"); else if (error & PERMISSION_INVALIDNAME) Send("550 Filename invalid."); else if (error) Send("550 Directory not found"); else { if (!RemoveDirectory(physicalFile)) { if (GetLastError() == ERROR_DIR_NOT_EMPTY) Send("550 Directory not empty."); else Send("450 Internal error deleting the directory."); } else Send("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("550 Can't create directory. Permission denied"); else if (error & PERMISSION_INVALIDNAME) Send("550 Filename invalid."); else if (error & PERMISSION_DOESALREADYEXIST && (error & PERMISSION_FILENOTDIR)!=PERMISSION_FILENOTDIR) Send("550 Directory already exists"); else if (error & PERMISSION_FILENOTDIR) Send("550 File with same name already exists"); else if (error) Send("550 Directoryname not valid"); else { CStdString str; BOOL res = FALSE; BOOL bReplySent = FALSE; physicalFile += "\\"; while (physicalFile != "") { CStdString piece = physicalFile.Left(physicalFile.Find("\\")+1); if (piece.Right(2) == ".\\") { Send("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("550 Directory already exists"); else Send("450 Internal error creating the directory."); } else Send("257 Directory created successfully"); } } break; case COMMAND_RNFR: { //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } RenName = ""; 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("350 File exists, ready for destination name."); break; } else if (error & PERMISSION_DENIED) Send("550 Permission denied"); else if (error & PERMISSION_INVALIDNAME) Send("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("350 Directory exists, ready for destination name."); } else if (error2 & PERMISSION_DENIED) Send("550 Permission denied"); else if (error2 & PERMISSION_INVALIDNAME) Send("550 Filename invalid."); else Send("550 file/directory not found"); break; } } break; case COMMAND_RNTO: { if (RenName=="") { Send("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 = ""; if (error & PERMISSION_DENIED) Send("550 Permission denied"); else if (error & PERMISSION_INVALIDNAME) Send("550 Filename invalid."); else if (error & PERMISSION_DOESALREADYEXIST && (error & PERMISSION_DIRNOTFILE)!=PERMISSION_DIRNOTFILE) Send("550 file exists"); else if (error) Send("550 Filename invalid"); else { if (!MoveFile(RenName, physicalFile)) Send("450 Internal error renaming the file"); else Send("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 = ""; if (error & PERMISSION_DENIED) Send("550 Permission denied"); else if (error & PERMISSION_INVALIDNAME) Send("550 Filename invalid."); else if (error & PERMISSION_DOESALREADYEXIST && (error & PERMISSION_FILENOTDIR)!=PERMISSION_FILENOTDIR) Send("550 file exists"); else if (error) Send("550 Filename invalid"); else { if (!MoveFile(RenName, physicalFile)) Send("450 Internal error renaming the file"); else Send("250 file renamed successfully"); } } } break; case COMMAND_ABOR: { if (m_transferstatus.socket) { if (m_transferstatus.socket->Started()) Send("426 Connection closed; transfer aborted."); } Send("226 ABOR command successful"); ResetTransferstatus(); break; } case COMMAND_SYST: Send("215 UNIX emulated by FileZilla"); break; case COMMAND_NOOP: case COMMAND_NOP: Send("200 OK"); break; case COMMAND_APPE: { if(m_transferstatus.pasv==-1) { Send("503 Bad sequence of commands."); break; } if(!m_transferstatus.pasv && (m_transferstatus.ip=="" || m_transferstatus.port==-1)) { Send("503 Bad sequence of commands."); break; } if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("550 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("550 Permission denied"); ResetTransferstatus(); } else if (error & PERMISSION_INVALIDNAME) { Send("550 Filename invalid."); ResetTransferstatus(); } else if (error) { Send("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("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("150 Opening data channel for file transfer, restarting at offset %I64d",size); Send(str); } else { m_transferstatus.socket->Init(physicalFile, TRANSFERMODE_RECEIVE, m_transferstatus.rest); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send("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("503 Bad sequence of commands."); break; } if (!m_transferstatus.pasv && (m_transferstatus.ip == "" || m_transferstatus.port == -1)) { Send("503 Bad sequence of commands."); break; } if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("550 PROT P required")); break; } //Much more checks else { //Check args, currently only supported argument is the directory which will be listed. args.TrimLeft(" "); args.TrimRight(" "); if (args!="") { BOOL bBreak=FALSE; while (args[0]=='-') //No parameters supported { if (args.GetLength()<2) { //Dash without param Send("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(" "); } else args=""; while (params!="") { //Some parameters are not support if (params[0]=='R') { Send("504 Command not implemented for that parameter"); bBreak = TRUE; break; } //Ignore other parameters params=params.Mid(1); } if (args=="") break; } if (bBreak) break; if (args != "") { //Unquote args if (!UnquoteArgs(args)) { Send( _T("501 Syntax error") ); break; } } } t_dirlisting *pResult; CStdString physicalDir, logicalDir; int error = m_pOwner->m_pPermissions->GetShortDirectoryListing(m_status.user, m_CurrentServerDir, args, pResult, physicalDir, logicalDir); if (error & PERMISSION_DENIED) { Send("550 Permission denied"); ResetTransferstatus(); } else if (error & PERMISSION_INVALIDNAME) { Send("550 Filename invalid."); ResetTransferstatus(); } else if (error) { Send("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("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("150 Opening data channel for directory list."); } else { m_transferstatus.socket->Init(pResult, TRANSFERMODE_NLST ); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send("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_READ, physicalFile, logicalFile); if (error & PERMISSION_DENIED) Send("550 Permission denied"); else if (error & PERMISSION_INVALIDNAME) Send("550 Filename invalid."); else if (error & 2) Send("550 File not found"); else { CFileStatus64 status; GetStatus64(physicalFile, status); status.m_mtime; CStdString str; SYSTEMTIME time; FileTimeToSystemTime(&status.m_mtime, &time); str.Format("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.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)) { break; } --retries; } if (retries <= 0) { delete m_transferstatus.socket; m_transferstatus.socket=0; Send("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(new CAsyncSslSocketLayer(), m_pSslLayer->GetContext()); if (!m_transferstatus.socket->Listen()) { delete m_transferstatus.socket; m_transferstatus.socket=0; Send("421 Can't create socket"); break; } //Now retrieve the port SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); BOOL bResult = m_transferstatus.socket->GetSockName((SOCKADDR*)&sockAddr, &nSockAddrLen); if (bResult) port = ntohs(sockAddr.sin_port); //Put the answer together CStdString str; str.Format("229 Entering Extended Passive Mode (|||%d|)", port); Send(str); 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("501 Syntax error"); break; } args = args.Mid(1); int pos = args.Find('|'); if (pos < 1 || (pos>=(args.GetLength()-1))) { Send("501 Syntax error"); break; } int protocol = _ttoi(args.Left(pos)); if (protocol != 1) { Send("522 Extended Port Failure - unknown network protocol"); break; } args = args.Mid(pos + 1); pos = args.Find('|'); if (pos < 1 || (pos>=(args.GetLength()-1))) { Send("501 Syntax error"); break; } CStdString ip = args.Left(pos); if (inet_addr(ip) == INADDR_NONE) { Send("501 Syntax error"); break; } args = args.Mid(pos + 1); pos = args.Find('|'); if (pos < 1) { Send("501 Syntax error"); break; } int port = _ttoi(args.Left(pos)); if (port<1 || port>65535) { Send("501 Syntax error"); break; } m_transferstatus.port = port; m_transferstatus.ip = ip; m_transferstatus.pasv=0; Send("200 Port command successful"); break; } case COMMAND_AUTH: { if (m_pGssLayer) { Send("534 Authentication type already set to GSSAPI"); break; } else if (m_pSslLayer) { Send("534 Authentication type already set to SSL"); break; } args.MakeUpper(); if (args == _T("GSSAPI")) { if (!m_pOwner->m_pOptions->GetOptionVal(OPTION_USEGSS)) { Send("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("Unable to init GSS", 1); } if (!res) { RemoveAllLayers(); delete m_pGssLayer; m_pGssLayer = NULL; Send("431 Could not initialize GSSAPI libraries"); break; } Send("334 Using authentication type GSSAPI; ADAT must follow"); } else if (args == _T("SSL") || args == _T("TLS")) { if (!m_pOwner->m_pOptions->GetOptionVal(OPTION_ENABLESSL) || ! m_pOwner->m_pOptions->GetOptionVal(OPTION_ALLOWEXPLICITSSL)) { Send("502 SSL/TLS authentication not allowed"); break; } m_pSslLayer = new CAsyncSslSocketLayer; BOOL res = AddLayer(m_pSslLayer); if (res) { CString error; 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)); if (res == SSL_FAILURE_LOADDLLS) SendStatus("Failed to load SSL libraries", 1); else if (res == SSL_FAILURE_INITSSL) SendStatus("Failed to initialize SSL libraries", 1); else if (res == SSL_FAILURE_VERIFYCERT) { if (error != "") SendStatus(error, 1); else SendStatus("Failed to set certificate and private key", 1); } if (res) { RemoveAllLayers(); delete m_pSslLayer; m_pSslLayer = NULL; Send("431 Could not initialize SSL connection"); break; } } if (res) { int code = m_pSslLayer->InitSSLConnection(false); if (code == SSL_FAILURE_LOADDLLS) SendStatus("Failed to load SSL libraries", 1); else if (code == SSL_FAILURE_INITSSL) SendStatus("Failed to initialize SSL library", 1); res = (code == 0); } if (res) { CStdString reply = "234 Using authentication type " + args + "\r\n"; const int len = reply.GetLength(); SendStatus(reply, 3); res = (m_pSslLayer->SendRaw(reply, len) == len); } if (!res) { RemoveAllLayers(); delete m_pSslLayer; m_pSslLayer = NULL; Send("431 Could not initialize SSL connection"); break; } } else { Send("504 Auth type not supported"); break; } break; } case COMMAND_ADAT: if (m_pGssLayer) { char sendme[4096]; char command1[4096]; char args1[4096]; strcpy(command1, command); strupr(command1); strcpy(args1, args); m_pGssLayer->ProcessCommand(command1, args1, sendme); Send(sendme); } else Send("502 Command not implemented for this authentication type"); break; case COMMAND_PBSZ: if (m_pGssLayer) { char sendme[4096]; char command1[4096]; char args1[4096]; strcpy(command1, command); strupr(command1); strcpy(args1, args); m_pGssLayer->ProcessCommand(command1, args1, sendme); Send(sendme); } else if (m_pSslLayer) Send("200 PBSZ=0"); else Send("502 Command not implemented for this authentication type"); break; case COMMAND_PROT: if (m_pGssLayer) { char sendme[4096]; char command1[4096]; char args1[4096]; strcpy(command1, command); strupr(command1); strcpy(args1, args); m_pGssLayer->ProcessCommand(command1, args1, sendme); Send(sendme); } else if (m_pSslLayer) { args.MakeUpper(); if (args == "C") { Send("200 Protection level set to C"); m_bProtP = false; } else if (args == "P") { Send("200 Protection level set to P"); m_bProtP = true; } else if (args == "S" || args == "E") Send("504 Protection level " + args + " not supported"); else Send("504 Protection level " + args + " not recognized"); } else Send("502 Command not implemented for this authentication type"); break; case COMMAND_FEAT: if (!Send("211-Features:")) break; if (!Send(" MDTM")) break; if (!Send(" REST STREAM")) break; if (!Send(" SIZE")) break; if (m_pOwner->m_pOptions->GetOptionVal(OPTION_MODEZ_USE)) { if (!Send(" MODE Z")) break; } if (!Send(" MLST type*;size*;modify*;")) break; if (!Send("211 End")) break; break; case COMMAND_MODE: if (args == "S" || args == "s") { m_transferMode = mode_stream; Send("200 MODE set to S."); } else if (args == "Z" || args == "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("200 MODE set to Z."); } else Send("504 MODE Z not allowed from your IP"); } else Send("504 MODE Z not enabled"); } else if (args == "C" || args == "c" || args == "B" || args == "b") Send("502 Unimplemented MODE type"); else Send("504 Unknown MODE type"); break; case COMMAND_OPTS: args.MakeUpper(); if (args.Left(13) == "MODE Z LEVEL ") { int level = atoi(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("200 MODE Z LEVEL set to %d", level); Send(str); } else Send("501 can't change MODE Z LEVEL do desired value"); } else Send("501 Option not understood"); break; case COMMAND_HELP: if (args == "") { Send("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 += " "; str += " " + cmd; if (!((i + 1) % 8)) { Send(str); str = ""; } } if (str != "") Send(str); Send("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("214 Command %s is supported by FileZilla Server", args); Send(str); break; } } if (i == (sizeof(commands)/sizeof(t_command))) { CStdString str; str.Format("502 Command %s is not recognized or supported by FileZilla Server", args); Send(str); } } break; case COMMAND_ALLO: Send("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); if (res & PERMISSION_DENIED) { Send("550 Permission denied."); break; } else if (res & PERMISSION_INVALIDNAME) { Send("550 Filename invalid."); break; } else if (res) { Send("550 File or directory not found."); break; } CString str; str.Format("250-Listing %s", logicalName); if (!Send(str)) break; fact = " " + fact; if (!Send(fact)) break; Send("250 End"); } break; case COMMAND_MLSD: if (m_transferstatus.pasv == -1) { Send("503 Bad sequence of commands."); break; } if (!m_transferstatus.pasv && (m_transferstatus.ip == "" || m_transferstatus.port == -1)) Send("503 Bad sequence of commands."); //Much more checks else { if (m_pSslLayer && m_pOwner->m_pOptions->GetOptionVal(OPTION_FORCEPROTP) && !m_bProtP) { Send(_T("550 PROT P required")); break; } if (args != "") { //Unquote args if (!UnquoteArgs(args)) { Send(_T("501 Syntax error")); break; } } t_dirlisting *pResult; CStdString physicalDir, logicalDir; int error = m_pOwner->m_pPermissions->GetFacts(m_status.user, m_CurrentServerDir, args, pResult, physicalDir, logicalDir); if (error & PERMISSION_DENIED) { Send("550 Permission denied"); ResetTransferstatus(); } else if (error & PERMISSION_INVALIDNAME) { Send("550 Filename invalid."); ResetTransferstatus(); } else if (error) { Send("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("550 could not initialize zlib, please use MODE S instead"); ResetTransferstatus(); break; } } if (!CreateTransferSocket(transfersocket)) break; SendTransferinfoNotification(TRANSFERMODE_LIST, physicalDir, logicalDir); Send("150 Opening data channel for directory list."); } else { m_transferstatus.socket->Init(pResult, TRANSFERMODE_LIST ); if (m_transferMode == mode_zlib) { if (!m_transferstatus.socket->InitZLib(m_zlibLevel)) { Send("550 could not initialize zlib, please use MODE S instead"); ResetTransferstatus(); break; } } SendTransferinfoNotification(TRANSFERMODE_LIST, physicalDir, logicalDir); m_transferstatus.socket->PasvTransfer(); } } } break; default: Send("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_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("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("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("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("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("226 Transfer OK"); } else if (status==1) Send("426 Connection closed; transfer aborted."); else if (status==2) Send("425 Can't open data connection."); else if (status==3) Send("450 can't access file."); else if (status==4) { Send("426 Connection timed out, aborting transfer"); ForceClose(1); return; } else if (status==5) Send("425 Can't open data connection"); else if (status==6) Send("450 zlib error"); if (status>=0 && m_bWaitGoOffline) ForceClose(0); else if (m_bQuitCommand) { Send("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 (!nReason) Send("421 Server is going offline"); else if (nReason==1) Send("421 Connection timed out."); else if (nReason==2) Send("421 No-transfer-time exceeded. Closing control connection."); else if (nReason==3) Send("421 Login time exceeded. Closing control connection."); else if (nReason==4) Send("421 Kicked by Administrator"); else if (nReason==5) { // 221 Goodbye } SendStatus("disconnected.",0); 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 = 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 = ""; 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); if (args.Find('"')!=-1 || args.Left(1)==" " || args.Right(1)==" ") return FALSE; 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("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(const char* password, bool skipPass /*=false*/) { CUser user; if (!m_pOwner->m_pPermissions->CheckUserLogin(m_status.user, password, user, skipPass)) { AntiHammerIncrease(2); SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); BOOL bResult = GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen); if (bResult) m_pOwner->AntiHammerIncrease(sockAddr.sin_addr.s_addr); Send("530 Login or password incorrect!"); return FALSE; } if (!user.IsEnabled()) { Send("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("Refusing connection. Reason: Max. connection count reached.",1); Send("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("Refusing connection. Reason: Max. connection count reached for the user \"%s\".", m_status.user); SendStatus(str,1); Send("421 Too many users logged in for this account. Try again later."); ForceClose(-1); return FALSE; } CStdString ip; unsigned int nPort; SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); BOOL bResult = GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen); if (bResult) { if (!user.AccessAllowed(sockAddr)) { Send("421 This user is not allowed to connect from this IP"); ForceClose(-1); return FALSE; } nPort = ntohs(sockAddr.sin_port); ip = inet_ntoa(sockAddr.sin_addr); } int count = m_pOwner->GetIpCount(ip); if (user.GetIpLimit() && count >= user.GetIpLimit()) { CStdString str; if (count==1) str.Format("Refusing connection. Reason: No more connections allowed from this IP. (%s already connected once)",ip); else str.Format("Refusing connection. Reason: No more connections allowed from this IP. (%s already connected %d times)",ip,count); SendStatus(str, 1); Send("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 == "") { Send("550 Could not get home dir!"); ForceClose(-1); return FALSE; } m_status.ip = ip; count = GetUserCount(user.user); if (user.GetUserLimit() && count >= user.GetUserLimit()) { CStdString str; str.Format("Refusing connection. Reason: Maximum connection count (%d) reached for this user", user.GetUserLimit()); SendStatus(str, 1); str.Format("421 Refusing connection. Maximum connection count reached for the user '%s'", user.user); Send(str); ForceClose(-1); return FALSE; } m_pOwner->IncIpCount(ip); 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 bCreated = FALSE; // Get local port SOCKADDR_IN sockAddr; int nSockAddrLen = sizeof(sockAddr); memset(&sockAddr, 0, sizeof(sockAddr)); // 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; BOOL bResult = this->GetSockName((SOCKADDR*)&sockAddr, &nSockAddrLen); if (bResult) controlIP = inet_ntoa(sockAddr.sin_addr); if (GetSockName((SOCKADDR *)&sockAddr, &nSockAddrLen)) { int nPort = ntohs(sockAddr.sin_port); // Try create control conn. port - 1 if (nPort > 1) if (pTransferSocket->Create(nPort - 1, SOCK_STREAM, FD_CONNECT, controlIP)) bCreated = TRUE; // Try create control conn. port + 1 if necessary if (!bCreated && nPort < 65535) if (pTransferSocket->Create(nPort + 1, SOCK_STREAM, FD_CONNECT, controlIP)) bCreated = TRUE; } if (!bCreated) { // Let the OS find a valid port if (!pTransferSocket->Create(0, SOCK_STREAM, FD_CONNECT, controlIP)) { // Give up Send("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 (GetLastError() != WSAEWOULDBLOCK) { Send("425 Can't open data connection"); ResetTransferstatus(); return FALSE; } } if (m_pSslLayer && m_bProtP) pTransferSocket->UseSSL(new CAsyncSslSocketLayer(), m_pSslLayer->GetContext()); return TRUE; } bool CControlSocket::CheckIpForZlib() { SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); BOOL bResult = GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen); if (!bResult) return true; unsigned int ip = htonl(sockAddr.sin_addr.s_addr); const char *pIp = inet_ntoa(sockAddr.sin_addr); if (!m_pOwner->m_pOptions->GetOptionVal(OPTION_MODEZ_ALLOWLOCAL)) { if (ip >= 0x0A000000 && ip <= 0x0AFFFFFF) return false; if (ip >= 0xAC100000 && ip <= 0xAC1FFFFF) return false; if (ip >= 0xC0A80000 && ip <= 0xC0A80000) return false; if (ip == 0x7F000001) 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, ip, pIp)) 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_ESTABLISHED) SendStatus("SSL connection established", 0); else if (iter->nType == LAYERCALLBACK_LAYERSPECIFIC && iter->nParam1 == SSL_INFO && iter->nParam2 == SSL_INFO_SHUTDOWNCOMPLETE) { if (!m_bQuitCommand) 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; 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)); if (res == SSL_FAILURE_LOADDLLS) SendStatus("Failed to load SSL libraries", 1); else if (res == SSL_FAILURE_INITSSL) SendStatus("Failed to initialize SSL libraries", 1); else if (res == SSL_FAILURE_VERIFYCERT) { if (error != "") SendStatus(error, 1); else SendStatus("Failed to set certificate and private key", 1); } if (res) { RemoveAllLayers(); delete m_pSslLayer; m_pSslLayer = NULL; Send("431 Could not initialize SSL connection", 1); return false; } int code = m_pSslLayer->InitSSLConnection(false); if (code == SSL_FAILURE_LOADDLLS) SendStatus("Failed to load SSL libraries", 1); else if (code == SSL_FAILURE_INITSSL) SendStatus("Failed to initialize SSL library", 1); if (!code) return true; RemoveAllLayers(); delete m_pSslLayer; m_pSslLayer = NULL; Send("431 Could not initialize SSL connection"); //Close socket Close(); SendStatus("disconnected.", 0); m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid); return false; } bool CControlSocket::CanQuit() { if (m_pSslLayer) return false; return true; }