Example #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 );
}
Example #2
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);
}