void ProtocolAdmin::adminCommandCloseServer() { g_game.setGameState(GAME_STATE_CLOSED); addLogLine(this, LOGTYPE_EVENT, 1, "close server ok"); AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); while(it != Player::listPlayer.list.end()){ if(!(*it).second->hasFlag(PlayerFlag_CanAlwaysLogin)){ (*it).second->kickPlayer(); it = Player::listPlayer.list.begin(); } else{ ++it; } } OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false); if(output){ TRACK_MESSAGE(output); output->AddByte(AP_MSG_COMMAND_OK); OutputMessagePool::getInstance()->send(output); } }
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 ProtocolAdmin::deleteProtocolTask() { addLogLine(NULL, LOGTYPE_EVENT, 1, "end connection"); g_adminConfig->removeConnection(); Protocol::deleteProtocolTask(); }
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 ProtocolManager::deleteProtocolTask() { addLogLine(LOGTYPE_EVENT, "Closing protocol"); Manager::getInstance()->removeConnection(this); Protocol::deleteProtocolTask(); }
CommandDispatcher::CommandDispatcher() { logLineCounter = 0; cmdLineCounter = 0; addCmdLine("<no command>"); addLogLine("start logging"); }
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); }
void ProtocolAdmin::releaseProtocol() { addLogLine(LOGTYPE_EVENT, "end connection"); Admin::getInstance()->removeConnection(); Protocol::releaseProtocol(); }