LCOV - code coverage report
Current view: top level - src/network - serverpackethandler.cpp (source / functions) Hit Total Coverage
Test: report Lines: 1 1139 0.1 %
Date: 2015-07-11 18:23:49 Functions: 2 26 7.7 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2015 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "server.h"
      21             : #include "log.h"
      22             : 
      23             : #include "content_abm.h"
      24             : #include "content_sao.h"
      25             : #include "emerge.h"
      26             : #include "nodedef.h"
      27             : #include "player.h"
      28             : #include "rollback_interface.h"
      29             : #include "scripting_game.h"
      30             : #include "settings.h"
      31             : #include "tool.h"
      32             : #include "version.h"
      33             : #include "network/networkprotocol.h"
      34             : #include "network/serveropcodes.h"
      35             : #include "util/auth.h"
      36             : #include "util/base64.h"
      37             : #include "util/pointedthing.h"
      38             : #include "util/serialize.h"
      39             : #include "util/srp.h"
      40             : 
      41           0 : void Server::handleCommand_Deprecated(NetworkPacket* pkt)
      42             : {
      43           0 :         infostream << "Server: " << toServerCommandTable[pkt->getCommand()].name
      44           0 :                 << " not supported anymore" << std::endl;
      45           0 : }
      46             : 
      47           0 : void Server::handleCommand_Init(NetworkPacket* pkt)
      48             : {
      49             : 
      50           0 :         if(pkt->getSize() < 1)
      51           0 :                 return;
      52             : 
      53           0 :         RemoteClient* client = getClient(pkt->getPeerId(), CS_Created);
      54             : 
      55           0 :         std::string addr_s;
      56             :         try {
      57           0 :                 Address address = getPeerAddress(pkt->getPeerId());
      58           0 :                 addr_s = address.serializeString();
      59             :         }
      60           0 :         catch (con::PeerNotFoundException &e) {
      61             :                 /*
      62             :                  * no peer for this packet found
      63             :                  * most common reason is peer timeout, e.g. peer didn't
      64             :                  * respond for some time, your server was overloaded or
      65             :                  * things like that.
      66             :                  */
      67           0 :                 infostream << "Server::ProcessData(): Canceling: peer "
      68           0 :                                 << pkt->getPeerId() << " not found" << std::endl;
      69           0 :                 return;
      70             :         }
      71             : 
      72             :         // If net_proto_version is set, this client has already been handled
      73           0 :         if (client->getState() > CS_Created) {
      74           0 :                 verbosestream << "Server: Ignoring multiple TOSERVER_INITs from "
      75           0 :                                 << addr_s << " (peer_id=" << pkt->getPeerId() << ")" << std::endl;
      76           0 :                 return;
      77             :         }
      78             : 
      79           0 :         verbosestream << "Server: Got TOSERVER_INIT from " << addr_s << " (peer_id="
      80           0 :                         << pkt->getPeerId() << ")" << std::endl;
      81             : 
      82             :         // Do not allow multiple players in simple singleplayer mode.
      83             :         // This isn't a perfect way to do it, but will suffice for now
      84           0 :         if (m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1) {
      85           0 :                 infostream << "Server: Not allowing another client (" << addr_s
      86           0 :                                 << ") to connect in simple singleplayer mode" << std::endl;
      87           0 :                 DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_SINGLEPLAYER);
      88           0 :                 return;
      89             :         }
      90             : 
      91             :         // First byte after command is maximum supported
      92             :         // serialization version
      93             :         u8 client_max;
      94             :         u16 supp_compr_modes;
      95           0 :         u16 min_net_proto_version = 0;
      96             :         u16 max_net_proto_version;
      97           0 :         std::string playerName;
      98             : 
      99           0 :         *pkt >> client_max >> supp_compr_modes >> min_net_proto_version
     100           0 :                         >> max_net_proto_version >> playerName;
     101             : 
     102           0 :         u8 our_max = SER_FMT_VER_HIGHEST_READ;
     103             :         // Use the highest version supported by both
     104           0 :         u8 depl_serial_v = std::min(client_max, our_max);
     105             :         // If it's lower than the lowest supported, give up.
     106             :         if (depl_serial_v < SER_FMT_VER_LOWEST)
     107             :                 depl_serial_v = SER_FMT_VER_INVALID;
     108             : 
     109           0 :         if (depl_serial_v == SER_FMT_VER_INVALID) {
     110           0 :                 actionstream << "Server: A mismatched client tried to connect from "
     111           0 :                                 << addr_s << std::endl;
     112           0 :                 infostream<<"Server: Cannot negotiate serialization version with "
     113           0 :                                 << addr_s << std::endl;
     114           0 :                 DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_VERSION);
     115           0 :                 return;
     116             :         }
     117             : 
     118           0 :         client->setPendingSerializationVersion(depl_serial_v);
     119             : 
     120             :         /*
     121             :                 Read and check network protocol version
     122             :         */
     123             : 
     124           0 :         u16 net_proto_version = 0;
     125             : 
     126             :         // Figure out a working version if it is possible at all
     127           0 :         if (max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
     128           0 :                         min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX) {
     129             :                 // If maximum is larger than our maximum, go with our maximum
     130           0 :                 if (max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
     131           0 :                         net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
     132             :                 // Else go with client's maximum
     133             :                 else
     134           0 :                         net_proto_version = max_net_proto_version;
     135             :         }
     136             : 
     137           0 :         verbosestream << "Server: " << addr_s << ": Protocol version: min: "
     138           0 :                         << min_net_proto_version << ", max: " << max_net_proto_version
     139           0 :                         << ", chosen: " << net_proto_version << std::endl;
     140             : 
     141           0 :         client->net_proto_version = net_proto_version;
     142             : 
     143             :         // On this handler at least protocol version 25 is required
     144           0 :         if (net_proto_version < 25 ||
     145           0 :                         net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
     146             :                         net_proto_version > SERVER_PROTOCOL_VERSION_MAX) {
     147           0 :                 actionstream << "Server: A mismatched client tried to connect from "
     148           0 :                                 << addr_s << std::endl;
     149           0 :                 DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_VERSION);
     150           0 :                 return;
     151             :         }
     152             : 
     153           0 :         if (g_settings->getBool("strict_protocol_version_checking")) {
     154           0 :                 if (net_proto_version != LATEST_PROTOCOL_VERSION) {
     155           0 :                         actionstream << "Server: A mismatched (strict) client tried to "
     156           0 :                                         << "connect from " << addr_s << std::endl;
     157           0 :                         DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_VERSION);
     158           0 :                         return;
     159             :                 }
     160             :         }
     161             : 
     162             :         /*
     163             :                 Validate player name
     164             :         */
     165           0 :         const char* playername = playerName.c_str();
     166             : 
     167           0 :         size_t pns = playerName.size();
     168           0 :         if (pns == 0 || pns > PLAYERNAME_SIZE) {
     169           0 :                 actionstream << "Server: Player with "
     170           0 :                         << ((pns > PLAYERNAME_SIZE) ? "a too long" : "an empty")
     171           0 :                         << " name tried to connect from " << addr_s << std::endl;
     172           0 :                 DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_NAME);
     173           0 :                 return;
     174             :         }
     175             : 
     176           0 :         if (string_allowed(playerName, PLAYERNAME_ALLOWED_CHARS) == false) {
     177           0 :                 actionstream << "Server: Player with an invalid name "
     178           0 :                                 << "tried to connect from " << addr_s << std::endl;
     179           0 :                 DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_CHARS_IN_NAME);
     180           0 :                 return;
     181             :         }
     182             : 
     183           0 :         m_clients.setPlayerName(pkt->getPeerId(), playername);
     184             :         //TODO (later) case insensitivity
     185             : 
     186           0 :         std::string legacyPlayerNameCasing = playerName;
     187             : 
     188           0 :         if (!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0) {
     189           0 :                 actionstream << "Server: Player with the name \"singleplayer\" "
     190           0 :                                 << "tried to connect from " << addr_s << std::endl;
     191           0 :                 DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_NAME);
     192           0 :                 return;
     193             :         }
     194             : 
     195             :         {
     196           0 :                 std::string reason;
     197           0 :                 if (m_script->on_prejoinplayer(playername, addr_s, &reason)) {
     198           0 :                         actionstream << "Server: Player with the name \"" << playerName << "\" "
     199           0 :                                         << "tried to connect from " << addr_s << " "
     200           0 :                                         << "but it was disallowed for the following reason: "
     201           0 :                                         << reason << std::endl;
     202           0 :                         DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING,
     203           0 :                                         reason.c_str());
     204           0 :                         return;
     205             :                 }
     206             :         }
     207             : 
     208           0 :         infostream << "Server: New connection: \"" << playerName << "\" from "
     209           0 :                         << addr_s << " (peer_id=" << pkt->getPeerId() << ")" << std::endl;
     210             : 
     211             :         // Enforce user limit.
     212             :         // Don't enforce for users that have some admin right
     213           0 :         if (m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
     214           0 :                         !checkPriv(playername, "server") &&
     215           0 :                         !checkPriv(playername, "ban") &&
     216           0 :                         !checkPriv(playername, "privs") &&
     217           0 :                         !checkPriv(playername, "password") &&
     218           0 :                         playername != g_settings->get("name")) {
     219           0 :                 actionstream << "Server: " << playername << " tried to join from "
     220           0 :                                 << addr_s << ", but there" << " are already max_users="
     221           0 :                                 << g_settings->getU16("max_users") << " players." << std::endl;
     222           0 :                 DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_TOO_MANY_USERS);
     223           0 :                 return;
     224             :         }
     225             : 
     226             :         /*
     227             :                 Compose auth methods for answer
     228             :         */
     229           0 :         std::string encpwd; // encrypted Password field for the user
     230           0 :         bool has_auth = m_script->getAuth(playername, &encpwd, NULL);
     231           0 :         u32 auth_mechs = 0;
     232             : 
     233           0 :         client->chosen_mech = AUTH_MECHANISM_NONE;
     234             : 
     235           0 :         if (has_auth) {
     236           0 :                 std::vector<std::string> pwd_components = str_split(encpwd, '#');
     237           0 :                 if (pwd_components.size() == 4) {
     238           0 :                         if (pwd_components[1] == "1") { // 1 means srp
     239           0 :                                 auth_mechs |= AUTH_MECHANISM_SRP;
     240           0 :                                 client->enc_pwd = encpwd;
     241             :                         } else {
     242           0 :                                 actionstream << "User " << playername
     243           0 :                                         << " tried to log in, but password field"
     244           0 :                                         << " was invalid (unknown mechcode)." << std::endl;
     245           0 :                                 DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_SERVER_FAIL);
     246           0 :                                 return;
     247             :                         }
     248           0 :                 } else if (base64_is_valid(encpwd)) {
     249           0 :                         auth_mechs |= AUTH_MECHANISM_LEGACY_PASSWORD;
     250           0 :                         client->enc_pwd = encpwd;
     251             :                 } else {
     252           0 :                         actionstream << "User " << playername
     253           0 :                                 << " tried to log in, but password field"
     254           0 :                                 << " was invalid (invalid base64)." << std::endl;
     255           0 :                         DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_SERVER_FAIL);
     256           0 :                         return;
     257             :                 }
     258             :         } else {
     259           0 :                 std::string default_password = g_settings->get("default_password");
     260           0 :                 if (default_password.length() == 0) {
     261           0 :                         auth_mechs |= AUTH_MECHANISM_FIRST_SRP;
     262             :                 } else {
     263             :                         // Take care of default passwords.
     264           0 :                         client->enc_pwd = getSRPVerifier(playerName, default_password);
     265           0 :                         auth_mechs |= AUTH_MECHANISM_SRP;
     266             :                 }
     267             :         }
     268             : 
     269             :         /*
     270             :                 Answer with a TOCLIENT_HELLO
     271             :         */
     272             : 
     273           0 :         verbosestream << "Sending TOCLIENT_HELLO with auth method field: "
     274           0 :                 << auth_mechs << std::endl;
     275             : 
     276             :         NetworkPacket resp_pkt(TOCLIENT_HELLO, 1 + 4
     277           0 :                 + legacyPlayerNameCasing.size(), pkt->getPeerId());
     278             : 
     279           0 :         u16 depl_compress_mode = NETPROTO_COMPRESSION_NONE;
     280           0 :         resp_pkt << depl_serial_v << depl_compress_mode << net_proto_version
     281           0 :                 << auth_mechs << legacyPlayerNameCasing;
     282             : 
     283           0 :         Send(&resp_pkt);
     284             : 
     285           0 :         client->allowed_auth_mechs = auth_mechs;
     286           0 :         client->setDeployedCompressionMode(depl_compress_mode);
     287             : 
     288           0 :         m_clients.event(pkt->getPeerId(), CSE_Hello);
     289             : }
     290             : 
     291           0 : void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
     292             : {
     293             :         // [0] u8 SER_FMT_VER_HIGHEST_READ
     294             :         // [1] u8[20] player_name
     295             :         // [21] u8[28] password <--- can be sent without this, from old versions
     296             : 
     297           0 :         if (pkt->getSize() < 1+PLAYERNAME_SIZE)
     298           0 :                 return;
     299             : 
     300           0 :         RemoteClient* client = getClient(pkt->getPeerId(), CS_Created);
     301             : 
     302           0 :         std::string addr_s;
     303             :         try {
     304           0 :                 Address address = getPeerAddress(pkt->getPeerId());
     305           0 :                 addr_s = address.serializeString();
     306             :         }
     307           0 :         catch (con::PeerNotFoundException &e) {
     308             :                 /*
     309             :                  * no peer for this packet found
     310             :                  * most common reason is peer timeout, e.g. peer didn't
     311             :                  * respond for some time, your server was overloaded or
     312             :                  * things like that.
     313             :                  */
     314           0 :                 infostream << "Server::ProcessData(): Canceling: peer "
     315           0 :                                 << pkt->getPeerId() << " not found" << std::endl;
     316           0 :                 return;
     317             :         }
     318             : 
     319             :         // If net_proto_version is set, this client has already been handled
     320           0 :         if (client->getState() > CS_Created) {
     321           0 :                 verbosestream << "Server: Ignoring multiple TOSERVER_INITs from "
     322           0 :                                 << addr_s << " (peer_id=" << pkt->getPeerId() << ")" << std::endl;
     323           0 :                 return;
     324             :         }
     325             : 
     326           0 :         verbosestream << "Server: Got TOSERVER_INIT_LEGACY from " << addr_s << " (peer_id="
     327           0 :                         << pkt->getPeerId() << ")" << std::endl;
     328             : 
     329             :         // Do not allow multiple players in simple singleplayer mode.
     330             :         // This isn't a perfect way to do it, but will suffice for now
     331           0 :         if (m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1) {
     332           0 :                 infostream << "Server: Not allowing another client (" << addr_s
     333           0 :                                 << ") to connect in simple singleplayer mode" << std::endl;
     334           0 :                 DenyAccess_Legacy(pkt->getPeerId(), L"Running in simple singleplayer mode.");
     335           0 :                 return;
     336             :         }
     337             : 
     338             :         // First byte after command is maximum supported
     339             :         // serialization version
     340             :         u8 client_max;
     341             : 
     342           0 :         *pkt >> client_max;
     343             : 
     344           0 :         u8 our_max = SER_FMT_VER_HIGHEST_READ;
     345             :         // Use the highest version supported by both
     346           0 :         int deployed = std::min(client_max, our_max);
     347             :         // If it's lower than the lowest supported, give up.
     348           0 :         if (deployed < SER_FMT_VER_LOWEST)
     349           0 :                 deployed = SER_FMT_VER_INVALID;
     350             : 
     351           0 :         if (deployed == SER_FMT_VER_INVALID) {
     352           0 :                 actionstream << "Server: A mismatched client tried to connect from "
     353           0 :                                 << addr_s << std::endl;
     354           0 :                 infostream<<"Server: Cannot negotiate serialization version with "
     355           0 :                                 << addr_s << std::endl;
     356           0 :                 DenyAccess_Legacy(pkt->getPeerId(), std::wstring(
     357             :                                 L"Your client's version is not supported.\n"
     358             :                                 L"Server version is ")
     359           0 :                                 + narrow_to_wide(g_version_string) + L"."
     360           0 :                 );
     361           0 :                 return;
     362             :         }
     363             : 
     364           0 :         client->setPendingSerializationVersion(deployed);
     365             : 
     366             :         /*
     367             :                 Read and check network protocol version
     368             :         */
     369             : 
     370           0 :         u16 min_net_proto_version = 0;
     371           0 :         if (pkt->getSize() >= 1 + PLAYERNAME_SIZE + PASSWORD_SIZE + 2)
     372           0 :                 min_net_proto_version = pkt->getU16(1 + PLAYERNAME_SIZE + PASSWORD_SIZE);
     373             : 
     374             :         // Use same version as minimum and maximum if maximum version field
     375             :         // doesn't exist (backwards compatibility)
     376           0 :         u16 max_net_proto_version = min_net_proto_version;
     377           0 :         if (pkt->getSize() >= 1 + PLAYERNAME_SIZE + PASSWORD_SIZE + 2 + 2)
     378           0 :                 max_net_proto_version = pkt->getU16(1 + PLAYERNAME_SIZE + PASSWORD_SIZE + 2);
     379             : 
     380             :         // Start with client's maximum version
     381           0 :         u16 net_proto_version = max_net_proto_version;
     382             : 
     383             :         // Figure out a working version if it is possible at all
     384           0 :         if (max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
     385             :                         min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX) {
     386             :                 // If maximum is larger than our maximum, go with our maximum
     387           0 :                 if (max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
     388           0 :                         net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
     389             :                 // Else go with client's maximum
     390             :                 else
     391           0 :                         net_proto_version = max_net_proto_version;
     392             :         }
     393             : 
     394             :         // The client will send up to date init packet, ignore this one
     395           0 :         if (net_proto_version >= 25)
     396           0 :                 return;
     397             : 
     398           0 :         verbosestream << "Server: " << addr_s << ": Protocol version: min: "
     399           0 :                         << min_net_proto_version << ", max: " << max_net_proto_version
     400           0 :                         << ", chosen: " << net_proto_version << std::endl;
     401             : 
     402           0 :         client->net_proto_version = net_proto_version;
     403             : 
     404           0 :         if (net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
     405             :                         net_proto_version > SERVER_PROTOCOL_VERSION_MAX) {
     406           0 :                 actionstream << "Server: A mismatched client tried to connect from "
     407           0 :                                 << addr_s << std::endl;
     408           0 :                 DenyAccess_Legacy(pkt->getPeerId(), std::wstring(
     409             :                                 L"Your client's version is not supported.\n"
     410             :                                 L"Server version is ")
     411           0 :                                 + narrow_to_wide(g_version_string) + L",\n"
     412           0 :                                 + L"server's PROTOCOL_VERSION is "
     413           0 :                                 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
     414           0 :                                 + L"..."
     415           0 :                                 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
     416           0 :                                 + L", client's PROTOCOL_VERSION is "
     417           0 :                                 + narrow_to_wide(itos(min_net_proto_version))
     418           0 :                                 + L"..."
     419           0 :                                 + narrow_to_wide(itos(max_net_proto_version))
     420           0 :                 );
     421           0 :                 return;
     422             :         }
     423             : 
     424           0 :         if (g_settings->getBool("strict_protocol_version_checking")) {
     425           0 :                 if (net_proto_version != LATEST_PROTOCOL_VERSION) {
     426           0 :                         actionstream << "Server: A mismatched (strict) client tried to "
     427           0 :                                         << "connect from " << addr_s << std::endl;
     428           0 :                         DenyAccess_Legacy(pkt->getPeerId(), std::wstring(
     429             :                                         L"Your client's version is not supported.\n"
     430             :                                         L"Server version is ")
     431           0 :                                         + narrow_to_wide(g_version_string) + L",\n"
     432           0 :                                         + L"server's PROTOCOL_VERSION (strict) is "
     433           0 :                                         + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
     434           0 :                                         + L", client's PROTOCOL_VERSION is "
     435           0 :                                         + narrow_to_wide(itos(min_net_proto_version))
     436           0 :                                         + L"..."
     437           0 :                                         + narrow_to_wide(itos(max_net_proto_version))
     438           0 :                         );
     439           0 :                         return;
     440             :                 }
     441             :         }
     442             : 
     443             :         /*
     444             :                 Set up player
     445             :         */
     446             :         char playername[PLAYERNAME_SIZE];
     447           0 :         unsigned int playername_length = 0;
     448           0 :         for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
     449           0 :                 playername[playername_length] = pkt->getChar(1+playername_length);
     450           0 :                 if (pkt->getChar(1+playername_length) == 0)
     451           0 :                         break;
     452             :         }
     453             : 
     454           0 :         if (playername_length == PLAYERNAME_SIZE) {
     455           0 :                 actionstream << "Server: Player with name exceeding max length "
     456           0 :                                 << "tried to connect from " << addr_s << std::endl;
     457           0 :                 DenyAccess_Legacy(pkt->getPeerId(), L"Name too long");
     458           0 :                 return;
     459             :         }
     460             : 
     461             : 
     462           0 :         if (playername[0]=='\0') {
     463           0 :                 actionstream << "Server: Player with an empty name "
     464           0 :                                 << "tried to connect from " << addr_s << std::endl;
     465           0 :                 DenyAccess_Legacy(pkt->getPeerId(), L"Empty name");
     466           0 :                 return;
     467             :         }
     468             : 
     469           0 :         if (string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false) {
     470           0 :                 actionstream << "Server: Player with an invalid name "
     471           0 :                                 << "tried to connect from " << addr_s << std::endl;
     472           0 :                 DenyAccess_Legacy(pkt->getPeerId(), L"Name contains unallowed characters");
     473           0 :                 return;
     474             :         }
     475             : 
     476           0 :         if (!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0) {
     477           0 :                 actionstream << "Server: Player with the name \"singleplayer\" "
     478           0 :                                 << "tried to connect from " << addr_s << std::endl;
     479           0 :                 DenyAccess_Legacy(pkt->getPeerId(), L"Name is not allowed");
     480           0 :                 return;
     481             :         }
     482             : 
     483             :         {
     484           0 :                 std::string reason;
     485           0 :                 if (m_script->on_prejoinplayer(playername, addr_s, &reason)) {
     486           0 :                         actionstream << "Server: Player with the name \"" << playername << "\" "
     487           0 :                                         << "tried to connect from " << addr_s << " "
     488           0 :                                         << "but it was disallowed for the following reason: "
     489           0 :                                         << reason << std::endl;
     490           0 :                         DenyAccess_Legacy(pkt->getPeerId(), narrow_to_wide(reason.c_str()));
     491           0 :                         return;
     492             :                 }
     493             :         }
     494             : 
     495           0 :         infostream<<"Server: New connection: \""<<playername<<"\" from "
     496           0 :                         <<addr_s<<" (peer_id="<<pkt->getPeerId()<<")"<<std::endl;
     497             : 
     498             :         // Get password
     499             :         char given_password[PASSWORD_SIZE];
     500           0 :         if (pkt->getSize() < 1 + PLAYERNAME_SIZE + PASSWORD_SIZE) {
     501             :                 // old version - assume blank password
     502           0 :                 given_password[0] = 0;
     503             :         }
     504             :         else {
     505           0 :                 for (u16 i = 0; i < PASSWORD_SIZE - 1; i++) {
     506           0 :                         given_password[i] = pkt->getChar(21 + i);
     507             :                 }
     508           0 :                 given_password[PASSWORD_SIZE - 1] = 0;
     509             :         }
     510             : 
     511           0 :         if (!base64_is_valid(given_password)) {
     512           0 :                 actionstream << "Server: " << playername
     513           0 :                                 << " supplied invalid password hash" << std::endl;
     514           0 :                 DenyAccess_Legacy(pkt->getPeerId(), L"Invalid password hash");
     515           0 :                 return;
     516             :         }
     517             : 
     518             :         // Enforce user limit.
     519             :         // Don't enforce for users that have some admin right
     520           0 :         if (m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
     521           0 :                         !checkPriv(playername, "server") &&
     522           0 :                         !checkPriv(playername, "ban") &&
     523           0 :                         !checkPriv(playername, "privs") &&
     524           0 :                         !checkPriv(playername, "password") &&
     525           0 :                         playername != g_settings->get("name")) {
     526           0 :                 actionstream << "Server: " << playername << " tried to join, but there"
     527           0 :                                 << " are already max_users="
     528           0 :                                 << g_settings->getU16("max_users") << " players." << std::endl;
     529           0 :                 DenyAccess_Legacy(pkt->getPeerId(), L"Too many users.");
     530           0 :                 return;
     531             :         }
     532             : 
     533           0 :         std::string checkpwd; // Password hash to check against
     534           0 :         bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
     535             : 
     536             :         // If no authentication info exists for user, create it
     537           0 :         if (!has_auth) {
     538           0 :                 if (!isSingleplayer() &&
     539           0 :                                 g_settings->getBool("disallow_empty_password") &&
     540           0 :                                 std::string(given_password) == "") {
     541           0 :                         actionstream << "Server: " << playername
     542           0 :                                         << " supplied empty password" << std::endl;
     543           0 :                         DenyAccess_Legacy(pkt->getPeerId(), L"Empty passwords are "
     544           0 :                                         L"disallowed. Set a password and try again.");
     545           0 :                         return;
     546             :                 }
     547             :                 std::string raw_default_password =
     548           0 :                         g_settings->get("default_password");
     549             :                 std::string initial_password =
     550           0 :                         translatePassword(playername, raw_default_password);
     551             : 
     552             :                 // If default_password is empty, allow any initial password
     553           0 :                 if (raw_default_password.length() == 0)
     554           0 :                         initial_password = given_password;
     555             : 
     556           0 :                 m_script->createAuth(playername, initial_password);
     557             :         }
     558             : 
     559           0 :         has_auth = m_script->getAuth(playername, &checkpwd, NULL);
     560             : 
     561           0 :         if (!has_auth) {
     562           0 :                 actionstream << "Server: " << playername << " cannot be authenticated"
     563           0 :                                 << " (auth handler does not work?)" << std::endl;
     564           0 :                 DenyAccess_Legacy(pkt->getPeerId(), L"Not allowed to login");
     565           0 :                 return;
     566             :         }
     567             : 
     568           0 :         if (given_password != checkpwd) {
     569           0 :                 actionstream << "Server: " << playername << " supplied wrong password"
     570           0 :                                 << std::endl;
     571           0 :                 DenyAccess_Legacy(pkt->getPeerId(), L"Wrong password");
     572           0 :                 return;
     573             :         }
     574             : 
     575             :         RemotePlayer *player =
     576           0 :                         static_cast<RemotePlayer*>(m_env->getPlayer(playername));
     577             : 
     578           0 :         if (player && player->peer_id != 0) {
     579           0 :                 actionstream << "Server: " << playername << ": Failed to emerge player"
     580           0 :                                 << " (player allocated to an another client)" << std::endl;
     581           0 :                 DenyAccess_Legacy(pkt->getPeerId(), L"Another client is connected with this "
     582             :                                 L"name. If your client closed unexpectedly, try again in "
     583           0 :                                 L"a minute.");
     584             :         }
     585             : 
     586           0 :         m_clients.setPlayerName(pkt->getPeerId(), playername);
     587             : 
     588             :         /*
     589             :                 Answer with a TOCLIENT_INIT
     590             :         */
     591             : 
     592             :         NetworkPacket resp_pkt(TOCLIENT_INIT_LEGACY, 1 + 6 + 8 + 4,
     593           0 :                         pkt->getPeerId());
     594             : 
     595           0 :         resp_pkt << (u8) deployed << (v3s16) floatToInt(v3f(0,0,0), BS)
     596           0 :                         << (u64) m_env->getServerMap().getSeed()
     597           0 :                         << g_settings->getFloat("dedicated_server_step");
     598             : 
     599           0 :         Send(&resp_pkt);
     600           0 :         m_clients.event(pkt->getPeerId(), CSE_InitLegacy);
     601             : }
     602             : 
     603           0 : void Server::handleCommand_Init2(NetworkPacket* pkt)
     604             : {
     605           0 :         verbosestream << "Server: Got TOSERVER_INIT2 from "
     606           0 :                         << pkt->getPeerId() << std::endl;
     607             : 
     608           0 :         m_clients.event(pkt->getPeerId(), CSE_GotInit2);
     609           0 :         u16 protocol_version = m_clients.getProtocolVersion(pkt->getPeerId());
     610             : 
     611             : 
     612             :         ///// begin compatibility code
     613           0 :         PlayerSAO* playersao = NULL;
     614           0 :         if (protocol_version <= 22) {
     615           0 :                 playersao = StageTwoClientInit(pkt->getPeerId());
     616             : 
     617           0 :                 if (playersao == NULL) {
     618             :                         actionstream
     619           0 :                                 << "TOSERVER_INIT2 stage 2 client init failed for peer "
     620           0 :                                 << pkt->getPeerId() << std::endl;
     621           0 :                         return;
     622             :                 }
     623             :         }
     624             :         ///// end compatibility code
     625             : 
     626             :         /*
     627             :                 Send some initialization data
     628             :         */
     629             : 
     630           0 :         infostream << "Server: Sending content to "
     631           0 :                         << getPlayerName(pkt->getPeerId()) << std::endl;
     632             : 
     633             :         // Send player movement settings
     634           0 :         SendMovement(pkt->getPeerId());
     635             : 
     636             :         // Send item definitions
     637           0 :         SendItemDef(pkt->getPeerId(), m_itemdef, protocol_version);
     638             : 
     639             :         // Send node definitions
     640           0 :         SendNodeDef(pkt->getPeerId(), m_nodedef, protocol_version);
     641             : 
     642           0 :         m_clients.event(pkt->getPeerId(), CSE_SetDefinitionsSent);
     643             : 
     644             :         // Send media announcement
     645           0 :         sendMediaAnnouncement(pkt->getPeerId());
     646             : 
     647             :         // Send detached inventories
     648           0 :         sendDetachedInventories(pkt->getPeerId());
     649             : 
     650             :         // Send time of day
     651           0 :         u16 time = m_env->getTimeOfDay();
     652           0 :         float time_speed = g_settings->getFloat("time_speed");
     653           0 :         SendTimeOfDay(pkt->getPeerId(), time, time_speed);
     654             : 
     655             :         ///// begin compatibility code
     656           0 :         if (protocol_version <= 22) {
     657           0 :                 m_clients.event(pkt->getPeerId(), CSE_SetClientReady);
     658           0 :                 m_script->on_joinplayer(playersao);
     659             :         }
     660             :         ///// end compatibility code
     661             : 
     662             :         // Warnings about protocol version can be issued here
     663           0 :         if (getClient(pkt->getPeerId())->net_proto_version < LATEST_PROTOCOL_VERSION) {
     664           0 :                 SendChatMessage(pkt->getPeerId(), L"# Server: WARNING: YOUR CLIENT'S "
     665           0 :                                 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
     666             :         }
     667             : }
     668             : 
     669           0 : void Server::handleCommand_RequestMedia(NetworkPacket* pkt)
     670             : {
     671           0 :         std::vector<std::string> tosend;
     672             :         u16 numfiles;
     673             : 
     674           0 :         *pkt >> numfiles;
     675             : 
     676           0 :         infostream << "Sending " << numfiles << " files to "
     677           0 :                         << getPlayerName(pkt->getPeerId()) << std::endl;
     678           0 :         verbosestream << "TOSERVER_REQUEST_MEDIA: " << std::endl;
     679             : 
     680           0 :         for (u16 i = 0; i < numfiles; i++) {
     681           0 :                 std::string name;
     682             : 
     683           0 :                 *pkt >> name;
     684             : 
     685           0 :                 tosend.push_back(name);
     686           0 :                 verbosestream << "TOSERVER_REQUEST_MEDIA: requested file "
     687           0 :                                 << name << std::endl;
     688             :         }
     689             : 
     690           0 :         sendRequestedMedia(pkt->getPeerId(), tosend);
     691           0 : }
     692             : 
     693           0 : void Server::handleCommand_ReceivedMedia(NetworkPacket* pkt)
     694             : {
     695           0 : }
     696             : 
     697           0 : void Server::handleCommand_ClientReady(NetworkPacket* pkt)
     698             : {
     699           0 :         u16 peer_id = pkt->getPeerId();
     700           0 :         u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
     701             : 
     702             :         // clients <= protocol version 22 did not send ready message,
     703             :         // they're already initialized
     704           0 :         if (peer_proto_ver <= 22) {
     705           0 :                 infostream << "Client sent message not expected by a "
     706           0 :                         << "client using protocol version <= 22,"
     707           0 :                         << "disconnecting peer_id: " << peer_id << std::endl;
     708           0 :                 m_con.DisconnectPeer(peer_id);
     709           0 :                 return;
     710             :         }
     711             : 
     712           0 :         PlayerSAO* playersao = StageTwoClientInit(peer_id);
     713             : 
     714           0 :         if (playersao == NULL) {
     715             :                 actionstream
     716           0 :                         << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
     717           0 :                         << peer_id << std::endl;
     718           0 :                 m_con.DisconnectPeer(peer_id);
     719           0 :                 return;
     720             :         }
     721             : 
     722             : 
     723           0 :         if (pkt->getSize() < 8) {
     724             :                 errorstream
     725           0 :                         << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
     726           0 :                         << peer_id << std::endl;
     727           0 :                 m_con.DisconnectPeer(peer_id);
     728           0 :                 return;
     729             :         }
     730             : 
     731             :         u8 major_ver, minor_ver, patch_ver, reserved;
     732           0 :         std::string full_ver;
     733           0 :         *pkt >> major_ver >> minor_ver >> patch_ver >> reserved >> full_ver;
     734             : 
     735           0 :         m_clients.setClientVersion(
     736             :                         peer_id, major_ver, minor_ver, patch_ver,
     737           0 :                         full_ver);
     738             : 
     739           0 :         m_clients.event(peer_id, CSE_SetClientReady);
     740           0 :         m_script->on_joinplayer(playersao);
     741             : }
     742             : 
     743           0 : void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
     744             : {
     745           0 :         if (pkt->getSize() < 1)
     746           0 :                 return;
     747             : 
     748             :         /*
     749             :                 [0] u16 command
     750             :                 [2] u8 count
     751             :                 [3] v3s16 pos_0
     752             :                 [3+6] v3s16 pos_1
     753             :                 ...
     754             :         */
     755             : 
     756             :         u8 count;
     757           0 :         *pkt >> count;
     758             : 
     759           0 :         RemoteClient *client = getClient(pkt->getPeerId());
     760             : 
     761           0 :         for (u16 i = 0; i < count; i++) {
     762           0 :                 if ((s16)pkt->getSize() < 1 + (i + 1) * 6)
     763             :                         throw con::InvalidIncomingDataException
     764           0 :                                 ("GOTBLOCKS length is too short");
     765           0 :                 v3s16 p;
     766             : 
     767           0 :                 *pkt >> p;
     768             : 
     769           0 :                 client->GotBlock(p);
     770             :         }
     771             : }
     772             : 
     773           0 : void Server::handleCommand_PlayerPos(NetworkPacket* pkt)
     774             : {
     775           0 :         if (pkt->getSize() < 12 + 12 + 4 + 4)
     776           0 :                 return;
     777             : 
     778           0 :         v3s32 ps, ss;
     779             :         s32 f32pitch, f32yaw;
     780             : 
     781           0 :         *pkt >> ps;
     782           0 :         *pkt >> ss;
     783           0 :         *pkt >> f32pitch;
     784           0 :         *pkt >> f32yaw;
     785             : 
     786           0 :         f32 pitch = (f32)f32pitch / 100.0;
     787           0 :         f32 yaw = (f32)f32yaw / 100.0;
     788           0 :         u32 keyPressed = 0;
     789             : 
     790           0 :         if (pkt->getSize() >= 12 + 12 + 4 + 4 + 4)
     791           0 :                 *pkt >> keyPressed;
     792             : 
     793           0 :         v3f position((f32)ps.X / 100.0, (f32)ps.Y / 100.0, (f32)ps.Z / 100.0);
     794           0 :         v3f speed((f32)ss.X / 100.0, (f32)ss.Y / 100.0, (f32)ss.Z / 100.0);
     795             : 
     796           0 :         pitch = modulo360f(pitch);
     797           0 :         yaw = modulo360f(yaw);
     798             : 
     799           0 :         Player *player = m_env->getPlayer(pkt->getPeerId());
     800           0 :         if (player == NULL) {
     801             :                 errorstream << "Server::ProcessData(): Canceling: "
     802           0 :                                 "No player for peer_id=" << pkt->getPeerId()
     803           0 :                                 << " disconnecting peer!" << std::endl;
     804           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
     805           0 :                 return;
     806             :         }
     807             : 
     808             :         // If player is dead we don't care of this packet
     809           0 :         if (player->isDead()) {
     810           0 :                 verbosestream << "TOSERVER_PLAYERPOS: " << player->getName()
     811           0 :                         << " is dead. Ignoring packet";
     812           0 :                 return;
     813             :         }
     814             : 
     815           0 :         PlayerSAO *playersao = player->getPlayerSAO();
     816           0 :         if (playersao == NULL) {
     817             :                 errorstream << "Server::ProcessData(): Canceling: "
     818           0 :                                 "No player object for peer_id=" << pkt->getPeerId()
     819           0 :                                 << " disconnecting peer!" << std::endl;
     820           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
     821           0 :                 return;
     822             :         }
     823             : 
     824           0 :         player->setPosition(position);
     825           0 :         player->setSpeed(speed);
     826           0 :         player->setPitch(pitch);
     827           0 :         player->setYaw(yaw);
     828           0 :         player->keyPressed = keyPressed;
     829           0 :         player->control.up = (keyPressed & 1);
     830           0 :         player->control.down = (keyPressed & 2);
     831           0 :         player->control.left = (keyPressed & 4);
     832           0 :         player->control.right = (keyPressed & 8);
     833           0 :         player->control.jump = (keyPressed & 16);
     834           0 :         player->control.aux1 = (keyPressed & 32);
     835           0 :         player->control.sneak = (keyPressed & 64);
     836           0 :         player->control.LMB = (keyPressed & 128);
     837           0 :         player->control.RMB = (keyPressed & 256);
     838             : 
     839           0 :         if (playersao->checkMovementCheat()) {
     840             :                 // Call callbacks
     841           0 :                 m_script->on_cheat(playersao, "moved_too_fast");
     842           0 :                 SendMovePlayer(pkt->getPeerId());
     843             :         }
     844             : }
     845             : 
     846           0 : void Server::handleCommand_DeletedBlocks(NetworkPacket* pkt)
     847             : {
     848           0 :         if (pkt->getSize() < 1)
     849           0 :                 return;
     850             : 
     851             :         /*
     852             :                 [0] u16 command
     853             :                 [2] u8 count
     854             :                 [3] v3s16 pos_0
     855             :                 [3+6] v3s16 pos_1
     856             :                 ...
     857             :         */
     858             : 
     859             :         u8 count;
     860           0 :         *pkt >> count;
     861             : 
     862           0 :         RemoteClient *client = getClient(pkt->getPeerId());
     863             : 
     864           0 :         for (u16 i = 0; i < count; i++) {
     865           0 :                 if ((s16)pkt->getSize() < 1 + (i + 1) * 6)
     866             :                         throw con::InvalidIncomingDataException
     867           0 :                                 ("DELETEDBLOCKS length is too short");
     868           0 :                 v3s16 p;
     869           0 :                 *pkt >> p;
     870             : 
     871           0 :                 client->SetBlockNotSent(p);
     872             :         }
     873             : }
     874             : 
     875           0 : void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
     876             : {
     877           0 :         Player *player = m_env->getPlayer(pkt->getPeerId());
     878           0 :         if (player == NULL) {
     879             :                 errorstream << "Server::ProcessData(): Canceling: "
     880           0 :                                 "No player for peer_id=" << pkt->getPeerId()
     881           0 :                                 << " disconnecting peer!" << std::endl;
     882           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
     883           0 :                 return;
     884             :         }
     885             : 
     886           0 :         PlayerSAO *playersao = player->getPlayerSAO();
     887           0 :         if (playersao == NULL) {
     888             :                 errorstream << "Server::ProcessData(): Canceling: "
     889           0 :                                 "No player object for peer_id=" << pkt->getPeerId()
     890           0 :                                 << " disconnecting peer!" << std::endl;
     891           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
     892           0 :                 return;
     893             :         }
     894             : 
     895             :         // Strip command and create a stream
     896           0 :         std::string datastring(pkt->getString(0), pkt->getSize());
     897           0 :         verbosestream << "TOSERVER_INVENTORY_ACTION: data=" << datastring
     898           0 :                 << std::endl;
     899           0 :         std::istringstream is(datastring, std::ios_base::binary);
     900             :         // Create an action
     901           0 :         InventoryAction *a = InventoryAction::deSerialize(is);
     902           0 :         if (a == NULL) {
     903           0 :                 infostream << "TOSERVER_INVENTORY_ACTION: "
     904           0 :                                 << "InventoryAction::deSerialize() returned NULL"
     905           0 :                                 << std::endl;
     906           0 :                 return;
     907             :         }
     908             : 
     909             :         // If something goes wrong, this player is to blame
     910             :         RollbackScopeActor rollback_scope(m_rollback,
     911           0 :                         std::string("player:")+player->getName());
     912             : 
     913             :         /*
     914             :                 Note: Always set inventory not sent, to repair cases
     915             :                 where the client made a bad prediction.
     916             :         */
     917             : 
     918             :         /*
     919             :                 Handle restrictions and special cases of the move action
     920             :         */
     921           0 :         if (a->getType() == IACTION_MOVE) {
     922           0 :                 IMoveAction *ma = (IMoveAction*)a;
     923             : 
     924           0 :                 ma->from_inv.applyCurrentPlayer(player->getName());
     925           0 :                 ma->to_inv.applyCurrentPlayer(player->getName());
     926             : 
     927           0 :                 setInventoryModified(ma->from_inv, false);
     928           0 :                 setInventoryModified(ma->to_inv, false);
     929             : 
     930             :                 bool from_inv_is_current_player =
     931           0 :                         (ma->from_inv.type == InventoryLocation::PLAYER) &&
     932           0 :                         (ma->from_inv.name == player->getName());
     933             : 
     934             :                 bool to_inv_is_current_player =
     935           0 :                         (ma->to_inv.type == InventoryLocation::PLAYER) &&
     936           0 :                         (ma->to_inv.name == player->getName());
     937             : 
     938             :                 /*
     939             :                         Disable moving items out of craftpreview
     940             :                 */
     941           0 :                 if (ma->from_list == "craftpreview") {
     942           0 :                         infostream << "Ignoring IMoveAction from "
     943           0 :                                         << (ma->from_inv.dump()) << ":" << ma->from_list
     944           0 :                                         << " to " << (ma->to_inv.dump()) << ":" << ma->to_list
     945           0 :                                         << " because src is " << ma->from_list << std::endl;
     946           0 :                         delete a;
     947           0 :                         return;
     948             :                 }
     949             : 
     950             :                 /*
     951             :                         Disable moving items into craftresult and craftpreview
     952             :                 */
     953           0 :                 if (ma->to_list == "craftpreview" || ma->to_list == "craftresult") {
     954           0 :                         infostream << "Ignoring IMoveAction from "
     955           0 :                                         << (ma->from_inv.dump()) << ":" << ma->from_list
     956           0 :                                         << " to " << (ma->to_inv.dump()) << ":" << ma->to_list
     957           0 :                                         << " because dst is " << ma->to_list << std::endl;
     958           0 :                         delete a;
     959           0 :                         return;
     960             :                 }
     961             : 
     962             :                 // Disallow moving items in elsewhere than player's inventory
     963             :                 // if not allowed to interact
     964           0 :                 if (!checkPriv(player->getName(), "interact") &&
     965           0 :                                 (!from_inv_is_current_player ||
     966           0 :                                 !to_inv_is_current_player)) {
     967           0 :                         infostream << "Cannot move outside of player's inventory: "
     968           0 :                                         << "No interact privilege" << std::endl;
     969           0 :                         delete a;
     970           0 :                         return;
     971             :                 }
     972             :         }
     973             :         /*
     974             :                 Handle restrictions and special cases of the drop action
     975             :         */
     976           0 :         else if (a->getType() == IACTION_DROP) {
     977           0 :                 IDropAction *da = (IDropAction*)a;
     978             : 
     979           0 :                 da->from_inv.applyCurrentPlayer(player->getName());
     980             : 
     981           0 :                 setInventoryModified(da->from_inv, false);
     982             : 
     983             :                 /*
     984             :                         Disable dropping items out of craftpreview
     985             :                 */
     986           0 :                 if (da->from_list == "craftpreview") {
     987           0 :                         infostream << "Ignoring IDropAction from "
     988           0 :                                         << (da->from_inv.dump()) << ":" << da->from_list
     989           0 :                                         << " because src is " << da->from_list << std::endl;
     990           0 :                         delete a;
     991           0 :                         return;
     992             :                 }
     993             : 
     994             :                 // Disallow dropping items if not allowed to interact
     995           0 :                 if (!checkPriv(player->getName(), "interact")) {
     996           0 :                         delete a;
     997           0 :                         return;
     998             :                 }
     999             :         }
    1000             :         /*
    1001             :                 Handle restrictions and special cases of the craft action
    1002             :         */
    1003           0 :         else if (a->getType() == IACTION_CRAFT) {
    1004           0 :                 ICraftAction *ca = (ICraftAction*)a;
    1005             : 
    1006           0 :                 ca->craft_inv.applyCurrentPlayer(player->getName());
    1007             : 
    1008           0 :                 setInventoryModified(ca->craft_inv, false);
    1009             : 
    1010             :                 //bool craft_inv_is_current_player =
    1011             :                 //      (ca->craft_inv.type == InventoryLocation::PLAYER) &&
    1012             :                 //      (ca->craft_inv.name == player->getName());
    1013             : 
    1014             :                 // Disallow crafting if not allowed to interact
    1015           0 :                 if (!checkPriv(player->getName(), "interact")) {
    1016           0 :                         infostream << "Cannot craft: "
    1017           0 :                                         << "No interact privilege" << std::endl;
    1018           0 :                         delete a;
    1019           0 :                         return;
    1020             :                 }
    1021             :         }
    1022             : 
    1023             :         // Do the action
    1024           0 :         a->apply(this, playersao, this);
    1025             :         // Eat the action
    1026           0 :         delete a;
    1027             : 
    1028           0 :         SendInventory(playersao);
    1029             : }
    1030             : 
    1031           0 : void Server::handleCommand_ChatMessage(NetworkPacket* pkt)
    1032             : {
    1033             :         /*
    1034             :                 u16 command
    1035             :                 u16 length
    1036             :                 wstring message
    1037             :         */
    1038             :         u16 len;
    1039           0 :         *pkt >> len;
    1040             : 
    1041           0 :         std::wstring message;
    1042           0 :         for (u16 i = 0; i < len; i++) {
    1043             :                 u16 tmp_wchar;
    1044           0 :                 *pkt >> tmp_wchar;
    1045             : 
    1046           0 :                 message += (wchar_t)tmp_wchar;
    1047             :         }
    1048             : 
    1049           0 :         Player *player = m_env->getPlayer(pkt->getPeerId());
    1050           0 :         if (player == NULL) {
    1051             :                 errorstream << "Server::ProcessData(): Canceling: "
    1052           0 :                                 "No player for peer_id=" << pkt->getPeerId()
    1053           0 :                                 << " disconnecting peer!" << std::endl;
    1054           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1055           0 :                 return;
    1056             :         }
    1057             : 
    1058             :         // If something goes wrong, this player is to blame
    1059             :         RollbackScopeActor rollback_scope(m_rollback,
    1060           0 :                         std::string("player:")+player->getName());
    1061             : 
    1062             :         // Get player name of this client
    1063           0 :         std::wstring name = narrow_to_wide(player->getName());
    1064             : 
    1065             :         // Run script hook
    1066           0 :         bool ate = m_script->on_chat_message(player->getName(),
    1067           0 :                         wide_to_narrow(message));
    1068             :         // If script ate the message, don't proceed
    1069           0 :         if (ate)
    1070           0 :                 return;
    1071             : 
    1072             :         // Line to send to players
    1073           0 :         std::wstring line;
    1074             :         // Whether to send to the player that sent the line
    1075           0 :         bool send_to_sender_only = false;
    1076             : 
    1077             :         // Commands are implemented in Lua, so only catch invalid
    1078             :         // commands that were not "eaten" and send an error back
    1079           0 :         if (message[0] == L'/') {
    1080           0 :                 message = message.substr(1);
    1081           0 :                 send_to_sender_only = true;
    1082           0 :                 if (message.length() == 0)
    1083           0 :                         line += L"-!- Empty command";
    1084             :                 else
    1085           0 :                         line += L"-!- Invalid command: " + str_split(message, L' ')[0];
    1086             :         }
    1087             :         else {
    1088           0 :                 if (checkPriv(player->getName(), "shout")) {
    1089           0 :                         line += L"<";
    1090           0 :                         line += name;
    1091           0 :                         line += L"> ";
    1092           0 :                         line += message;
    1093             :                 } else {
    1094           0 :                         line += L"-!- You don't have permission to shout.";
    1095           0 :                         send_to_sender_only = true;
    1096             :                 }
    1097             :         }
    1098             : 
    1099           0 :         if (line != L"")
    1100             :         {
    1101             :                 /*
    1102             :                         Send the message to sender
    1103             :                 */
    1104           0 :                 if (send_to_sender_only) {
    1105           0 :                         SendChatMessage(pkt->getPeerId(), line);
    1106             :                 }
    1107             :                 /*
    1108             :                         Send the message to others
    1109             :                 */
    1110             :                 else {
    1111           0 :                         actionstream << "CHAT: " << wide_to_narrow(line)<<std::endl;
    1112             : 
    1113           0 :                         std::vector<u16> clients = m_clients.getClientIDs();
    1114             : 
    1115           0 :                         for (std::vector<u16>::iterator i = clients.begin();
    1116           0 :                                 i != clients.end(); ++i) {
    1117           0 :                                 if (*i != pkt->getPeerId())
    1118           0 :                                         SendChatMessage(*i, line);
    1119             :                         }
    1120             :                 }
    1121             :         }
    1122             : }
    1123             : 
    1124           0 : void Server::handleCommand_Damage(NetworkPacket* pkt)
    1125             : {
    1126             :         u8 damage;
    1127             : 
    1128           0 :         *pkt >> damage;
    1129             : 
    1130           0 :         Player *player = m_env->getPlayer(pkt->getPeerId());
    1131           0 :         if (player == NULL) {
    1132             :                 errorstream << "Server::ProcessData(): Canceling: "
    1133           0 :                                 "No player for peer_id=" << pkt->getPeerId()
    1134           0 :                                 << " disconnecting peer!" << std::endl;
    1135           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1136           0 :                 return;
    1137             :         }
    1138             : 
    1139           0 :         PlayerSAO *playersao = player->getPlayerSAO();
    1140           0 :         if (playersao == NULL) {
    1141             :                 errorstream << "Server::ProcessData(): Canceling: "
    1142           0 :                                 "No player object for peer_id=" << pkt->getPeerId()
    1143           0 :                                 << " disconnecting peer!" << std::endl;
    1144           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1145           0 :                 return;
    1146             :         }
    1147             : 
    1148           0 :         if (g_settings->getBool("enable_damage")) {
    1149           0 :                 actionstream << player->getName() << " damaged by "
    1150           0 :                                 << (int)damage << " hp at " << PP(player->getPosition() / BS)
    1151           0 :                                 << std::endl;
    1152             : 
    1153           0 :                 playersao->setHP(playersao->getHP() - damage);
    1154           0 :                 SendPlayerHPOrDie(playersao->getPeerID(), playersao->getHP() == 0);
    1155             :         }
    1156             : }
    1157             : 
    1158           0 : void Server::handleCommand_Breath(NetworkPacket* pkt)
    1159             : {
    1160             :         u16 breath;
    1161             : 
    1162           0 :         *pkt >> breath;
    1163             : 
    1164           0 :         Player *player = m_env->getPlayer(pkt->getPeerId());
    1165           0 :         if (player == NULL) {
    1166             :                 errorstream << "Server::ProcessData(): Canceling: "
    1167           0 :                                 "No player for peer_id=" << pkt->getPeerId()
    1168           0 :                                 << " disconnecting peer!" << std::endl;
    1169           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1170           0 :                 return;
    1171             :         }
    1172             : 
    1173             :         /*
    1174             :          * If player is dead, we don't need to update the breath
    1175             :          * He is dead !
    1176             :          */
    1177           0 :         if (player->isDead()) {
    1178           0 :                 verbosestream << "TOSERVER_BREATH: " << player->getName()
    1179           0 :                         << " is dead. Ignoring packet";
    1180           0 :                 return;
    1181             :         }
    1182             : 
    1183             : 
    1184           0 :         PlayerSAO *playersao = player->getPlayerSAO();
    1185           0 :         if (playersao == NULL) {
    1186             :                 errorstream << "Server::ProcessData(): Canceling: "
    1187           0 :                                 "No player object for peer_id=" << pkt->getPeerId()
    1188           0 :                                 << " disconnecting peer!" << std::endl;
    1189           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1190           0 :                 return;
    1191             :         }
    1192             : 
    1193           0 :         playersao->setBreath(breath);
    1194           0 :         SendPlayerBreath(pkt->getPeerId());
    1195             : }
    1196             : 
    1197           0 : void Server::handleCommand_Password(NetworkPacket* pkt)
    1198             : {
    1199           0 :         if (pkt->getSize() != PASSWORD_SIZE * 2)
    1200           0 :                 return;
    1201             : 
    1202           0 :         std::string oldpwd;
    1203           0 :         std::string newpwd;
    1204             : 
    1205             :         // Deny for clients using the new protocol
    1206           0 :         RemoteClient* client = getClient(pkt->getPeerId(), CS_Created);
    1207           0 :         if (client->net_proto_version >= 25) {
    1208           0 :                 infostream << "Server::handleCommand_Password(): Denying change: "
    1209           0 :                         << " Client protocol version for peer_id=" << pkt->getPeerId()
    1210           0 :                         << " too new!" << std::endl;
    1211           0 :                 return;
    1212             :         }
    1213             : 
    1214           0 :         for (u16 i = 0; i < PASSWORD_SIZE - 1; i++) {
    1215           0 :                 char c = pkt->getChar(i);
    1216           0 :                 if (c == 0)
    1217           0 :                         break;
    1218           0 :                 oldpwd += c;
    1219             :         }
    1220             : 
    1221           0 :         for (u16 i = 0; i < PASSWORD_SIZE - 1; i++) {
    1222           0 :                 char c = pkt->getChar(PASSWORD_SIZE + i);
    1223           0 :                 if (c == 0)
    1224           0 :                         break;
    1225           0 :                 newpwd += c;
    1226             :         }
    1227             : 
    1228           0 :         Player *player = m_env->getPlayer(pkt->getPeerId());
    1229           0 :         if (player == NULL) {
    1230             :                 errorstream << "Server::ProcessData(): Canceling: "
    1231           0 :                                 "No player for peer_id=" << pkt->getPeerId()
    1232           0 :                                 << " disconnecting peer!" << std::endl;
    1233           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1234           0 :                 return;
    1235             :         }
    1236             : 
    1237           0 :         if (!base64_is_valid(newpwd)) {
    1238           0 :                 infostream<<"Server: " << player->getName() <<
    1239           0 :                                 " supplied invalid password hash" << std::endl;
    1240             :                 // Wrong old password supplied!!
    1241           0 :                 SendChatMessage(pkt->getPeerId(), L"Invalid new password hash supplied. Password NOT changed.");
    1242           0 :                 return;
    1243             :         }
    1244             : 
    1245           0 :         infostream << "Server: Client requests a password change from "
    1246           0 :                         << "'" << oldpwd << "' to '" << newpwd << "'" << std::endl;
    1247             : 
    1248           0 :         std::string playername = player->getName();
    1249             : 
    1250           0 :         std::string checkpwd;
    1251           0 :         m_script->getAuth(playername, &checkpwd, NULL);
    1252             : 
    1253           0 :         if (oldpwd != checkpwd) {
    1254           0 :                 infostream << "Server: invalid old password" << std::endl;
    1255             :                 // Wrong old password supplied!!
    1256           0 :                 SendChatMessage(pkt->getPeerId(), L"Invalid old password supplied. Password NOT changed.");
    1257           0 :                 return;
    1258             :         }
    1259             : 
    1260           0 :         bool success = m_script->setPassword(playername, newpwd);
    1261           0 :         if (success) {
    1262           0 :                 actionstream << player->getName() << " changes password" << std::endl;
    1263           0 :                 SendChatMessage(pkt->getPeerId(), L"Password change successful.");
    1264             :         } else {
    1265           0 :                 actionstream << player->getName() << " tries to change password but "
    1266           0 :                                 << "it fails" << std::endl;
    1267           0 :                 SendChatMessage(pkt->getPeerId(), L"Password change failed or unavailable.");
    1268             :         }
    1269             : }
    1270             : 
    1271           0 : void Server::handleCommand_PlayerItem(NetworkPacket* pkt)
    1272             : {
    1273           0 :         if (pkt->getSize() < 2)
    1274           0 :                 return;
    1275             : 
    1276           0 :         Player *player = m_env->getPlayer(pkt->getPeerId());
    1277           0 :         if (player == NULL) {
    1278             :                 errorstream << "Server::ProcessData(): Canceling: "
    1279           0 :                                 "No player for peer_id=" << pkt->getPeerId()
    1280           0 :                                 << " disconnecting peer!" << std::endl;
    1281           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1282           0 :                 return;
    1283             :         }
    1284             : 
    1285           0 :         PlayerSAO *playersao = player->getPlayerSAO();
    1286           0 :         if (playersao == NULL) {
    1287             :                 errorstream << "Server::ProcessData(): Canceling: "
    1288           0 :                                 "No player object for peer_id=" << pkt->getPeerId()
    1289           0 :                                 << " disconnecting peer!" << std::endl;
    1290           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1291           0 :                 return;
    1292             :         }
    1293             : 
    1294             :         u16 item;
    1295             : 
    1296           0 :         *pkt >> item;
    1297             : 
    1298           0 :         playersao->setWieldIndex(item);
    1299             : }
    1300             : 
    1301           0 : void Server::handleCommand_Respawn(NetworkPacket* pkt)
    1302             : {
    1303           0 :         Player *player = m_env->getPlayer(pkt->getPeerId());
    1304           0 :         if (player == NULL) {
    1305             :                 errorstream << "Server::ProcessData(): Canceling: "
    1306           0 :                                 "No player for peer_id=" << pkt->getPeerId()
    1307           0 :                                 << " disconnecting peer!" << std::endl;
    1308           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1309           0 :                 return;
    1310             :         }
    1311             : 
    1312           0 :         if (!player->isDead())
    1313           0 :                 return;
    1314             : 
    1315           0 :         RespawnPlayer(pkt->getPeerId());
    1316             : 
    1317           0 :         actionstream << player->getName() << " respawns at "
    1318           0 :                         << PP(player->getPosition()/BS) << std::endl;
    1319             : 
    1320             :         // ActiveObject is added to environment in AsyncRunStep after
    1321             :         // the previous addition has been successfully removed
    1322             : }
    1323             : 
    1324           0 : void Server::handleCommand_Interact(NetworkPacket* pkt)
    1325             : {
    1326           0 :         std::string datastring(pkt->getString(0), pkt->getSize());
    1327           0 :         std::istringstream is(datastring, std::ios_base::binary);
    1328             : 
    1329             :         /*
    1330             :                 [0] u16 command
    1331             :                 [2] u8 action
    1332             :                 [3] u16 item
    1333             :                 [5] u32 length of the next item
    1334             :                 [9] serialized PointedThing
    1335             :                 actions:
    1336             :                 0: start digging (from undersurface) or use
    1337             :                 1: stop digging (all parameters ignored)
    1338             :                 2: digging completed
    1339             :                 3: place block or item (to abovesurface)
    1340             :                 4: use item
    1341             :         */
    1342           0 :         u8 action = readU8(is);
    1343           0 :         u16 item_i = readU16(is);
    1344           0 :         std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
    1345           0 :         PointedThing pointed;
    1346           0 :         pointed.deSerialize(tmp_is);
    1347             : 
    1348           0 :         verbosestream << "TOSERVER_INTERACT: action=" << (int)action << ", item="
    1349           0 :                         << item_i << ", pointed=" << pointed.dump() << std::endl;
    1350             : 
    1351           0 :         Player *player = m_env->getPlayer(pkt->getPeerId());
    1352           0 :         if (player == NULL) {
    1353             :                 errorstream << "Server::ProcessData(): Canceling: "
    1354           0 :                                 "No player for peer_id=" << pkt->getPeerId()
    1355           0 :                                 << " disconnecting peer!" << std::endl;
    1356           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1357           0 :                 return;
    1358             :         }
    1359             : 
    1360           0 :         PlayerSAO *playersao = player->getPlayerSAO();
    1361           0 :         if (playersao == NULL) {
    1362             :                 errorstream << "Server::ProcessData(): Canceling: "
    1363           0 :                                 "No player object for peer_id=" << pkt->getPeerId()
    1364           0 :                                 << " disconnecting peer!" << std::endl;
    1365           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1366           0 :                 return;
    1367             :         }
    1368             : 
    1369           0 :         if (player->isDead()) {
    1370           0 :                 verbosestream << "TOSERVER_INTERACT: " << player->getName()
    1371           0 :                         << " is dead. Ignoring packet";
    1372           0 :                 return;
    1373             :         }
    1374             : 
    1375           0 :         v3f player_pos = playersao->getLastGoodPosition();
    1376             : 
    1377             :         // Update wielded item
    1378           0 :         playersao->setWieldIndex(item_i);
    1379             : 
    1380             :         // Get pointed to node (undefined if not POINTEDTYPE_NODE)
    1381           0 :         v3s16 p_under = pointed.node_undersurface;
    1382           0 :         v3s16 p_above = pointed.node_abovesurface;
    1383             : 
    1384             :         // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
    1385           0 :         ServerActiveObject *pointed_object = NULL;
    1386           0 :         if (pointed.type == POINTEDTHING_OBJECT) {
    1387           0 :                 pointed_object = m_env->getActiveObject(pointed.object_id);
    1388           0 :                 if (pointed_object == NULL) {
    1389             :                         verbosestream << "TOSERVER_INTERACT: "
    1390           0 :                                 "pointed object is NULL" << std::endl;
    1391           0 :                         return;
    1392             :                 }
    1393             : 
    1394             :         }
    1395             : 
    1396           0 :         v3f pointed_pos_under = player_pos;
    1397           0 :         v3f pointed_pos_above = player_pos;
    1398           0 :         if (pointed.type == POINTEDTHING_NODE) {
    1399           0 :                 pointed_pos_under = intToFloat(p_under, BS);
    1400           0 :                 pointed_pos_above = intToFloat(p_above, BS);
    1401             :         }
    1402           0 :         else if (pointed.type == POINTEDTHING_OBJECT) {
    1403           0 :                 pointed_pos_under = pointed_object->getBasePosition();
    1404           0 :                 pointed_pos_above = pointed_pos_under;
    1405             :         }
    1406             : 
    1407             :         /*
    1408             :                 Check that target is reasonably close
    1409             :                 (only when digging or placing things)
    1410             :         */
    1411           0 :         if (action == 0 || action == 2 || action == 3) {
    1412           0 :                 float d = player_pos.getDistanceFrom(pointed_pos_under);
    1413           0 :                 float max_d = BS * 14; // Just some large enough value
    1414           0 :                 if (d > max_d) {
    1415           0 :                         actionstream << "Player " << player->getName()
    1416           0 :                                         << " tried to access " << pointed.dump()
    1417           0 :                                         << " from too far: "
    1418           0 :                                         << "d=" << d <<", max_d=" << max_d
    1419           0 :                                         << ". ignoring." << std::endl;
    1420             :                         // Re-send block to revert change on client-side
    1421           0 :                         RemoteClient *client = getClient(pkt->getPeerId());
    1422           0 :                         v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
    1423           0 :                         client->SetBlockNotSent(blockpos);
    1424             :                         // Call callbacks
    1425           0 :                         m_script->on_cheat(playersao, "interacted_too_far");
    1426             :                         // Do nothing else
    1427           0 :                         return;
    1428             :                 }
    1429             :         }
    1430             : 
    1431             :         /*
    1432             :                 Make sure the player is allowed to do it
    1433             :         */
    1434           0 :         if (!checkPriv(player->getName(), "interact")) {
    1435           0 :                 actionstream<<player->getName()<<" attempted to interact with "
    1436           0 :                                 <<pointed.dump()<<" without 'interact' privilege"
    1437           0 :                                 <<std::endl;
    1438             :                 // Re-send block to revert change on client-side
    1439           0 :                 RemoteClient *client = getClient(pkt->getPeerId());
    1440             :                 // Digging completed -> under
    1441           0 :                 if (action == 2) {
    1442           0 :                         v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
    1443           0 :                         client->SetBlockNotSent(blockpos);
    1444             :                 }
    1445             :                 // Placement -> above
    1446           0 :                 if (action == 3) {
    1447           0 :                         v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
    1448           0 :                         client->SetBlockNotSent(blockpos);
    1449             :                 }
    1450           0 :                 return;
    1451             :         }
    1452             : 
    1453             :         /*
    1454             :                 If something goes wrong, this player is to blame
    1455             :         */
    1456             :         RollbackScopeActor rollback_scope(m_rollback,
    1457           0 :                         std::string("player:")+player->getName());
    1458             : 
    1459             :         /*
    1460             :                 0: start digging or punch object
    1461             :         */
    1462           0 :         if (action == 0) {
    1463           0 :                 if (pointed.type == POINTEDTHING_NODE) {
    1464             :                         /*
    1465             :                                 NOTE: This can be used in the future to check if
    1466             :                                 somebody is cheating, by checking the timing.
    1467             :                         */
    1468           0 :                         MapNode n(CONTENT_IGNORE);
    1469             :                         bool pos_ok;
    1470           0 :                         n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
    1471           0 :                         if (pos_ok)
    1472           0 :                                 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
    1473             : 
    1474           0 :                         if (!pos_ok) {
    1475           0 :                                 infostream << "Server: Not punching: Node not found."
    1476           0 :                                                 << " Adding block to emerge queue."
    1477           0 :                                                 << std::endl;
    1478           0 :                                 m_emerge->enqueueBlockEmerge(pkt->getPeerId(), getNodeBlockPos(p_above), false);
    1479             :                         }
    1480             : 
    1481           0 :                         if (n.getContent() != CONTENT_IGNORE)
    1482           0 :                                 m_script->node_on_punch(p_under, n, playersao, pointed);
    1483             :                         // Cheat prevention
    1484           0 :                         playersao->noCheatDigStart(p_under);
    1485             :                 }
    1486           0 :                 else if (pointed.type == POINTEDTHING_OBJECT) {
    1487             :                         // Skip if object has been removed
    1488           0 :                         if (pointed_object->m_removed)
    1489           0 :                                 return;
    1490             : 
    1491           0 :                         actionstream<<player->getName()<<" punches object "
    1492           0 :                                         <<pointed.object_id<<": "
    1493           0 :                                         <<pointed_object->getDescription()<<std::endl;
    1494             : 
    1495           0 :                         ItemStack punchitem = playersao->getWieldedItem();
    1496             :                         ToolCapabilities toolcap =
    1497           0 :                                         punchitem.getToolCapabilities(m_itemdef);
    1498           0 :                         v3f dir = (pointed_object->getBasePosition() -
    1499           0 :                                         (player->getPosition() + player->getEyeOffset())
    1500           0 :                                                 ).normalize();
    1501             :                         float time_from_last_punch =
    1502           0 :                                 playersao->resetTimeFromLastPunch();
    1503             : 
    1504           0 :                         s16 src_original_hp = pointed_object->getHP();
    1505           0 :                         s16 dst_origin_hp = playersao->getHP();
    1506             : 
    1507           0 :                         pointed_object->punch(dir, &toolcap, playersao,
    1508           0 :                                         time_from_last_punch);
    1509             : 
    1510             :                         // If the object is a player and its HP changed
    1511           0 :                         if (src_original_hp != pointed_object->getHP() &&
    1512           0 :                                         pointed_object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
    1513           0 :                                 SendPlayerHPOrDie(((PlayerSAO*)pointed_object)->getPeerID(),
    1514           0 :                                                 pointed_object->getHP() == 0);
    1515             :                         }
    1516             : 
    1517             :                         // If the puncher is a player and its HP changed
    1518           0 :                         if (dst_origin_hp != playersao->getHP()) {
    1519           0 :                                 SendPlayerHPOrDie(playersao->getPeerID(), playersao->getHP() == 0);
    1520             :                         }
    1521             :                 }
    1522             : 
    1523             :         } // action == 0
    1524             : 
    1525             :         /*
    1526             :                 1: stop digging
    1527             :         */
    1528           0 :         else if (action == 1) {
    1529             :         } // action == 1
    1530             : 
    1531             :         /*
    1532             :                 2: Digging completed
    1533             :         */
    1534           0 :         else if (action == 2) {
    1535             :                 // Only digging of nodes
    1536           0 :                 if (pointed.type == POINTEDTHING_NODE) {
    1537             :                         bool pos_ok;
    1538           0 :                         MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
    1539           0 :                         if (!pos_ok) {
    1540           0 :                                 infostream << "Server: Not finishing digging: Node not found."
    1541           0 :                                                    << " Adding block to emerge queue."
    1542           0 :                                                    << std::endl;
    1543           0 :                                 m_emerge->enqueueBlockEmerge(pkt->getPeerId(), getNodeBlockPos(p_above), false);
    1544             :                         }
    1545             : 
    1546             :                         /* Cheat prevention */
    1547           0 :                         bool is_valid_dig = true;
    1548           0 :                         if (!isSingleplayer() && !g_settings->getBool("disable_anticheat")) {
    1549           0 :                                 v3s16 nocheat_p = playersao->getNoCheatDigPos();
    1550           0 :                                 float nocheat_t = playersao->getNoCheatDigTime();
    1551           0 :                                 playersao->noCheatDigEnd();
    1552             :                                 // If player didn't start digging this, ignore dig
    1553           0 :                                 if (nocheat_p != p_under) {
    1554           0 :                                         infostream << "Server: NoCheat: " << player->getName()
    1555           0 :                                                         << " started digging "
    1556           0 :                                                         << PP(nocheat_p) << " and completed digging "
    1557           0 :                                                         << PP(p_under) << "; not digging." << std::endl;
    1558           0 :                                         is_valid_dig = false;
    1559             :                                         // Call callbacks
    1560           0 :                                         m_script->on_cheat(playersao, "finished_unknown_dig");
    1561             :                                 }
    1562             :                                 // Get player's wielded item
    1563           0 :                                 ItemStack playeritem;
    1564           0 :                                 InventoryList *mlist = playersao->getInventory()->getList("main");
    1565           0 :                                 if (mlist != NULL)
    1566           0 :                                         playeritem = mlist->getItem(playersao->getWieldIndex());
    1567             :                                 ToolCapabilities playeritem_toolcap =
    1568           0 :                                                 playeritem.getToolCapabilities(m_itemdef);
    1569             :                                 // Get diggability and expected digging time
    1570           0 :                                 DigParams params = getDigParams(m_nodedef->get(n).groups,
    1571           0 :                                                 &playeritem_toolcap);
    1572             :                                 // If can't dig, try hand
    1573           0 :                                 if (!params.diggable) {
    1574           0 :                                         const ItemDefinition &hand = m_itemdef->get("");
    1575           0 :                                         const ToolCapabilities *tp = hand.tool_capabilities;
    1576           0 :                                         if (tp)
    1577           0 :                                                 params = getDigParams(m_nodedef->get(n).groups, tp);
    1578             :                                 }
    1579             :                                 // If can't dig, ignore dig
    1580           0 :                                 if (!params.diggable) {
    1581           0 :                                         infostream << "Server: NoCheat: " << player->getName()
    1582           0 :                                                         << " completed digging " << PP(p_under)
    1583           0 :                                                         << ", which is not diggable with tool. not digging."
    1584           0 :                                                         << std::endl;
    1585           0 :                                         is_valid_dig = false;
    1586             :                                         // Call callbacks
    1587           0 :                                         m_script->on_cheat(playersao, "dug_unbreakable");
    1588             :                                 }
    1589             :                                 // Check digging time
    1590             :                                 // If already invalidated, we don't have to
    1591           0 :                                 if (!is_valid_dig) {
    1592             :                                         // Well not our problem then
    1593             :                                 }
    1594             :                                 // Clean and long dig
    1595           0 :                                 else if (params.time > 2.0 && nocheat_t * 1.2 > params.time) {
    1596             :                                         // All is good, but grab time from pool; don't care if
    1597             :                                         // it's actually available
    1598           0 :                                         playersao->getDigPool().grab(params.time);
    1599             :                                 }
    1600             :                                 // Short or laggy dig
    1601             :                                 // Try getting the time from pool
    1602           0 :                                 else if (playersao->getDigPool().grab(params.time)) {
    1603             :                                         // All is good
    1604             :                                 }
    1605             :                                 // Dig not possible
    1606             :                                 else {
    1607           0 :                                         infostream << "Server: NoCheat: " << player->getName()
    1608           0 :                                                         << " completed digging " << PP(p_under)
    1609           0 :                                                         << "too fast; not digging." << std::endl;
    1610           0 :                                         is_valid_dig = false;
    1611             :                                         // Call callbacks
    1612           0 :                                         m_script->on_cheat(playersao, "dug_too_fast");
    1613             :                                 }
    1614             :                         }
    1615             : 
    1616             :                         /* Actually dig node */
    1617             : 
    1618           0 :                         if (is_valid_dig && n.getContent() != CONTENT_IGNORE)
    1619           0 :                                 m_script->node_on_dig(p_under, n, playersao);
    1620             : 
    1621           0 :                         v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
    1622           0 :                         RemoteClient *client = getClient(pkt->getPeerId());
    1623             :                         // Send unusual result (that is, node not being removed)
    1624           0 :                         if (m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR) {
    1625             :                                 // Re-send block to revert change on client-side
    1626           0 :                                 client->SetBlockNotSent(blockpos);
    1627             :                         }
    1628             :                         else {
    1629           0 :                                 client->ResendBlockIfOnWire(blockpos);
    1630             :                         }
    1631             :                 }
    1632             :         } // action == 2
    1633             : 
    1634             :         /*
    1635             :                 3: place block or right-click object
    1636             :         */
    1637           0 :         else if (action == 3) {
    1638           0 :                 ItemStack item = playersao->getWieldedItem();
    1639             : 
    1640             :                 // Reset build time counter
    1641           0 :                 if (pointed.type == POINTEDTHING_NODE &&
    1642           0 :                                 item.getDefinition(m_itemdef).type == ITEM_NODE)
    1643           0 :                         getClient(pkt->getPeerId())->m_time_from_building = 0.0;
    1644             : 
    1645           0 :                 if (pointed.type == POINTEDTHING_OBJECT) {
    1646             :                         // Right click object
    1647             : 
    1648             :                         // Skip if object has been removed
    1649           0 :                         if (pointed_object->m_removed)
    1650           0 :                                 return;
    1651             : 
    1652           0 :                         actionstream << player->getName() << " right-clicks object "
    1653           0 :                                         << pointed.object_id << ": "
    1654           0 :                                         << pointed_object->getDescription() << std::endl;
    1655             : 
    1656             :                         // Do stuff
    1657           0 :                         pointed_object->rightClick(playersao);
    1658             :                 }
    1659           0 :                 else if (m_script->item_OnPlace(
    1660             :                                 item, playersao, pointed)) {
    1661             :                         // Placement was handled in lua
    1662             : 
    1663             :                         // Apply returned ItemStack
    1664           0 :                         if (playersao->setWieldedItem(item)) {
    1665           0 :                                 SendInventory(playersao);
    1666             :                         }
    1667             :                 }
    1668             : 
    1669             :                 // If item has node placement prediction, always send the
    1670             :                 // blocks to make sure the client knows what exactly happened
    1671           0 :                 RemoteClient *client = getClient(pkt->getPeerId());
    1672           0 :                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
    1673           0 :                 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
    1674           0 :                 if (item.getDefinition(m_itemdef).node_placement_prediction != "") {
    1675           0 :                         client->SetBlockNotSent(blockpos);
    1676           0 :                         if (blockpos2 != blockpos) {
    1677           0 :                                 client->SetBlockNotSent(blockpos2);
    1678             :                         }
    1679             :                 }
    1680             :                 else {
    1681           0 :                         client->ResendBlockIfOnWire(blockpos);
    1682           0 :                         if (blockpos2 != blockpos) {
    1683           0 :                                 client->ResendBlockIfOnWire(blockpos2);
    1684             :                         }
    1685             :                 }
    1686             :         } // action == 3
    1687             : 
    1688             :         /*
    1689             :                 4: use
    1690             :         */
    1691           0 :         else if (action == 4) {
    1692           0 :                 ItemStack item = playersao->getWieldedItem();
    1693             : 
    1694           0 :                 actionstream << player->getName() << " uses " << item.name
    1695           0 :                                 << ", pointing at " << pointed.dump() << std::endl;
    1696             : 
    1697           0 :                 if (m_script->item_OnUse(
    1698             :                                 item, playersao, pointed)) {
    1699             :                         // Apply returned ItemStack
    1700           0 :                         if (playersao->setWieldedItem(item)) {
    1701           0 :                                 SendInventory(playersao);
    1702             :                         }
    1703             :                 }
    1704             : 
    1705             :         } // action == 4
    1706             : 
    1707             : 
    1708             :         /*
    1709             :                 Catch invalid actions
    1710             :         */
    1711             :         else {
    1712           0 :                 infostream << "WARNING: Server: Invalid action "
    1713           0 :                                 << action << std::endl;
    1714             :         }
    1715             : }
    1716             : 
    1717           0 : void Server::handleCommand_RemovedSounds(NetworkPacket* pkt)
    1718             : {
    1719             :         u16 num;
    1720           0 :         *pkt >> num;
    1721           0 :         for (u16 k = 0; k < num; k++) {
    1722             :                 s32 id;
    1723             : 
    1724           0 :                 *pkt >> id;
    1725             : 
    1726             :                 std::map<s32, ServerPlayingSound>::iterator i =
    1727           0 :                         m_playing_sounds.find(id);
    1728             : 
    1729           0 :                 if (i == m_playing_sounds.end())
    1730           0 :                         continue;
    1731             : 
    1732           0 :                 ServerPlayingSound &psound = i->second;
    1733           0 :                 psound.clients.erase(pkt->getPeerId());
    1734           0 :                 if (psound.clients.empty())
    1735           0 :                         m_playing_sounds.erase(i++);
    1736             :         }
    1737           0 : }
    1738             : 
    1739           0 : void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt)
    1740             : {
    1741           0 :         v3s16 p;
    1742           0 :         std::string formname;
    1743             :         u16 num;
    1744             : 
    1745           0 :         *pkt >> p >> formname >> num;
    1746             : 
    1747           0 :         StringMap fields;
    1748           0 :         for (u16 k = 0; k < num; k++) {
    1749           0 :                 std::string fieldname;
    1750           0 :                 *pkt >> fieldname;
    1751           0 :                 fields[fieldname] = pkt->readLongString();
    1752             :         }
    1753             : 
    1754           0 :         Player *player = m_env->getPlayer(pkt->getPeerId());
    1755           0 :         if (player == NULL) {
    1756             :                 errorstream << "Server::ProcessData(): Canceling: "
    1757           0 :                                 "No player for peer_id=" << pkt->getPeerId()
    1758           0 :                                 << " disconnecting peer!" << std::endl;
    1759           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1760           0 :                 return;
    1761             :         }
    1762             : 
    1763           0 :         PlayerSAO *playersao = player->getPlayerSAO();
    1764           0 :         if (playersao == NULL) {
    1765             :                 errorstream << "Server::ProcessData(): Canceling: "
    1766           0 :                                 "No player object for peer_id=" << pkt->getPeerId()
    1767           0 :                                 << " disconnecting peer!"  << std::endl;
    1768           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1769           0 :                 return;
    1770             :         }
    1771             : 
    1772             :         // If something goes wrong, this player is to blame
    1773             :         RollbackScopeActor rollback_scope(m_rollback,
    1774           0 :                         std::string("player:")+player->getName());
    1775             : 
    1776             :         // Check the target node for rollback data; leave others unnoticed
    1777           0 :         RollbackNode rn_old(&m_env->getMap(), p, this);
    1778             : 
    1779           0 :         m_script->node_on_receive_fields(p, formname, fields, playersao);
    1780             : 
    1781             :         // Report rollback data
    1782           0 :         RollbackNode rn_new(&m_env->getMap(), p, this);
    1783           0 :         if (rollback() && rn_new != rn_old) {
    1784           0 :                 RollbackAction action;
    1785           0 :                 action.setSetNode(p, rn_old, rn_new);
    1786           0 :                 rollback()->reportAction(action);
    1787             :         }
    1788             : }
    1789             : 
    1790           0 : void Server::handleCommand_InventoryFields(NetworkPacket* pkt)
    1791             : {
    1792           0 :         std::string formname;
    1793             :         u16 num;
    1794             : 
    1795           0 :         *pkt >> formname >> num;
    1796             : 
    1797           0 :         StringMap fields;
    1798           0 :         for (u16 k = 0; k < num; k++) {
    1799           0 :                 std::string fieldname;
    1800           0 :                 *pkt >> fieldname;
    1801           0 :                 fields[fieldname] = pkt->readLongString();
    1802             :         }
    1803             : 
    1804           0 :         Player *player = m_env->getPlayer(pkt->getPeerId());
    1805           0 :         if (player == NULL) {
    1806             :                 errorstream << "Server::ProcessData(): Canceling: "
    1807           0 :                                 "No player for peer_id=" << pkt->getPeerId()
    1808           0 :                                 << " disconnecting peer!" << std::endl;
    1809           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1810           0 :                 return;
    1811             :         }
    1812             : 
    1813           0 :         PlayerSAO *playersao = player->getPlayerSAO();
    1814           0 :         if (playersao == NULL) {
    1815             :                 errorstream << "Server::ProcessData(): Canceling: "
    1816           0 :                                 "No player object for peer_id=" << pkt->getPeerId()
    1817           0 :                                 << " disconnecting peer!" << std::endl;
    1818           0 :                 m_con.DisconnectPeer(pkt->getPeerId());
    1819           0 :                 return;
    1820             :         }
    1821             : 
    1822           0 :         m_script->on_playerReceiveFields(playersao, formname, fields);
    1823             : }
    1824             : 
    1825           0 : void Server::handleCommand_FirstSrp(NetworkPacket* pkt)
    1826             : {
    1827           0 :         RemoteClient* client = getClient(pkt->getPeerId(), CS_Invalid);
    1828           0 :         ClientState cstate = client->getState();
    1829             : 
    1830           0 :         std::string playername = client->getName();
    1831             : 
    1832           0 :         std::string salt;
    1833           0 :         std::string verification_key;
    1834             : 
    1835           0 :         std::string addr_s = getPeerAddress(pkt->getPeerId()).serializeString();
    1836             :         u8 is_empty;
    1837             : 
    1838           0 :         *pkt >> salt >> verification_key >> is_empty;
    1839             : 
    1840           0 :         verbosestream << "Server: Got TOSERVER_FIRST_SRP from " << addr_s
    1841           0 :                 << ", with is_empty= " << is_empty << std::endl;
    1842             : 
    1843             :         // Either this packet is sent because the user is new or to change the password
    1844           0 :         if (cstate == CS_HelloSent) {
    1845           0 :                 if (!client->isMechAllowed(AUTH_MECHANISM_FIRST_SRP)) {
    1846           0 :                         actionstream << "Server: Client from " << addr_s
    1847           0 :                                         << " tried to set password without being "
    1848           0 :                                         << "authenticated, or the username being new." << std::endl;
    1849           0 :                         DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_UNEXPECTED_DATA);
    1850           0 :                         return;
    1851             :                 }
    1852             : 
    1853           0 :                 if (!isSingleplayer() &&
    1854           0 :                                 g_settings->getBool("disallow_empty_password") &&
    1855           0 :                                 is_empty == 1) {
    1856           0 :                         actionstream << "Server: " << playername
    1857           0 :                                         << " supplied empty password from " << addr_s << std::endl;
    1858           0 :                         DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_EMPTY_PASSWORD);
    1859           0 :                         return;
    1860             :                 }
    1861             : 
    1862           0 :                 std::string initial_ver_key;
    1863           0 :                 std::string raw_default_password = g_settings->get("default_password");
    1864             :                 // If default_password is empty, allow any initial password
    1865           0 :                 if (raw_default_password.length() == 0) {
    1866           0 :                         initial_ver_key = encodeSRPVerifier(verification_key, salt);
    1867             :                 } else {
    1868           0 :                         initial_ver_key = getSRPVerifier(playername, raw_default_password);
    1869             :                 }
    1870             : 
    1871           0 :                 m_script->createAuth(playername, initial_ver_key);
    1872             : 
    1873           0 :                 acceptAuth(pkt->getPeerId(), false);
    1874             :         } else {
    1875           0 :                 if (cstate < CS_SudoMode) {
    1876           0 :                         infostream << "Server::ProcessData(): Ignoring TOSERVER_FIRST_SRP from "
    1877           0 :                                         << addr_s << ": " << "Client has wrong state " << cstate << "."
    1878           0 :                                         << std::endl;
    1879           0 :                         return;
    1880             :                 }
    1881           0 :                 m_clients.event(pkt->getPeerId(), CSE_SudoLeave);
    1882           0 :                 std::string pw_db_field = encodeSRPVerifier(verification_key, salt);
    1883           0 :                 bool success = m_script->setPassword(playername, pw_db_field);
    1884           0 :                 if (success) {
    1885           0 :                         actionstream << playername << " changes password" << std::endl;
    1886           0 :                         SendChatMessage(pkt->getPeerId(), L"Password change successful.");
    1887             :                 } else {
    1888           0 :                         actionstream << playername << " tries to change password but "
    1889           0 :                                 << "it fails" << std::endl;
    1890           0 :                         SendChatMessage(pkt->getPeerId(), L"Password change failed or unavailable.");
    1891             :                 }
    1892             :         }
    1893             : }
    1894             : 
    1895           0 : void Server::handleCommand_SrpBytesA(NetworkPacket* pkt)
    1896             : {
    1897           0 :         RemoteClient* client = getClient(pkt->getPeerId(), CS_Invalid);
    1898           0 :         ClientState cstate = client->getState();
    1899             : 
    1900           0 :         bool wantSudo = (cstate == CS_Active);
    1901             : 
    1902           0 :         if (!((cstate == CS_HelloSent) || (cstate == CS_Active))) {
    1903           0 :                 actionstream << "Server: got SRP _A packet in wrong state "
    1904           0 :                         << cstate << " from "
    1905           0 :                         << getPeerAddress(pkt->getPeerId()).serializeString()
    1906           0 :                         << ". Ignoring." << std::endl;
    1907           0 :                 return;
    1908             :         }
    1909             : 
    1910           0 :         if (client->chosen_mech != AUTH_MECHANISM_NONE) {
    1911           0 :                 actionstream << "Server: got SRP _A packet, while auth"
    1912           0 :                         << "is already going on with mech " << client->chosen_mech
    1913           0 :                         << " from " << getPeerAddress(pkt->getPeerId()).serializeString()
    1914           0 :                         << " (wantSudo=" << wantSudo << "). Ignoring." << std::endl;
    1915           0 :                 if (wantSudo) {
    1916           0 :                         DenySudoAccess(pkt->getPeerId());
    1917           0 :                         return;
    1918             :                 } else {
    1919           0 :                         DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_UNEXPECTED_DATA);
    1920           0 :                         return;
    1921             :                 }
    1922             :         }
    1923             : 
    1924           0 :         std::string bytes_A;
    1925             :         u8 based_on;
    1926           0 :         *pkt >> bytes_A >> based_on;
    1927             : 
    1928           0 :         infostream << "Server: TOSERVER_SRP_BYTES_A received with "
    1929           0 :                 << "based_on=" << int(based_on) << " and len_A="
    1930           0 :                 << bytes_A.length() << "." << std::endl;
    1931             : 
    1932           0 :         AuthMechanism chosen = (based_on == 0) ?
    1933           0 :                 AUTH_MECHANISM_LEGACY_PASSWORD : AUTH_MECHANISM_SRP;
    1934             : 
    1935           0 :         if (wantSudo) {
    1936           0 :                 if (!client->isSudoMechAllowed(chosen)) {
    1937           0 :                         actionstream << "Server: Player \"" << client->getName()
    1938           0 :                                 << "\" at " << getPeerAddress(pkt->getPeerId()).serializeString()
    1939           0 :                                 << " tried to change password using unallowed mech "
    1940           0 :                                 << chosen << "." << std::endl;
    1941           0 :                         DenySudoAccess(pkt->getPeerId());
    1942           0 :                         return;
    1943             :                 }
    1944             :         } else {
    1945           0 :                 if (!client->isMechAllowed(chosen)) {
    1946           0 :                         actionstream << "Server: Client tried to authenticate from "
    1947           0 :                                 << getPeerAddress(pkt->getPeerId()).serializeString()
    1948           0 :                                 << " using unallowed mech " << chosen << "." << std::endl;
    1949           0 :                         DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_UNEXPECTED_DATA);
    1950           0 :                         return;
    1951             :                 }
    1952             :         }
    1953             : 
    1954           0 :         client->chosen_mech = chosen;
    1955             : 
    1956           0 :         std::string bytes_s;
    1957           0 :         std::string bytes_v;
    1958             : 
    1959           0 :         if (based_on == 0) {
    1960           0 :                 char *p_bytes_s = 0;
    1961           0 :                 size_t len_s = 0;
    1962           0 :                 char *p_bytes_v = 0;
    1963           0 :                 size_t len_v = 0;
    1964           0 :                 getSRPVerifier(client->getName(), client->enc_pwd,
    1965             :                         &p_bytes_s, &len_s,
    1966           0 :                         &p_bytes_v, &len_v);
    1967           0 :                 bytes_s = std::string(p_bytes_s, len_s);
    1968           0 :                 bytes_v = std::string(p_bytes_v, len_v);
    1969           0 :                 free(p_bytes_s);
    1970           0 :                 free(p_bytes_v);
    1971           0 :         } else if (!decodeSRPVerifier(client->enc_pwd, &bytes_s, &bytes_v)) {
    1972             :                 // Non-base64 errors should have been catched in the init handler
    1973           0 :                 actionstream << "Server: User " << client->getName()
    1974           0 :                         << " tried to log in, but srp verifier field"
    1975           0 :                         << " was invalid (most likely invalid base64)." << std::endl;
    1976           0 :                 DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_SERVER_FAIL);
    1977           0 :                 return;
    1978             :         }
    1979             : 
    1980           0 :         char *bytes_B = 0;
    1981           0 :         size_t len_B = 0;
    1982             : 
    1983           0 :         client->auth_data = srp_verifier_new(SRP_SHA256, SRP_NG_2048,
    1984           0 :                 client->getName().c_str(),
    1985           0 :                 (const unsigned char *) bytes_s.c_str(), bytes_s.size(),
    1986           0 :                 (const unsigned char *) bytes_v.c_str(), bytes_v.size(),
    1987           0 :                 (const unsigned char *) bytes_A.c_str(), bytes_A.size(),
    1988             :                 NULL, 0,
    1989           0 :                 (unsigned char **) &bytes_B, &len_B, NULL, NULL);
    1990             : 
    1991           0 :         if (!bytes_B) {
    1992           0 :                 actionstream << "Server: User " << client->getName()
    1993           0 :                         << " tried to log in, SRP-6a safety check violated in _A handler."
    1994           0 :                         << std::endl;
    1995           0 :                 if (wantSudo) {
    1996           0 :                         DenySudoAccess(pkt->getPeerId());
    1997           0 :                         return;
    1998             :                 } else {
    1999           0 :                         DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_UNEXPECTED_DATA);
    2000           0 :                         return;
    2001             :                 }
    2002             :         }
    2003             : 
    2004           0 :         NetworkPacket resp_pkt(TOCLIENT_SRP_BYTES_S_B, 0, pkt->getPeerId());
    2005           0 :         resp_pkt << bytes_s << std::string(bytes_B, len_B);
    2006           0 :         Send(&resp_pkt);
    2007             : }
    2008             : 
    2009           0 : void Server::handleCommand_SrpBytesM(NetworkPacket* pkt)
    2010             : {
    2011           0 :         RemoteClient* client = getClient(pkt->getPeerId(), CS_Invalid);
    2012           0 :         ClientState cstate = client->getState();
    2013             : 
    2014           0 :         bool wantSudo = (cstate == CS_Active);
    2015             : 
    2016           0 :         verbosestream << "Server: Recieved TOCLIENT_SRP_BYTES_M." << std::endl;
    2017             : 
    2018           0 :         if (!((cstate == CS_HelloSent) || (cstate == CS_Active))) {
    2019           0 :                 actionstream << "Server: got SRP _M packet in wrong state "
    2020           0 :                         << cstate << " from "
    2021           0 :                         << getPeerAddress(pkt->getPeerId()).serializeString()
    2022           0 :                         << ". Ignoring." << std::endl;
    2023           0 :                 return;
    2024             :         }
    2025             : 
    2026           0 :         if ((client->chosen_mech != AUTH_MECHANISM_SRP)
    2027           0 :                 && (client->chosen_mech != AUTH_MECHANISM_LEGACY_PASSWORD)) {
    2028           0 :                 actionstream << "Server: got SRP _M packet, while auth"
    2029           0 :                         << "is going on with mech " << client->chosen_mech
    2030           0 :                         << " from " << getPeerAddress(pkt->getPeerId()).serializeString()
    2031           0 :                         << " (wantSudo=" << wantSudo << "). Denying." << std::endl;
    2032           0 :                 if (wantSudo) {
    2033           0 :                         DenySudoAccess(pkt->getPeerId());
    2034           0 :                         return;
    2035             :                 } else {
    2036           0 :                         DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_UNEXPECTED_DATA);
    2037           0 :                         return;
    2038             :                 }
    2039             :         }
    2040             : 
    2041           0 :         std::string bytes_M;
    2042           0 :         *pkt >> bytes_M;
    2043             : 
    2044           0 :         if (srp_verifier_get_session_key_length((SRPVerifier *) client->auth_data)
    2045           0 :                         != bytes_M.size()) {
    2046           0 :                 actionstream << "Server: User " << client->getName()
    2047           0 :                         << " at " << getPeerAddress(pkt->getPeerId()).serializeString()
    2048           0 :                         << " sent bytes_M with invalid length " << bytes_M.size() << std::endl;
    2049           0 :                 DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_UNEXPECTED_DATA);
    2050           0 :                 return;
    2051             :         }
    2052             : 
    2053           0 :         unsigned char *bytes_HAMK = 0;
    2054             : 
    2055           0 :         srp_verifier_verify_session((SRPVerifier *) client->auth_data,
    2056           0 :                 (unsigned char *)bytes_M.c_str(), &bytes_HAMK);
    2057             : 
    2058           0 :         if (!bytes_HAMK) {
    2059           0 :                 if (wantSudo) {
    2060           0 :                         actionstream << "Server: User " << client->getName()
    2061           0 :                                 << " at " << getPeerAddress(pkt->getPeerId()).serializeString()
    2062           0 :                                 << " tried to change their password, but supplied wrong"
    2063           0 :                                 << " (SRP) password for authentication." << std::endl;
    2064           0 :                         DenySudoAccess(pkt->getPeerId());
    2065           0 :                         return;
    2066             :                 } else {
    2067           0 :                         actionstream << "Server: User " << client->getName()
    2068           0 :                                 << " at " << getPeerAddress(pkt->getPeerId()).serializeString()
    2069           0 :                                 << " supplied wrong (SRP) password from address "
    2070           0 :                                 << getPeerAddress(pkt->getPeerId()).serializeString()
    2071           0 :                                 << "." << std::endl;
    2072           0 :                         DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_PASSWORD);
    2073           0 :                         return;
    2074             :                 }
    2075             :         }
    2076             : 
    2077           0 :         acceptAuth(pkt->getPeerId(), wantSudo);
    2078           3 : }

Generated by: LCOV version 1.11