Viewing file: AdminSocket.cpp (9.85 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
// 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.
// AdminSocket.cpp: Implementierung der Klasse CAdminSocket.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "AdminSocket.h"
#include "AdminInterface.h"
#include "OptionTypes.h"
#include "misc\md5.h"
#include "iputils.h"
#include "Options.h"
#include "version.h"
#define BUFSIZE 4096
//////////////////////////////////////////////////////////////////////
// Konstruktion/Destruktion
//////////////////////////////////////////////////////////////////////
CAdminSocket::CAdminSocket(CAdminInterface *pAdminInterface)
{
ASSERT(pAdminInterface);
m_pAdminInterface = pAdminInterface;
m_bStillNeedAuth = TRUE;
m_pRecvBuffer = new unsigned char[BUFSIZE];
m_nRecvBufferLen = BUFSIZE;
m_nRecvBufferPos = 0;
SYSTEMTIME sTime;
GetSystemTime(&sTime);
VERIFY(SystemTimeToFileTime(&sTime, &m_LastRecvTime));
}
CAdminSocket::~CAdminSocket()
{
for (std::list<t_data>::iterator iter=m_SendBuffer.begin(); iter!=m_SendBuffer.end(); iter++)
delete [] iter->pData;
delete [] m_pRecvBuffer;
}
BOOL CAdminSocket::Init()
{
char *buffer = new char[100];
char *p = buffer;
strcpy(buffer, "FZS");
p += 3;
*p++ = 0;
*p++ = 4;
memcpy(p, &SERVER_VERSION, 4);
p += 4;
*p++ = 0;
*p++ = 4;
memcpy(p, &PROTOCOL_VERSION, 4);
p+=4;
COptions options;
CStdString pass = options.GetOption(OPTION_ADMINPASS);
CStdString peerAddress;
UINT port = 0;
if (GetPeerName(peerAddress, port) && IsLocalhost(peerAddress) && pass == _T(""))
{
BOOL res = Send(buffer, p-buffer) == p - buffer;
delete [] buffer;
if (!res)
{
Close();
return FALSE;
}
return FinishLogon();
}
else
{
*p++ = 0;
DWORD len = 20;
memcpy(p, &len, 4);
p += 4;
*p++ = 0;
*p++ = 8;
int i;
for (i = 0; i < 8; i++)
{
m_Nonce1[i] = (rand()*256)/(RAND_MAX+1);
*p++ = m_Nonce1[i];
}
*p++ = 0;
*p++ = 8;
for (i = 0; i < 8; i++)
{
m_Nonce2[i] = (rand()*256)/(RAND_MAX+1);
*p++ = m_Nonce2[i];
}
}
int res = Send(buffer, p-buffer) == p-buffer;
delete [] buffer;
return res;
}
BOOL CAdminSocket::SendCommand(int nType, int nID, const void *pData, int nDataLength)
{
if (m_bStillNeedAuth)
return TRUE;
t_data data;
data.pData = new unsigned char[nDataLength + 5];
*data.pData = nType;
*data.pData |= nID << 2;
data.dwOffset = 0;
memcpy(data.pData + 1, &nDataLength, 4);
if (pData)
memcpy(data.pData+5, pData, nDataLength);
data.dwLength = nDataLength + 5;
m_SendBuffer.push_back(data);
do
{
data = m_SendBuffer.front();
m_SendBuffer.pop_front();
int nSent = Send(data.pData + data.dwOffset, data.dwLength - data.dwOffset);
if (!nSent)
return FALSE;
if (nSent == SOCKET_ERROR)
{
if (WSAGetLastError()!=WSAEWOULDBLOCK)
return FALSE;
m_SendBuffer.push_front(data);
return TRUE;
}
if ((unsigned int)nSent < (data.dwLength-data.dwOffset))
{
data.dwOffset += nSent;
m_SendBuffer.push_front(data);
}
else
{
delete [] data.pData;
SYSTEMTIME sTime;
GetSystemTime(&sTime);
VERIFY(SystemTimeToFileTime(&sTime, &m_LastRecvTime));
}
} while (!m_SendBuffer.empty());
return TRUE;
}
void CAdminSocket::OnReceive(int nErrorCode)
{
if (nErrorCode)
{
Close();
m_pAdminInterface->Remove(this);
return;
}
int numread = Receive(m_pRecvBuffer + m_nRecvBufferPos, m_nRecvBufferLen - m_nRecvBufferPos);
if (numread > 0)
{
SYSTEMTIME sTime;
GetSystemTime(&sTime);
VERIFY(SystemTimeToFileTime(&sTime, &m_LastRecvTime));
m_nRecvBufferPos += numread;
if (m_nRecvBufferLen-m_nRecvBufferPos < (BUFSIZE/4))
{
unsigned char *tmp=m_pRecvBuffer;
m_nRecvBufferLen *= 2;
m_pRecvBuffer = new unsigned char[m_nRecvBufferLen];
memcpy(m_pRecvBuffer, tmp, m_nRecvBufferPos);
delete [] tmp;
}
int parseResult;
while ((parseResult = ParseRecvBuffer()) > 0);
if (parseResult == -1)
return;
}
if (numread == 0)
{
if (ParseRecvBuffer() == -1)
return;
Close();
m_pAdminInterface->Remove(this);
return;
}
else if (numread == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
if (ParseRecvBuffer() == -1)
return;
Close();
m_pAdminInterface->Remove(this);
return;
}
}
while (ParseRecvBuffer() > 0);
}
void CAdminSocket::OnSend(int nErrorCode)
{
if (nErrorCode)
{
Close();
m_pAdminInterface->Remove(this);
return;
}
while (!m_SendBuffer.empty())
{
t_data data=m_SendBuffer.front();
m_SendBuffer.pop_front();
int nSent = Send(data.pData+data.dwOffset, data.dwLength-data.dwOffset);
if (!nSent)
{
Close();
m_pAdminInterface->Remove(this);
return;
}
if (nSent == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
Close();
m_pAdminInterface->Remove(this);
}
m_SendBuffer.push_front(data);
return;
}
if ((unsigned int)nSent<(data.dwLength-data.dwOffset))
{
data.dwOffset+=nSent;
m_SendBuffer.push_front(data);
}
else
delete [] data.pData;
}
}
int CAdminSocket::ParseRecvBuffer()
{
if (m_nRecvBufferPos<5)
return 0;
if ((m_pRecvBuffer[0]&0x03) != 0)
{
SendCommand(_T("Protocol error: Unknown command type, closing connection."), 1);
Close();
m_pAdminInterface->Remove(this);
return -1;
}
else
{
DWORD len;
memcpy(&len, m_pRecvBuffer+1, 4);
if (len > 0xFFFFFF)
{
SendCommand(_T("Protocol error: Invalid data length, closing connection."), 1);
Close();
m_pAdminInterface->Remove(this);
return -1;
}
if (m_nRecvBufferPos < len+5)
return 0;
else
{
int nID = (m_pRecvBuffer[0]&0x7C) >> 2;
if (m_bStillNeedAuth)
{
if (nID)
{
SendCommand(_T("Protocol error: Not authenticated, closing connection."), 1);
Close();
m_pAdminInterface->Remove(this);
return -1;
}
if (len != 16)
{
SendCommand(_T("Protocol error: Auth data len invalid, closing connection."), 1);
Close();
m_pAdminInterface->Remove(this);
return -1;
}
MD5 md5;
md5.update(m_Nonce1, 8);
COptions options;
CStdString pass = options.GetOption(OPTION_ADMINPASS);
if (pass.GetLength() < 6)
{
SendCommand(_T("Protocol error: Server misconfigured, admin password not set correctly"), 1);
Close();
m_pAdminInterface->Remove(this);
return -1;
}
char* utf8 = ConvToNetwork(pass);
if (!utf8)
{
SendCommand(_T("Failed to convert password to UTF-8"), 1);
Close();
m_pAdminInterface->Remove(this);
return -1;
}
md5.update((unsigned char *)utf8, strlen(utf8));
delete [] utf8;
md5.update(m_Nonce2, 8);
md5.finalize();
unsigned char *digest = md5.raw_digest();
if (memcmp(m_pRecvBuffer + 5, digest, 16))
{
delete [] digest;
SendCommand(_T("Protocol error: Auth failed, closing connection."), 1);
Close();
m_pAdminInterface->Remove(this);
return -1;
}
delete [] digest;
FinishLogon();
}
else
m_pAdminInterface->ProcessCommand(this, nID, m_pRecvBuffer+5, len);
memmove(m_pRecvBuffer, m_pRecvBuffer+len+5, m_nRecvBufferPos-len-5);
m_nRecvBufferPos-=len+5;
}
}
return 1;
}
BOOL CAdminSocket::SendCommand(LPCTSTR pszCommand, int nTextType)
{
DWORD nDataLength;
const char *utf8 = 0;
if (!pszCommand)
nDataLength = 0;
else
{
utf8 = ConvToNetwork(pszCommand);
nDataLength = strlen(utf8) + 1;
}
t_data data;
data.pData = new unsigned char[nDataLength + 5];
*data.pData = 2;
*data.pData |= 1 << 2;
data.dwOffset = 0;
memcpy(data.pData + 1, &nDataLength, 4);
*(data.pData+5) = nTextType;
if (utf8)
memcpy(reinterpret_cast<char *>(data.pData+6), utf8, nDataLength - 1);
delete [] utf8;
data.dwLength = nDataLength + 5;
m_SendBuffer.push_back(data);
do
{
data = m_SendBuffer.front();
m_SendBuffer.pop_front();
int nSent = Send(data.pData + data.dwOffset, data.dwLength - data.dwOffset);
if (!nSent)
return FALSE;
if (nSent == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
return FALSE;
m_SendBuffer.push_front(data);
return TRUE;
}
if ((unsigned int)nSent < (data.dwLength - data.dwOffset))
{
data.dwOffset += nSent;
m_SendBuffer.push_front(data);
}
else
delete [] data.pData;
} while (!m_SendBuffer.empty());
return TRUE;
}
BOOL CAdminSocket::CheckForTimeout()
{
SYSTEMTIME sTime;
FILETIME fTime;
GetSystemTime(&sTime);
VERIFY(SystemTimeToFileTime(&sTime, &fTime));
_int64 LastRecvTime = ((_int64)m_LastRecvTime.dwHighDateTime << 32) + m_LastRecvTime.dwLowDateTime;
_int64 CurTime = ((_int64)fTime.dwHighDateTime << 32) + fTime.dwLowDateTime;
if ((CurTime - LastRecvTime) > 600000000) // 60 seconds
return TRUE;
return FALSE;
}
BOOL CAdminSocket::FinishLogon()
{
m_bStillNeedAuth = FALSE;
//Logon successful
if (!SendCommand(1, 0, NULL, 0))
return FALSE;
return TRUE;
}
|