IPchkExt.cpp
资源名称:warftpd.zip [点击查看]
上传用户:surprise9
上传日期:2007-01-04
资源大小:426k
文件大小:17k
源码类别:
Ftp客户端
开发平台:
Visual C++
- // IPchkExt.cpp : Defines the initialization routines for the DLL.
- //
- #include "stdafx.h"
- #include "WarDaemon.h"
- #include "IPchkExt.h"
- #include <afxdllx.h>
- #include "resource.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- static AFX_EXTENSION_MODULE IPchkExtDLL = { NULL, NULL };
- int CallOnConnect(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam);
- int CallOnVerifyIPAddress(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam);
- int CallOnBadPassword(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam);
- int CallOnHasLoggedOn(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam);
- int CallOnVerifyLogin(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam);
- int CallOnSocketIsDestroyed(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam);
- ////////////////////////////////////////
- // ADDED: This is required for plugin's
- static CIPchkExt *pMe;
- extern "C" int APIENTRY
- DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
- {
- if (dwReason == DLL_PROCESS_ATTACH)
- {
- TRACE0("IPCHKEXT.DLL Initializing!n");
- // Extension DLL one-time initialization
- AfxInitExtensionModule(IPchkExtDLL, hInstance);
- // Insert this DLL into the resource chain
- new CDynLinkLibrary(IPchkExtDLL);
- pMe = new CIPchkExt;
- if (pMe->Register("IPchkExt") != 0)
- return 0; // Failure
- }
- else if (dwReason == DLL_PROCESS_DETACH)
- {
- TRACE0("IPCHKEXT.DLL Terminating!n");
- ////////////////////////////////////////
- // ADDED: This is required for plugin's
- if (pMe)
- delete pMe;
- }
- return 1; // ok
- }
- // Initialize the extended COptions variables
- void CIPchkExt::InitializeCOptions()
- {
- DeclOpt("Connection delay", m_ConnectionDelay, 1, 1, DATATYPE_INT);
- DeclOpt("Passwd retries", m_MaxPasswdRetries, 3, 2, DATATYPE_INT);
- DeclOpt("Passwd retry delay", m_PasswdRetryDelay, 3, 3, DATATYPE_INT);
- DeclOpt("Hack pswd attmpt", m_MaxPasswdHacks, 9, 4, DATATYPE_INT);
- DeclOpt("Hack delay", m_HackDely, 6, 5, DATATYPE_INT);
- }
- CIPchkExt::CIPchkExt()
- {
- }
- CIPchkExt::~CIPchkExt()
- {
- CIPConnList::KillAll(this);
- }
- int CIPchkSock::OnConnect(int Event, WPARAM wParam, LPARAM lParam)
- {
- CIPConnList *pConn = NULL;
- CString cBuf("- No message -"), cFmt;
- m_SessionBadPwdCnt = 0;
- if (Event)
- return 0; // We don't want to handle socket errors...
- if (!CIPConnList::VerifyConnection(pSock, &pConn))
- {
- if (pSock->IsKindOf(RUNTIME_CLASS(CTextSock)))
- {
- CTextSock *pTextSock = (CTextSock *)pSock;
- if (pConn->m_IsHacker)
- {
- cBuf.LoadString(IDS_FUCKHACKERS);
- }
- else
- {
- cFmt.LoadString(IDS_TIMEOUTACTIVE);
- DWORD TimeLeft = pConn->m_Suspend.TimeLeft(pConn->m_SuspendVal);
- TimeLeft /= (1000 * 60);
- if (!TimeLeft)
- TimeLeft = 1;
- cBuf.Format(cFmt, TimeLeft );
- }
- // We need to send the message directly to bypass the framework's
- // processing. (The connection is not yet ready for normal control messages).
- cFmt.Format("421 %srn", cBuf);
- cBuf = cFmt;
- pTextSock->CAsyncSocket::Send(cBuf, cBuf.GetLength());
- }
- pMe->LogMsg(LOGF_SECURITY, "CIPchkSock::OnConnect() Access denied. Told client: %s", cBuf);
- CSocketException::Throw(pSock, "CIPchkSock::OnConnect()", -1, cBuf);
- }
- return 0;
- }
- int CIPchkSock::OnBadPassword(int Event, WPARAM wParam, LPARAM lParam)
- {
- CIPConnList *pConn = NULL;
- CString Name;
- if (pConn = CIPConnList::Find(pSock, Name))
- {
- ++m_SessionBadPwdCnt;
- ++pConn->m_BadPwdCnt;
- if (pConn->m_BadPwdCnt >= pMe->m_MaxPasswdHacks)
- {
- // Hacker!
- pConn->m_IsHacker = TRUE;
- pConn->m_SuspendVal = pMe->m_HackDely * 1000 * 60 * 60;
- pConn->m_ExpiryVal = max(pConn->m_ExpiryVal, pConn->m_SuspendVal);
- pConn->m_BadPwdCnt = 0; // Reset for the next user on this IP, - in a couple of hours...
- // Say gently goodbye...
- ASSERT(pSock->IsKindOf(RUNTIME_CLASS(CTextSock)));
- CTextSock *pTextSock = (CTextSock *)pSock;
- pTextSock->LogMsg(LOGF_SECURITY,"CIPchkSock::OnBadPassword() - HACKER detected. Turning on full protection.");
- pTextSock->SendMsg(530,"Hacking is a very bad habbit... Goodbye.");
- CSocketException::Throw(pSock, "CIPchkSock::OnBadPassword()", -1, "Hacker detected.");
- }
- if (m_SessionBadPwdCnt >= pMe->m_MaxPasswdRetries)
- {
- pConn->m_SuspendVal = pMe->m_PasswdRetryDelay * 1000 * 60;
- pConn->m_ExpiryVal = max(pConn->m_ExpiryVal, pConn->m_SuspendVal);
- // Say gently goodbye...
- ASSERT(pSock->IsKindOf(RUNTIME_CLASS(CTextSock)));
- CTextSock *pTextSock = (CTextSock *)pSock;
- pTextSock->LogMsg(LOGF_SECURITY,"CIPchkSock::OnBadPassword() - Too many bad passwords. Disconnecting user.");
- pTextSock->SendMsg(530,"You better check your login name and password. Goodbye.");
- CSocketException::Throw(pSock, "CIPchkSock::OnBadPassword()", -1, "Too many login attempts");
- }
- }
- return 0;
- }
- int CIPchkSock::OnVerifyLogin(int Event, WPARAM wParam, LPARAM lParam)
- {
- USER *pUser = (USER *)wParam;
- LOGINPRMS *pLP = (LOGINPRMS *)lParam;
- CIPConnList *pConn = NULL;
- CString Name;
- if (CUsr::IsAdmin(*pUser))
- return 0; // Don't mess with admins...
- if (pConn = CIPConnList::Find(pSock, Name))
- {
- // Check IP/Domain shitlist for the user
- if (pConn->IsBanned(*pUser, pSock))
- {
- pLP->Sock->LogMsg(LOGF_SECURITY,"CIPchkSock::OnVerifyLogin() - User %s from %s is shitlisted on IP/domain level. Access is denied.", pLP->UserID, pLP->Sock->m_DNSName);
- pLP->Sock->SendMsg(530,"Your IP address or domain name is shitlisted. Goodbye.");
- CSocketException::Throw(pSock, "CIPchkSock::OnVerifyLogin()", -1, "Shitlisted");
- }
- // Check max logins on the IP for the user account
- int MaxConnections = CUsr::GetRecursiveParam(*pUser, "IP MaxConn", 0);
- if (MaxConnections > 0)
- {
- int Count = 0;
- for(CLinkedListItem *Item = CSock::m_SocketList.First()
- ; Item
- ; Item = CSock::m_SocketList.Next(Item))
- {
- CSock *pSck = (CSock *)CSock::m_SocketList.Ptr(Item);
- if (!pSck->IsKindOf(RUNTIME_CLASS(CTextSock)))
- continue;
- if (pSck->m_PeerName == pConn->m_Name)
- ++Count;
- }
- if (Count > MaxConnections)
- {
- pLP->Sock->LogMsg(LOGF_SECURITY,"CIPchkSock::OnVerifyLogin() - To many connections from IP %s. Access is denied.", pLP->UserID, pConn->m_Name);
- pLP->Sock->SendMsg(530,"Your have exeeded your limit of %d concurrent sessions. Goodbye.", MaxConnections);
- CSocketException::Throw(pSock, "CIPchkSock::OnVerifyLogin()", -1, "To many connections from IP");
- }
- }
- }
- return 0;
- }
- int CIPchkSock::OnHasLoggedOn(int Event, WPARAM wParam, LPARAM lParam)
- {
- CIPConnList *pConn = NULL;
- CString Name;
- if (pConn = CIPConnList::Find(pSock, Name))
- {
- // Reset counters and flags.
- pConn->m_BadPwdCnt = 0;
- pConn->m_SuspendVal = ((DWORD)pMe->m_ConnectionDelay * 1000 * 60);
- pConn->m_IsHacker = FALSE;
- }
- return 0;
- }
- int CIPchkSock::OnVerifyIPAddress(int Event, WPARAM wParam, LPARAM lParam)
- {
- return 0;
- }
- int CallOnConnect(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam)
- {
- return ((CIPchkSock *)Origin)->OnConnect(Event, wParam, lParam);
- }
- int CallOnVerifyIPAddress(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam)
- {
- return ((CIPchkSock *)Origin)->OnVerifyIPAddress(Event, wParam, lParam);
- }
- int CallOnBadPassword(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam)
- {
- return ((CIPchkSock *)Origin)->OnBadPassword(Event, wParam, lParam);
- }
- int CallOnHasLoggedOn(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam)
- {
- return ((CIPchkSock *)Origin)->OnHasLoggedOn(Event, wParam, lParam);
- }
- int CallOnVerifyLogin(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam)
- {
- return ((CIPchkSock *)Origin)->OnVerifyLogin(Event, wParam, lParam);
- }
- // Reqired function if sockets extentions are used
- // Creates a new socket derived
- int CallOnSocketIsDestroyed(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam)
- {
- delete (CIPchkSock *)Origin; // CSocketAPI destructor will delete references
- return 0;
- }
- // Required function
- int CallApiInitInstance(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam)
- {
- return ((CIPchkExt *)Origin)->ApiInitInstance(Event, wParam, lParam);
- }
- // Required function
- int CallApiExitInstance(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam)
- {
- return ((CIPchkExt *)Origin)->ApiExitInstance(Event, wParam, lParam);
- }
- void CIPchkExt::LogMsg(int flag, LPCSTR Format, ...)
- {
- ASSERT(AfxIsValidAddress(this,sizeof(CIPchkExt)));
- ASSERT(m_pLog != NULL);
- ASSERT(AfxIsValidAddress(m_pLog, sizeof(CLog)));
- if (!ShouldLog(m_pLog, flag))
- return;
- {
- CString cBuf;
- ASSERT(AfxIsValidString(Format, FALSE));
- cBuf.Format("(CIPchkExt) %s", Format);
- va_list argList;
- va_start(argList, Format);
- m_pLog->LogMsgV(flag, cBuf, argList);
- va_end(argList);
- }
- }
- // We check _all_ sockets. This to prevent server to server transfers to
- // banned sites.
- int CallOnNewSocket(LPVOID Origin, int Event, WPARAM wParam, LPARAM lParam)
- {
- CSock *pSock = (CSock *)lParam;
- // Create a new CNTFTPConn object and link it to the calls we will use.
- CDllInfo *pDLL = pMe->GetDLLInfo();
- ASSERT(pDLL != NULL);
- if (pDLL == NULL)
- return 0;
- CIPchkSock *pConn = new CIPchkSock;
- pConn->pSock = pSock; // Required
- pSock->m_Funcs[CSock::iOnSocketIsDestroyed].AddLast(pDLL, CSock::iOnSocketIsDestroyed, pConn, CallOnSocketIsDestroyed);
- pSock->m_Funcs[CSock::iOnConnect].AddLast(pDLL, CSock::iOnConnect, pConn, CallOnConnect);
- pSock->m_Funcs[CSock::iOnVerifyIPAddress].AddLast(pDLL, CSock::iOnVerifyIPAddress, pConn, CallOnVerifyIPAddress);
- pSock->m_Funcs[CSock::iOnBadPassword].AddLast(pDLL, CSock::iOnBadPassword, pConn, CallOnBadPassword);
- pSock->m_Funcs[CSock::iOnHasLoggedOn].AddLast(pDLL, CSock::iOnHasLoggedOn, pConn, CallOnHasLoggedOn);
- pSock->m_Funcs[CSock::iOnVerifyLogin].AddLast(pDLL, CSock::iOnVerifyLogin, pConn, CallOnVerifyLogin);
- return 0;
- }
- //////////////////////////////////////////////////////////////////////////////////////////
- // CIPConnList
- CIPConnList::CIPConnList(LPCSTR Name)
- {
- m_Name = Name;
- m_BadPwdCnt = 0;
- m_ExpiryVal = 1000 * 60 * 60; // Remember a connection for 1 hours
- m_SuspendVal = 0;
- m_IsHacker = FALSE;
- }
- CIPConnList::~CIPConnList()
- {
- }
- void CIPConnList::KillAll(CIPchkExt *pExt)
- {
- CIPConnList *pConn;
- while(pConn = (CIPConnList *)pExt->m_History.GetAndDeleteFirst())
- delete pConn;
- }
- // Verify if a connection can be accepted.
- // Called from OnConnect()
- BOOL CIPConnList::VerifyConnection(CSock *pSock, CIPConnList **ppConn)
- {
- CIPConnList *pConn;
- CString Name("");
- BOOL Rval = TRUE;
- if (pConn = Find(pSock, Name))
- {
- if (pConn->m_IsHacker || pSock->IsKindOf(RUNTIME_CLASS(CTextSock)))
- {
- if (!pConn->m_Suspend.TimeOut(pConn->m_SuspendVal))
- {
- Rval = FALSE;
- }
- else
- pConn->m_IsHacker = FALSE; // Only hacker until timeout...
- if (pSock->IsKindOf(RUNTIME_CLASS(CTextSock)))
- {
- // We always reset the timeout periods on CTextSock connection
- // or attempted connections...
- pConn->m_Suspend.Reset();
- pConn->m_Expiry.Reset();
- }
- }
- }
- else
- {
- // Just add the socket
- if (Name.IsEmpty())
- return FALSE; // Find() is supposed to initialize 'Name'
- pConn = new CIPConnList(Name);
- pMe->m_History.AddFirst((LPVOID)pConn);
- }
- ASSERT(pConn != NULL);
- // Set the suspend length.
- if (!pConn->m_IsHacker && !pConn->m_BadPwdCnt)
- {
- pConn->m_SuspendVal = ((DWORD)pMe->m_ConnectionDelay * 1000 * 60);
- }
- // Make sure that the expery val is larger or equal to than the suspend val
- pConn->m_ExpiryVal = max(pConn->m_ExpiryVal, pConn->m_SuspendVal);
- if (ppConn)
- *ppConn = pConn;
- return Rval;
- }
- CIPConnList *CIPConnList::Find(CSock *pSock, CString& Name)
- {
- UINT Dummy;
- if (!pMe)
- return FALSE; // Dll not loaded. Something bad is going on...
- if (!pSock->GetPeerName(Name, Dummy))
- {
- pMe->LogMsg(LOGF_WARNINGS,"CIPConnList::Find() - Can't resolve IP name. Connection refused.");
- return FALSE;
- }
- return Find(Name);
- }
- CIPConnList *CIPConnList::Find(LPCSTR Name)
- {
- if (!pMe)
- return NULL; // Dll not loaded. Something bad is going on...
- for(CLinkedListItem *Item = pMe->m_History.First(); Item;)
- {
- CLinkedListItem *Curr = Item;
- Item = pMe->m_History.Next(Item);
- CIPConnList *pConn = (CIPConnList *)pMe->m_History.Ptr(Curr);
- if (pConn->m_Expiry.TimeOut(pConn->m_ExpiryVal))
- {
- pMe->m_History.DeleteItem(Curr);
- delete pConn;
- continue;
- }
- if (pConn->m_Name == Name)
- return pConn;
- }
- return NULL;
- }
- // Check if a connection is banned.
- // Verification is done on both IP name and DNS name.
- // Exceptions override denials.
- // Scan order: Server, class, group, user
- BOOL CIPConnList::IsBanned(USER User, CSock *pSock)
- {
- USER ParseOrder[5];
- memset(&ParseOrder, 0, sizeof(ParseOrder));
- int Index;
- BOOL Denied = FALSE;
- if (User == INVALID_USER_VALUE)
- {
- // Use the system list only
- ParseOrder[0] = CUsr::FindUser(UT_SYSTEM, "*");
- // Don't do anything if the shitlist is disabled
- if (CUsr::GetRecursiveParam(ParseOrder[0], "Disable IP Shitlist", FALSE) == TRUE)
- return FALSE;
- }
- else
- {
- // Don't do anything if the shitlist is disabled
- if (CUsr::GetRecursiveParam(User, "Disable IP Shitlist", FALSE) == TRUE)
- return FALSE;
- // Full scan
- Index = 0;
- USER Test;
- if ((Test = CUsr::GetUserSystem(User)) != INVALID_USER_VALUE)
- ParseOrder[Index++] = Test;
- if ((Test = CUsr::GetUserClass(User)) != INVALID_USER_VALUE)
- ParseOrder[Index++] = Test;
- if ((Test = CUsr::GetUserGroup(User)) != INVALID_USER_VALUE)
- ParseOrder[Index++] = Test;
- ParseOrder[Index] = User;
- }
- // Check shitlist
- for(Index = 0; ParseOrder[Index]; Index++)
- {
- CString AccessList;
- CUsr::GetParam(ParseOrder[Index], "IP Shitlist", "", AccessList);
- if (!AccessList.IsEmpty())
- {
- TranslateList(AccessList);
- Denied = IPGenericIsIpInList(m_Name, AccessList);
- if (!Denied && (m_Name != pSock->m_DNSName))
- Denied = IPGenericIsIpInList(pSock->m_DNSName, AccessList);
- if (Denied)
- break;
- }
- }
- if (Denied)
- {
- // Check viplist
- for(Index = 0; ParseOrder[Index]; Index++)
- {
- CString AccessList;
- CUsr::GetParam(ParseOrder[Index], "IP Viplist", "", AccessList);
- if (!AccessList.IsEmpty())
- {
- TranslateList(AccessList);
- Denied = (IPGenericIsIpInList(m_Name, AccessList) == FALSE);
- if (Denied && (m_Name != pSock->m_DNSName))
- Denied = (IPGenericIsIpInList(pSock->m_DNSName, AccessList) == FALSE);
- if (!Denied)
- break;
- }
- }
- }
- return Denied;
- }
- /////////////////////////////////////////////////////////////////////////////////////
- // IP mask based pattern matching
- // Parse the rule and return the mask
- BOOL IPVerifyRule(LPCSTR Rule,int **IPmask)
- {
- int Index = 0;
- int FromTo = 0;
- int MyMask[4][2];
- if (!Rule || !*Rule)
- return FALSE;
- // 1.2.3.4
- // *.2.3.4
- // 1-4.200-203.*.4
- // Initialize
- memset(MyMask,0,sizeof(MyMask));
- while(*Rule)
- {
- // Determine token type
- if (*Rule == '*')
- {
- if (MyMask[Index][0])
- return FALSE;
- MyMask[Index][0] = 0;
- MyMask[Index][1] = 255;
- FromTo = 1;
- ++Rule;
- if (*Rule && (*Rule != '.'))
- return FALSE;
- }
- else if (*Rule == ' ')
- {
- ++Rule; // Ignore space
- }
- else if (*Rule == '-')
- {
- if (FromTo)
- return FALSE;
- ++FromTo;
- if (!isdigit(*++Rule))
- return FALSE;
- }
- else if (*Rule == '.')
- {
- if (!FromTo)
- MyMask[Index][1] = MyMask[Index][0];
- FromTo = 0;
- if (!isdigit(*++Rule) && (*Rule != '*'))
- return FALSE;
- if ((MyMask[Index][0] > 255) || (MyMask[Index][1] > 255))
- return FALSE;
- if (++Index == 4)
- return FALSE;
- }
- else
- {
- MyMask[Index][FromTo] *= 10;
- MyMask[Index][FromTo] += *(Rule++) - '0';
- if (*Rule == '*')
- return FALSE;
- }
- }
- if (Index != 3)
- return FALSE;
- if (!FromTo)
- MyMask[Index][1] = MyMask[Index][0];
- if ((MyMask[Index][0] > 255) || (MyMask[Index][1] > 255))
- return FALSE;
- if (IPmask)
- memcpy(IPmask,MyMask,sizeof(MyMask));
- return TRUE;
- }
- BOOL IPGenericIsIpInList(LPCSTR IPaddess,CString &cList)
- {
- int MyMask[4][2];
- int MyIp[4];
- int Index;
- CString Rules = cList;
- char *p = Rules.GetBuffer(1);
- int Match;
- if (!*p)
- return FALSE; // No rule
- if (inet_addr(IPaddess) == INADDR_NONE)
- goto name_lookup;
- memset(MyIp,0,sizeof(MyIp));
- // Parse IPaddess and get the ip address numbers
- if (sscanf(IPaddess,"%d.%d.%d.%d", &MyIp[0], &MyIp[1], &MyIp[2], &MyIp[3]) != 4)
- goto name_lookup;
- for(p = strtok(p,";rn"); p && *p; p = strtok(NULL, ";rn"))
- {
- if (IPVerifyRule(p,(int **)MyMask))
- {
- Match = 0;
- for(Index = 0; Index < 4; Index++)
- {
- if ((MyIp[Index] >= MyMask[Index][0]) && (MyIp[Index] <= MyMask[Index][1]))
- ++Match;
- }
- if (Match == 4)
- return TRUE;
- }
- else
- {
- name_lookup:
- if (PatternMatchesName(p, IPaddess))
- return TRUE;
- }
- }
- return FALSE;
- }
- void TranslateList(CString &Val)
- {
- CString cBuf = Val;
- LPSTR p = cBuf.GetBuffer(1);
- Val = "";
- for(p = strtok(p, ";rn"); p; p = strtok(NULL, ";rn"))
- {
- if (!Val.IsEmpty())
- Val += "rn";
- Val += p;
- }
- }