bool isPlayerHasGuildhouse(Player *player, Creature *_creature, bool whisper = false) { QueryResult *result; result = SD2Database.PQuery("SELECT `comment` FROM `guildhouses` WHERE `guildId` = %u", player->GetGuildId()); if (result) { if (whisper) { //whisper to player "already have etc..." Field *fields = result->Fetch(); char msg[100]; sprintf(msg, MSG_ALREADYHAVEGH, fields[0].GetString()); _creature->MonsterWhisper(msg, player->GetGUID()); } delete result; return true; } return false; }
bool showBuyList(Player *player, Creature *_creature, uint32 showFromId = 0) { //show not occupied guildhouses QueryResult *result; result = SD2Database.PQuery("SELECT `id`, `comment` FROM `guildhouses` WHERE `guildId` = 0 AND `id` > %u ORDER BY `id` ASC LIMIT %u", showFromId, GOSSIP_COUNT_MAX); if (result) { uint32 guildhouseId = 0; std::string comment = ""; do { Field *fields = result->Fetch(); guildhouseId = fields[0].GetInt32(); comment = fields[1].GetString(); //send comment as a gossip item //transmit guildhouseId in Action variable player->ADD_GOSSIP_ITEM(ICON_GOSSIP_TABARD, comment, GOSSIP_SENDER_MAIN, guildhouseId + OFFSET_GH_ID_TO_ACTION); } while (result->NextRow()); if (result->GetRowCount() == GOSSIP_COUNT_MAX) { //assume that we have additional page //add link to next GOSSIP_COUNT_MAX items player->ADD_GOSSIP_ITEM(ICON_GOSSIP_BALOONDOTS, MSG_GOSSIP_NEXTPAGE, GOSSIP_SENDER_MAIN, guildhouseId + OFFSET_SHOWBUY_FROM); } delete result; player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, _creature->GetGUID()); return true; } else { if (showFromId = 0) { //all guildhouses are occupied _creature->MonsterWhisper(MSG_NOFREEGH, player->GetGUID()); player->CLOSE_GOSSIP_MENU(); } else { //this condition occurs when COUNT(guildhouses) % GOSSIP_COUNT_MAX == 0 //just show GHs from beginning showBuyList(player, _creature, 0); } } return false; }
void buyGuildhouse(Player *player, Creature *_creature, uint32 guildhouseId) { if (player->GetMoney() < COST_GH_BUY) { //show how much money player need to buy GH (in gold) char msg[100]; sprintf(msg, MSG_NOTENOUGHMONEY, COST_GH_BUY / 10000); _creature->MonsterWhisper(msg, player->GetGUID()); return; } if (isPlayerHasGuildhouse(player, _creature, true)) { //player already have GH return; } QueryResult *result; //check if somebody already occupied this GH result = SD2Database.PQuery("SELECT `id` FROM `guildhouses` WHERE `id` = %u AND `guildId` <> 0", guildhouseId); if (result) { delete result; _creature->MonsterWhisper(MSG_GHOCCUPIED, player->GetGUID()); return; } //update DB result = SD2Database.PQuery("UPDATE `guildhouses` SET `guildId` = %u WHERE `id` = %u", player->GetGuildId(), guildhouseId); if (result) delete result; player->ModifyMoney(-COST_GH_BUY); _creature->MonsterSay(MSG_CONGRATULATIONS, LANG_UNIVERSAL, player->GetGUID()); }
void sellGuildhouse(Player *player, Creature *_creature) { if (isPlayerHasGuildhouse(player, _creature)) { QueryResult *result; result = SD2Database.PQuery("UPDATE `guildhouses` SET `guildId` = 0 WHERE `guildId` = %u", player->GetGuildId()); if (result) delete result; player->ModifyMoney(COST_GH_SELL); //display message e.g. "here your money etc." char msg[100]; sprintf(msg, MSG_SOLD, COST_GH_SELL / 10000); _creature->MonsterWhisper(msg, player->GetGUID()); } }
bool getGuildHouseCoords(uint32 guildId, float &x, float &y, float &z, uint32 &map) { if (guildId == 0) { //if player has no guild return false; } QueryResult *result; result = SD2Database.PQuery("SELECT `x`, `y`, `z`, `map` FROM `guildhouses` WHERE `guildId` = %u", guildId); if(result) { Field *fields = result->Fetch(); x = fields[0].GetFloat(); y = fields[1].GetFloat(); z = fields[2].GetFloat(); map = fields[3].GetUInt32(); delete result; return true; } return false; }
void SQLStorage::Load () { uint32 maxi; Field *fields; QueryResult *result = sDatabase.PQuery("SELECT MAX(`entry`) FROM `%s`",table); if(!result) { sLog.outError("Error loading `%s` table (not exist?)\n",table); exit(1); // Stop server at loading non exited table or not accessable table } maxi= (*result)[0].GetUInt32()+1; delete result; result = sDatabase.PQuery("SELECT COUNT(*) FROM `%s`",table); fields = result->Fetch(); RecordCount=fields[0].GetUInt32(); delete result; result = sDatabase.PQuery("SELECT * FROM `%s`",table); if(!result) { sLog.outError("`%s` table is empty!\n",table); RecordCount = 0; return; } uint32 recordsize=0; uint32 offset=0; if(iNumFields!=result->GetFieldCount()) { RecordCount = 0; sLog.outError("Error in `%s` table, probably sql file format was updated (there should be %d fields in sql).\n",table,iNumFields); delete result; exit(1); // Stop server at loading broken or non-compatiable table. } if(sizeof(char*)==sizeof(uint32)) recordsize=4*iNumFields; else { //get struct size uint32 sc=0; for(uint32 x=0;x<iNumFields;x++) if(format[x]==FT_STRING) sc++; recordsize=(iNumFields-sc)*4+sc*sizeof(char*); } char** newIndex=new char*[maxi]; memset(newIndex,0,maxi*sizeof(char*)); char * _data= new char[RecordCount *recordsize]; uint32 count=0; barGoLink bar( RecordCount ); do { fields = result->Fetch(); bar.step(); char *p=(char*)&_data[recordsize*count]; newIndex[fields[0].GetUInt32()]=p; offset=0; for(uint32 x=0;x<iNumFields;x++) switch(format[x]) { case FT_INT: *((uint32*)(&p[offset]))=fields[x].GetUInt32(); offset+=sizeof(uint32); break; case FT_FLOAT: *((float*)(&p[offset]))=fields[x].GetFloat(); offset+=sizeof(float); break; case FT_STRING: char * tmp=(char*)fields[x].GetString(); char* st; if(!tmp) { st=new char[1]; *st=0; } else { uint32 l=strlen(tmp)+1; st=new char[l]; memcpy(st,tmp,l); } *((char**)(&p[offset]))=st; offset+=sizeof(char*); break; } count++; }while( result->NextRow() ); delete result; if(data) //Reload table AddEvent((EventHandler)(&FreeStorage),this,20000); pOldData=data; pOldIndex=pIndex; iOldNumRecords=MaxEntry; pIndex =newIndex; MaxEntry=maxi; data=_data; }
/// %Realm List command handler bool AuthSocket::_HandleRealmList() { DEBUG_LOG("Entering _HandleRealmList"); if (ibuf.GetLength() < 5) return false; ibuf.Remove(5); ///- Get the user id (else close the connection) // No SQL injection (escaped user name) QueryResult *result = dbRealmServer.PQuery("SELECT `id`,`I` FROM `account` WHERE `username` = '%s'",_safelogin.c_str()); if(!result) { sLog.outError("[ERROR] user %s tried to login and we cannot find him in the database.",_login.c_str()); this->Close(); return false; } uint32 id = (*result)[0].GetUInt32(); std::string rI = (*result)[1].GetCppString(); delete result; ///- Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) uint8 AmountOfCharacters = 0; ByteBuffer pkt; pkt << (uint32) 0; pkt << (uint16) m_realmList.size(); RealmList::RealmMap::const_iterator i; for( i = m_realmList.begin(); i != m_realmList.end(); i++ ) { pkt << i->second->icon; // realm type pkt << (uint8) 0; // if 1, then realm locked pkt << i->second->color; // if 2, then realm is offline pkt << i->first; pkt << i->second->address; /// \todo Fix realm population pkt << (float) 0.0; //this is population 0.5 = low 1.0 = medium 2.0 high (float)(maxplayers / players)*2 // No SQL injection. id of realm is controlled by the database. result = dbRealmServer.PQuery( "SELECT `numchars` FROM `realmcharacters` WHERE `realmid` = '%d' AND `acctid`='%u'",i->second->m_ID,id); if( result ) { Field *fields = result->Fetch(); AmountOfCharacters = fields[0].GetUInt8(); delete result; } pkt << AmountOfCharacters; pkt << i->second->timezone; pkt << (uint8) 0x2C; // unk, may be realm number/id? } pkt << (uint8) 0x10; pkt << (uint8) 0x00; ByteBuffer hdr; hdr << (uint8) REALM_LIST; hdr << (uint16)pkt.size(); hdr.append(pkt); SendBuf((char *)hdr.contents(), hdr.size()); // Set check field before possable relogin to realm _SetVSFields(rI); return true; }
/// Logon Challenge command handler bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); if (ibuf.GetLength() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); ibuf.Read((char *)&buf[0], 4); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (ibuf.GetLength() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet ibuf.Read((char *)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); ByteBuffer pkt; _login = (const char*)ch->I; //Escape the user login to avoid further SQL injection //Memory will be freed on AuthSocket object destruction _safelogin=_login; dbRealmServer.escape_string(_safelogin); ///- Check if the client has one of the expected version numbers bool valid_version=false; int accepted_versions[]=EXPECTED_MANGOS_CLIENT_BUILD; for(int i=0;accepted_versions[i];i++) if(ch->build==accepted_versions[i]) { valid_version=true; break; } /// <ul><li> if this is a valid version if(valid_version) { pkt << (uint8) AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) dbRealmServer.Execute("DELETE FROM `ip_banned` WHERE `unbandate`<=UNIX_TIMESTAMP() AND `unbandate`<>`bandate`"); QueryResult *result = dbRealmServer.PQuery( "SELECT * FROM `ip_banned` WHERE `ip` = '%s'",GetRemoteAddress().c_str()); if(result) { pkt << (uint8)REALM_AUTH_ACCOUNT_BANNED; sLog.outBasic("[AuthChallenge] Banned ip %s tries to login!",GetRemoteAddress().c_str ()); delete result; } else { ///- Get the account details from the account table // No SQL injection (escaped user name) QueryResult *result = dbRealmServer.PQuery("SELECT `I`,`id`,`locked`,`last_ip`,`online` FROM `account` WHERE `username` = '%s'",_safelogin.c_str ()); if( result ) { ///- If the IP is 'locked', check that the player comes indeed from the correct IP address bool locked = false; if((*result)[2].GetUInt8() == 1) // if ip is locked { DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*result)[3].GetString()); DEBUG_LOG("[AuthChallenge] Player address is '%s'", GetRemoteAddress().c_str()); if ( strcmp((*result)[3].GetString(),GetRemoteAddress().c_str()) ) { DEBUG_LOG("[AuthChallenge] Account IP differs"); pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED; locked=true; } else { DEBUG_LOG("[AuthChallenge] Account IP matches"); } } else { DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); } if (!locked) { //set expired bans to inactive dbRealmServer.Execute("UPDATE `account_banned` SET `active` = 0 WHERE `unbandate`<=UNIX_TIMESTAMP() AND `unbandate`<>`bandate`"); ///- If the account is banned, reject the logon attempt QueryResult *banresult = dbRealmServer.PQuery("SELECT `bandate`,`unbandate` FROM `account_banned` WHERE `id` = %u AND `active` = 1", (*result)[1].GetUInt32()); if(banresult) { if((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) { pkt << (uint8) REALM_AUTH_ACCOUNT_BANNED; sLog.outBasic("[AuthChallenge] Banned account %s tries to login!",_login.c_str ()); } else { pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED; sLog.outBasic("[AuthChallenge] Temporarily banned account %s tries to login!",_login.c_str ()); } delete banresult; } else { ///- Get the password from the account table, upper it, and make the SRP6 calculation std::string rI = (*result)[0].GetCppString(); _SetVSFields(rI); b.SetRand(19 * 8); BigNumber gmod=g.ModExp(b, N); B = ((v * 3) + gmod) % N; ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk3; unk3.SetRand(16*8); ///- Fill the response packet with the result pkt << (uint8)REALM_AUTH_SUCCESS; pkt.append(B.AsByteArray(), 32); pkt << (uint8)1; pkt.append(g.AsByteArray(), 1); pkt << (uint8)32; pkt.append(N.AsByteArray(), 32); pkt.append(s.AsByteArray(), s.GetNumBytes()); pkt.append(unk3.AsByteArray(), 16); pkt << (uint8)0; // Added in 1.12.x client branch } } delete result; } else //no account { pkt<< (uint8) REALM_AUTH_NO_MATCH; } } } //valid version else ///<li> else { ///- Check if we have the apropriate patch on the disk char tmp[64]; // No buffer overflow (fixed length of arguments) sprintf(tmp,"./patches/%d%c%c%c%c.mpq",ch->build,ch->country[3], ch->country[2],ch->country[1],ch->country[0]); // This will be closed at the destruction of the AuthSocket (client deconnection) FILE *pFile=fopen(tmp,"rb"); if(!pFile) { pkt << (uint8) AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; pkt << (uint8) REALM_AUTH_WRONG_BUILD_NUMBER; DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", ch->build); DEBUG_LOG("[AuthChallenge] Patch %s not found",tmp); }else { //have patch pPatch=pFile; XFER_INIT xferh; ///- Get the MD5 hash of the patch file (get it from preloaded Patcher cache or calculate it) if(PatchesCache.GetHash(tmp,(uint8*)&xferh.md5)) { DEBUG_LOG("\n[AuthChallenge] Found precached patch info for patch %s",tmp); } else { //calculate patch md5 printf("\n[AuthChallenge] Patch info for %s was not cached.",tmp); PatchesCache.LoadPatchMD5(tmp); PatchesCache.GetHash(tmp,(uint8*)&xferh.md5); } ///- Send a packet to the client with the file length and MD5 hash uint8 data[2]={AUTH_LOGON_PROOF,REALM_AUTH_UPDATE_CLIENT}; SendBuf((const char*)data,sizeof(data)); memcpy(&xferh,"0\x05Patch",7); xferh.cmd=XFER_INITIATE; fseek(pPatch,0,SEEK_END); xferh.file_size=ftell(pPatch); SendBuf((const char*)&xferh,sizeof(xferh)); return true; } } /// </ul> SendBuf((char *)pkt.contents(), pkt.size()); return true; }