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 ); }
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; }
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; }
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); }