BOOL CUsersDlgGeneral::SaveUser(t_user & user) { user.nEnabled = m_nEnabled; if (!m_bNeedpass) user.password = _T(""); else if (m_cPass.GetModify() && m_Pass != _T("")) { user.generateSalt(); auto saltedPassword = ConvToNetwork(m_Pass + user.salt); CAsyncSslSocketLayer ssl(0); user.password = ConvFromNetwork(ssl.SHA512(reinterpret_cast<unsigned char const*>(saltedPassword.c_str()), saltedPassword.size()).c_str()); if (user.password.IsEmpty()) { // Something went very wrong, disable user. user.nEnabled = false; } } user.nBypassUserLimit = m_nMaxUsersBypass; user.nUserLimit = _ttoi(m_MaxConnCount); user.nIpLimit = _ttoi(m_IpLimit); if (m_cGroup.GetCurSel()<=0) user.group = _T(""); else m_cGroup.GetLBText(m_cGroup.GetCurSel(), user.group); user.comment = m_Comments; user.forceSsl = m_nForceSsl; return TRUE; }
void CServer::ShowStatus(DWORD eventDateHigh, DWORD eventDateLow, LPCTSTR msg, int nType) { auto utf8 = ConvToNetwork(msg); if (utf8.empty()) return; char *pBuffer = new char[utf8.size() + 1 + 8]; *pBuffer = nType; memcpy(pBuffer + 1, &eventDateHigh, 4); memcpy(pBuffer + 5, &eventDateLow, 4); memcpy(pBuffer + 1 + 8, utf8.c_str(), utf8.size()); if (m_pAdminInterface) m_pAdminInterface->SendCommand(2, 4, pBuffer, utf8.size() + 1 + 8); delete [] pBuffer; //Log string if (m_pFileLogger) { FILETIME fFileTime; SYSTEMTIME sFileTime; fFileTime.dwHighDateTime = eventDateHigh; fFileTime.dwLowDateTime = eventDateLow; if (!FileTimeToSystemTime(&fFileTime, &sFileTime)) { return; } TCHAR text[80]; if (!GetDateFormat( LOCALE_USER_DEFAULT, // locale for which date is to be formatted DATE_SHORTDATE, // flags specifying function options &sFileTime, // date to be formatted 0, // date format string text, // buffer for storing formatted string 80 // size of buffer )) return; CStdString text2 = _T(" "); text2 += text; if (!GetTimeFormat( LOCALE_USER_DEFAULT, // locale for which date is to be formatted TIME_FORCE24HOURFORMAT, // flags specifying function options &sFileTime, // date to be formatted 0, // date format string text, // buffer for storing formatted string 80 // size of buffer )) return; text2 += _T(" "); text2 += text; CStdString str = msg; int pos = str.Find(_T("-")); if (pos!=-1) { str.Insert(pos, text2 + _T(" ")); } m_pFileLogger->Log(str); } }
void COptions::SaveOptions() { USES_CONVERSION; CStdString xmlFileName = GetExecutableDirectory() + _T("FileZilla Server.xml"); char* bufferA = T2A(xmlFileName); if (!bufferA) return; TiXmlDocument document; if (!document.LoadFile(bufferA)) return; TiXmlElement* pRoot = document.FirstChildElement("FileZillaServer"); if (!pRoot) return; TiXmlElement* pSettings; while ((pSettings = pRoot->FirstChildElement("Settings"))) pRoot->RemoveChild(pSettings); pSettings = pRoot->LinkEndChild(new TiXmlElement("Settings"))->ToElement(); for (unsigned int i = 0; i < OPTIONS_NUM; i++) { if (!m_OptionsCache[i].bCached) continue; CStdString valuestr; if (!m_OptionsCache[i].nType) valuestr = m_OptionsCache[i].str; else valuestr.Format( _T("%I64d"), m_OptionsCache[i].value); TiXmlElement* pItem = pSettings->LinkEndChild(new TiXmlElement("Item"))->ToElement(); pItem->SetAttribute("name", ConvToNetwork(m_Options[i].name).c_str()); if (!m_OptionsCache[i].nType) pItem->SetAttribute("type", "string"); else pItem->SetAttribute("type", "numeric"); pItem->LinkEndChild(new TiXmlText(ConvToNetwork(valuestr).c_str())); } SaveSpeedLimits(pSettings); document.SaveFile(bufferA); }
BOOL CFileLogger::Log(LPCTSTR msg) { if (m_hLogFile==INVALID_HANDLE_VALUE) return TRUE; auto utf8 = ConvToNetwork(msg); if (utf8.empty()) return FALSE; DWORD numwritten; if (!WriteFile(m_hLogFile, utf8.c_str(), utf8.size(), &numwritten, 0) || !WriteFile(m_hLogFile, "\r\n", 2, &numwritten, 0)) { CloseHandle(m_hLogFile); m_hLogFile = INVALID_HANDLE_VALUE; return FALSE; } return TRUE; }
BOOL CAdminSocket::SendCommand(LPCTSTR pszCommand, int nTextType) { std::string utf8; if (pszCommand) utf8 = ConvToNetwork(pszCommand); DWORD nDataLength = utf8.size() + 1; t_data data(nDataLength + 5); *data.pData = 2; *data.pData |= 1 << 2; memcpy(&*data.pData + 1, &nDataLength, 4); *(&*data.pData+5) = nTextType; memcpy(reinterpret_cast<char *>(&*data.pData+6), utf8.c_str(), nDataLength - 1); m_SendBuffer.push_back(data); return SendPendingData(); }
BOOL CUsersDlgGeneral::SaveUser(t_user *pUser) { if (!pUser) return FALSE; pUser->nEnabled = m_nEnabled; pUser->password = m_Pass; if (!m_bNeedpass) pUser->password = _T(""); else if (m_cPass.GetModify() && m_Pass != _T("")) { char *tmp = ConvToNetwork(pUser->password); if (!tmp) { tmp = new char[1]; *tmp = 0; } MD5 md5; md5.update((unsigned char *)tmp, strlen(tmp)); delete [] tmp; md5.finalize(); char *res = md5.hex_digest(); CString hash = res; delete [] res; pUser->password = hash; } pUser->nBypassUserLimit = m_nMaxUsersBypass; pUser->nUserLimit = _ttoi(m_MaxConnCount); pUser->nIpLimit = _ttoi(m_IpLimit); if (m_cGroup.GetCurSel()<=0) pUser->group = _T(""); else m_cGroup.GetLBText(m_cGroup.GetCurSel(), pUser->group); pUser->comment = m_Comments; pUser->forceSsl = m_nForceSsl; return TRUE; }
BOOL CFileLogger::Log(LPCTSTR msg) { if (m_hLogFile==INVALID_HANDLE_VALUE) return TRUE; char* utf8 = ConvToNetwork(msg); if (!utf8) return FALSE; DWORD numwritten; if (!WriteFile(m_hLogFile, utf8, strlen(utf8), &numwritten, 0) || !WriteFile(m_hLogFile, "\r\n", 2, &numwritten, 0)) { delete [] utf8; CloseHandle(m_hLogFile); m_hLogFile = INVALID_HANDLE_VALUE; return FALSE; } delete [] utf8; return TRUE; }
void CServer::ShowStatus(LPCTSTR msg, int nType, CAdminSocket* pAdminSocket) { if (!msg) return; auto utf8 = ConvToNetwork(msg); if (utf8.empty()) return; char *pBuffer = new char[utf8.size() + 1]; *pBuffer = nType; memcpy(pBuffer + 1, utf8.c_str(), utf8.size()); if (pAdminSocket) { pAdminSocket->SendCommand(2, 1, pBuffer, utf8.size() + 1); } else if (m_pAdminInterface) m_pAdminInterface->SendCommand(2, 1, pBuffer, utf8.size() + 1); delete [] pBuffer; if (m_pFileLogger) m_pFileLogger->Log(msg); }
BOOL CServer::ProcessCommand(CAdminSocket *pAdminSocket, int nID, unsigned char *pData, int nDataLength) { switch (nID) { case 2: if (!nDataLength) { unsigned char buffer[2]; buffer[0] = m_nServerState / 256; buffer[1] = m_nServerState % 256; pAdminSocket->SendCommand(1, 2, buffer, 2); } else if (nDataLength == 2) { ToggleActive(*pData * 256 + pData[1]); unsigned char buffer[2]; buffer[0] = m_nServerState / 256; buffer[1] = m_nServerState % 256; pAdminSocket->SendCommand(1, 2, buffer, 2); } else pAdminSocket->SendCommand(1, 1, "\001Protocol error: Unexpected data length", strlen("\001Protocol error: Unexpected data length") + 1); break; case 3: if (!nDataLength) { pAdminSocket->SendCommand(1, 1, "\001Protocol error: Unexpected data length", strlen("\001Protocol error: Unexpected data length") + 1); } else if (*pData == USERCONTROL_GETLIST) { int len = 4; std::map<int, t_connectiondata>::iterator iter; for (iter = m_UsersList.begin(); iter != m_UsersList.end(); ++iter) { const t_connectiondata& data = iter->second; auto ip = ConvToNetwork(data.ip); auto user = ConvToNetwork(data.user); len += 4 + ip.size() + 2 + 4 + user.size() + 2 + 1; if (data.transferMode) { auto physicalFile = ConvToNetwork(data.physicalFile); auto logicalFile = ConvToNetwork(data.logicalFile); len += 2 + physicalFile.size() + 2 + logicalFile.size(); if (data.currentOffset != 0) len += 8; if (data.totalSize != -1) len += 8; } } unsigned char *buffer = new unsigned char[len]; buffer[0] = USERCONTROL_GETLIST; buffer[1] = ((m_UsersList.size() / 256) / 256) & 0xff; buffer[2] = (m_UsersList.size() / 256) & 0xff; buffer[3] = m_UsersList.size() % 256; unsigned char *p = buffer + 4; for (iter = m_UsersList.begin(); iter != m_UsersList.end(); ++iter) { const t_connectiondata& data = iter->second; auto ip = ConvToNetwork(data.ip); auto user = ConvToNetwork(data.user); memcpy(p, &data.userid, 4); p += 4; *p++ = (ip.size() / 256) & 0xff; *p++ = ip.size() % 256; memcpy(p, ip.c_str(), ip.size()); p += ip.size(); memcpy(p, &data.port, 4); p += 4; *p++ = (user.size() / 256) & 0xff; *p++ = user.size() % 256; memcpy(p, user.c_str(), user.size()); p += user.size(); *p = data.transferMode; if (data.transferMode) { // Bit 5 and 6 indicate presence of currentOffset and totalSize. if (data.currentOffset != 0) { *p |= 0x20; } if (data.totalSize != -1) { *p |= 0x40; } p++; auto physicalFile = ConvToNetwork(data.physicalFile); *p++ = (physicalFile.size() / 256) & 0xff; *p++ = physicalFile.size() % 256; memcpy(p, physicalFile.c_str(), physicalFile.size()); p += physicalFile.size(); auto logicalFile = ConvToNetwork(data.logicalFile); *p++ = (logicalFile.size() / 256) & 0xff; *p++ = logicalFile.size() % 256; memcpy(p, logicalFile.c_str(), logicalFile.size()); p += logicalFile.size(); if (data.currentOffset != 0) { memcpy(p, &data.currentOffset, 8); p += 8; } if (data.totalSize != -1) { memcpy(p, &data.totalSize, 8); p += 8; } } else { p++; } } m_pAdminInterface->SendCommand(1, 3, buffer, len); delete [] buffer; } else if (*pData == USERCONTROL_KICK || *pData == USERCONTROL_BAN) { if (nDataLength != 5) pAdminSocket->SendCommand(1, 1, "\001Protocol error: Unexpected data length", strlen("\001Protocol error: Unexpected data length")+1); else { int nUserID; memcpy(&nUserID, pData+1, 4); std::map<int, t_connectiondata>::iterator iter = m_UsersList.find(nUserID); if (iter!=m_UsersList.end()) { if (*pData == USERCONTROL_BAN) { // Get the list of IP filter rules. CStdString ips = m_pOptions->GetOption(OPTION_IPFILTER_DISALLOWED); if (ips != _T("")) ips += _T(" "); int pos = ips.Find(' '); while (pos != -1) { CStdString blockedIP = ips.Left(pos); ips = ips.Mid(pos + 1); pos = ips.Find(' '); if (MatchesFilter(blockedIP, iter->second.ip)) break; } if (pos == -1) { ips = m_pOptions->GetOption(OPTION_IPFILTER_DISALLOWED); if (ips != _T("")) ips += _T(" "); ips += iter->second.ip; m_pOptions->SetOption(OPTION_IPFILTER_DISALLOWED, ips); } } t_controlmessage *msg = new t_controlmessage; msg->command = USERCONTROL_KICK; msg->socketid = nUserID; iter->second.pThread->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_CONTROL, (LPARAM)msg); char buffer[2]; buffer[0] = *pData; buffer[1] = 0; pAdminSocket->SendCommand(1, 3, &buffer, 2); } else { char buffer[2]; buffer[0] = USERCONTROL_KICK; buffer[1] = 1; pAdminSocket->SendCommand(1, 3, &buffer, 2); } } } else pAdminSocket->SendCommand(1, 1, "\001Protocol error: Invalid data", strlen("\001Protocol error: Invalid data")+1); break; case 5: if (!nDataLength) { unsigned char *pBuffer = NULL; DWORD nBufferLength = 0; if (m_pOptions && m_pOptions->GetAsCommand(&pBuffer, &nBufferLength)) { pAdminSocket->SendCommand(1, 5, pBuffer, nBufferLength); delete [] pBuffer; } } else if (m_pOptions) { if (nDataLength < 2) pAdminSocket->SendCommand(1, 1, "\001Protocol error: Unexpected data length", strlen("\001Protocol error: Unexpected data length")+1); else { CStdString const listenPorts = m_pOptions->GetOption(OPTION_SERVERPORT); CStdString const listenPortsSsl = m_pOptions->GetOption(OPTION_TLSPORTS); bool const enableSsl = m_pOptions->GetOptionVal(OPTION_ENABLETLS) != 0; CStdString const ipBindings = m_pOptions->GetOption(OPTION_IPBINDINGS); int const nAdminListenPort = (int)m_pOptions->GetOptionVal(OPTION_ADMINPORT); CStdString const adminIpBindings = m_pOptions->GetOption(OPTION_ADMINIPBINDINGS); CStdString peerIP; UINT port = 0; bool bLocal = false; if (!pAdminSocket->GetPeerName(peerIP, port)) return FALSE; else bLocal = IsLocalhost(peerIP); if (!m_pOptions->ParseOptionsCommand(pData, nDataLength, bLocal)) { pAdminSocket->SendCommand(1, 1, "\001Protocol error: Invalid data, could not import settings.", strlen("\001Protocol error: Invalid data, could not import settings.")+1); char buffer = 1; pAdminSocket->SendCommand(1, 5, &buffer, 1); break; } char buffer = 0; pAdminSocket->SendCommand(1, 5, &buffer, 1); unsigned int threadnum = (int)m_pOptions->GetOptionVal(OPTION_THREADNUM); if (m_nServerState & STATE_ONLINE) { if (threadnum > m_ThreadArray.size()) { while (threadnum > m_ThreadArray.size()) { int index = GetNextThreadNotificationID(); CServerThread *pThread = new CServerThread(WM_FILEZILLA_SERVERMSG + index); m_ThreadNotificationIDs[index] = pThread; if (pThread->Create(THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED)) { pThread->ResumeThread(); m_ThreadArray.push_back(pThread); } } CStdString str; str.Format(_T("Number of threads increased to %d."), threadnum); ShowStatus(str, 0); } else if (threadnum < m_ThreadArray.size()) { CStdString str; str.Format(_T("Decreasing number of threads to %d."), threadnum); ShowStatus(str, 0); unsigned int i = 0; std::vector<CServerThread *> newList; for (auto iter = m_ThreadArray.begin(); iter != m_ThreadArray.end(); iter++, i++) { if (i >= threadnum) { (*iter)->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_GOOFFLINE, 2); m_ClosedThreads.push_back(*iter); } else newList.push_back(*iter); } m_ThreadArray.swap(newList); } } if (listenPorts != m_pOptions->GetOption(OPTION_SERVERPORT) || enableSsl != (m_pOptions->GetOptionVal(OPTION_ENABLETLS) != 0) || (m_pOptions->GetOptionVal(OPTION_ENABLETLS) && listenPortsSsl != m_pOptions->GetOption(OPTION_TLSPORTS)) || ipBindings != m_pOptions->GetOption(OPTION_IPBINDINGS)) { if (!m_ListenSocketList.empty()) { ShowStatus(_T("Closing all listening sockets"), 0); for (std::list<CListenSocket*>::iterator listIter = m_ListenSocketList.begin(); listIter != m_ListenSocketList.end(); ++listIter) { (*listIter)->Close(); delete *listIter; } m_ListenSocketList.clear(); if (!CreateListenSocket()) { ShowStatus(_T("Failed to create a listen socket on any of the specified ports. Server is not online!"), 1); m_nServerState &= ~STATE_ONLINE; } else { ShowStatus(_T("Listen socket port changed"), 0); if (!(m_nServerState & STATE_MASK_GOOFFLINE)) m_nServerState |= STATE_ONLINE; } SendState(); } } if (nAdminListenPort != m_pOptions->GetOptionVal(OPTION_ADMINPORT) || adminIpBindings != m_pOptions->GetOption(OPTION_ADMINIPBINDINGS)) { CreateAdminListenSocket(); } VerifyTlsSettings(pAdminSocket); VerifyPassiveModeSettings(pAdminSocket); } } break; case 6: if (!nDataLength) { unsigned char *pBuffer = NULL; DWORD nBufferLength = 0; CPermissions permissions = CPermissions(std::function<void()>()); permissions.GetAsCommand(&pBuffer, &nBufferLength); pAdminSocket->SendCommand(1, 6, pBuffer, nBufferLength); delete [] pBuffer; } else { if (nDataLength < 2) pAdminSocket->SendCommand(1, 1, "\001Protocol error: Unexpected data length", strlen("\001Protocol error: Unexpected data length")+1); else { CPermissions permissions = CPermissions(std::function<void()>()); if (!permissions.ParseUsersCommand(pData, nDataLength)) { pAdminSocket->SendCommand(1, 1, "\001Protocol error: Invalid data, could not import account settings.", strlen("\001Protocol error: Invalid data, could not import account settings.")+1); char buffer = 1; pAdminSocket->SendCommand(1, 6, &buffer, 1); break; } char buffer = 0; pAdminSocket->SendCommand(1, 6, &buffer, 1); } } break; case 8: pAdminSocket->SendCommand(1, 8, NULL, 0); break; default: { CStdStringA str; str.Format("\001Protocol error: Unknown command (%d).", nID); pAdminSocket->SendCommand(1, 1, str.c_str(), str.GetLength()); } break; } return TRUE; }
LRESULT CServer::OnServerMessage(CServerThread* pThread, WPARAM wParam, LPARAM lParam) { if (wParam == FSM_STATUSMESSAGE) { t_statusmsg *msg = reinterpret_cast<t_statusmsg *>(lParam); if (!msg) return 0; CStdString str; FILETIME fFileTime; SystemTimeToFileTime(&msg->time, &fFileTime); str.Format(_T("(%06d)- %s (%s)> %s"), msg->userid, (LPCTSTR)msg->user, (LPCTSTR)msg->ip, (LPCTSTR)msg->status); ShowStatus(fFileTime.dwHighDateTime, fFileTime.dwLowDateTime, str, msg->type); delete [] msg->status; delete [] msg->user; delete msg; } else if (wParam == FSM_CONNECTIONDATA) { t_connop *pConnOp = reinterpret_cast<t_connop*>(lParam); if (!pConnOp) return 0; int len{}; unsigned char *buffer{}; switch (pConnOp->op) { case USERCONTROL_CONNOP_ADD: { t_connectiondata_add* pData = (t_connectiondata_add*)pConnOp->data; t_connectiondata data; data.userid = pConnOp->userid; data.pThread = pThread; _tcsncpy(data.ip, pData->ip, 40); data.port = pData->port; data.transferMode = 0; data.currentOffset = 0; data.totalSize = -1; m_UsersList[pConnOp->userid] = data; auto utf8 = ConvToNetwork(pData->ip); len = 2 + 4 + 2 + utf8.size() + 4; buffer = new unsigned char[len]; buffer[2 + 4] = (utf8.size() / 256) & 0xff; buffer[2 + 4 + 1] = utf8.size() % 256; memcpy(buffer + 2 + 4 + 2, utf8.c_str(), utf8.size()); memcpy(buffer + 2 + 4 + 2 + utf8.size(), &pData->port, 4); delete pData; } break; case USERCONTROL_CONNOP_CHANGEUSER: { t_connectiondata_changeuser* pData = (t_connectiondata_changeuser*)pConnOp->data; m_UsersList[pConnOp->userid].user = pData->user; auto utf8 = ConvToNetwork(pData->user); len = 2 + 4 + 2 + utf8.size(); buffer = new unsigned char[len]; buffer[2 + 4] = (utf8.size() / 256) & 0xff; buffer[2 + 4 + 1] = utf8.size() % 256; memcpy(buffer + 2 + 4 + 2, utf8.c_str(), utf8.size()); delete pData; } break; case USERCONTROL_CONNOP_REMOVE: { std::map<int, t_connectiondata>::iterator iter = m_UsersList.find(pConnOp->userid); if (iter != m_UsersList.end()) m_UsersList.erase(iter); len = 6; buffer = new unsigned char[len]; } break; case USERCONTROL_CONNOP_TRANSFERINIT: { t_connectiondata_transferinfo* pData = (t_connectiondata_transferinfo*)pConnOp->data; t_connectiondata& data = m_UsersList[pConnOp->userid]; data.transferMode = pData->transferMode; data.physicalFile = pData->physicalFile; data.logicalFile = pData->logicalFile; data.currentOffset = pData->startOffset; data.totalSize = pData->totalSize; if (data.transferMode) { auto physicalFile = ConvToNetwork(pData->physicalFile); auto logicalFile = ConvToNetwork(pData->logicalFile); len = 2 + 4 + 1 + 2 + physicalFile.size() + 2 + logicalFile.size(); if (data.currentOffset != 0) len += 8; if (data.totalSize != -1) len += 8; buffer = new unsigned char[len]; unsigned char *p = buffer + 6; *p = data.transferMode; // Bit 5 and 6 indicate presence of currentOffset and totalSize. if (data.currentOffset != 0) *p |= 0x20; if (data.totalSize != -1) *p |= 0x40; p++; *p++ = (physicalFile.size() / 256) & 0xff; *p++ = physicalFile.size() % 256; memcpy(p, physicalFile.c_str(), physicalFile.size()); p += physicalFile.size(); *p++ = (logicalFile.size() / 256) & 0xff; *p++ = logicalFile.size() % 256; memcpy(p, logicalFile.c_str(), logicalFile.size()); p += logicalFile.size(); if (data.currentOffset != 0) { memcpy(p, &data.currentOffset, 8); p += 8; } if (data.totalSize != -1) { memcpy(p, &data.totalSize, 8); p += 8; } } else { len = 2 + 4 + 1; buffer = new unsigned char[len]; buffer[2 + 4] = 0; } delete pData; } break; case USERCONTROL_CONNOP_TRANSFEROFFSETS: { t_connectiondata_transferoffsets* pData = (t_connectiondata_transferoffsets*)pConnOp->data; buffer = pData->pData; len = pData->len; unsigned char* p = buffer + 2; int* userid; __int64* offset; while ((p - buffer + 12) <= len) { userid = (int*)p; offset = (__int64*)(p + 4); t_connectiondata& data = m_UsersList[*userid]; data.currentOffset = *offset; p += 12; } delete pData; } break; default: delete pConnOp; return 0; } buffer[0] = USERCONTROL_CONNOP; buffer[1] = pConnOp->op; if (pConnOp->op != USERCONTROL_CONNOP_TRANSFEROFFSETS) memcpy(buffer + 2, &pConnOp->userid, 4); m_pAdminInterface->SendCommand(2, 3, buffer, len); delete [] buffer; delete pConnOp; } else if (wParam == FSM_THREADCANQUIT) { for (auto iter = m_ThreadArray.begin(); iter != m_ThreadArray.end(); ++iter) { if (*iter == pThread) { HANDLE handle = pThread->m_hThread; pThread->PostThreadMessage(WM_QUIT, 0, 0); int res = WaitForSingleObject(handle, INFINITE); if (res == WAIT_FAILED) res = GetLastError(); m_ThreadArray.erase(iter); FreeThreadNotificationID(pThread); if (!m_ThreadArray.size() && !m_ClosedThreads.size()) { m_nServerState &= ~(STATE_ONLINE | STATE_MASK_GOOFFLINE); SendState(); if (!m_bQuit) ShowStatus(_T("Server offline."), 1); else { hMainWnd = 0; DestroyWindow(m_hWnd); m_hWnd = 0; } } return -1; } } for (auto iter = m_ClosedThreads.begin(); iter != m_ClosedThreads.end(); ++iter) { if (*iter == pThread) { HANDLE handle = pThread->m_hThread; pThread->PostThreadMessage(WM_QUIT, 0, 0); int res = WaitForSingleObject(handle, INFINITE); if (res == WAIT_FAILED) res = GetLastError(); m_ClosedThreads.erase(iter); FreeThreadNotificationID(pThread); if (!m_ThreadArray.size() && !m_ClosedThreads.size()) { m_nServerState &= ~(STATE_ONLINE | STATE_MASK_GOOFFLINE); SendState(); if (!m_bQuit) ShowStatus(_T("Server offline."), 1); else { hMainWnd = 0; DestroyWindow(m_hWnd); m_hWnd = 0; } } return -1; } } } else if (wParam == FSM_SEND) { char buffer[5]; buffer[0] = 1; memcpy(buffer+1, &lParam, 4); m_pAdminInterface->SendCommand(2, 7, buffer, 5); m_nSendCount += lParam; } else if (wParam == FSM_RECV) { char buffer[5]; buffer[0] = 0; memcpy(buffer+1, &lParam, 4); m_pAdminInterface->SendCommand(2, 7, buffer, 5); m_nRecvCount += lParam; } return 0; }
BOOL COptions::GetAsCommand(char **pBuffer, DWORD *nBufferLength) { int i; DWORD len = 2; simple_lock lock(m_mutex); for (i=0; i<OPTIONS_NUM; ++i) { len+=1; if (!m_Options[i].nType) { len += 3; auto utf8 = ConvToNetwork(GetOption(i + 1)); if ((i + 1) != OPTION_ADMINPASS) len += utf8.size(); else { if (GetOption(i+1).GetLength() < 6 && utf8.size() > 0) len++; } } else len += 8; } len += 4; SPEEDLIMITSLIST::const_iterator iter; for (i = 0; i < 2; i++) for (iter = m_sSpeedLimits[i].begin(); iter != m_sSpeedLimits[i].end(); iter++) len += iter->GetRequiredBufferLen(); *pBuffer=new char[len]; char *p=*pBuffer; *p++ = OPTIONS_NUM / 256; *p++ = OPTIONS_NUM % 256; for (i=0; i<OPTIONS_NUM; ++i) { *p++ = m_Options[i].nType; switch(m_Options[i].nType) { case 0: { CStdString str = GetOption(i+1); if ((i+1)==OPTION_ADMINPASS) //Do NOT send admin password, //instead send empty string if admin pass is set //and send a single char if admin pass is invalid (len < 6) { if (str.GetLength() >= 6 || str == _T("")) str = _T(""); else str = _T("*"); } auto utf8 = ConvToNetwork(str); int len = utf8.size(); *p++ = (len / 256) / 256; *p++ = (len / 256) % 256; *p++ = len % 256; memcpy(p, utf8.c_str(), len); p += len; } break; case 1: { _int64 value = GetOptionVal(i+1); memcpy(p, &value, 8); p+=8; } break; default: ASSERT(FALSE); } } for (i = 0; i < 2; ++i) { *p++ = m_sSpeedLimits[i].size() >> 8; *p++ = m_sSpeedLimits[i].size() % 256; for (iter = m_sSpeedLimits[i].begin(); iter != m_sSpeedLimits[i].end(); iter++) p = iter->FillBuffer(p); } *nBufferLength = len; return TRUE; }
void COptions::SetOption(int nOptionID, LPCTSTR value, bool save /*=true*/) { CStdString str = value; Init(); switch (nOptionID) { case OPTION_SERVERPORT: case OPTION_TLSPORTS: { std::set<int> portSet; str.TrimLeft(_T(" ,")); int pos = str.FindOneOf(_T(" ,")); while (pos != -1) { int port = _ttoi(str.Left(pos)); if (port >= 1 && port <= 65535) portSet.insert(port); str = str.Mid(pos + 1); str.TrimLeft(_T(" ,")); pos = str.FindOneOf(_T(" ,")); } if (str != _T("")) { int port = _ttoi(str); if (port >= 1 && port <= 65535) portSet.insert(port); } str = _T(""); for (std::set<int>::const_iterator iter = portSet.begin(); iter != portSet.end(); iter++) { CStdString tmp; tmp.Format(_T("%d "), *iter); str += tmp; } str.TrimRight(' '); } break; case OPTION_WELCOMEMESSAGE: { std::vector<CStdString> msgLines; int oldpos = 0; str.Replace(_T("\r\n"), _T("\n")); int pos = str.Find(_T("\n")); CStdString line; while (pos != -1) { if (pos) { line = str.Mid(oldpos, pos - oldpos); line = line.Left(CONST_WELCOMEMESSAGE_LINESIZE); line.TrimRight(_T(" ")); if (msgLines.size() || line != _T("")) msgLines.push_back(line); } oldpos = pos + 1; pos = str.Find(_T("\n"), oldpos); } line = str.Mid(oldpos); if (line != _T("")) { line = line.Left(CONST_WELCOMEMESSAGE_LINESIZE); msgLines.push_back(line); } str = _T(""); for (unsigned int i = 0; i < msgLines.size(); i++) str += msgLines[i] + _T("\r\n"); str.TrimRight(_T("\r\n")); if (str == _T("")) { str = _T("%v"); str += _T("\r\nwritten by Tim Kosse ([email protected])"); str += _T("\r\nPlease visit https://filezilla-project.org/"); } } break; case OPTION_ADMINIPBINDINGS: { CStdString sub; std::list<CStdString> ipBindList; for (unsigned int i = 0; i<_tcslen(value); i++) { TCHAR cur = value[i]; if ((cur < '0' || cur > '9') && cur != '.' && cur != ':') { if (sub == _T("") && cur == '*') { ipBindList.clear(); ipBindList.push_back(_T("*")); break; } if (sub != _T("")) { if (IsIpAddress(sub)) ipBindList.push_back(sub); sub = _T(""); } } else sub += cur; } if (sub != _T("")) { if (IsIpAddress(sub)) ipBindList.push_back(sub); } str = _T(""); for (std::list<CStdString>::iterator iter = ipBindList.begin(); iter!=ipBindList.end(); iter++) if (!IsLocalhost(*iter)) str += *iter + _T(" "); str.TrimRight(_T(" ")); } break; case OPTION_ADMINPASS: if (str != _T("") && str.GetLength() < 6) return; break; case OPTION_MODEZ_DISALLOWED_IPS: case OPTION_IPFILTER_ALLOWED: case OPTION_IPFILTER_DISALLOWED: case OPTION_ADMINIPADDRESSES: { str.Replace('\r', ' '); str.Replace('\n', ' '); str.Replace('\r', ' '); while (str.Replace(_T(" "), _T(" "))); str += _T(" "); CStdString ips; int pos = str.Find(' '); while (pos != -1) { CStdString sub = str.Left(pos); str = str.Mid(pos + 1); str.TrimLeft(' '); if (sub == _T("*")) ips += _T(" ") + sub; else { if (IsValidAddressFilter(sub)) ips += " " + sub; pos = str.Find(' '); } } ips.TrimLeft(' '); str = ips; } break; case OPTION_IPBINDINGS: { std::list<CStdString> ipBindList; str += _T(" "); while (!str.empty()) { int pos = str.Find(' '); if (pos < 0) { break; } CStdString sub = str.Left(pos); str = str.Mid(pos + 1); if (sub == _T("*")) { ipBindList.clear(); ipBindList.push_back(_T("*")); break; } else if (IsIpAddress(sub, true)) { ipBindList.push_back(sub); } } if (ipBindList.empty()) ipBindList.push_back(_T("*")); str.clear(); for (auto const& ip : ipBindList) { str += ip + _T(" "); } str.TrimRight(_T(" ")); } break; case OPTION_CUSTOMPASVIPSERVER: if (str.Find(_T("filezilla.sourceforge.net")) != -1) str = _T("http://ip.filezilla-project.org/ip.php"); break; } { simple_lock lock(m_mutex); m_sOptionsCache[nOptionID-1].bCached = TRUE; m_sOptionsCache[nOptionID-1].nType = 0; m_sOptionsCache[nOptionID-1].str = str; m_OptionsCache[nOptionID-1]=m_sOptionsCache[nOptionID-1]; } if (!save) return; USES_CONVERSION; CStdString xmlFileName = GetExecutableDirectory() + _T("FileZilla Server.xml"); char* bufferA = T2A(xmlFileName); if (!bufferA) return; TiXmlDocument document; if (!document.LoadFile(bufferA)) return; TiXmlElement* pRoot = document.FirstChildElement("FileZillaServer"); if (!pRoot) return; TiXmlElement* pSettings = pRoot->FirstChildElement("Settings"); if (!pSettings) pSettings = pRoot->LinkEndChild(new TiXmlElement("Settings"))->ToElement(); TiXmlElement* pItem; for (pItem = pSettings->FirstChildElement("Item"); pItem; pItem = pItem->NextSiblingElement("Item")) { const char* pName = pItem->Attribute("name"); if (!pName) continue; CStdString name(pName); if (name != m_Options[nOptionID-1].name) continue; break; } if (!pItem) pItem = pSettings->LinkEndChild(new TiXmlElement("Item"))->ToElement(); pItem->Clear(); pItem->SetAttribute("name", ConvToNetwork(m_Options[nOptionID - 1].name).c_str()); pItem->SetAttribute("type", "string"); pItem->LinkEndChild(new TiXmlText(ConvToNetwork(value).c_str())); document.SaveFile(bufferA); }
void COptions::SetOption(int nOptionID, _int64 value, bool save /*=true*/) { switch (nOptionID) { case OPTION_MAXUSERS: if (value < 0) value = 0; break; case OPTION_THREADNUM: if (value < 1) value = 2; else if (value > 50) value = 2; break; case OPTION_TIMEOUT: if (value < 0) value = 120; else if (value > 9999) value = 120; break; case OPTION_NOTRANSFERTIMEOUT: if (value < 600 && value != 0) value = 600; else if (value > 9999) value = 600; break; case OPTION_LOGINTIMEOUT: if (value < 0) value = 60; else if (value > 9999) value = 60; break; case OPTION_ADMINPORT: if (value > 65535) value = 14147; else if (value < 1) value = 14147; break; case OPTION_LOGTYPE: if (value != 0 && value != 1) value = 0; break; case OPTION_LOGLIMITSIZE: if ((value > 999999 || value < 10) && value != 0) value = 100; break; case OPTION_LOGDELETETIME: if (value > 999 || value < 0) value = 14; break; case OPTION_DOWNLOADSPEEDLIMITTYPE: case OPTION_UPLOADSPEEDLIMITTYPE: if (value < 0 || value > 2) value = 0; break; case OPTION_DOWNLOADSPEEDLIMIT: case OPTION_UPLOADSPEEDLIMIT: if (value < 1) value = 1; else if (value > 1048576) value = 1048576; break; case OPTION_BUFFERSIZE: if (value < 256 || value > (1024*1024)) value = 32768; break; case OPTION_BUFFERSIZE2: if (value < 256 || value > (1024*1024*128)) value = 262144; break; case OPTION_CUSTOMPASVIPTYPE: if (value < 0 || value > 2) value = 0; break; case OPTION_MODEZ_USE: if (value < 0 || value > 1) value = 0; break; case OPTION_MODEZ_LEVELMIN: if (value < 0 || value > 8) value = 1; break; case OPTION_MODEZ_LEVELMAX: if (value < 8 || value > 9) value = 9; break; case OPTION_MODEZ_ALLOWLOCAL: if (value < 0 || value > 1) value = 0; break; case OPTION_AUTOBAN_ATTEMPTS: if (value < OPTION_AUTOBAN_ATTEMPTS_MIN) value = OPTION_AUTOBAN_ATTEMPTS_MIN; if (value > OPTION_AUTOBAN_ATTEMPTS_MAX) value = OPTION_AUTOBAN_ATTEMPTS_MAX; break; case OPTION_AUTOBAN_BANTIME: if (value < 1) value = 1; if (value > 999) value = 999; break; } Init(); { simple_lock lock(m_mutex); m_sOptionsCache[nOptionID-1].nType = 1; m_sOptionsCache[nOptionID-1].value = value; m_sOptionsCache[nOptionID-1].bCached = TRUE; m_OptionsCache[nOptionID-1] = m_sOptionsCache[nOptionID - 1]; } if (!save) return; CStdString valuestr; valuestr.Format( _T("%I64d"), value); USES_CONVERSION; CStdString xmlFileName = GetExecutableDirectory() + _T("FileZilla Server.xml"); char* bufferA = T2A(xmlFileName); if (!bufferA) return; TiXmlDocument document; if (!document.LoadFile(bufferA)) return; TiXmlElement* pRoot = document.FirstChildElement("FileZillaServer"); if (!pRoot) return; TiXmlElement* pSettings = pRoot->FirstChildElement("Settings"); if (!pSettings) pSettings = pRoot->LinkEndChild(new TiXmlElement("Settings"))->ToElement(); TiXmlElement* pItem; for (pItem = pSettings->FirstChildElement("Item"); pItem; pItem = pItem->NextSiblingElement("Item")) { const char* pName = pItem->Attribute("name"); if (!pName) continue; CStdString name(pName); if (name != m_Options[nOptionID-1].name) continue; break; } if (!pItem) pItem = pSettings->LinkEndChild(new TiXmlElement("Item"))->ToElement(); pItem->Clear(); pItem->SetAttribute("name", ConvToNetwork(m_Options[nOptionID-1].name).c_str()); pItem->SetAttribute("type", "numeric"); pItem->LinkEndChild(new TiXmlText(ConvToNetwork(valuestr).c_str())); document.SaveFile(bufferA); }
static void SetText(TiXmlElement* pElement, const CStdString& text) { pElement->Clear(); pElement->LinkEndChild(new TiXmlText(ConvToNetwork(text).c_str())); }
bool COptionsDlg::GetAsCommand(unsigned char **pBuffer, DWORD *nBufferLength) { DWORD len = 2; int i; for (i = 0; i < OPTIONS_NUM; ++i) { ++len; if (!m_Options[i].nType) { int strlen = ConvToNetwork(GetOption(i + 1)).size(); if (strlen > 0xFFFFFF) return false; len += strlen; len += 3; } else len += 8; } len += 4; //Number of rules if (m_pOptionsSpeedLimitPage->m_DownloadSpeedLimits.size() > 0xffff || m_pOptionsSpeedLimitPage->m_UploadSpeedLimits.size() > 0xffff) { return false; } for (auto const& limit : m_pOptionsSpeedLimitPage->m_DownloadSpeedLimits) { len += limit.GetRequiredBufferLen(); } for (auto const& limit : m_pOptionsSpeedLimitPage->m_UploadSpeedLimits) { len += limit.GetRequiredBufferLen(); } *pBuffer = new unsigned char[len]; unsigned char *p = *pBuffer; *p++ = OPTIONS_NUM / 256; *p++ = OPTIONS_NUM % 256; for (i = 0; i < OPTIONS_NUM; ++i) { *p++ = m_Options[i].nType; switch (m_Options[i].nType) { case 0: { auto utf8 = ConvToNetwork(GetOption(i + 1)); int slen = utf8.size(); *p++ = ((slen / 256) / 256) & 0xffu; *p++ = (slen / 256) & 0xffu; *p++ = slen % 256; memcpy(p, utf8.c_str(), slen); p += slen; } break; case 1: { _int64 value = GetOptionVal(i+1); memcpy(p, &value, 8); p+=8; } break; default: return false; } } *p++ = (m_pOptionsSpeedLimitPage->m_DownloadSpeedLimits.size() >> 8) & 0xffu; *p++ = m_pOptionsSpeedLimitPage->m_DownloadSpeedLimits.size() % 256; for (auto const& limit : m_pOptionsSpeedLimitPage->m_DownloadSpeedLimits) { p = limit.FillBuffer(p); } *p++ = (m_pOptionsSpeedLimitPage->m_UploadSpeedLimits.size() >> 8) & 0xffu; *p++ = m_pOptionsSpeedLimitPage->m_UploadSpeedLimits.size() % 256; for (auto const& limit : m_pOptionsSpeedLimitPage->m_UploadSpeedLimits) { p = limit.FillBuffer(p); } *nBufferLength = len; return true; }
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; } auto utf8 = ConvToNetwork(pass); if (utf8.empty() && !pass.empty()) { SendCommand(_T("Failed to convert password to UTF-8"), 1); Close(); m_pAdminInterface->Remove(this); return -1; } md5.update((unsigned char *)utf8.c_str(), utf8.size()); 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; }