void ProtocolAdmin::parsePacket(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->closeConnection(); return; } uint8_t recvbyte = msg.GetByte(); OutputMessagePool* outputPool = OutputMessagePool::getInstance(); OutputMessage_ptr output = outputPool->getOutputMessage(this, false); if (!output) { return; } switch (m_state) { case ENCRYPTION_NO_SET: { if (g_adminConfig->requireEncryption()) { if ((time(NULL) - m_startTime) > 30000) { getConnection()->closeConnection(); addLogLine(this, LOGTYPE_WARNING, 1, "encryption timeout"); return; } if (recvbyte != AP_MSG_ENCRYPTION && recvbyte != AP_MSG_KEY_EXCHANGE) { output->AddByte(AP_MSG_ERROR); output->AddString("encryption needed"); outputPool->send(output); getConnection()->closeConnection(); addLogLine(this, LOGTYPE_WARNING, 1, "wrong command while ENCRYPTION_NO_SET"); return; } break; } else { m_state = NO_LOGGED_IN; } } case NO_LOGGED_IN: { if (g_adminConfig->requireLogin()) { if ((time(NULL) - m_startTime) > 30000) { //login timeout getConnection()->closeConnection(); addLogLine(this, LOGTYPE_WARNING, 1, "login timeout"); return; } if (m_loginTries > 3) { output->AddByte(AP_MSG_ERROR); output->AddString("too many login tries"); outputPool->send(output); getConnection()->closeConnection(); addLogLine(this, LOGTYPE_WARNING, 1, "too many login tries"); return; } if (recvbyte != AP_MSG_LOGIN) { output->AddByte(AP_MSG_ERROR); output->AddString("you are not logged in"); outputPool->send(output); getConnection()->closeConnection(); addLogLine(this, LOGTYPE_WARNING, 1, "wrong command while NO_LOGGED_IN"); return; } break; } else { m_state = LOGGED_IN; } } case LOGGED_IN: { //can execute commands break; } default: { getConnection()->closeConnection(); return; } } m_lastCommand = time(NULL); switch (recvbyte) { case AP_MSG_LOGIN: { if (m_state == NO_LOGGED_IN && g_adminConfig->requireLogin()) { std::string password = msg.GetString(); if (g_adminConfig->passwordMatch(password)) { m_state = LOGGED_IN; output->AddByte(AP_MSG_LOGIN_OK); addLogLine(this, LOGTYPE_EVENT, 1, "login ok"); } else { m_loginTries++; output->AddByte(AP_MSG_LOGIN_FAILED); output->AddString("wrong password"); addLogLine(this, LOGTYPE_WARNING, 1, "login failed.(" + password + ")"); } } else { output->AddByte(AP_MSG_LOGIN_FAILED); output->AddString("can not login"); addLogLine(this, LOGTYPE_WARNING, 1, "wrong state at login"); } break; } case AP_MSG_ENCRYPTION: { if (m_state == ENCRYPTION_NO_SET && g_adminConfig->requireEncryption()) { uint8_t keyType = msg.GetByte(); if (keyType == ENCRYPTION_RSA1024XTEA) { RSA* rsa = g_adminConfig->getRSAKey(ENCRYPTION_RSA1024XTEA); if (!rsa) { output->AddByte(AP_MSG_ENCRYPTION_FAILED); addLogLine(this, LOGTYPE_WARNING, 1, "no valid server key type"); break; } if (RSA_decrypt(rsa, msg)) { m_state = NO_LOGGED_IN; uint32_t k[4]; k[0] = msg.GetU32(); k[1] = msg.GetU32(); k[2] = msg.GetU32(); k[3] = msg.GetU32(); //use for in/out the new key we have enableXTEAEncryption(); setXTEAKey(k); output->AddByte(AP_MSG_ENCRYPTION_OK); addLogLine(this, LOGTYPE_EVENT, 1, "encryption ok"); } else { output->AddByte(AP_MSG_ENCRYPTION_FAILED); output->AddString("wrong encrypted packet"); addLogLine(this, LOGTYPE_WARNING, 1, "wrong encrypted packet"); } } else { output->AddByte(AP_MSG_ENCRYPTION_FAILED); output->AddString("no valid key type"); addLogLine(this, LOGTYPE_WARNING, 1, "no valid client key type"); } } else { output->AddByte(AP_MSG_ENCRYPTION_FAILED); output->AddString("can not set encryption"); addLogLine(this, LOGTYPE_EVENT, 1, "can not set encryption"); } break; } case AP_MSG_KEY_EXCHANGE: { if (m_state == ENCRYPTION_NO_SET && g_adminConfig->requireEncryption()) { uint8_t keyType = msg.GetByte(); if (keyType == ENCRYPTION_RSA1024XTEA) { RSA* rsa = g_adminConfig->getRSAKey(ENCRYPTION_RSA1024XTEA); if (!rsa) { output->AddByte(AP_MSG_KEY_EXCHANGE_FAILED); addLogLine(this, LOGTYPE_WARNING, 1, "no valid server key type"); break; } output->AddByte(AP_MSG_KEY_EXCHANGE_OK); output->AddByte(ENCRYPTION_RSA1024XTEA); char RSAPublicKey[128]; rsa->getPublicKey(RSAPublicKey); output->AddBytes(RSAPublicKey, 128); } else { output->AddByte(AP_MSG_KEY_EXCHANGE_FAILED); addLogLine(this, LOGTYPE_WARNING, 1, "no valid client key type"); } } else { output->AddByte(AP_MSG_KEY_EXCHANGE_FAILED); output->AddString("can not get public key"); addLogLine(this, LOGTYPE_WARNING, 1, "can not get public key"); } break; } case AP_MSG_COMMAND: { if (m_state != LOGGED_IN) { addLogLine(this, LOGTYPE_ERROR, 1, "recvbyte == AP_MSG_COMMAND && m_state != LOGGED_IN !!!"); // We should never reach this point break; } uint8_t command = msg.GetByte(); switch (command) { case CMD_BROADCAST: { const std::string message = msg.GetString(); addLogLine(this, LOGTYPE_EVENT, 1, "broadcast: " + message); g_dispatcher.addTask(createTask(boost::bind(&Game::broadcastMessage, &g_game, message, MSG_STATUS_WARNING))); output->AddByte(AP_MSG_COMMAND_OK); break; } case CMD_CLOSE_SERVER: { g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandCloseServer, this))); break; } case CMD_PAY_HOUSES: { g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandPayHouses, this))); break; } case CMD_OPEN_SERVER: { g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandOpenServer, this))); break; } case CMD_SHUTDOWN_SERVER: { g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandShutdownServer, this))); getConnection()->closeConnection(); return; } case CMD_KICK: { const std::string name = msg.GetString(); g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandKickPlayer, this, name))); break; } case CMD_SETOWNER: { const std::string param = msg.GetString(); g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandSetOwner, this, param))); break; } default: { output->AddByte(AP_MSG_COMMAND_FAILED); output->AddString("not known server command"); addLogLine(this, LOGTYPE_WARNING, 1, "not known server command"); break; } } break; } case AP_MSG_PING: { output->AddByte(AP_MSG_PING_OK); break; } default: { output->AddByte(AP_MSG_ERROR); output->AddString("not known command byte"); addLogLine(this, LOGTYPE_WARNING, 1, "not known command byte"); break; } } if (output->getMessageLength() > 0) { outputPool->send(output); } }
void ProtocolStatus::sendStatusString() { OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false); if (!output) { getConnection()->closeConnection(); return; } setRawMessages(true); pugi::xml_document doc; pugi::xml_node decl = doc.prepend_child(pugi::node_declaration); decl.append_attribute("version") = "1.0"; pugi::xml_node tsqp = doc.append_child("tsqp"); tsqp.append_attribute("version") = "1.0"; pugi::xml_node serverinfo = tsqp.append_child("serverinfo"); uint64_t uptime = (OTSYS_TIME() - ProtocolStatus::start) / 1000; serverinfo.append_attribute("uptime") = std::to_string(uptime).c_str(); serverinfo.append_attribute("ip") = g_config.getString(ConfigManager::IP).c_str(); serverinfo.append_attribute("servername") = g_config.getString(ConfigManager::SERVER_NAME).c_str(); serverinfo.append_attribute("port") = std::to_string((uint32_t)g_config.getNumber(ConfigManager::LOGIN_PORT)).c_str(); serverinfo.append_attribute("location") = g_config.getString(ConfigManager::LOCATION).c_str(); serverinfo.append_attribute("url") = g_config.getString(ConfigManager::URL).c_str(); serverinfo.append_attribute("server") = STATUS_SERVER_NAME; serverinfo.append_attribute("version") = STATUS_SERVER_VERSION; serverinfo.append_attribute("client") = CLIENT_VERSION_STR; pugi::xml_node owner = tsqp.append_child("owner"); owner.append_attribute("name") = g_config.getString(ConfigManager::OWNER_NAME).c_str(); owner.append_attribute("email") = g_config.getString(ConfigManager::OWNER_EMAIL).c_str(); pugi::xml_node players = tsqp.append_child("players"); players.append_attribute("online") = std::to_string(g_game.getPlayersOnline()).c_str(); players.append_attribute("max") = std::to_string((uint32_t)g_config.getNumber(ConfigManager::MAX_PLAYERS)).c_str(); players.append_attribute("peak") = std::to_string(g_game.getPlayersRecord()).c_str(); pugi::xml_node monsters = tsqp.append_child("monsters"); monsters.append_attribute("total") = std::to_string(g_game.getMonstersOnline()).c_str(); pugi::xml_node npcs = tsqp.append_child("npcs"); npcs.append_attribute("total") = std::to_string(g_game.getNpcsOnline()).c_str(); pugi::xml_node rates = tsqp.append_child("rates"); rates.append_attribute("experience") = std::to_string((uint32_t)g_config.getNumber(ConfigManager::RATE_EXPERIENCE)).c_str(); rates.append_attribute("skill") = std::to_string((uint32_t)g_config.getNumber(ConfigManager::RATE_SKILL)).c_str(); rates.append_attribute("loot") = std::to_string((uint32_t)g_config.getNumber(ConfigManager::RATE_LOOT)).c_str(); rates.append_attribute("magic") = std::to_string((uint32_t)g_config.getNumber(ConfigManager::RATE_MAGIC)).c_str(); rates.append_attribute("spawn") = std::to_string((uint32_t)g_config.getNumber(ConfigManager::RATE_SPAWN)).c_str(); pugi::xml_node map = tsqp.append_child("map"); map.append_attribute("name") = g_config.getString(ConfigManager::MAP_NAME).c_str(); map.append_attribute("author") = g_config.getString(ConfigManager::MAP_AUTHOR).c_str(); uint32_t mapWidth, mapHeight; g_game.getMapDimensions(mapWidth, mapHeight); map.append_attribute("width") = std::to_string(mapWidth).c_str(); map.append_attribute("height") = std::to_string(mapHeight).c_str(); pugi::xml_node motd = tsqp.append_child("motd"); motd.text() = g_config.getString(ConfigManager::MOTD).c_str(); std::ostringstream ss; doc.save(ss, "", pugi::format_raw); std::string data = ss.str(); output->AddBytes(data.c_str(), data.size()); OutputMessagePool::getInstance()->send(output); getConnection()->closeConnection(); }