Skip to content

Commit

Permalink
Fix not working reconnect.
Browse files Browse the repository at this point in the history
  • Loading branch information
sfence committed Apr 1, 2024
1 parent 5368098 commit d6c265b
Show file tree
Hide file tree
Showing 15 changed files with 162 additions and 81 deletions.
23 changes: 12 additions & 11 deletions src/client/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ void PacketCounter::print(std::ostream &o) const

Client::Client(
const std::string &playername,
const std::string &password,
//const std::string &password,
ClientAuth *auth,
MapDrawControl &control,
IWritableTextureSource *tsrc,
IWritableShaderSource *shsrc,
Expand Down Expand Up @@ -126,7 +127,7 @@ Client::Client(
m_allow_login_or_register(allow_login_or_register),
m_server_ser_ver(SER_FMT_VER_INVALID),
m_last_chat_message_sent(time(NULL)),
m_auth(playername, password),
m_auth(auth),
m_chosen_auth_mech(AUTH_MECHANISM_NONE),
m_media_downloader(new ClientMediaDownloader()),
m_state(LC_Created),
Expand Down Expand Up @@ -1113,7 +1114,7 @@ void Client::interact(InteractAction action, const PointedThing& pointed)

void Client::deleteAuthData()
{
m_auth.clear();
m_auth->clearSessionData();
m_chosen_auth_mech = AUTH_MECHANISM_NONE;
}

Expand Down Expand Up @@ -1155,33 +1156,33 @@ void Client::startAuth(AuthMechanism chosen_auth_mechanism)
switch (chosen_auth_mechanism) {
case AUTH_MECHANISM_FIRST_SRP: {
// send srp verifier to server
const std::string &verifier = m_auth.getSrpVerifier();
const std::string &salt = m_auth.getSrpSalt();
const std::string &verifier = m_auth->getSrpVerifier();
const std::string &salt = m_auth->getSrpSalt();

NetworkPacket resp_pkt(TOSERVER_FIRST_SRP, 0);
resp_pkt << salt << verifier << (u8)((m_auth.getIsEmpty()) ? 1 : 0);
resp_pkt << salt << verifier << (u8)((m_auth->getIsEmpty()) ? 1 : 0);

Send(&resp_pkt);
break;
}
case AUTH_MECHANISM_SRP:
case AUTH_MECHANISM_LEGACY_PASSWORD: {
u8 based_on;
void * auth_data;
SRPUser *auth_data;

if (chosen_auth_mechanism == AUTH_MECHANISM_LEGACY_PASSWORD) {
based_on = 0;
auth_data = m_auth.getLegacyAuthData();
auth_data = m_auth->getLegacyAuthData();
}
else {
based_on = 1;
auth_data = m_auth.getSrpAuthData();
auth_data = m_auth->getSrpAuthData();
}

char *bytes_A = 0;
size_t len_A = 0;
SRP_Result res = srp_user_start_authentication(
static_cast<struct SRPUser *>(auth_data), NULL, NULL, 0,
auth_data, NULL, NULL, 0,
reinterpret_cast<unsigned char **>(&bytes_A), &len_A);
FATAL_ERROR_IF(res != SRP_OK, "Creating local SRP user failed.");

Expand Down Expand Up @@ -1343,7 +1344,7 @@ void Client::sendChangePassword(const std::string &oldpassword,

// get into sudo mode and then send new password to server
std::string playername = m_env.getLocalPlayer()->getName();
m_auth.applyPassword(playername, oldpassword);
m_auth->applyPassword(playername, oldpassword);
m_new_auth.applyPassword(playername, newpassword);
startAuth(choseAuthMech(m_sudo_auth_methods));
}
Expand Down
5 changes: 3 additions & 2 deletions src/client/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef

Client(
const std::string &playername,
const std::string &password,
//const std::string &password,
ClientAuth *auth,
MapDrawControl &control,
IWritableTextureSource *tsrc,
IWritableShaderSource *shsrc,
Expand Down Expand Up @@ -533,7 +534,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef

// Auth data
std::string m_playername;
ClientAuth m_auth;
ClientAuth *m_auth;
// If set, this will be sent (and cleared) upon a TOCLIENT_ACCEPT_SUDO_MODE
ClientAuth m_new_auth;
// Usable by auth mechanisms.
Expand Down
14 changes: 14 additions & 0 deletions src/client/clientauth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,17 @@ void ClientAuth::clear()
m_srp_verifier.clear();
m_srp_salt.clear();
}

void ClientAuth::clearSessionData()
{
if (m_legacy_auth_data != nullptr) {
srp_user_clear_sessiondata(m_legacy_auth_data);
}
if (m_srp_auth_data != nullptr) {
srp_user_clear_sessiondata(m_srp_auth_data);
}
// This is need only for first login to server.
// So, there is no need to keep this for reconnect purposes.
m_srp_verifier.clear();
m_srp_salt.clear();
}
1 change: 1 addition & 0 deletions src/client/clientauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class ClientAuth
SRPUser * getAuthData(AuthMechanism chosen_auth_mech) const;

void clear();
void clearSessionData();
private:
bool m_is_empty;

Expand Down
49 changes: 49 additions & 0 deletions src/client/clientgamestartdata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
Minetest
Copyright (C) 2024 SFENCE, <sfence.software@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#pragma once

#include "gameparams.h"
#include "clientauth.h"

// Information processed by main menu
struct ClientGameStartData : GameParams
{
ClientGameStartData(const GameStartData &start_data):
GameParams(start_data),
name(start_data.name),
address(start_data.address),
local_server(start_data.local_server),
allow_login_or_register(start_data.allow_login_or_register),
world_spec(start_data.world_spec)
{
}

bool isSinglePlayer() const { return address.empty() && !local_server; }

std::string name;
ClientAuth auth;
std::string address;
bool local_server;

ELoginRegister allow_login_or_register = ELoginRegister::Any;

// "world_path" must be kept in sync!
WorldSpec world_spec;
};
39 changes: 27 additions & 12 deletions src/client/clientlauncher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
* - Local server (for main menu only)
*/

init_args(start_data, cmd_args);
ClientGameStartData client_start_data(start_data);
init_args(client_start_data, cmd_args);

#if USE_SOUND
if (g_settings->getBool("enable_sound"))
Expand Down Expand Up @@ -190,7 +191,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
core::rect<s32>(0, 0, 10000, 10000));

bool should_run_game = launch_game(error_message, reconnect_requested,
start_data, cmd_args);
client_start_data, cmd_args);

// Reset the reconnect_requested flag
reconnect_requested = false;
Expand Down Expand Up @@ -218,7 +219,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
kill,
input,
m_rendering_engine,
start_data,
client_start_data,
error_message,
chat_backend,
&reconnect_requested
Expand Down Expand Up @@ -276,7 +277,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
return retval;
}

void ClientLauncher::init_args(GameStartData &start_data, const Settings &cmd_args)
void ClientLauncher::init_args(ClientGameStartData &start_data, const Settings &cmd_args)
{
skip_main_menu = cmd_args.getFlag("go");

Expand Down Expand Up @@ -373,20 +374,22 @@ void ClientLauncher::init_guienv(gui::IGUIEnvironment *guienv)
}

bool ClientLauncher::launch_game(std::string &error_message,
bool reconnect_requested, GameStartData &start_data,
bool reconnect_requested, ClientGameStartData &start_data,
const Settings &cmd_args)
{
// Prepare and check the start data to launch a game
std::string error_message_lua = error_message;
error_message.clear();

std::string password;

if (cmd_args.exists("password"))
start_data.password = cmd_args.get("password");
password = cmd_args.get("password");

if (cmd_args.exists("password-file")) {
std::ifstream passfile(cmd_args.get("password-file"));
if (passfile.good()) {
std::getline(passfile, start_data.password);
std::getline(passfile, password);
} else {
error_message = gettext("Provided password file "
"failed to open: ")
Expand Down Expand Up @@ -415,7 +418,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
MainMenuData menudata;
menudata.address = start_data.address;
menudata.name = start_data.name;
menudata.password = start_data.password;
menudata.password = password;
menudata.port = itos(start_data.socket_port);
menudata.script_data.errormessage = std::move(error_message_lua);
menudata.script_data.reconnect_requested = reconnect_requested;
Expand Down Expand Up @@ -447,14 +450,14 @@ bool ClientLauncher::launch_game(std::string &error_message,
}

start_data.name = menudata.name;
start_data.password = menudata.password;
password = menudata.password;
start_data.address = std::move(menudata.address);
start_data.allow_login_or_register = menudata.allow_login_or_register;
server_name = menudata.servername;
server_description = menudata.serverdescription;

/* make sure that password will not stay somewhere in memory */
porting::clear_string(menudata.password);
porting::secure_clear_string(menudata.password);

start_data.local_server = !menudata.simple_singleplayer_mode &&
start_data.address.empty();
Expand All @@ -463,24 +466,36 @@ bool ClientLauncher::launch_game(std::string &error_message,
start_data.address.empty() && !start_data.name.empty();
}

if (!m_rendering_engine->run())
if (!m_rendering_engine->run()) {
/* make sure that password will not stay somewhere in memory */
porting::secure_clear_string(password);
return false;
}

if (!start_data.isSinglePlayer() && start_data.name.empty()) {
error_message = gettext("Please choose a name!");
errorstream << error_message << std::endl;
/* make sure that password will not stay somewhere in memory */
porting::secure_clear_string(password);
return false;
}

// If using simple singleplayer mode, override
if (start_data.isSinglePlayer()) {
start_data.name = "singleplayer";
start_data.password = "";
password = "";
start_data.socket_port = myrand_range(49152, 65535);
} else {
g_settings->set("name", start_data.name);
}

if (!reconnect_requested) {
// This should not be call on reconnect request, because password has been erased.
start_data.auth.applyPassword(start_data.name, password);
}
/* make sure that password will not stay somewhere in memory */
porting::secure_clear_string(password);

if (start_data.name.length() > PLAYERNAME_SIZE - 1) {
error_message = gettext("Player name too long.");
start_data.name.resize(PLAYERNAME_SIZE);
Expand Down
6 changes: 3 additions & 3 deletions src/client/clientlauncher.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#include "irrlichttypes_extrabloated.h"
#include "client/inputhandler.h"
#include "gameparams.h"
#include "clientgamestartdata.h"

class RenderingEngine;

Expand All @@ -35,13 +35,13 @@ class ClientLauncher
bool run(GameStartData &start_data, const Settings &cmd_args);

private:
void init_args(GameStartData &start_data, const Settings &cmd_args);
void init_args(ClientGameStartData &start_data, const Settings &cmd_args);
bool init_engine();
void init_input();
void init_guienv(gui::IGUIEnvironment *guienv);

bool launch_game(std::string &error_message, bool reconnect_requested,
GameStartData &start_data, const Settings &cmd_args);
ClientGameStartData &start_data, const Settings &cmd_args);

void main_menu(MainMenuData *menudata);

Expand Down

0 comments on commit d6c265b

Please sign in to comment.