Пример #1
0
byte CClient::Login_ServerList( const char * pszAccount, const char * pszPassword )
{
	ADDTOCALLSTACK("CClient::Login_ServerList");
	// XCMD_ServersReq
	// Initial login (Login on "loginserver", new format)
	// If the messages are garbled make sure they are terminated to correct length.

	tchar szAccount[MAX_ACCOUNT_NAME_SIZE+3];
	size_t iLenAccount = Str_GetBare( szAccount, pszAccount, sizeof(szAccount)-1 );
	if ( iLenAccount > MAX_ACCOUNT_NAME_SIZE )
		return( PacketLoginError::BadAccount );
	if ( iLenAccount != strlen(pszAccount))
		return( PacketLoginError::BadAccount );

	tchar szPassword[MAX_NAME_SIZE+3];
	size_t iLenPassword = Str_GetBare( szPassword, pszPassword, sizeof( szPassword )-1 );
	if ( iLenPassword > MAX_NAME_SIZE )
		return( PacketLoginError::BadPassword );
	if ( iLenPassword != strlen(pszPassword))
		return( PacketLoginError::BadPassword );

	// don't bother logging in yet.
	// Give the server list to everyone.
	// if ( LogIn( pszAccount, pszPassword ) )
	//   return( PacketLoginError::BadPass );
	CSString sMsg;
	byte lErr = LogIn( pszAccount, pszPassword, sMsg );
	if ( lErr != PacketLoginError::Success )
	{
		return( lErr );
	}

	new PacketServerList(this);

	m_Targ_Mode = CLIMODE_SETUP_SERVERS;
	return( PacketLoginError::Success );
}
Пример #2
0
void CServerDef::SetName( lpctstr pszName )
{
	ADDTOCALLSTACK("CServerDef::SetName");
	if ( ! pszName )
		return;

	// No HTML tags using <> either.
	tchar szName[ 2*MAX_SERVER_NAME_SIZE ];
	size_t len = Str_GetBare( szName, pszName, sizeof(szName), "<>/\"\\" );
	if ( len <= 0 )
		return;

	// allow just basic chars. No spaces, only numbers, letters and underbar.
	if ( g_Cfg.IsObscene( szName ) )
	{
		DEBUG_ERR(( "Obscene server '%s' ignored.\n", szName ));
		return;
	}

	m_sName = szName;
}
Пример #3
0
bool CServerDef::r_LoadVal( CScript & s )
{
	ADDTOCALLSTACK("CServerDef::r_LoadVal");
	EXC_TRY("LoadVal");
	switch ( FindTableSorted( s.GetKey(), sm_szLoadKeys, CountOf( sm_szLoadKeys )-1 ) )
	{
		case SC_ACCAPP:
		case SC_ACCAPPS:
			// Treat it as a value or a string.
			if ( IsDigit( s.GetArgStr()[0] ))
				m_eAccApp = static_cast<ACCAPP_TYPE>(s.GetArgVal() );
			else
			{
				// Treat it as a string. "Manual","Automatic","Guest"
				m_eAccApp = static_cast<ACCAPP_TYPE>(FindTable(s.GetArgStr(), sm_AccAppTable, CountOf(sm_AccAppTable)));
			}
			if ( m_eAccApp < 0 || m_eAccApp >= ACCAPP_QTY )
				m_eAccApp = ACCAPP_Unspecified;
			break;
		case SC_AGE:
			break;
		case SC_CLIENTVERSION:
			m_sClientVersion = s.GetArgRaw();
			// m_ClientVersion.SetClientVer( s.GetArgRaw());
			break;
		case SC_CREATE:
			m_timeCreate = CServerTime::GetCurrentTime() - ( s.GetArgLLVal() * TICK_PER_SEC );
			break;
		case SC_ADMINEMAIL:
			if ( this != &g_Serv && !g_Serv.m_sEMail.IsEmpty() && strstr(s.GetArgStr(), g_Serv.m_sEMail) )
				return false;
			if ( !g_Cfg.IsValidEmailAddressFormat(s.GetArgStr()) )
				return false;
			if ( g_Cfg.IsObscene(s.GetArgStr()) )
				return false;
			m_sEMail = s.GetArgStr();
			break;
		case SC_LANG:
			{
				tchar szLang[ 32 ];
				Str_GetBare( szLang, s.GetArgStr(), sizeof(szLang), "<>/\"\\" );
				if ( g_Cfg.IsObscene(szLang) )	// Is the name unacceptable?
					return false;
				m_sLang = szLang;
			}
			break;
		case SC_LASTVALIDDATE:
			m_dateLastValid.Read( s.GetArgStr() );
			break;
		case SC_LASTVALIDTIME:
			{
				int iVal = s.GetArgVal() * TICK_PER_SEC;
				if ( iVal < 0 )
					m_timeLastValid = CServerTime::GetCurrentTime() + iVal;
				else
					m_timeLastValid = CServerTime::GetCurrentTime() - iVal;
			}
			break;
		case SC_SERVIP:
			m_ip.SetHostPortStr( s.GetArgStr() );
			break;

		case SC_NAME:
		case SC_SERVNAME:
			SetName( s.GetArgStr() );
			break;
		case SC_SERVPORT:
			m_ip.SetPort( (word)s.GetArgVal() );
			break;

		case SC_ACCOUNTS:
			SetStat( SERV_STAT_ACCOUNTS, s.GetArgVal() );
			break;

		case SC_CLIENTS:
			{
				int iClients = s.GetArgVal();
				if ( iClients < 0 )
					return false;				// invalid
				if ( iClients > FD_SETSIZE )	// Number is bugged !
					return false;
				SetStat( SERV_STAT_CLIENTS, iClients );
			}
			break;
		case SC_ITEMS:
			SetStat( SERV_STAT_ITEMS, s.GetArgVal() );
			break;
		case SC_CHARS:
			SetStat( SERV_STAT_CHARS, s.GetArgVal() );
			break;
		case SC_TIMEZONE:
			m_TimeZone = (char)s.GetArgVal();
			break;
		case SC_URL:
		case SC_URLLINK:
			// It is a basically valid URL ?
			if ( this != &g_Serv )
			{
				if ( !g_Serv.m_sURL.IsEmpty() && strstr(s.GetArgStr(), g_Serv.m_sURL) )
					return false;
			}
			if ( !strchr(s.GetArgStr(), '.' ) )
				return false;
			if ( g_Cfg.IsObscene( s.GetArgStr()) )	// Is the name unacceptable?
				return false;
			m_sURL = s.GetArgStr();
			break;
		default:
			return CScriptObj::r_LoadVal(s);
	}
	return true;
	EXC_CATCH;

	EXC_DEBUG_START;
	EXC_ADD_SCRIPT;
	EXC_DEBUG_END;
	return false;
}
Пример #4
0
bool CWebPageDef::ServPage( CClient * pClient, TCHAR * pszPage, CGTime * pdateIfModifiedSince )	// static
{
	ADDTOCALLSTACK("CWebPageDef::ServPage");
	// make sure this is a valid format for the request.

	TCHAR szPageName[_MAX_PATH];
	Str_GetBare( szPageName, pszPage, sizeof(szPageName), "!\"#$%&()*,:;<=>?[]^{|}-+'`" );

	int iError = 404;
	CWebPageDef * pWebPage = g_Cfg.FindWebPage(szPageName);
	if ( pWebPage )
	{
		iError = pWebPage->ServPageRequest(pClient, szPageName, pdateIfModifiedSince);
		if ( ! iError )
			return true;
	}

	// Is it a file in the Script directory ?
	if ( iError == 404 )
	{
		const RESOURCE_ID ridjunk( RES_UNKNOWN, 1 );
		CWebPageDef tmppage( ridjunk );
		if ( tmppage.SetSourceFile( szPageName, pClient ))
		{
			if ( !tmppage.ServPageRequest(pClient, szPageName, pdateIfModifiedSince) )
				return true;
		}
	}

	// Can't find it !?
	// just take the default page. or have a custom 404 page ?

	pClient->m_Targ_Text = pszPage;

	TCHAR	*pszTemp = Str_GetTemp();
	sprintf(pszTemp, GRAY_FILE "%d.htm", iError);
	pWebPage = g_Cfg.FindWebPage(pszTemp);
	if ( pWebPage )
	{
		if ( ! pWebPage->ServPageRequest( pClient, pszPage, NULL ))
			return true;
	}

	// Hmm we should do something !!!?
	// Try to give a reasonable default error msg.

	LPCTSTR pszErrText;
	switch (iError)
	{
		case 401: pszErrText = "Authorization Required"; break;
		case 403: pszErrText = "Forbidden"; break;
		case 404: pszErrText = "Object Not Found"; break;
		case 500: pszErrText = "Internal Server Error"; break;
		default: pszErrText = "Unknown Error"; break;
	}

	CGTime datetime = CGTime::GetCurrentTime();
	const char *sDate = datetime.FormatGmt(NULL);
	CGString sMsgHead;
	CGString sText;

	sText.Format(
		"<html><head><title>Error %d</title>"
		"<meta name=robots content=noindex>"
		"</head><body>"
		"<h2>HTTP Error %d</h2><p><strong>%d %s</strong></p>"
		"<p>The " GRAY_TITLE " server cannot deliver the file or script you asked for.</p>"
		"<p>Please contact the server's administrator if this problem persists.</p>"
		"</body></html>",
		iError,
		iError,
		iError,
		static_cast<LPCTSTR>(pszErrText));

	sMsgHead.Format(
		"HTTP/1.1 %d %s\r\n"
		"Date: %s\r\n"
		"Server: " GRAY_TITLE " V " GRAY_VERSION "\r\n"
		"Content-Type: text/html\r\n"
		"Content-Length: %d\r\n"
		"Connection: close\r\n"
		"\r\n%s",
		iError, static_cast<LPCTSTR>(pszErrText),
		static_cast<LPCTSTR>(sDate),
		sText.GetLength(),
		static_cast<LPCTSTR>(sText));

	new PacketWeb(pClient, reinterpret_cast<const BYTE *>(sMsgHead.GetPtr()), sMsgHead.GetLength());
	return false;
}
Пример #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 != 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 );
}
Пример #6
0
bool CClient::OnRxWebPageRequest( byte * pRequest, size_t iLen )
{
	ADDTOCALLSTACK("CClient::OnRxWebPageRequest");
	// Seems to be a web browser pointing at us ? typical stuff :
	if ( GetConnectType() != CONNECT_HTTP )
		return false;

	// ensure request is null-terminated (if the request is well-formed, we are overwriting a trailing \n here)
	pRequest[iLen - 1] = '\0';

	if ( strlen(reinterpret_cast<char *>(pRequest)) > 1024 )			// too long request
		return false;

	if ( !strpbrk( reinterpret_cast<char *>(pRequest), " \t\012\015" ) )	// malformed request
		return false;

	tchar * ppLines[16];
	size_t iQtyLines = Str_ParseCmds(reinterpret_cast<char *>(pRequest), ppLines, CountOf(ppLines), "\r\n");
	if (( iQtyLines < 1 ) || ( iQtyLines >= 15 ))	// too long request
		return false;

	// Look for what they want to do with the connection.
	bool fKeepAlive = false;
	CSTime dateIfModifiedSince;
	tchar * pszReferer = NULL;
	size_t stContentLength = 0;
	for ( size_t j = 1; j < iQtyLines; j++ )
	{
		tchar	*pszArgs = Str_TrimWhitespace(ppLines[j]);
		if ( !strnicmp(pszArgs, "Connection:", 11 ) )
		{
			pszArgs += 11;
			GETNONWHITESPACE(pszArgs);
			if ( !strnicmp(pszArgs, "Keep-Alive", 10) )
				fKeepAlive = true;
		}
		else if ( !strnicmp(pszArgs, "Referer:", 8) )
		{
			pszReferer = pszArgs+8;
		}
		else if ( !strnicmp(pszArgs, "Content-Length:", 15) )
		{
			pszArgs += 15;
			GETNONWHITESPACE(pszArgs);
			stContentLength = strtoul(pszArgs, NULL, 10);
		}
		else if ( ! strnicmp( pszArgs, "If-Modified-Since:", 18 ))
		{
			// If-Modified-Since: Fri, 17 Dec 1999 14:59:20 GMT\r\n
			pszArgs += 18;
			dateIfModifiedSince.Read(pszArgs);
		}
	}

	tchar * ppRequest[4];
	size_t iQtyArgs = Str_ParseCmds(ppLines[0], ppRequest, CountOf(ppRequest), " ");
	if (( iQtyArgs < 2 ) || ( strlen(ppRequest[1]) >= _MAX_PATH ))
		return false;

	if ( strchr(ppRequest[1], '\r') || strchr(ppRequest[1], 0x0c) )
		return false;

	// if the client hasn't requested a keep alive, we must act as if they had
	// when async networking is used, otherwise data may not be completely sent
	if ( fKeepAlive == false )
	{
		fKeepAlive = m_net->isAsyncMode();

		// must switch to a blocking socket when the connection is not being kept
		// alive, or else pending data will be lost when the socket shuts down

		if ( fKeepAlive == false )
			m_net->m_socket.SetNonBlocking(false);
	}

	linger llinger;
	llinger.l_onoff = 1;
	llinger.l_linger = 500;	// in mSec
	m_net->m_socket.SetSockOpt(SO_LINGER, reinterpret_cast<char *>(&llinger), sizeof(linger));
	char nbool = true;
	m_net->m_socket.SetSockOpt(SO_KEEPALIVE, &nbool, sizeof(char));

	// disable NAGLE algorythm for data compression
	nbool = true;
	m_net->m_socket.SetSockOpt( TCP_NODELAY, &nbool, sizeof(char), IPPROTO_TCP);
	
	if ( memcmp(ppLines[0], "POST", 4) == 0 )
	{
		if ( stContentLength > strlen(ppLines[iQtyLines-1]) )
			return false;

		// POST /--WEBBOT-SELF-- HTTP/1.1
		// Referer: http://127.0.0.1:2593/spherestatus.htm
		// Content-Type: application/x-www-form-urlencoded
		// Host: 127.0.0.1:2593
		// Content-Length: 29
		// T1=stuff1&B1=Submit&T2=stuff2

		g_Log.Event(LOGM_HTTP|LOGL_EVENT, "%x:HTTP Page Post '%s'\n", GetSocketID(), static_cast<lpctstr>(ppRequest[1]));

		CWebPageDef	*pWebPage = g_Cfg.FindWebPage(ppRequest[1]);
		if ( !pWebPage )
			pWebPage = g_Cfg.FindWebPage(pszReferer);
		if ( pWebPage )
		{
			if ( pWebPage->ServPagePost(this, ppRequest[1], ppLines[iQtyLines-1], stContentLength) )
			{
				if ( fKeepAlive )
					return true;
				return false;
			}
			return false;
		}
	}
	else if ( !memcmp(ppLines[0], "GET", 3) )
	{
		// GET /pagename.htm HTTP/1.1\r\n
		// If-Modified-Since: Fri, 17 Dec 1999 14:59:20 GMT\r\n
		// Host: localhost:2593\r\n
		// \r\n

		tchar szPageName[_MAX_PATH];
		if ( !Str_GetBare( szPageName, Str_TrimWhitespace(ppRequest[1]), sizeof(szPageName), "!\"#$%&()*,:;<=>?[]^{|}-+'`" ) )
			return false;

		g_Log.Event(LOGM_HTTP|LOGL_EVENT, "%x:HTTP Page Request '%s', alive=%d\n", GetSocketID(), static_cast<lpctstr>(szPageName), fKeepAlive);
		if ( CWebPageDef::ServPage(this, szPageName, &dateIfModifiedSince) )
		{
			if ( fKeepAlive )
				return true;
			return false;
		}
	}


	return false;
}
Пример #7
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);
}