diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index 66f86565..bd8fdf58 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -878,24 +878,25 @@ struct C_Login_BB_93 { ptext unused2; ptext password; ptext unused3; - uint64_t hardware_info; + // Note: Unlike other versions, BB puts the version string in the client // config at connect time. So the first time the server gets this command, it // will be something like "Ver. 1.24.3". Note also that some old versions // (before 1.23.8?) omit the hardware_info field before the client config, so // the client config starts 8 bytes earlier on those versions and the entire - // command is 8 bytes shorter. - union ClientConfigFields { - ClientConfigBB cfg; - ptext version_string; - ClientConfigFields() : version_string() { } - ClientConfigFields(const ClientConfigFields& other) - : version_string(other.version_string) { } - inline ClientConfigFields& operator=(const ClientConfigFields& other) { - this->version_string = other.version_string; - return *this; - } - } client_config; + // command is 8 bytes shorter, hence this odd-looking union. + union VariableLengthSection { + union ClientConfigFields { + ClientConfigBB cfg; + ptext version_string; + }; + + ClientConfigFields old_clients_cfg; + struct NewFormat { + uint64_t hardware_info; + ClientConfigFields cfg; + } new_clients; + } var; }; // 94: Invalid command diff --git a/src/ProxyCommands.cc b/src/ProxyCommands.cc index d550d9b6..01fa7d64 100644 --- a/src/ProxyCommands.cc +++ b/src/ProxyCommands.cc @@ -236,7 +236,7 @@ static bool process_server_bb_03(shared_ptr, if (!session.detector_crypt.get()) { throw runtime_error("BB linked session has no detector crypt"); } - if (!session.login_command_bb.username.len()) { + if (session.login_command_bb.empty()) { throw logic_error("linked BB session does not have a saved login command"); } @@ -251,8 +251,7 @@ static bool process_server_bb_03(shared_ptr, session.detector_crypt, cmd.client_key.data(), sizeof(cmd.client_key), false)); // Forward the login command we saved during the unlinked session. - session.send_to_end(true, 0x93, 0x00, &session.login_command_bb, - sizeof(session.login_command_bb)); + session.send_to_end(true, 0x93, 0x00, session.login_command_bb); return false; } diff --git a/src/ProxyServer.cc b/src/ProxyServer.cc index 52b94b6a..60dd58f2 100644 --- a/src/ProxyServer.cc +++ b/src/ProxyServer.cc @@ -276,7 +276,7 @@ void ProxyServer::UnlinkedSession::on_client_input() { uint32_t sub_version = 0; string character_name; ClientConfigBB client_config; - C_Login_BB_93 login_command_bb; + string login_command_bb; try { for_each_received_command(this->bev.get(), this->version, this->crypt_in.get(), @@ -318,7 +318,7 @@ void ProxyServer::UnlinkedSession::on_client_input() { const auto& cmd = check_size_t(data); license = this->server->state->license_manager->verify_bb( cmd.username, cmd.password); - login_command_bb = cmd; + login_command_bb = data; } else { throw logic_error("unsupported unlinked session version"); @@ -379,7 +379,7 @@ void ProxyServer::UnlinkedSession::on_client_input() { try { if (this->version == GameVersion::BB) { session->resume(move(this->bev), this->crypt_in, this->crypt_out, - this->detector_crypt, login_command_bb); + this->detector_crypt, move(login_command_bb)); } else { session->resume(move(this->bev), this->crypt_in, this->crypt_out, this->detector_crypt, sub_version, character_name); @@ -502,8 +502,8 @@ void ProxyServer::LinkedSession::resume( shared_ptr client_input_crypt, shared_ptr client_output_crypt, shared_ptr detector_crypt, - C_Login_BB_93 login_command_bb) { - this->login_command_bb = login_command_bb; + string&& login_command_bb) { + this->login_command_bb = move(login_command_bb); this->resume_inner(move(client_bev), client_input_crypt, client_output_crypt, detector_crypt); } diff --git a/src/ProxyServer.hh b/src/ProxyServer.hh index dd9feb0e..5d6968ee 100644 --- a/src/ProxyServer.hh +++ b/src/ProxyServer.hh @@ -53,7 +53,7 @@ public: GameVersion version; uint32_t sub_version; std::string character_name; - C_Login_BB_93 login_command_bb; + std::string login_command_bb; uint32_t remote_guild_card_number; parray remote_client_config_data; @@ -132,7 +132,7 @@ public: std::shared_ptr client_input_crypt, std::shared_ptr client_output_crypt, std::shared_ptr detector_crypt, - C_Login_BB_93 login_command_bb); + std::string&& login_command_bb); void resume(struct bufferevent* client_bev); void resume_inner( std::unique_ptr&& client_bev, diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 8a2d4d72..73cd3e46 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -311,7 +311,17 @@ void process_login_d_e_pc_gc(shared_ptr s, shared_ptr c, void process_login_bb(shared_ptr s, shared_ptr c, uint16_t, uint32_t, const string& data) { // 93 - const auto& cmd = check_size_t(data); + const auto& cmd = check_size_t(data, + sizeof(C_Login_BB_93) - 8, sizeof(C_Login_BB_93)); + + bool is_old_format; + if (data.size() == sizeof(C_Login_BB_93) - 8) { + is_old_format = true; + } else if (data.size() == sizeof(C_Login_BB_93)) { + is_old_format = false; + } else { + throw runtime_error("invalid size for 93 command"); + } c->flags |= flags_for_version(c->version, 0); @@ -326,7 +336,11 @@ void process_login_bb(shared_ptr s, shared_ptr c, } try { - c->import_config(cmd.client_config.cfg); + if (is_old_format) { + c->import_config(cmd.var.old_clients_cfg.cfg); + } else { + c->import_config(cmd.var.new_clients.cfg.cfg); + } if (c->bb_game_state < ClientStateBB::IN_GAME) { c->bb_game_state++; }