Пример #1
0
bool CClient::xProcessClientSetup( CEvent * pEvent, size_t iLen )
{
	ADDTOCALLSTACK("CClient::xProcessClientSetup");
	// If this is a login then try to process the data and figure out what client it is.
	// try to figure out which client version we are talking to.
	// (CEvent::ServersReq) or (CEvent::CharListReq)
	// NOTE: Anything else we get at this point is tossed !
	ASSERT( GetConnectType() == CONNECT_CRYPT );
	ASSERT( !m_Crypt.IsInit());
	ASSERT( pEvent != NULL );
	ASSERT( iLen > 0 );

	// Try all client versions on the msg.
	CEvent bincopy;		// in buffer. (from client)
	ASSERT( iLen <= sizeof(bincopy));
	memcpy( bincopy.m_Raw, pEvent->m_Raw, iLen );

	if ( !m_Crypt.Init( m_net->m_seed, bincopy.m_Raw, iLen, GetNetState()->isClientKR() ) )
	{
		DEBUG_MSG(( "%x:Odd login message length %" PRIuSIZE_T "?\n", GetSocketID(), iLen ));
#ifdef _DEBUG
		xRecordPacketData(this, (const byte *)pEvent, iLen, "client->server");
#endif
		addLoginErr( PacketLoginError::BadEncLength );
		return false;
	}
	
	GetNetState()->detectAsyncMode();
	SetConnectType( m_Crypt.GetConnectType() );

	if ( !xCanEncLogin() )
	{
		addLoginErr((uchar)((m_Crypt.GetEncryptionType() == ENC_NONE? PacketLoginError::EncNoCrypt : PacketLoginError::EncCrypt) ));
		return false;
	}
	else if ( m_Crypt.GetConnectType() == CONNECT_LOGIN && !xCanEncLogin(true) )
	{
		addLoginErr( PacketLoginError::BadVersion );
		return false;
	}
	
	byte lErr = PacketLoginError::EncUnknown;
	
	m_Crypt.Decrypt( pEvent->m_Raw, bincopy.m_Raw, iLen );
	
	tchar szAccount[MAX_ACCOUNT_NAME_SIZE+3];

	switch ( pEvent->Default.m_Cmd )
	{
		case XCMD_ServersReq:
		{
			if ( iLen < sizeof( pEvent->ServersReq ))
				return false;

			lErr = Login_ServerList( pEvent->ServersReq.m_acctname, pEvent->ServersReq.m_acctpass );
			if ( lErr == PacketLoginError::Success )
			{
				Str_GetBare( szAccount, pEvent->ServersReq.m_acctname, sizeof(szAccount)-1 );
				CAccountRef pAcc = g_Accounts.Account_Find( szAccount );
				if (pAcc)
				{
					pAcc->m_TagDefs.SetNum("clientversion", m_Crypt.GetClientVer());
					pAcc->m_TagDefs.SetNum("reportedcliver", GetNetState()->getReportedVersion());
				}
				else
				{
					// If i can't set the tag is better to stop login now
					lErr = PacketLoginError::Invalid;
				}
			}

			break;
		}

		case XCMD_CharListReq:
		{
			if ( iLen < sizeof( pEvent->CharListReq ))
				return false;

			lErr = Setup_ListReq( pEvent->CharListReq.m_acctname, pEvent->CharListReq.m_acctpass, true );
			if ( lErr == PacketLoginError::Success )
			{
				// pass detected client version to the game server to make valid cliver used
				Str_GetBare( szAccount, pEvent->CharListReq.m_acctname, sizeof(szAccount)-1 );
				CAccountRef pAcc = g_Accounts.Account_Find( szAccount );
				if (pAcc)
				{
					dword tmSid = 0x7f000001;
					dword tmVer = (dword)(pAcc->m_TagDefs.GetKeyNum("clientversion"));
					dword tmVerReported = (dword)(pAcc->m_TagDefs.GetKeyNum("reportedcliver"));
					pAcc->m_TagDefs.DeleteKey("clientversion");
					pAcc->m_TagDefs.DeleteKey("reportedcliver");

					if ( g_Cfg.m_fUseAuthID )
					{
						tmSid = (dword)(pAcc->m_TagDefs.GetKeyNum("customerid"));
						pAcc->m_TagDefs.DeleteKey("customerid");
					}

					DEBUG_MSG(("%x:xProcessClientSetup for %s, with AuthId %u and CliVersion %u / CliVersionReported %u\n", GetSocketID(), pAcc->GetName(), tmSid, tmVer, tmVerReported));

					if ( tmSid != 0 && tmSid == pEvent->CharListReq.m_Account )
					{
						// request client version if the client has not reported it to server yet
						if ( tmVerReported == 0 )
							new PacketClientVersionReq(this);

						if ( tmVerReported != 0 )
						{
							GetNetState()->m_reportedVersion = tmVerReported;
						}
						else if ( tmVer != 0 )
						{
							m_Crypt.SetClientVerEnum(tmVer, false);
							GetNetState()->m_clientVersion = tmVer;
						}

						// client version change may toggle async mode, it's important to flush pending data to the client before this happens
						GetNetState()->detectAsyncMode();

						if ( !xCanEncLogin(true) )
							lErr = PacketLoginError::BadVersion;
					}
					else
					{
						lErr = PacketLoginError::BadAuthID;
					}
				}
				else
				{
					lErr = PacketLoginError::Invalid;
				}
			}

			break;
		}

#ifdef _DEBUG
		default:
		{
			DEBUG_ERR(("Unknown/bad packet to receive at this time: 0x%X\n", pEvent->Default.m_Cmd));
		}
#endif
	}
	
	xRecordPacketData(this, (const byte *)pEvent, iLen, "client->server");

	if ( lErr != PacketLoginError::Success )	// it never matched any crypt format.
	{
		addLoginErr( lErr );
	}

	return( lErr == PacketLoginError::Success );
}
Пример #2
0
bool CClient::OnRxConsole( const byte * pData, size_t iLen )
{
	ADDTOCALLSTACK("CClient::OnRxConsole");
	// A special console version of the client. (Not game protocol)
	if ( !iLen || ( GetConnectType() != CONNECT_TELNET ))
		return false;

	if ( IsSetEF( EF_AllowTelnetPacketFilter ) )
	{
		bool fFiltered = xPacketFilter(pData, iLen);
		if ( fFiltered )
			return fFiltered;
	}

	while ( iLen -- )
	{
		int iRet = OnConsoleKey( m_Targ_Text, *pData++, GetAccount() != NULL );
		if ( ! iRet )
			return false;
		if ( iRet == 2 )
		{
			if ( GetAccount() == NULL )
			{
				if ( !m_zLogin[0] )
				{
					if ( (uint)(m_Targ_Text.GetLength()) > (CountOf(m_zLogin) - 1) )
					{
						SysMessage("Login:\n");
					}
					else
					{
						strcpy(m_zLogin, m_Targ_Text);
						SysMessage("Password:\n");
					}
					m_Targ_Text.Empty();
				}
				else
				{
					CSString sMsg;

					CAccountRef pAccount = g_Accounts.Account_Find(m_zLogin);
					if (( pAccount == NULL ) || ( pAccount->GetPrivLevel() < PLEVEL_Admin ))
					{
						SysMessagef("%s\n", g_Cfg.GetDefaultMsg(DEFMSG_CONSOLE_NOT_PRIV));
						m_Targ_Text.Empty();
						return false;
					}
					if ( LogIn(m_zLogin, m_Targ_Text, sMsg ) == PacketLoginError::Success )
					{
						m_Targ_Text.Empty();
						return OnRxConsoleLoginComplete();
					}
					else if ( ! sMsg.IsEmpty())
					{
						SysMessage( sMsg );
						return false;
					}
					m_Targ_Text.Empty();
				}
				return true;
			}
			else
			{
				iRet = g_Serv.OnConsoleCmd( m_Targ_Text, this );

				if (g_Cfg.m_fTelnetLog && GetPrivLevel() >= g_Cfg.m_iCommandLog)
					g_Log.Event(LOGM_GM_CMDS, "%x:'%s' commands '%s'=%d\n", GetSocketID(), GetName(), static_cast<lpctstr>(m_Targ_Text), iRet);
			}
		}
	}
	return true;
}
Пример #3
0
bool CClient::OnRxAxis( const byte * pData, size_t iLen )
{
	ADDTOCALLSTACK("CClient::OnRxAxis");
	if ( !iLen || ( GetConnectType() != CONNECT_AXIS ))
		return false;

	while ( iLen -- )
	{
		int iRet = OnConsoleKey( m_Targ_Text, *pData++, GetAccount() != NULL );
		if ( ! iRet )
			return false;
		if ( iRet == 2 )
		{
			if ( GetAccount() == NULL )
			{
				if ( !m_zLogin[0] )
				{
					if ( (uint)(m_Targ_Text.GetLength()) <= (CountOf(m_zLogin) - 1) )
						strcpy(m_zLogin, m_Targ_Text);
					m_Targ_Text.Empty();
				}
				else
				{
					CSString sMsg;

					CAccountRef pAccount = g_Accounts.Account_Find(m_zLogin);
					if (( pAccount == NULL ) || ( pAccount->GetPrivLevel() < PLEVEL_Counsel ))
					{
						SysMessagef("\"MSG:%s\"", g_Cfg.GetDefaultMsg(DEFMSG_AXIS_NOT_PRIV));
						m_Targ_Text.Empty();
						return false;
					}
					if ( LogIn(m_zLogin, m_Targ_Text, sMsg ) == PacketLoginError::Success )
					{
						m_Targ_Text.Empty();
						if ( GetPrivLevel() < PLEVEL_Counsel )
						{
							SysMessagef("\"MSG:%s\"", g_Cfg.GetDefaultMsg(DEFMSG_AXIS_NOT_PRIV));
							return false;
						}
						if (GetPeer().IsValidAddr())
						{
							CScriptTriggerArgs Args;
							Args.m_VarsLocal.SetStrNew("Account",GetName());
							Args.m_VarsLocal.SetStrNew("IP",GetPeer().GetAddrStr());
							TRIGRET_TYPE tRet = TRIGRET_RET_DEFAULT;
							r_Call("f_axis_preload", this, &Args, NULL, &tRet);
							if ( tRet == TRIGRET_RET_FALSE )
								return false;
							if ( tRet == TRIGRET_RET_TRUE )
							{
								SysMessagef("\"MSG:%s\"", g_Cfg.GetDefaultMsg(DEFMSG_AXIS_DENIED));
								return false;
							}

							time_t dateChange;
							dword dwSize;
							if ( ! CSFileList::ReadFileInfo( "Axis.db", dateChange, dwSize ))
							{
								SysMessagef("\"MSG:%s\"", g_Cfg.GetDefaultMsg(DEFMSG_AXIS_INFO_ERROR));
								return false;
							}

							CSFile FileRead;
							if ( ! FileRead.Open( "Axis.db", OF_READ|OF_BINARY ))
							{
								SysMessagef("\"MSG:%s\"", g_Cfg.GetDefaultMsg(DEFMSG_AXIS_FILE_ERROR));
								return false;
							}

							tchar szTmp[8*1024];
							PacketWeb packet;
							for (;;)
							{
								size_t iLength = FileRead.Read( szTmp, sizeof( szTmp ) );
								if ( iLength <= 0 )
									break;
								packet.setData((byte*)szTmp, iLength);
								packet.send(this);
								dwSize -= (dword)iLength;
								if ( dwSize <= 0 )
									break;
							}
							return true;
						}
						return false;
					}
					else if ( ! sMsg.IsEmpty())
					{
						SysMessagef("\"MSG:%s\"", (lpctstr)sMsg);
						return false;
					}
					m_Targ_Text.Empty();
				}
				return true;
			}
		}
	}
	return true;
}
Пример #4
0
bool CClient::xProcessClientSetup( CEvent * pEvent, size_t iLen )
{
	ADDTOCALLSTACK("CClient::xProcessClientSetup");
	// If this is a login then try to process the data and figure out what client it is.
	// try to figure out which client version we are talking to.
	// (CEvent::ServersReq) or (CEvent::CharListReq)
	// NOTE: Anything else we get at this point is tossed !
	ASSERT(GetConnectType() == CONNECT_CRYPT);
	ASSERT(!m_Crypt.IsInit());
	ASSERT(pEvent);
	ASSERT(iLen > 0);

	// Try all client versions on the msg.
	CEvent bincopy;		// in buffer (from client)
	ASSERT(iLen <= sizeof(bincopy));
	memcpy(bincopy.m_Raw, pEvent->m_Raw, iLen);

	if ( !m_Crypt.Init(m_NetState->m_seed, bincopy.m_Raw, iLen, m_NetState->isClientKR()) )
	{
		DEBUG_MSG(("%lx:Odd login message length %" FMTSIZE_T "?\n", GetSocketID(), iLen));
#ifdef _DEBUG
		xRecordPacketData(this, (const BYTE *)pEvent, iLen, "client->server");
#endif
		addLoginErr(PacketLoginError::BadEncLength);
		return false;
	}
	
	SetConnectType(m_Crypt.GetConnectType());

	if ( !xCanEncLogin() )
	{
		addLoginErr(m_Crypt.GetEncryptionType() == ENC_NONE ? PacketLoginError::EncNoCrypt : PacketLoginError::EncCrypt);
		return false;
	}
	else if ( (m_Crypt.GetConnectType() == CONNECT_LOGIN) && !xCanEncLogin(true) )
	{
		addLoginErr(PacketLoginError::BadVersion);
		return false;
	}
	
	BYTE lErr = PacketLoginError::EncUnknown;
	m_Crypt.Decrypt(pEvent->m_Raw, bincopy.m_Raw, iLen);
	TCHAR szAccount[MAX_ACCOUNT_NAME_SIZE + 3];

	switch ( pEvent->Default.m_Cmd )
	{
		case XCMD_ServersReq:
		{
			if ( iLen < sizeof(pEvent->ServersReq) )
				return false;

			lErr = Login_ServerList(pEvent->ServersReq.m_acctname, pEvent->ServersReq.m_acctpass);
			if ( lErr == PacketLoginError::Success )
			{
				Str_GetBare(szAccount, pEvent->ServersReq.m_acctname, sizeof(szAccount) - 1);
				CAccountRef pAcc = g_Accounts.Account_Find(szAccount);
				if ( pAcc )
				{
					// On login proccess, the client will connect on IP only to request the servers list, and after select an server,
					// it will disconnect from this IP and connect again now on server IP to request the account character list. But
					// on the 2nd connection the client doesn't report its version to server again, so we must use tags to temporarily
					// store the client version on XCMD_ServersReq and restore it on XCMD_CharListReq.
					if ( m_Crypt.GetClientVer() )
						pAcc->m_TagDefs.SetNum("ClientVersion", m_Crypt.GetClientVer());
					if ( m_NetState->getReportedVersion() )
						pAcc->m_TagDefs.SetNum("ReportedCliVer", m_NetState->getReportedVersion());
					else
						new PacketClientVersionReq(this);
				}
				else
				{
					lErr = PacketLoginError::Invalid;
				}
			}
			break;
		}

		case XCMD_CharListReq:
		{
			if ( iLen < sizeof(pEvent->CharListReq) )
				return false;

			Str_GetBare(szAccount, pEvent->CharListReq.m_acctname, sizeof(szAccount) - 1);
			CAccountRef pAcc = g_Accounts.Account_Find(szAccount);
			DWORD dwCustomerID = 0x7f000001;
			if ( pAcc )
			{
				if ( g_Cfg.m_fUseAuthID )
				{
					dwCustomerID = static_cast<DWORD>(pAcc->m_TagDefs.GetKeyNum("CustomerID"));
					pAcc->m_TagDefs.DeleteKey("CustomerID");
				}

				DWORD tmVer = static_cast<DWORD>(pAcc->m_TagDefs.GetKeyNum("ClientVersion"));
				if ( tmVer )
				{
					m_Crypt.SetClientVerEnum(tmVer, false);
					m_NetState->m_clientVersion = tmVer;
					pAcc->m_TagDefs.DeleteKey("ClientVersion");
				}

				DWORD tmVerReported = static_cast<DWORD>(pAcc->m_TagDefs.GetKeyNum("ReportedCliVer"));
				if ( tmVerReported )
				{
					m_NetState->m_reportedVersion = tmVerReported;
					pAcc->m_TagDefs.DeleteKey("ReportedCliVer");
				}

				// Enhanced clients must enable some specific features on UpdateFeatureFlags() but they only report the
				// client type to server after this function, so we must estimate the client type based on client version
				// to enable these features properly even when the client don't reported its client type to server yet.
				if ( m_NetState->isClientVersion(MASK_CLIENTTYPE_EC) )
					m_NetState->m_clientType = CLIENTTYPE_EC;
			}

			lErr = Setup_ListReq(pEvent->CharListReq.m_acctname, pEvent->CharListReq.m_acctpass, true);
			if ( lErr == PacketLoginError::Success )
			{
				if ( pAcc )
				{
					DEBUG_MSG(("%lx:xProcessClientSetup for %s, with AuthId %lu and CliVersion %lu / CliVersionReported %lu\n", GetSocketID(), pAcc->GetName(), CustomerID, m_Crypt.GetClientVer(), m_NetState->getReportedVersion()));

					if ( (dwCustomerID != 0) && (dwCustomerID == pEvent->CharListReq.m_Account) )
					{
						if ( !xCanEncLogin(true) )
							lErr = PacketLoginError::BadVersion;
					}
					else
					{
						lErr = PacketLoginError::BadAuthID;
					}
				}
				else
				{
					lErr = PacketLoginError::Invalid;
				}
			}
			break;
		}

#ifdef _DEBUG
		default:
			DEBUG_ERR(("Unknown/bad packet to receive at this time: 0x%X\n", pEvent->Default.m_Cmd));
#endif
	}
	
	xRecordPacketData(this, (const BYTE *)pEvent, iLen, "client->server");

	if ( lErr != PacketLoginError::Success )	// it never matched any crypt format.
		addLoginErr(lErr);

	return (lErr == PacketLoginError::Success);
}