void ProtocolStatus::onRecvFirstMessage(NetworkMessage& msg) { uint32_t ip = getIP(); if (ip != 0x0100007F) { std::string ipStr = convertIPToString(ip); if (ipStr != g_config.getString(ConfigManager::IP)) { std::map<uint32_t, int64_t>::const_iterator it = ipConnectMap.find(ip); if (it != ipConnectMap.end() && (OTSYS_TIME() < (it->second + g_config.getNumber(ConfigManager::STATUSQUERY_TIMEOUT)))) { disconnect(); return; } } } ipConnectMap[ip] = OTSYS_TIME(); switch (msg.getByte()) { //XML info protocol case 0xFF: { if (msg.getString(4) == "info") { g_dispatcher.addTask(createTask(std::bind(&ProtocolStatus::sendStatusString, std::static_pointer_cast<ProtocolStatus>(shared_from_this())))); return; } break; } //Another ServerInfo protocol case 0x01: { uint16_t requestedInfo = msg.get<uint16_t>(); // only a Byte is necessary, though we could add new info here std::string characterName; if (requestedInfo & REQUEST_PLAYER_STATUS_INFO) { characterName = msg.getString(); } g_dispatcher.addTask(createTask(std::bind(&ProtocolStatus::sendInfo, std::static_pointer_cast<ProtocolStatus>(shared_from_this()), requestedInfo, characterName))); return; } default: break; } disconnect(); }
void ProtocolSpectator::parseSpectatorSay(NetworkMessage& msg) { SpeakClasses type = (SpeakClasses)msg.getByte(); uint16_t channelId = 0; if (type == TALKTYPE_CHANNEL_Y) { channelId = msg.get<uint16_t>(); } else { return; } const std::string text = msg.getString(); if (text.length() > 255 || channelId != CHANNEL_CAST || !client) { return; } if (client) { g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::broadcastSpectatorMessage, client, text))); } }
void ProtocolSpectator::onRecvFirstMessage(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->close(); return; } operatingSystem = (OperatingSystem_t)msg.get<uint16_t>(); version = msg.get<uint16_t>(); msg.skipBytes(7); // U32 clientVersion, U8 clientType if (!RSA_decrypt(msg)) { getConnection()->close(); return; } uint32_t key[4]; key[0] = msg.get<uint32_t>(); key[1] = msg.get<uint32_t>(); key[2] = msg.get<uint32_t>(); key[3] = msg.get<uint32_t>(); enableXTEAEncryption(); setXTEAKey(key); if (operatingSystem >= CLIENTOS_OTCLIENT_LINUX) { NetworkMessage opcodeMessage; opcodeMessage.addByte(0x32); opcodeMessage.addByte(0x00); opcodeMessage.add<uint16_t>(0x00); writeToOutputBuffer(opcodeMessage); } msg.skipBytes(1); // gamemaster flag std::string password = msg.getString(); std::string characterName = msg.getString(); uint32_t timeStamp = msg.get<uint32_t>(); uint8_t randNumber = msg.getByte(); if (m_challengeTimestamp != timeStamp || m_challengeRandom != randNumber) { getConnection()->close(); return; } auto dispatchDisconnectClient = [this](const std::string& msg) { g_dispatcher.addTask(createTask( std::bind(&ProtocolSpectator::disconnectSpectator, this, msg))); }; if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return; } if (g_game.getGameState() == GAME_STATE_STARTUP) { dispatchDisconnectClient("Gameworld is starting up. Please wait."); return; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { dispatchDisconnectClient("Gameworld is under maintenance. Please re-connect in a while."); return; } BanInfo banInfo; if (IOBan::isIpBanned(getIP(), banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; dispatchDisconnectClient(ss.str()); return; } password.erase(password.begin()); g_dispatcher.addTask(createTask(std::bind(&ProtocolSpectator::login, this, characterName, password))); }
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->close(); return; } msg.skipBytes(2); // client OS uint16_t version = msg.get<uint16_t>(); if (version >= 971) { msg.skipBytes(17); } else { msg.skipBytes(12); } /* * Skipped bytes: * 4 bytes: protocolVersion * 12 bytes: dat, spr, pic signatures (4 bytes each) * 1 byte: 0 */ #define dispatchDisconnectClient(err) g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::disconnectClient, this, err, version))) if (version <= 760) { dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return; } if (!Protocol::RSA_decrypt(msg)) { getConnection()->close(); return; } uint32_t key[4]; key[0] = msg.get<uint32_t>(); key[1] = msg.get<uint32_t>(); key[2] = msg.get<uint32_t>(); key[3] = msg.get<uint32_t>(); enableXTEAEncryption(); setXTEAKey(key); if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return; } if (g_game.getGameState() == GAME_STATE_STARTUP) { dispatchDisconnectClient("Gameworld is starting up. Please wait."); return; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { dispatchDisconnectClient("Gameworld is under maintenance.\nPlease re-connect in a while."); return; } BanInfo banInfo; if (IOBan::isIpBanned(getConnection()->getIP(), banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; dispatchDisconnectClient(ss.str()); return; } std::string accountName = msg.getString(); std::string password = msg.getString(); if (accountName.empty()) { if (!g_config.getBoolean(ConfigManager::ENABLE_LIVE_CASTING)) { dispatchDisconnectClient("Invalid account name."); } else { g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCastingStreamsList, this, password, version))); } return; } #undef dispatchDisconnectClient g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, this, accountName, password, version))); }
void ProtocolManager::parsePacket(NetworkMessage& msg) { if(g_game.getGameState() == GAMESTATE_SHUTDOWN) { getConnection()->close(); return; } uint8_t recvbyte = msg.get<char>(); OutputMessage_ptr output = getOutputBuffer(); if(!output) return; TRACK_MESSAGE(output); switch(m_state) { case NO_LOGGED_IN: { if((time(NULL) - m_startTime) > 30000) { //login timeout getConnection()->close(); addLogLine(LOGTYPE_WARNING, "Login timeout"); return; } if(m_loginTries > 3) { output->put<char>(MP_MSG_ERROR); output->putString("Too many login attempts"); getConnection()->send(output); getConnection()->close(); addLogLine(LOGTYPE_WARNING, "Too many login attempts"); return; } if(recvbyte != MP_MSG_LOGIN) { output->put<char>(MP_MSG_ERROR); output->putString("You are not logged in"); getConnection()->send(output); getConnection()->close(); addLogLine(LOGTYPE_WARNING, "Wrong command while not logged in"); return; } break; } case LOGGED_IN: break; default: { getConnection()->close(); addLogLine(LOGTYPE_ERROR, "No valid connection state"); return; } } m_lastCommand = time(NULL); switch(recvbyte) { case MP_MSG_LOGIN: { if(m_state == NO_LOGGED_IN) { std::string pass = msg.getString(), word = g_config.getString(ConfigManager::MANAGER_PASSWORD); _encrypt(word, false); if(pass == word) { if(!Manager::getInstance()->loginConnection(this)) { output->put<char>(MP_MSG_FAILURE); output->putString("Unknown connection"); getConnection()->send(output); getConnection()->close(); addLogLine(LOGTYPE_ERROR, "Login failed due to unknown connection"); return; } else { m_state = LOGGED_IN; output->put<char>(MP_MSG_USERS); addLogLine(LOGTYPE_EVENT, "Logged in, sending users"); std::map<uint32_t, std::string> users; for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) { if(!it->second->isRemoved()) users[it->first] = it->second->getName(); } output->put<uint16_t>(users.size()); for(std::map<uint32_t, std::string>::iterator it = users.begin(); it != users.end(); ++it) { output->put<uint32_t>(it->first); output->putString(it->second); } } } else { output->put<char>(MP_MSG_FAILURE); output->putString("Wrong password"); m_loginTries++; addLogLine(LOGTYPE_EVENT, "Login failed due to wrong password (" + pass + ")"); } } else { output->put<char>(MP_MSG_FAILURE); output->putString("Cannot login right now!"); addLogLine(LOGTYPE_ERROR, "Wrong state at login"); } break; } case MP_MSG_LOGOUT: { output->put<char>(MP_MSG_BYE); output->putString("Bye, bye!"); getConnection()->send(output); getConnection()->close(); addLogLine(LOGTYPE_EVENT, "Logout"); return; } case MP_MSG_KEEP_ALIVE: break; case MP_MSG_PING: output->put<char>(MP_MSG_PONG); break; case MP_MSG_LUA: { std::string script = msg.getString(); if(!Manager::getInstance()->execute(script)) { output->put<char>(MP_MSG_FAILURE); output->putString("Unable to reserve enviroment for Lua script"); addLogLine(LOGTYPE_ERROR, "Unable to reserve enviroment for Lua script"); } else { output->put<char>(MP_MSG_SUCCESS); addLogLine(LOGTYPE_EVENT, "Executed Lua script"); } break; } case MP_MSG_USER_INFO: { uint32_t playerId = msg.get<uint32_t>(); if(Player* player = g_game.getPlayerByID(playerId)) { output->put<char>(MP_MSG_USER_DATA); output->put<uint32_t>(playerId); output->put<uint32_t>(player->getGroupId()); output->put<uint32_t>(player->getVocationId()); output->put<uint32_t>(player->getLevel()); output->put<uint32_t>(player->getMagicLevel()); // TODO? } else { output->put<char>(MP_MSG_FAILURE); output->putString("Player not found"); } } case MP_MSG_CHAT_REQUEST: { output->put<char>(MP_MSG_CHAT_LIST); ChannelList list = g_chat.getPublicChannels(); output->put<uint16_t>(list.size()); for(ChannelList::const_iterator it = list.begin(); it != list.end(); ++it) { output->put<uint16_t>((*it)->getId()); output->putString((*it)->getName()); output->put<uint16_t>((*it)->getFlags()); output->put<uint16_t>((*it)->getUsers().size()); } break; } case MP_MSG_CHAT_OPEN: { ChatChannel* channel = NULL; uint16_t channelId = msg.get<uint16_t>(); if((channel = g_chat.getChannelById(channelId)) && g_chat.isPublicChannel(channelId)) { m_channels |= (uint32_t)channelId; output->put<char>(MP_MSG_CHAT_USERS); UsersMap users = channel->getUsers(); output->put<uint16_t>(users.size()); for(UsersMap::const_iterator it = users.begin(); it != users.end(); ++it) output->put<uint32_t>(it->first); } else { output->put<char>(MP_MSG_FAILURE); output->putString("Invalid channel"); } break; } case MP_MSG_CHAT_CLOSE: { uint16_t channelId = msg.get<uint16_t>(); if(g_chat.getChannelById(channelId) && g_chat.isPublicChannel(channelId)) { m_channels &= ~(uint32_t)channelId; output->put<char>(MP_MSG_SUCCESS); } else { output->put<char>(MP_MSG_FAILURE); output->putString("Invalid channel"); } break; } case MP_MSG_CHAT_TALK: { std::string name = msg.getString(); uint16_t channelId = msg.get<uint16_t>(); SpeakClasses type = (SpeakClasses)msg.get<char>(); std::string message = msg.getString(); ChatChannel* channel = NULL; if((channel = g_chat.getChannelById(channelId)) && g_chat.isPublicChannel(channelId)) { if(!channel->talk(name, type, message)) { output->put<char>(MP_MSG_FAILURE); output->putString("Could not talk to channel"); } else output->put<char>(MP_MSG_SUCCESS); } else { output->put<char>(MP_MSG_FAILURE); output->putString("Invalid channel"); } break; } default: { output->put<char>(MP_MSG_ERROR); output->putString("Unknown command"); addLogLine(LOGTYPE_WARNING, "Unknown command"); break; } } }
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg) { if( #if defined(WINDOWS) && !defined(_CONSOLE) !GUI::getInstance()->m_connections || #endif g_game.getGameState() == GAMESTATE_SHUTDOWN) { getConnection()->close(); return; } uint32_t clientIp = getConnection()->getIP(); msg.get<uint16_t>(); uint16_t version = msg.get<uint16_t>(); msg.skip(12); #ifdef _MULTIPLATFORM77 if(!RSA_decrypt(msg)) { getConnection()->close(); return; } uint32_t key[4] = {msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>()}; enableXTEAEncryption(); setXTEAKey(key); #endif uint32_t name = msg.get<uint32_t>(); std::string password = msg.getString(); if(!name) { if(!g_config.getBool(ConfigManager::ACCOUNT_MANAGER)) { disconnectClient(0x0A, "Invalid account name."); return; } name = 1; password = "******"; } if(!g_config.getBool(ConfigManager::MANUAL_ADVANCED_CONFIG)) { if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { disconnectClient(0x0A, CLIENT_VERSION_STRING); return; } else if(version < g_config.getNumber(ConfigManager::VERSION_MIN) || version > g_config.getNumber(ConfigManager::VERSION_MAX)) { disconnectClient(0x0A, g_config.getString(ConfigManager::VERSION_MSG).c_str()); return; } } #ifdef CLIENT_VERSION_DATA if(sprSignature != CLIENT_VERSION_SPR) { disconnectClient(0x0A, CLIENT_VERSION_DATA); return; } if(datSignature != CLIENT_VERSION_DAT) { disconnectClient(0x0A, CLIENT_VERSION_DATA); return; } if(picSignature != CLIENT_VERSION_PIC) { disconnectClient(0x0A, CLIENT_VERSION_DATA); return; } #endif if(g_game.getGameState() < GAMESTATE_NORMAL) { disconnectClient(0x0A, "Server is just starting up, please wait."); return; } if(g_game.getGameState() == GAMESTATE_MAINTAIN) { disconnectClient(0x0A, "Server is under maintenance, please re-connect in a while."); return; } if(ConnectionManager::getInstance()->isDisabled(clientIp, protocolId)) { disconnectClient(0x0A, "Too many connections attempts from your IP address, please try again later."); return; } if(IOBan::getInstance()->isIpBanished(clientIp)) { disconnectClient(0x0A, "Your IP is banished!"); return; } uint32_t id = 1; if(!IOLoginData::getInstance()->getAccountId(name, id)) { ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, false); disconnectClient(0x0A, "Invalid account id."); return; } Account account = IOLoginData::getInstance()->loadAccount(id); if(!encryptTest(account.salt + password, account.password)) { ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, false); disconnectClient(0x0A, "Invalid password."); return; } Ban ban; ban.value = account.number; ban.type = BAN_ACCOUNT; if(IOBan::getInstance()->getData(ban) && !IOLoginData::getInstance()->hasFlag(account.number, PlayerFlag_CannotBeBanned)) { bool deletion = ban.expires < 0; std::string name_ = "Automatic "; if(!ban.adminId) name_ += (deletion ? "deletion" : "banishment"); else IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true); std::stringstream ss; ss << "Your account has been " << (deletion ? "deleted" : "banished") << " at:\n" << formatDateEx(ban.added, "%d %b %Y").c_str() << " by: " << name_.c_str() << "\nReason:\n" << getReason(ban.reason).c_str() << ".\nComment:\n" << ban.comment.c_str() << ".\nYour " << (deletion ? "account won't be undeleted" : "banishment will be lifted at:\n") << (deletion ? "" : formatDateEx(ban.expires).c_str()); disconnectClient(0x0A, ss.str().c_str()); return; } // remove premium days #ifndef __LOGIN_SERVER__ IOLoginData::getInstance()->removePremium(account); if(!g_config.getBool(ConfigManager::ACCOUNT_MANAGER) && !account.charList.size()) { disconnectClient(0x0A, std::string("This account does not contain any character yet.\nCreate a new character on the " + g_config.getString(ConfigManager::SERVER_NAME) + " website at " + g_config.getString(ConfigManager::URL) + ".").c_str()); return; } #else Characters charList; for(Characters::iterator it = account.charList.begin(); it != account.charList.end(); ++it) { if(version >= it->second.server->getVersionMin() && version <= it->second.server->getVersionMax()) charList[it->first] = it->second; } IOLoginData::getInstance()->removePremium(account); if(!g_config.getBool(ConfigManager::ACCOUNT_MANAGER) && !charList.size()) { disconnectClient(0x0A, std::string("This account does not contain any character on this client yet.\nCreate a new character on the " + g_config.getString(ConfigManager::SERVER_NAME) + " website at " + g_config.getString(ConfigManager::URL) + ".").c_str()); return; } #endif ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, true); if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false)) { TRACK_MESSAGE(output); output->put<char>(0x14); uint32_t serverIp = serverIps.front().first; for(std::list<std::pair<uint32_t, uint32_t> >::iterator it = serverIps.begin(); it != serverIps.end(); ++it) { if((it->first & it->second) != (clientIp & it->second)) continue; serverIp = it->first; break; } char motd[1300]; sprintf(motd, "%d\n%s", g_game.getMotdId(), g_config.getString(ConfigManager::MOTD).c_str()); output->putString(motd); //Add char list output->put<char>(0x64); if(g_config.getBool(ConfigManager::ACCOUNT_MANAGER) && account.number != 1) { output->put<char>(account.charList.size() + 1); output->putString("Account Manager"); output->putString(g_config.getString(ConfigManager::SERVER_NAME)); output->put<uint32_t>(serverIp); output->put<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT)); } else output->put<char>((uint8_t)account.charList.size()); #ifndef __LOGIN_SERVER__ for(Characters::iterator it = account.charList.begin(); it != account.charList.end(); ++it) { output->putString((*it)); if(g_config.getBool(ConfigManager::ON_OR_OFF_CHARLIST) && !g_config.getBool(ConfigManager::CHARLIST_INFO)) { if(g_game.getPlayerByName((*it))) output->putString("Online"); else output->putString("Offline"); } else if(g_config.getBool(ConfigManager::CHARLIST_INFO)) { std::stringstream str; Player *player = g_game.getPlayerByName((*it)); bool v = false; if(g_config.getBool(ConfigManager::ON_OR_OFF_CHARLIST)) { if(player) str << "On"; else str << "Off"; str << "/"; } if(!player) { v = true; player = g_game.getPlayerByNameEx((*it)); } str << player->getLevel(); str << "/"; str << player->getVocation()->getName(); output->putString(str.str()); if(v) delete player; } else output->putString(g_config.getString(ConfigManager::SERVER_NAME)); output->put<uint32_t>(serverIp); output->put<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT)); } #else for(Characters::iterator it = charList.begin(); it != charList.end(); ++it) { output->putString(it->second.name); if(!g_config.getBool(ConfigManager::ON_OR_OFF_CHARLIST) || it->second.status < 0) output->putString(it->second.server->getName()); else if(it->second.status) output->putString("Online"); else output->putString("Offline"); output->put<uint32_t>(it->second.server->getAddress()); IntegerVec games = it->second.server->getPorts(); output->put<uint16_t>(games[random_range(0, games.size() - 1)]); } #endif //Add premium days if(g_config.getBool(ConfigManager::FREE_PREMIUM)) output->put<uint16_t>(GRATIS_PREMIUM); else output->put<uint16_t>(account.premiumDays); OutputMessagePool::getInstance()->send(output); } getConnection()->close(); }
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { disconnect(); return; } /*uint16_t clientos = */ msg.get<uint16_t>(); uint16_t version = msg.get<uint16_t>(); msg.skipBytes(12); /* * Skipped bytes: * 4 bytes: protocolVersion * 12 bytes: dat, spr, pic signatures (4 bytes each) * 1 byte: 0 */ if (version <= 760) { disconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return; } if (!Protocol::RSA_decrypt(msg)) { disconnect(); return; } uint32_t key[4]; key[0] = msg.get<uint32_t>(); key[1] = msg.get<uint32_t>(); key[2] = msg.get<uint32_t>(); key[3] = msg.get<uint32_t>(); enableXTEAEncryption(); setXTEAKey(key); uint32_t accountName = msg.get<uint32_t>(); std::string password = msg.getString(); if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { disconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return; } if (g_game.getGameState() == GAME_STATE_STARTUP) { disconnectClient("Gameworld is starting up. Please wait."); return; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { disconnectClient("Gameworld is under maintenance.\nPlease re-connect in a while."); return; } BanInfo banInfo; auto connection = getConnection(); if (!connection) { return; } if (IOBan::isIpBanned(connection->getIP(), banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; disconnectClient(ss.str()); return; } if (accountName == 0) { disconnectClient("Invalid account name."); return; } auto thisPtr = std::dynamic_pointer_cast<ProtocolLogin>(shared_from_this()); g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountName, password))); }
void ProtocolAdmin::parsePacket(NetworkMessage& msg) { if(g_game.getGameState() == GAMESTATE_SHUTDOWN) { getConnection()->close(); return; } uint8_t recvbyte = msg.get<char>(); OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false); if(!output) return; TRACK_MESSAGE(output); switch(m_state) { case ENCRYPTION_NO_SET: { if(Admin::getInstance()->isEncypted()) { if((time(NULL) - m_startTime) > 30000) { getConnection()->close(); addLogLine(LOGTYPE_EVENT, "encryption timeout"); return; } if(recvbyte != AP_MSG_ENCRYPTION && recvbyte != AP_MSG_KEY_EXCHANGE) { output->put<char>(AP_MSG_ERROR); output->putString("encryption needed"); OutputMessagePool::getInstance()->send(output); getConnection()->close(); addLogLine(LOGTYPE_EVENT, "wrong command while ENCRYPTION_NO_SET"); return; } } else m_state = NO_LOGGED_IN; break; } case NO_LOGGED_IN: { if(g_config.getBool(ConfigManager::ADMIN_REQUIRE_LOGIN)) { if((time(NULL) - m_startTime) > 30000) { //login timeout getConnection()->close(); addLogLine(LOGTYPE_EVENT, "login timeout"); return; } if(m_loginTries > 3) { output->put<char>(AP_MSG_ERROR); output->putString("too many login tries"); OutputMessagePool::getInstance()->send(output); getConnection()->close(); addLogLine(LOGTYPE_EVENT, "too many login tries"); return; } if(recvbyte != AP_MSG_LOGIN) { output->put<char>(AP_MSG_ERROR); output->putString("you are not logged in"); OutputMessagePool::getInstance()->send(output); getConnection()->close(); addLogLine(LOGTYPE_EVENT, "wrong command while NO_LOGGED_IN"); return; } } else m_state = LOGGED_IN; break; } case LOGGED_IN: break; default: { getConnection()->close(); addLogLine(LOGTYPE_EVENT, "no valid connection state!!!"); return; } } m_lastCommand = time(NULL); switch(recvbyte) { case AP_MSG_LOGIN: { if(m_state == NO_LOGGED_IN && g_config.getBool(ConfigManager::ADMIN_REQUIRE_LOGIN)) { std::string pass = msg.getString(), word = g_config.getString(ConfigManager::ADMIN_PASSWORD); _encrypt(word, false); if(pass == word) { m_state = LOGGED_IN; output->put<char>(AP_MSG_LOGIN_OK); addLogLine(LOGTYPE_EVENT, "login ok"); } else { m_loginTries++; output->put<char>(AP_MSG_LOGIN_FAILED); output->putString("wrong password"); addLogLine(LOGTYPE_EVENT, "login failed.("+ pass + ")"); } } else { output->put<char>(AP_MSG_LOGIN_FAILED); output->putString("cannot login"); addLogLine(LOGTYPE_EVENT, "wrong state at login"); } break; } case AP_MSG_ENCRYPTION: { if(m_state == ENCRYPTION_NO_SET && Admin::getInstance()->isEncypted()) { uint8_t keyType = msg.get<char>(); switch(keyType) { case ENCRYPTION_RSA1024XTEA: { RSA* rsa = Admin::getInstance()->getRSAKey(ENCRYPTION_RSA1024XTEA); if(!rsa) { output->put<char>(AP_MSG_ENCRYPTION_FAILED); addLogLine(LOGTYPE_EVENT, "no valid server key type"); break; } if(RSA_decrypt(rsa, msg)) { m_state = NO_LOGGED_IN; uint32_t k[4]= {msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>()}; //use for in/out the new key we have enableXTEAEncryption(); setXTEAKey(k); output->put<char>(AP_MSG_ENCRYPTION_OK); addLogLine(LOGTYPE_EVENT, "encryption ok"); } else { output->put<char>(AP_MSG_ENCRYPTION_FAILED); output->putString("wrong encrypted packet"); addLogLine(LOGTYPE_EVENT, "wrong encrypted packet"); } break; } default: { output->put<char>(AP_MSG_ENCRYPTION_FAILED); output->putString("no valid key type"); addLogLine(LOGTYPE_EVENT, "no valid client key type"); break; } } } else { output->put<char>(AP_MSG_ENCRYPTION_FAILED); output->putString("cannot set encryption"); addLogLine(LOGTYPE_EVENT, "cannot set encryption"); } break; } case AP_MSG_KEY_EXCHANGE: { if(m_state == ENCRYPTION_NO_SET && Admin::getInstance()->isEncypted()) { uint8_t keyType = msg.get<char>(); switch(keyType) { case ENCRYPTION_RSA1024XTEA: { RSA* rsa = Admin::getInstance()->getRSAKey(ENCRYPTION_RSA1024XTEA); if(!rsa) { output->put<char>(AP_MSG_KEY_EXCHANGE_FAILED); addLogLine(LOGTYPE_EVENT, "no valid server key type"); break; } output->put<char>(AP_MSG_KEY_EXCHANGE_OK); output->put<char>(ENCRYPTION_RSA1024XTEA); char RSAPublicKey[128]; rsa->getPublicKey(RSAPublicKey); output->put<char>s(RSAPublicKey, 128); break; } default: { output->put<char>(AP_MSG_KEY_EXCHANGE_FAILED); addLogLine(LOGTYPE_EVENT, "no valid client key type"); break; } } } else { output->put<char>(AP_MSG_KEY_EXCHANGE_FAILED); output->putString("cannot get public key"); addLogLine(LOGTYPE_EVENT, "cannot get public key"); } break; } case AP_MSG_COMMAND: { if(m_state != LOGGED_IN) { addLogLine(LOGTYPE_EVENT, "recvbyte == AP_MSG_COMMAND && m_state != LOGGED_IN !!!"); break; } uint8_t command = msg.get<char>(); switch(command) { case CMD_SAVE_SERVER: case CMD_SHALLOW_SAVE_SERVER: { uint8_t flags = (uint8_t)SAVE_PLAYERS | (uint8_t)SAVE_MAP | (uint8_t)SAVE_STATE; if(command == CMD_SHALLOW_SAVE_SERVER) flags |= SAVE_PLAYERS_SHALLOW; addLogLine(LOGTYPE_EVENT, "saving server"); Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::saveGameState, &g_game, flags))); output->put<char>(AP_MSG_COMMAND_OK); break; } case CMD_CLOSE_SERVER: { addLogLine(LOGTYPE_EVENT, "closing server"); Dispatcher::getInstance().addTask(createTask(boost::bind( &Game::setGameState, &g_game, GAMESTATE_CLOSED))); output->put<char>(AP_MSG_COMMAND_OK); break; } case CMD_OPEN_SERVER: { addLogLine(LOGTYPE_EVENT, "opening server"); g_game.setGameState(GAMESTATE_NORMAL); output->put<char>(AP_MSG_COMMAND_OK); break; } case CMD_SHUTDOWN_SERVER: { addLogLine(LOGTYPE_EVENT, "shutting down server"); Dispatcher::getInstance().addTask(createTask(boost::bind( &Game::setGameState, &g_game, GAMESTATE_SHUTDOWN))); output->put<char>(AP_MSG_COMMAND_OK); break; } case CMD_PAY_HOUSES: { Dispatcher::getInstance().addTask(createTask(boost::bind( &ProtocolAdmin::adminCommandPayHouses, this))); break; } case CMD_RELOAD_SCRIPTS: { const int8_t reload = msg.get<char>(); Dispatcher::getInstance().addTask(createTask(boost::bind( &ProtocolAdmin::adminCommandReload, this, reload))); break; } case CMD_KICK: { const std::string param = msg.getString(); Dispatcher::getInstance().addTask(createTask(boost::bind( &ProtocolAdmin::adminCommandKickPlayer, this, param))); break; } case CMD_SEND_MAIL: { const std::string xmlData = msg.getString(); Dispatcher::getInstance().addTask(createTask(boost::bind( &ProtocolAdmin::adminCommandSendMail, this, xmlData))); break; } case CMD_BROADCAST: { const std::string param = msg.getString(); addLogLine(LOGTYPE_EVENT, "broadcasting: " + param); Dispatcher::getInstance().addTask(createTask(boost::bind( &Game::broadcastMessage, &g_game, param, MSG_STATUS_WARNING))); output->put<char>(AP_MSG_COMMAND_OK); break; } default: { output->put<char>(AP_MSG_COMMAND_FAILED); output->putString("not known server command"); addLogLine(LOGTYPE_EVENT, "not known server command"); } } break; } case AP_MSG_PING: output->put<char>(AP_MSG_PING_OK); break; case AP_MSG_KEEP_ALIVE: break; default: { output->put<char>(AP_MSG_ERROR); output->putString("not known command byte"); addLogLine(LOGTYPE_EVENT, "not known command byte"); break; } } if(output->size() > 0) OutputMessagePool::getInstance()->send(output); }