Client* ClientConnectionSet::FindAccount(AccountID accountID, uint32_t excludeClient) { CS::Threading::RecursiveMutexScopedLock lock(mutex); AddressHash::GlobalIterator it(addrHash.GetIterator()); while(it.HasNext()) { Client* p = it.Next(); if(p->GetAccountID() == accountID && p->GetClientNum() != excludeClient) return p; } return NULL; }
void NPC::_AwardBounty(SystemEntity *who) { //double bounty = m_self->entityKillBounty(); double bounty = m_self->GetAttribute(AttrEntityKillBounty).get_float(); if(bounty <= 0) { return; //no bounty to award... } //TODO: handle case where drone strikes fatal blow... bounty goes to master. //TODO: handle distribution to gangs. if(who->IsClient() == false) { _log(NPC__TRACE, "Refusing to award bounty on %u to non-client %u", GetID(), who->GetID()); return; //bounty doesn't make sense for anything other than clients. } Client *killer = who->CastToClient(); killer->AddBalance(bounty); std::string reason = "Bounty"; //TODO: improve this. if(!m_services.serviceDB().GiveCash( killer->GetID(), RefType_playerDonation, //TODO: find the proper type m_self->itemID(), //probably actually a special concord item ID or something. killer->GetID(), "", //unknown const char *argID1, killer->GetAccountID(), accountCash, bounty, killer->GetBalance(), reason.c_str() )) { codelog(CLIENT__ERROR, "%s: Failed to record bountry of %f from death of %u (type %u)", killer->GetName(), bounty, GetID(), m_self->typeID()); //well.. this isnt a huge deal, so we will get over it. } }
void AuthenticationServer::HandleAuthent(MsgEntry *me, Client *notused) { csTicks start = csGetTicks(); psAuthenticationMessage msg(me); // This cracks message into members. if (!msg.valid) { Debug1(LOG_NET,me->clientnum,"Mangled psAuthenticationMessage received.\n"); return; } if (!CheckAuthenticationPreCondition(me->clientnum, msg.NetVersionOk(),msg.sUser)) return; csString status; status.Format("%s, %u, Received Authentication Message", (const char *) msg.sUser, me->clientnum); psserver->GetLogCSV()->Write(CSV_AUTHENT, status); if ( msg.sUser.Length() == 0 || msg.sPassword.Length() == 0) { psserver->RemovePlayer(me->clientnum,"No username or password entered"); Notify2(LOG_CONNECTIONS,"User '%s' authentication request rejected: No username or password.\n", (const char *)msg.sUser); return; } // Check if login was correct Notify2(LOG_CONNECTIONS,"Check Login for: '%s'\n", (const char*)msg.sUser); psAccountInfo *acctinfo=CacheManager::GetSingleton().GetAccountInfoByUsername((const char *)msg.sUser); if ( !acctinfo ) { // invalid psserver->RemovePlayer(me->clientnum,"Incorrect password or username."); Notify2(LOG_CONNECTIONS,"User '%s' authentication request rejected: No account found with that name.\n", (const char *)msg.sUser); return; } // Add account to cache to optimize repeated login attempts CacheManager::GetSingleton().AddToCache(acctinfo,msg.sUser,120); // Check if password was correct csString passwordhashandclientnum (acctinfo->password); passwordhashandclientnum.Append(":"); passwordhashandclientnum.Append(me->clientnum); csString encoded_hash = csMD5::Encode(passwordhashandclientnum).HexString(); if (strcmp( encoded_hash.GetData() , msg.sPassword.GetData())) // authentication error { psserver->RemovePlayer(me->clientnum, "Incorrect password or username."); Notify2(LOG_CONNECTIONS,"User '%s' authentication request rejected (Bad password).",(const char *)msg.sUser); // No delete necessary because AddToCache will auto-delete // delete acctinfo; return; } /** * Check if the client is already logged in */ Client* existingClient = clients->FindAccount(acctinfo->accountid, me->clientnum); if (existingClient) // account already logged in { // invalid authent message from a different client csString reason; if(existingClient->IsZombie()) { reason.Format("Your character(%s) was still in combat or casting a spell when you disconnected. " "This connection is being overridden by a new login.", existingClient->GetName()); } else { reason.Format("You are already logged on to this server as %s. " "This connection is being overridden by a new login..", existingClient->GetName()); } psserver->RemovePlayer(existingClient->GetClientNum(), reason); Notify2(LOG_CONNECTIONS,"User '%s' authentication request overrides an existing logged in user.\n", (const char *)msg.sUser); // No delete necessary because AddToCache will auto-delete // delete acctinfo; } if(csGetTicks() - start > 500) { csString status; status.Format("Warning: Spent %u time authenticating account ID %u, After password check", csGetTicks() - start, acctinfo->accountid); psserver->GetLogCSV()->Write(CSV_STATUS, status); } Client *client = clients->FindAny(me->clientnum); if (!client) { Bug2("Couldn't find client %d?!?",me->clientnum); // No delete necessary because AddToCache will auto-delete // delete acctinfo; return; } client->SetName(msg.sUser); client->SetAccountID( acctinfo->accountid ); // Check to see if the client is banned time_t now = time(0); BanEntry* ban = banmanager.GetBanByAccount(acctinfo->accountid); if (ban == NULL) { // Account not banned; try IP range ban = banmanager.GetBanByIPRange(client->GetIPRange()); // 2 day IP ban limit removed //if (ban && ban->end && now > ban->start + IP_RANGE_BAN_TIME) //{ // // Only ban by IP range for the first 2 days // ban = NULL; //} } if (ban) { if (now > ban->end) // Time served { banmanager.RemoveBan(acctinfo->accountid); } else // Notify and block { tm* timeinfo = gmtime(&(ban->end)); csString banmsg; banmsg.Format("You are banned until %d-%d-%d %d:%d GMT. Reason: %s", timeinfo->tm_year+1900, timeinfo->tm_mon+1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, ban->reason.GetData() ); psserver->RemovePlayer(me->clientnum, banmsg); Notify2(LOG_CONNECTIONS,"User '%s' authentication request rejected (Banned).",(const char *)msg.sUser); // No delete necessary because AddToCache will auto-delete // delete acctinfo; return; } } if(csGetTicks() - start > 500) { csString status; status.Format("Warning: Spent %u time authenticating account ID %u, After ban check", csGetTicks() - start, acctinfo->accountid); psserver->GetLogCSV()->Write(CSV_STATUS, status); } /** Check to see if there are any players on that account. All accounts should have * at least one player in this function. */ psCharacterList *charlist = psserver->CharacterLoader.LoadCharacterList(acctinfo->accountid); if (!charlist) { Error2("Could not load Character List for account! Rejecting client %s!\n",(const char *)msg.sUser); psserver->RemovePlayer( me->clientnum, "Could not load the list of characters for your account. Please contact a PS Admin for help."); delete acctinfo; return; } // cache will auto-delete this ptr if it times out CacheManager::GetSingleton().AddToCache(charlist, CacheManager::GetSingleton().MakeCacheName("list", client->GetAccountID().Unbox()),120); /** * CHECK 6: Connection limit * * We check against number of concurrent connections, but players with * security rank of GameMaster or higher are not subject to this limit. */ if (psserver->IsFull(clients->Count(),client)) { // invalid psserver->RemovePlayer(me->clientnum, "The server is full right now. Please try again in a few minutes."); Notify2(LOG_CONNECTIONS, "User '%s' authentication request rejected: Too many connections.\n", (const char *)msg.sUser ); // No delete necessary because AddToCache will auto-delete // delete acctinfo; status = "User limit hit!"; psserver->GetLogCSV()->Write(CSV_STATUS, status); return; } Notify3(LOG_CONNECTIONS,"User '%s' (%d) added to active client list\n",(const char*) msg.sUser, me->clientnum); // Get the struct to refresh // Update last login ip and time char addr[20]; client->GetIPAddress(addr); acctinfo->lastloginip = addr; tm* gmtm = gmtime(&now); csString timeStr; timeStr.Format("%d-%02d-%02d %02d:%02d:%02d", gmtm->tm_year+1900, gmtm->tm_mon+1, gmtm->tm_mday, gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec); acctinfo->lastlogintime = timeStr; acctinfo->os = msg.os_; acctinfo->gfxcard = msg.gfxcard_; acctinfo->gfxversion = msg.gfxversion_; CacheManager::GetSingleton().UpdateAccountInfo(acctinfo); iCachedObject *obj = CacheManager::GetSingleton().RemoveFromCache(CacheManager::GetSingleton().MakeCacheName("auth",acctinfo->accountid)); CachedAuthMessage *cam; if (!obj) { // Send approval message psAuthApprovedMessage *message = new psAuthApprovedMessage(me->clientnum,client->GetPID(), charlist->GetValidCount() ); if(csGetTicks() - start > 500) { csString status; status.Format("Warning: Spent %u time authenticating account ID %u, After approval", csGetTicks() - start, acctinfo->accountid); psserver->GetLogCSV()->Write(CSV_STATUS, status); } // Send out the character list to the auth'd player for (int i=0; i<MAX_CHARACTERS_IN_LIST; i++) { if (charlist->GetEntryValid(i)) { // Quick load the characters to get enough info to send to the client psCharacter* character = psserver->CharacterLoader.QuickLoadCharacterData( charlist->GetCharacterID(i), false ); if (character == NULL) { Error2("QuickLoadCharacterData failed for character '%s'", charlist->GetCharacterName(i)); continue; } Notify3(LOG_CHARACTER, "Sending %s to client %d\n", character->name.GetData(), me->clientnum ); character->AppendCharacterSelectData(*message); delete character; } } message->ConstructMsg(); cam = new CachedAuthMessage(message); } else { // recover underlying object cam = (CachedAuthMessage *)obj->RecoverObject(); // update client id since new connection here cam->msg->msg->clientnum = me->clientnum; } // Send auth approved and char list in one message now cam->msg->SendMessage(); CacheManager::GetSingleton().AddToCache(cam, CacheManager::GetSingleton().MakeCacheName("auth",acctinfo->accountid), 10); SendMsgStrings(me->clientnum, true); client->SetSpamPoints(acctinfo->spamPoints); client->SetAdvisorPoints(acctinfo->advisorPoints); client->SetSecurityLevel(acctinfo->securitylevel); if (acctinfo->securitylevel >= GM_TESTER) { psserver->GetAdminManager()->Admin(me->clientnum, client); } if (CacheManager::GetSingletonPtr()->GetCommandManager()->Validate(client->GetSecurityLevel(), "default advisor")) psserver->GetAdviceManager()->AddAdvisor(client); if (CacheManager::GetSingletonPtr()->GetCommandManager()->Validate(client->GetSecurityLevel(), "default buddylisthide")) client->SetBuddyListHide(true); psserver->GetWeatherManager()->SendClientGameTime(me->clientnum); if(csGetTicks() - start > 500) { csString status; status.Format("Warning: Spent %u time authenticating account ID %u, After load", csGetTicks() - start, acctinfo->accountid); psserver->GetLogCSV()->Write(CSV_STATUS, status); } status.Format("%s - %s, %u, Logged in", addr, (const char*) msg.sUser, me->clientnum); psserver->GetLogCSV()->Write(CSV_AUTHENT, status); }
bool WorldServer::Process() { ServerPacket *app = nullptr; while(app = connection->PopPacket()) { server_log->WorldTrace("Application packet received from server: 0x%.4X, (size %u)", app->opcode, app->size); if (server_log->DumpIn()) { DumpPacket(app); } switch(app->opcode) { case ServerOP_NewLSInfo: { if(app->size < sizeof(ServerNewLSInfo_Struct)) { server_log->Log(log_network_error, "Received application packet from server that had opcode ServerOP_NewLSInfo, " "but was too small. Discarded to avoid buffer overrun."); break; } server_log->WorldTrace("New Login Info Received."); ServerNewLSInfo_Struct *info = (ServerNewLSInfo_Struct*)app->pBuffer; Handle_NewLSInfo(info); break; } case ServerOP_LSStatus: { if(app->size < sizeof(ServerLSStatus_Struct)) { server_log->Log(log_network_error, "Received application packet from server that had opcode ServerOP_LSStatus, " "but was too small. Discarded to avoid buffer overrun."); break; } server_log->WorldTrace("World Server Status Received."); ServerLSStatus_Struct *ls_status = (ServerLSStatus_Struct*)app->pBuffer; Handle_LSStatus(ls_status); break; } case ServerOP_LSZoneInfo: case ServerOP_LSZoneShutdown: case ServerOP_LSZoneStart: case ServerOP_LSZoneBoot: case ServerOP_LSZoneSleep: case ServerOP_LSPlayerLeftWorld: case ServerOP_LSPlayerJoinWorld: case ServerOP_LSPlayerZoneChange: { //Not logging these to cut down on spam until we implement them break; } case ServerOP_UsertoWorldResp: { if(app->size < sizeof(UsertoWorldResponse_Struct)) { server_log->Log(log_network_error, "Received application packet from server that had opcode ServerOP_UsertoWorldResp, " "but was too small. Discarded to avoid buffer overrun."); break; } //I don't use world trace for this and here is why: //Because this is a part of the client login procedure it makes tracking client errors //While keeping world server spam with multiple servers connected almost impossible. server_log->Trace("User-To-World Response received."); UsertoWorldResponse_Struct *utwr = (UsertoWorldResponse_Struct*)app->pBuffer; server_log->Log(log_client, "Trying to find client with user id of %u.", utwr->lsaccountid); Client *c = server.CM->GetClient(utwr->lsaccountid); if(c && c->GetClientVersion() == cv_old) { if(utwr->response > 0) { SendClientAuth(c->GetConnection()->GetRemoteIP(), c->GetAccountName(), c->GetKey(), c->GetAccountID(), c->GetMacClientVersion()); } switch(utwr->response) { case 1: break; case 0: c->FatalError("\nError 1020: Your chosen World Server is DOWN.\n\nPlease select another."); break; case -1: c->FatalError("You have been suspended from the worldserver."); break; case -2: c->FatalError("You have been banned from the worldserver."); break; case -3: c->FatalError("That server is full."); break; case -4: c->FatalError("Error 1018: You currently have an active character on that EverQuest Server, please allow a minute for synchronization and try again."); break; case -5: c->FatalError("Error IP Limit Exceeded: \n\nYou have exceeded the maximum number of allowed IP addresses for this account."); break; } server_log->Log(log_client, "Found client with user id of %u and account name of %s.", utwr->lsaccountid, c->GetAccountName().c_str()); EQApplicationPacket *outapp = new EQApplicationPacket(OP_PlayEverquestRequest, 17); strncpy((char*) &outapp->pBuffer[1], c->GetKey().c_str(), c->GetKey().size()); c->SendPlayResponse(outapp); } else if(c) { server_log->Log(log_client, "Found client with user id of %u and account name of %s.", utwr->lsaccountid, c->GetAccountName().c_str()); EQApplicationPacket *outapp = new EQApplicationPacket(OP_PlayEverquestResponse, sizeof(PlayEverquestResponse_Struct)); PlayEverquestResponse_Struct *per = (PlayEverquestResponse_Struct*)outapp->pBuffer; per->Sequence = c->GetPlaySequence(); per->ServerNumber = c->GetPlayServerID(); server_log->Log(log_client, "Found sequence and play of %u %u", c->GetPlaySequence(), c->GetPlayServerID()); server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size); if (utwr->response > 0) { per->Allowed = 1; SendClientAuth(c->GetConnection()->GetRemoteIP(), c->GetAccountName(), c->GetKey(), c->GetAccountID()); } switch (utwr->response) { case 1: per->Message = 101; break; case 0: per->Message = 326; break; case -1: per->Message = 337; break; case -2: per->Message = 338; break; case -3: per->Message = 303; break; case -4: per->Message = 111; break; case -5: per->Message = 198; break; } server_log->Trace("Sending play response to client."); server_log->TracePacket((const char*)outapp->pBuffer, outapp->size); if (server_log->DumpOut()) { DumpPacket(outapp); } c->SendPlayResponse(outapp); delete outapp; } else { server_log->Log(log_client_error, "Received User-To-World Response for %u but could not find the client referenced!.", utwr->lsaccountid); } break; } case ServerOP_LSAccountUpdate: { if(app->size < sizeof(ServerLSAccountUpdate_Struct)) { server_log->Log(log_network_error, "Received application packet from server that had opcode ServerLSAccountUpdate_Struct, " "but was too small. Discarded to avoid buffer overrun."); break; } server_log->Log(log_network_trace, "ServerOP_LSAccountUpdate packet received from: %s", short_name.c_str()); ServerLSAccountUpdate_Struct *lsau = (ServerLSAccountUpdate_Struct*)app->pBuffer; if(trusted) { server_log->Log(log_network_trace, "ServerOP_LSAccountUpdate update processed for: %s", lsau->useraccount); string name; string password; string email; name.assign(lsau->useraccount); password.assign(lsau->userpassword); email.assign(lsau->useremail); db.CreateLSAccount(name, password, email, 0, "", ""); } break; } default: { server_log->Log(log_network_error, "Received application packet from server that had an unknown operation code 0x%.4X.", app->opcode); } } delete app; app = nullptr; } return true; }
bool WorldServer::Process() { ServerPacket *app = nullptr; while(app = connection->PopPacket()) { if(server.options.IsWorldTraceOn()) { server_log->Log(log_network_trace, "Application packet received from server: 0x%.4X, (size %u)", app->opcode, app->size); } if(server.options.IsDumpInPacketsOn()) { DumpPacket(app); } switch(app->opcode) { case ServerOP_NewLSInfo: { if(app->size < sizeof(ServerNewLSInfo_Struct)) { server_log->Log(log_network_error, "Received application packet from server that had opcode ServerOP_NewLSInfo, " "but was too small. Discarded to avoid buffer overrun."); break; } if(server.options.IsWorldTraceOn()) { server_log->Log(log_network_trace, "New Login Info Recieved."); } ServerNewLSInfo_Struct *info = (ServerNewLSInfo_Struct*)app->pBuffer; Handle_NewLSInfo(info); break; } case ServerOP_LSStatus: { if(app->size < sizeof(ServerLSStatus_Struct)) { server_log->Log(log_network_error, "Recieved application packet from server that had opcode ServerOP_LSStatus, " "but was too small. Discarded to avoid buffer overrun."); break; } if(server.options.IsWorldTraceOn()) { server_log->Log(log_network_trace, "World Server Status Recieved."); } ServerLSStatus_Struct *ls_status = (ServerLSStatus_Struct*)app->pBuffer; Handle_LSStatus(ls_status); break; } case ServerOP_LSZoneInfo: case ServerOP_LSZoneShutdown: case ServerOP_LSZoneStart: case ServerOP_LSZoneBoot: case ServerOP_LSZoneSleep: case ServerOP_LSPlayerLeftWorld: case ServerOP_LSPlayerJoinWorld: case ServerOP_LSPlayerZoneChange: { //Not logging these to cut down on spam until we implement them break; } case ServerOP_UsertoWorldResp: { if(app->size < sizeof(UsertoWorldResponse_Struct)) { server_log->Log(log_network_error, "Recieved application packet from server that had opcode ServerOP_UsertoWorldResp, " "but was too small. Discarded to avoid buffer overrun."); break; } //I don't use world trace for this and here is why: //Because this is a part of the client login procedure it makes tracking client errors //While keeping world server spam with multiple servers connected almost impossible. if(server.options.IsTraceOn()) { server_log->Log(log_network_trace, "User-To-World Response received."); } UsertoWorldResponse_Struct *utwr = (UsertoWorldResponse_Struct*)app->pBuffer; server_log->Log(log_client, "Trying to find client with user id of %u.", utwr->lsaccountid); Client *c = server.CM->GetClient(utwr->lsaccountid); if(c) { server_log->Log(log_client, "Found client with user id of %u and account name of %s.", utwr->lsaccountid, c->GetAccountName().c_str()); EQApplicationPacket *outapp = new EQApplicationPacket(OP_PlayEverquestResponse, sizeof(PlayEverquestResponse_Struct)); PlayEverquestResponse_Struct *per = (PlayEverquestResponse_Struct*)outapp->pBuffer; per->Sequence = c->GetPlaySequence(); per->ServerNumber = c->GetPlayServerID(); server_log->Log(log_client, "Found sequence and play of %u %u", c->GetPlaySequence(), c->GetPlayServerID()); server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size); if(utwr->response > 0) { per->Allowed = 1; SendClientAuth(c->GetConnection()->GetRemoteIP(), c->GetAccountName(), c->GetKey(), c->GetAccountID()); } switch(utwr->response) { case 1: per->Message = 101; break; case 0: per->Message = 326; break; case -1: per->Message = 337; break; case -2: per->Message = 338; break; case -3: per->Message = 303; break; } if(server.options.IsTraceOn()) { server_log->Log(log_network_trace, "Sending play response with following data, allowed %u, sequence %u, server number %u, message %u", per->Allowed, per->Sequence, per->ServerNumber, per->Message); server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size); } if(server.options.IsDumpOutPacketsOn()) { DumpPacket(outapp); } c->SendPlayResponse(outapp); delete outapp; } else { server_log->Log(log_client_error, "Recieved User-To-World Response for %u but could not find the client referenced!.", utwr->lsaccountid); } break; } case ServerOP_LSAccountUpdate: { server_log->Log(log_network_trace, "ServerOP_LSAccountUpdate packet received from: %s", short_name.c_str()); ServerLSAccountUpdate_Struct *lsau = (ServerLSAccountUpdate_Struct*)app->pBuffer; if(trusted) { server_log->Log(log_network_trace, "ServerOP_LSAccountUpdate update processed for: %s", lsau->useraccount); string name; string password; string email; name.assign(lsau->useraccount); password.assign(lsau->userpassword); email.assign(lsau->useremail); server.db->UpdateLSAccountInfo(lsau->useraccountid, name, password, email); } break; } default: { server_log->Log(log_network_error, "Recieved application packet from server that had an unknown operation code 0x%.4X.", app->opcode); } } delete app; app = nullptr; } return true; }