bool AccountMgr::GetName(uint32 acc_id, std::string &name) { QueryResult *result = loginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id); if(result) { name = (*result)[0].GetCppString(); delete result; return true; } return false; }
uint32 AccountMgr::GetSecurity(uint32 acc_id) { QueryResult *result = loginDatabase.PQuery("SELECT gmlevel FROM account WHERE id = '%u'", acc_id); if(result) { uint32 sec = (*result)[0].GetUInt32(); delete result; return sec; } return 0; }
uint32 AccountMgr::GetId(std::string username) { loginDatabase.escape_string(username); QueryResult *result = loginDatabase.PQuery("SELECT id FROM account WHERE username = '******'", username.c_str()); if(!result) return 0; else { uint32 id = (*result)[0].GetUInt32(); delete result; return id; } }
bool AccountMgr::CheckPassword(uint32 accid, std::string passwd) { loginDatabase.escape_string(passwd); QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash=SHA1(CONCAT(UPPER(username),':',UPPER('%s')))", accid, passwd.c_str()); if (result) { delete result; return true; } return false; }
int AccountMgr::ChangePassword(uint32 accid, std::string new_passwd) { QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); if(!result) return 1; // account doesn't exist delete result; loginDatabase.escape_string(new_passwd); if(!loginDatabase.PExecute("UPDATE account SET sha_pass_hash=SHA1(CONCAT(UPPER(username),':',UPPER('%s'))) WHERE id='%d'", new_passwd.c_str(), accid)) return -1; // unexpected error return 0; }
uint32 AccountMgr::GetId(std::string username) { loginDatabase.escape_string(username); QueryResult *result = loginDatabase.PQuery("SELECT `id` FROM `account` WHERE UPPER(`username`)=UPPER('%s')", username.c_str()); if(!result) return 0; else { uint32 id = (*result)[0].GetUInt32(); delete result; return id; } }
int AccountMgr::ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd) { QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM `account` WHERE `id`='%d'", accid); if(!result) return 1; // account doesn't exist delete result; loginDatabase.escape_string(new_uname); loginDatabase.escape_string(new_passwd); if(!loginDatabase.PExecute("UPDATE `account` SET `username`='%s',`I`=SHA1(CONCAT(UPPER('%s'),':',UPPER('%s'))) WHERE `id`='%d'", new_uname.c_str(), new_uname.c_str(), new_passwd.c_str(), accid)) return -1; // unexpected error return 0; }
AccountOpResult AccountMgr::DeleteAccount(uint32 accid) { QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); if(!result) return AOR_NAME_NOT_EXIST; // account doesn't exist delete result; result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE account='%d'",accid); if (result) { do { Field *fields = result->Fetch(); uint32 guidlo = fields[0].GetUInt32(); uint64 guid = MAKE_NEW_GUID(guidlo, 0, HIGHGUID_PLAYER); // kick if player currently if(Player* p = ObjectAccessor::FindPlayer(guid)) { WorldSession* s = p->GetSession(); s->KickPlayer(); // mark session to remove at next session list update s->LogoutPlayer(false); // logout player without waiting next session list update } Player::DeleteFromDB(guid, accid, false); // no need to update realm characters } while (result->NextRow()); delete result; } // table realm specific but common for all characters of account for realm CharacterDatabase.PExecute("DELETE FROM character_tutorial WHERE account = '%u'",accid); loginDatabase.BeginTransaction(); bool res = loginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) && loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid); loginDatabase.CommitTransaction(); if(!res) return AOR_DB_INTERNAL_ERROR; // unexpected error; return AOR_OK; }
AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd) { QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); if(!result) return AOR_NAME_NOT_EXIST; // account doesn't exist delete result; if (utf8length(new_passwd) > MAX_ACCOUNT_STR) return AOR_PASS_TOO_LONG; normilizeString(new_passwd); loginDatabase.escape_string(new_passwd); if(!loginDatabase.PExecute("UPDATE account SET sha_pass_hash=SHA1(CONCAT(username,':','%s')) WHERE id='%d'", new_passwd.c_str(), accid)) return AOR_DB_INTERNAL_ERROR; // unexpected error return AOR_OK; }
int AccountMgr::DeleteAccount(uint32 accid) { QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); if(!result) return 1; // account doesn't exist delete result; result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE account='%d'",accid); if (result) { do { Field *fields = result->Fetch(); uint32 guidlo = fields[0].GetUInt32(); uint64 guid = MAKE_GUID(guidlo, HIGHGUID_PLAYER); // kick if player currently if(Player* p = objmgr.GetPlayer(guid)) { WorldSession* s = p->GetSession(); s->KickPlayer(); // mark session to remove at next session list update s->LogoutPlayer(false); // logout player without waiting next session list update } Player::DeleteFromDB(guid, accid, false); // no need to update realm characters } while (result->NextRow()); delete result; } loginDatabase.BeginTransaction(); bool res = loginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) && loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid); loginDatabase.CommitTransaction(); if(!res) return -1; // unexpected error; return 0; }
int AccountMgr::CreateAccount(std::string username, std::string password) { if(username.length() > 16) return 1; // username's too long loginDatabase.escape_string(username); QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM `account` WHERE `username`='%s'", username.c_str()); if(result) { delete result; return 2; // username does already exist } loginDatabase.escape_string(password); if(!loginDatabase.PExecute("INSERT INTO `account`(`username`,`I`,`joindate`) VALUES('%s',SHA1(CONCAT(UPPER('%s'),':',UPPER('%s'))),NOW())", username.c_str(), username.c_str(), password.c_str())) return -1; // unexpected error loginDatabase.Execute("INSERT INTO `realmcharacters` (`realmid`, `acctid`, `numchars`) SELECT `realmlist`.`id`, `account`.`id`, 0 FROM `account`, `realmlist` WHERE `account`.`id` NOT IN (SELECT `acctid` FROM `realmcharacters`)"); return 0; // everything's fine }
int AccountMgr::CreateAccount(std::string username, std::string password) { if(username.length() > 16) return 1; // username's too long std::transform( username.begin(), username.end(), username.begin(), ::toupper ); loginDatabase.escape_string(username); QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE username='******'", username.c_str()); if(result) { delete result; return 2; // username does already exist } loginDatabase.escape_string(password); if(!loginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s',SHA1(CONCAT(UPPER('%s'),':',UPPER('%s'))),NOW())", username.c_str(), username.c_str(), password.c_str())) return -1; // unexpected error loginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM account, realmlist WHERE account.id NOT IN (SELECT acctid FROM realmcharacters)"); return 0; // everything's fine }
AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password) { if(utf8length(username) > MAX_ACCOUNT_STR) return AOR_NAME_TOO_LONG; // username's too long normilizeString(username); normilizeString(password); loginDatabase.escape_string(username); loginDatabase.escape_string(password); QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE username = '******'", username.c_str()); if(result) { delete result; return AOR_NAME_ALREDY_EXIST; // username does already exist } if(!loginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s',SHA1(CONCAT('%s',':','%s')),NOW())", username.c_str(), username.c_str(), password.c_str())) return AOR_DB_INTERNAL_ERROR; // unexpected error loginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist,account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL"); return AOR_OK; // everything's fine }
/// %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()); SetCloseAndDelete(); return false; } uint32 id = (*result)[0].GetUInt32(); std::string rI = (*result)[1].GetCppString(); delete result; ///- Update realm list if need m_realmList.UpdateIfNeed(); ///- Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) 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++ ) { uint8 AmountOfCharacters; // 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; } else AmountOfCharacters = 0; uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; pkt << i->second.icon; // realm type pkt << lock; // if 1, then realm locked pkt << i->second.color; // if 2, then realm is offline pkt << i->first; pkt << i->second.address; pkt << i->second.populationLevel; 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 const*)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) result = dbRealmServer.PQuery("SELECT `I`,`id`,`locked`,`last_ip`,`gmlevel` 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 uint8 secLevel = (*result)[4].GetUInt8(); _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; QueryResult *localeresult = dbRealmServer.PQuery("SELECT `locale` FROM `localization` WHERE `string` = '%c%c'",ch->country[3],ch->country[2]); if( localeresult ) _localization=(*localeresult)[0].GetUInt8(); else _localization=LOCALE_ENG; if (_localization>=MAX_LOCALE) _localization=LOCALE_ENG; sLog.outBasic("[AuthChallenge] acount %s is using '%c%c' locale (%u)", _login.c_str (), ch->country[3],ch->country[2], _localization); } } 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 const*)pkt.contents(), pkt.size()); return true; }
void SQLStorage::Load () { uint32 maxi; Field *fields; QueryResult *result = WorldDatabase.PQuery("SELECT MAX(%s) FROM %s",entry_field,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 = WorldDatabase.PQuery("SELECT COUNT(*) FROM %s",table); if(result) { fields = result->Fetch(); RecordCount=fields[0].GetUInt32(); delete result; } else RecordCount = 0; result = WorldDatabase.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-compatible table. } //get struct size uint32 sc=0; uint32 bo=0; uint32 bb=0; for(uint32 x=0;x<iNumFields;x++) if(format[x]==FT_STRING) ++sc; else if (format[x]==FT_LOGIC) ++bo; else if (format[x]==FT_BYTE) ++bb; recordsize=(iNumFields-sc-bo-bb)*4+sc*sizeof(char*)+bo*sizeof(bool)+bb*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_LOGIC: *((bool*)(&p[offset]))=(fields[x].GetUInt32()>0); offset+=sizeof(bool); break; case FT_BYTE: *((char*)(&p[offset]))=(fields[x].GetUInt8()); offset+=sizeof(char); break; 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 const* tmp = 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; pIndex =newIndex; MaxEntry=maxi; data=_data; }