Skip to content

Commit

Permalink
Change the way how password is stored in C++ engine.
Browse files Browse the repository at this point in the history
  • Loading branch information
sfence committed Feb 4, 2025
1 parent b2a6c3b commit 2d73fea
Show file tree
Hide file tree
Showing 18 changed files with 395 additions and 100 deletions.
8 changes: 8 additions & 0 deletions games/devtest/mods/util_commands/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,11 @@ core.register_chatcommand("set_saturation", {
core.get_player_by_name(player_name):set_lighting({saturation = saturation })
end
})

core.register_chatcommand("shutdown_with_reconnect", {
params = "",
description = "Shutdown server with reconnect request.",
func = function(player_name, param)
minetest.request_shutdown("Shutdown with reconnect.", true, 5)
end
})
1 change: 1 addition & 0 deletions src/client/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ set(client_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/activeobjectmgr.cpp
${CMAKE_CURRENT_SOURCE_DIR}/camera.cpp
${CMAKE_CURRENT_SOURCE_DIR}/client.cpp
${CMAKE_CURRENT_SOURCE_DIR}/clientauth.cpp
${CMAKE_CURRENT_SOURCE_DIR}/clientenvironment.cpp
${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
${CMAKE_CURRENT_SOURCE_DIR}/clientmap.cpp
Expand Down
69 changes: 32 additions & 37 deletions src/client/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ void PacketCounter::print(std::ostream &o) const
*/

Client::Client(
const char *playername,
const std::string &password,
const std::string &playername,
//const std::string &password,
ClientAuth *auth,
MapDrawControl &control,
IWritableTextureSource *tsrc,
IWritableShaderSource *shsrc,
Expand All @@ -113,14 +114,14 @@ 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_password(password),
m_auth(auth),
m_chosen_auth_mech(AUTH_MECHANISM_NONE),
m_media_downloader(new ClientMediaDownloader()),
m_state(LC_Created),
m_modchannel_mgr(new ModChannelMgr())
{
// Add local player
m_env.setLocalPlayer(new LocalPlayer(this, playername));
m_env.setLocalPlayer(new LocalPlayer(this, playername.c_str()));

// Make the mod storage database and begin the save for later
m_mod_storage_database =
Expand Down Expand Up @@ -1104,20 +1105,7 @@ void Client::interact(InteractAction action, const PointedThing& pointed)

void Client::deleteAuthData()
{
if (!m_auth_data)
return;

switch (m_chosen_auth_mech) {
case AUTH_MECHANISM_FIRST_SRP:
break;
case AUTH_MECHANISM_SRP:
case AUTH_MECHANISM_LEGACY_PASSWORD:
srp_user_delete((SRPUser *) m_auth_data);
m_auth_data = NULL;
break;
case AUTH_MECHANISM_NONE:
break;
}
m_auth->clearSessionData();
m_chosen_auth_mech = AUTH_MECHANISM_NONE;
}

Expand Down Expand Up @@ -1156,36 +1144,34 @@ void Client::startAuth(AuthMechanism chosen_auth_mechanism)
switch (chosen_auth_mechanism) {
case AUTH_MECHANISM_FIRST_SRP: {
// send srp verifier to server
std::string verifier;
std::string salt;
generate_srp_verifier_and_salt(playername, m_password,
&verifier, &salt);
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_password.empty()) ? 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 = 1;
u8 based_on;
SRPUser *auth_data;

if (chosen_auth_mechanism == AUTH_MECHANISM_LEGACY_PASSWORD) {
m_password = translate_password(playername, m_password);
based_on = 0;
auth_data = m_auth->getLegacyAuthData();
}
else {
based_on = 1;
auth_data = m_auth->getSrpAuthData();
}

std::string playername_u = lowercase(playername);
m_auth_data = srp_user_new(SRP_SHA256, SRP_NG_2048,
playername.c_str(), playername_u.c_str(),
(const unsigned char *) m_password.c_str(),
m_password.length(), NULL, NULL);
char *bytes_A = 0;
size_t len_A = 0;
SRP_Result res = srp_user_start_authentication(
(struct SRPUser *) m_auth_data, NULL, NULL, 0,
(unsigned char **) &bytes_A, &len_A);
auth_data, NULL, NULL, 0,
reinterpret_cast<unsigned char **>(&bytes_A), &len_A);
FATAL_ERROR_IF(res != SRP_OK, "Creating local SRP user failed.");

NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_A, 0);
Expand Down Expand Up @@ -1337,16 +1323,25 @@ void Client::clearOutChatQueue()
m_out_chat_queue = std::queue<std::wstring>();
}

void Client::sendChangePassword(const std::string &oldpassword,
const std::string &newpassword)
void Client::sendChangePassword(std::string &oldpassword,
std::string &newpassword)
{
LocalPlayer *player = m_env.getLocalPlayer();
if (player == NULL)
if (player == NULL) {
porting::secure_clear_string(oldpassword);
porting::secure_clear_string(newpassword);
return;
}

// get into sudo mode and then send new password to server
m_password = oldpassword;
m_new_password = newpassword;
std::string playername = m_env.getLocalPlayer()->getName();
m_auth->applyPassword(playername, oldpassword);
m_new_auth.applyPassword(playername, newpassword);

// we do not need to keep passwords in memory
porting::secure_clear_string(oldpassword);
porting::secure_clear_string(newpassword);

startAuth(choseAuthMech(m_sudo_auth_methods));
}

Expand Down
16 changes: 9 additions & 7 deletions src/client/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "network/peerhandler.h"
#include "gameparams.h"
#include "script/common/c_types.h" // LuaError
#include "clientdynamicinfo.h"
#include "clientauth.h"
#include "util/numeric.h"
#include "util/string.h" // StringMap
#include "config.h"
Expand Down Expand Up @@ -108,8 +110,9 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
*/

Client(
const char *playername,
const std::string &password,
const std::string &playername,
//const std::string &password,
ClientAuth *auth,
MapDrawControl &control,
IWritableTextureSource *tsrc,
IWritableShaderSource *shsrc,
Expand Down Expand Up @@ -231,8 +234,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
void sendInventoryAction(InventoryAction *a);
void sendChatMessage(const std::wstring &message);
void clearOutChatQueue();
void sendChangePassword(const std::string &oldpassword,
const std::string &newpassword);
void sendChangePassword(std::string &oldpassword,
std::string &newpassword);
void sendDamage(u16 damage);
void sendRespawnLegacy();
void sendReady();
Expand Down Expand Up @@ -515,12 +518,11 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef

// Auth data
std::string m_playername;
std::string m_password;
ClientAuth *m_auth;
// If set, this will be sent (and cleared) upon a TOCLIENT_ACCEPT_SUDO_MODE
std::string m_new_password;
ClientAuth m_new_auth;
// Usable by auth mechanisms.
AuthMechanism m_chosen_auth_mech;
void *m_auth_data = nullptr;

bool m_access_denied = false;
bool m_access_denied_reconnect = false;
Expand Down
104 changes: 104 additions & 0 deletions src/client/clientauth.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Luanti
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (C) 2024-2025 SFENCE, <[email protected]>

#include "clientauth.h"
#include "util/auth.h"
#include "util/srp.h"
#include "util/string.h"

ClientAuth::ClientAuth() :
m_is_empty(true)
{
}

ClientAuth::ClientAuth(const std::string &player_name, const std::string &password)
{
applyPassword(player_name, password);
}

ClientAuth::~ClientAuth()
{
clear();
}

ClientAuth &ClientAuth::operator=(ClientAuth &&other)
{
clear();

m_is_empty = other.m_is_empty;

m_srp_verifier = other.m_srp_verifier;
m_srp_salt = other.m_srp_salt;

m_legacy_auth_data = other.m_legacy_auth_data;
m_srp_auth_data = other.m_srp_auth_data;

other.m_legacy_auth_data = nullptr;
other.m_srp_auth_data = nullptr;

other.clear();

return *this;
}

void ClientAuth::applyPassword(const std::string &player_name, const std::string &password)
{
clear();
// AUTH_MECHANISM_FIRST_SRP
generate_srp_verifier_and_salt(player_name, password, &m_srp_verifier, &m_srp_salt);
m_is_empty = password.empty();

std::string player_name_u = lowercase(player_name);
// AUTH_MECHANISM_SRP
m_srp_auth_data = srp_user_new(SRP_SHA256, SRP_NG_2048,
player_name.c_str(), player_name_u.c_str(),
reinterpret_cast<const unsigned char *>(password.c_str()),
password.length(), NULL, NULL);
// AUTH_MECHANISM_LEGACY_PASSWORD
std::string translated = translate_password(player_name, password);
m_legacy_auth_data = srp_user_new(SRP_SHA256, SRP_NG_2048,
player_name.c_str(), player_name_u.c_str(),
reinterpret_cast<const unsigned char *>(translated.c_str()),
translated.length(), NULL, NULL);
}

SRPUser * ClientAuth::getAuthData(AuthMechanism chosen_auth_mech) const
{
switch (chosen_auth_mech) {
case AUTH_MECHANISM_LEGACY_PASSWORD:
return m_legacy_auth_data;
case AUTH_MECHANISM_SRP:
return m_srp_auth_data;
default:
return nullptr;
}
}

void ClientAuth::clear()
{
if (m_legacy_auth_data != nullptr) {
srp_user_delete(m_legacy_auth_data);
m_legacy_auth_data = nullptr;
}
if (m_srp_auth_data != nullptr) {
srp_user_delete(m_srp_auth_data);
m_srp_auth_data = nullptr;
}
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();
}
59 changes: 59 additions & 0 deletions src/client/clientauth.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
Minetest
Copyright (C) 2024 SFENCE, <[email protected]>
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 <string>
#include "network/networkprotocol.h"
#include "util/basic_macros.h"

struct SRPUser;

class ClientAuth
{
public:
ClientAuth();
ClientAuth(const std::string &player_name, const std::string &password);

~ClientAuth();
DISABLE_CLASS_COPY(ClientAuth);

ClientAuth(ClientAuth &&other) { *this = std::move(other); }
ClientAuth &operator=(ClientAuth &&other);

void applyPassword(const std::string &player_name, const std::string &password);

bool getIsEmpty() const { return m_is_empty; }
const std::string &getSrpVerifier() const { return m_srp_verifier; }
const std::string &getSrpSalt() const { return m_srp_salt; }
SRPUser * getLegacyAuthData() const { return m_legacy_auth_data; }
SRPUser * getSrpAuthData() const { return m_srp_auth_data; }
SRPUser * getAuthData(AuthMechanism chosen_auth_mech) const;

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

std::string m_srp_verifier;
std::string m_srp_salt;

SRPUser *m_legacy_auth_data = nullptr;
SRPUser *m_srp_auth_data = nullptr;
};
Loading

0 comments on commit 2d73fea

Please sign in to comment.