Beispiel #1
0
CClient::CClient(NetState* state)
{
	// This may be a web connection or Telnet ?
	m_net = state;
	SetConnectType( CONNECT_UNK );	// don't know what sort of connect this is yet.

	// update ip history
#ifndef _MTNETWORK
	HistoryIP& history = g_NetworkIn.getIPHistoryManager().getHistoryForIP(GetPeer());
#else
	HistoryIP& history = g_NetworkManager.getIPHistoryManager().getHistoryForIP(GetPeer());
#endif
	history.m_connecting++;
	history.m_connected++;

	m_Crypt.SetClientVer( g_Serv.m_ClientVersion );
	m_pAccount = NULL;

	m_pChar = NULL;
	m_pGMPage = NULL;

	m_timeLogin.Init();
	m_timeLastSend =
	m_timeLastEvent = CServTime::GetCurrentTime();
	m_timeLastEventWalk = CServTime::GetCurrentTime();

	m_iWalkStepCount = 0;
	m_iWalkTimeAvg	= 100;
	m_timeWalkStep = GetTickCount();

	m_Targ_Timeout.Init();
	m_Targ_Mode = CLIMODE_SETUP_CONNECTING;
	m_Prompt_Mode = CLIMODE_NORMAL;

	m_tmSetup.m_dwIP = 0;
	m_tmSetup.m_iConnect = 0;
	m_tmSetup.m_bNewSeed = false;

	m_Env.SetInvalid();

	g_Log.Event(LOGM_CLIENTS_LOG, "%lx:Client connected [Total:%lu] ('%s' %ld/%ld)\n",
		GetSocketID(), g_Serv.StatGet(SERV_STAT_CLIENTS), GetPeerStr(), history.m_connecting, history.m_connected);

	m_zLastMessage[0] = 0;
	m_zLastObjMessage[0] = 0;
	m_tNextPickup.Init();

	m_BfAntiCheat.lastvalue = m_BfAntiCheat.count = 0x0;
	m_ScreenSize.x = m_ScreenSize.y = 0x0;
	m_pPopupPacket = NULL;
	m_pHouseDesign = NULL;
	m_fUpdateStats = 0;
}
Beispiel #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 != 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 );
}
Beispiel #3
0
CClient::CClient(NetState *state)
{
	m_pChar = NULL;

	m_Env.SetInvalid();

	m_fUpdateStats = 0;

	m_iWalkTimeAvg = 100;
	m_iWalkStepCount = 0;
	m_timeWalkStep = GetTickCount64();

	m_ScreenSize.x = m_ScreenSize.y = 0;

	m_Prompt_Mode = CLIMODE_NORMAL;

	SetConnectType(CONNECT_UNK);	// don't know what sort of connect this is yet
	m_NetState = state;
	m_pAccount = NULL;

	m_FeatureFlags = 0;
	m_CharacterListFlags = 0;
	m_TooltipEnabled = false;
	m_ContainerGridEnabled = false;
	m_UseNewChatSystem = false;

	m_timeLogin.Init();
	m_timeLastEvent = CServTime::GetCurrentTime();
	m_timeLastEventItemPickup = CServTime::GetCurrentTime();
	m_timeLastEventWalk = CServTime::GetCurrentTime();
	m_timeNextEventWalk = 0;

	m_pGMPage = NULL;

	m_timeLastSkillThrowing.Init();
	m_pSkillThrowingTarg = NULL;
	m_SkillThrowingAnimID = ITEMID_NOTHING;
	m_SkillThrowingAnimHue = 0;
	m_SkillThrowingAnimRender = 0;

	m_Targ_Mode = CLIMODE_SETUP_CONNECTING;
	m_Targ_Timeout.Init();

	m_Crypt.SetClientVer(g_Serv.m_ClientVersion);

	m_pPopupPacket = NULL;

	m_zLastMessage[0] = 0;
	m_zLastObjMessage[0] = 0;

	m_pHouseDesign = NULL;

	// Update IP history
#ifdef _MTNETWORK
	HistoryIP &history = g_NetworkManager.getIPHistoryManager().getHistoryForIP(GetPeer());
#else
	HistoryIP &history = g_NetworkIn.getIPHistoryManager().getHistoryForIP(GetPeer());
#endif
	++history.m_connecting;
	++history.m_connected;

	g_Log.Event(LOGM_CLIENTS_LOG, "%lx:Client connected [Total:%lu] ('%s' %ld/%ld)\n", GetSocketID(), g_Serv.StatGet(SERV_STAT_CLIENTS), GetPeerStr(), history.m_connecting, history.m_connected);
}
Beispiel #4
0
bool CClient::OnRxPing( const byte * pData, size_t iLen )
{
	ADDTOCALLSTACK("CClient::OnRxPing");
	// packet iLen < 5
	// UOMon should work like this.
	// RETURN: true = keep the connection open.
	if ( GetConnectType() != CONNECT_UNK )
		return false;

	if ( !iLen || iLen > 4 )
		return false;

	switch ( pData[0] )
	{
		// Remote Admin Console
		case '\x1':
		case ' ':
		{
			if ( (iLen > 1) &&
				 (iLen != 2 || pData[1] != '\n') &&
				 (iLen != 3 || pData[1] != '\r' || pData[2] != '\n') &&
				 (iLen != 3 || pData[1] != '\n' || pData[2] != '\0') )
				break;

			// enter into remote admin mode. (look for password).
			SetConnectType( CONNECT_TELNET );
			m_zLogin[0] = 0;
			SysMessagef("%s %s Admin Telnet\n", g_Cfg.GetDefaultMsg(DEFMSG_CONSOLE_WELCOME_1), g_Serv.GetName());

			if ( g_Cfg.m_fLocalIPAdmin )
			{
				// don't bother logging in if local.

				if ( GetPeer().IsLocalAddr() )
				{
					CAccountRef pAccount = g_Accounts.Account_Find("Administrator");
					if ( !pAccount )
						pAccount = g_Accounts.Account_Find("RemoteAdmin");
					if ( pAccount )
					{
						CSString sMsg;
						byte lErr = LogIn( pAccount, sMsg );
						if ( lErr != PacketLoginError::Success )
						{
							if ( lErr != PacketLoginError::Invalid )
								SysMessage( sMsg );
							return false;
						}
						return OnRxConsoleLoginComplete();
					}
				}
			}

			SysMessage("Login:\n");
			return true;
		}

		//Axis Connection
		case '@':
		{
			if ( (iLen > 1) &&
				 (iLen != 2 || pData[1] != '\n') &&
				 (iLen != 3 || pData[1] != '\r' || pData[2] != '\n') &&
				 (iLen != 3 || pData[1] != '\n' || pData[2] != '\0') )
				break;

			// enter into Axis mode. (look for password).
			SetConnectType( CONNECT_AXIS );
			m_zLogin[0] = 0;

			time_t dateChange;
			dword dwSize = 0;
			CSFileList::ReadFileInfo( "Axis.db", dateChange, dwSize );
			SysMessagef("%u",dwSize);
			return true;
		}

		// ConnectUO Status
		case 0xF1:
		{
			// ConnectUO sends a 4-byte packet when requesting status info
			// byte Cmd		(0xF1)
			// word Unk		(0x04)
			// byte SubCmd	(0xFF)

			if ( iLen != MAKEWORD( pData[2], pData[1] ) )
				break;

			if ( pData[3] != 0xFF )
				break;

			if ( g_Cfg.m_fCUOStatus == false )
			{
				g_Log.Event( LOGM_CLIENTS_LOG|LOGL_EVENT, "%x:CUO Status request from %s has been rejected.\n", GetSocketID(), GetPeerStr());
				return false;
			}

			// enter 'remote admin mode'
			SetConnectType( CONNECT_TELNET );

			g_Log.Event( LOGM_CLIENTS_LOG|LOGL_EVENT, "%x:CUO Status request from %s\n", GetSocketID(), GetPeerStr());

			SysMessage( g_Serv.GetStatusString( 0x25 ) );

			// exit 'remote admin mode'
			SetConnectType( CONNECT_UNK );
			return false;
		}

		// UOGateway Status
		case 0xFF:
		case 0x7F:
		case 0x22:
		{
			if ( iLen > 1 )
				break;

			if ( g_Cfg.m_fUOGStatus == false )
			{
				g_Log.Event( LOGM_CLIENTS_LOG|LOGL_EVENT, "%x:UOG Status request from %s has been rejected.\n", GetSocketID(), GetPeerStr());
				return false;
			}

			// enter 'remote admin mode'
			SetConnectType( CONNECT_TELNET );

			g_Log.Event( LOGM_CLIENTS_LOG|LOGL_EVENT, "%x:UOG Status request from %s\n", GetSocketID(), GetPeerStr());

			if (pData[0] == 0x7F)
				SetConnectType( CONNECT_UOG );

			SysMessage( g_Serv.GetStatusString( 0x22 ) );

			// exit 'remote admin mode'
			SetConnectType( CONNECT_UNK );
			return false;
		}
	}

	g_Log.Event( LOGM_CLIENTS_LOG|LOGL_EVENT, "%x:Unknown/invalid ping data '0x%x' from %s (Len: %" PRIuSIZE_T ")\n", GetSocketID(), pData[0], GetPeerStr(), iLen);
	return false;
}
Beispiel #5
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);
}