Prepare Protocol v25 init & authentication.
authorLoic Blot <loic.blot@unix-experience.fr>
Fri, 13 Mar 2015 15:35:21 +0000 (16:35 +0100)
committerLoic Blot <loic.blot@unix-experience.fr>
Fri, 13 Mar 2015 19:23:03 +0000 (20:23 +0100)
* TOSERVER_INIT and TOCLIENT_INIT renamed to _LEGACY
* TOSERVER_PASSWORD merged from dev-0.5, can use protocol v24 and v25
* TOCLIENT_ACCESS_DENIED merged from dev-0.5, can use protocol v24 and v25, with normalized strings an a custom id for custom errors
* new TOSERVER_INIT packet only send MT version, supported compressions, protocols and serialization, this permit to rework everything later without break the _INIT packet
* new TOSERVER_AUTH packet which auth the client
* new TOCLIENT_HELLO packet which send server serialization version atm
* new TOCLIENT_AUTH_ACCEPTED which is send when TOCLIENT_AUTH was okay. After this packet, the client load datas from servers, like after TOCLIENT_INIT_LEGACY packet

src/client.h
src/clientiface.h
src/network/clientopcodes.cpp
src/network/networkprotocol.h
src/network/packethandlers/client.cpp
src/network/packethandlers/server.cpp
src/network/serveropcodes.cpp
src/script/lua_api/l_server.cpp
src/server.cpp
src/server.h

index a0add689a8ae443b7311c4efd469e0475524b18c..9baa034dea82d952eec48d9715e706722bdb9ce5 100644 (file)
@@ -349,7 +349,9 @@ public:
 
        void handleCommand_Null(NetworkPacket* pkt) {};
        void handleCommand_Deprecated(NetworkPacket* pkt);
-       void handleCommand_Init(NetworkPacket* pkt);
+       void handleCommand_Hello(NetworkPacket* pkt);
+       void handleCommand_AuthAccept(NetworkPacket* pkt);
+       void handleCommand_InitLegacy(NetworkPacket* pkt);
        void handleCommand_AccessDenied(NetworkPacket* pkt);
        void handleCommand_RemoveNode(NetworkPacket* pkt);
        void handleCommand_AddNode(NetworkPacket* pkt);
index cc303734afe1998584c6f16f4639d98651c8d97e..2fd293de2ec437971a374e72f3980537a92e1278 100644 (file)
@@ -217,6 +217,7 @@ public:
                m_version_minor(0),
                m_version_patch(0),
                m_full_version("unknown"),
+               m_supported_compressions(0),
                m_connection_time(getTime(PRECISION_SECONDS))
        {
        }
@@ -293,6 +294,9 @@ public:
        void setPendingSerializationVersion(u8 version)
                { m_pending_serialization_version = version; }
 
+       void setSupportedCompressionModes(u8 byteFlag)
+               { m_supported_compressions = byteFlag; }
+
        void confirmSerializationVersion()
                { serialization_version = m_pending_serialization_version; }
 
@@ -370,6 +374,8 @@ private:
 
        std::string m_full_version;
 
+       u8 m_supported_compressions;
+
        /*
                time this client was created
         */
index f236b635329db4c5c81d6c20b09d7d1d47ee87a2..556e8d0c0e40ebb75a1fea2d9952ff0fa5c95481 100644 (file)
@@ -26,8 +26,8 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
 {
        null_command_handler, // 0x00 (never use this)
        null_command_handler, // 0x01
-       null_command_handler, // 0x02
-       null_command_handler, // 0x03
+       { "TOCLIENT_HELLO",                   TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_Hello }, // 0x02
+       { "TOCLIENT_AUTH_ACCEPT",             TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_AuthAccept }, // 0x03
        null_command_handler, // 0x04
        null_command_handler, // 0x05
        null_command_handler, // 0x06
@@ -40,7 +40,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
        null_command_handler, // 0x0D
        null_command_handler, // 0x0E
        null_command_handler, // 0x0F
-       { "TOCLIENT_INIT",                    TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_Init }, // 0x10
+       { "TOCLIENT_INIT",                    TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_InitLegacy }, // 0x10
        null_command_handler,
        null_command_handler,
        null_command_handler,
index 1e0896ebf930dc64b552bf75f8e6e0f667ea00ca..599b70006c7d22c082d65440da4094c3b4de41dc 100644 (file)
@@ -110,14 +110,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
                ContentFeatures: change number of special tiles to 6 (CF_SPECIAL_COUNT)
        PROTOCOL_VERSION 25:
                Rename TOCLIENT_ACCESS_DENIED to TOCLIENT_ACCESS_DENIED_LEGAGY
-               Rename TOCLIENT_DELETE_PARTICLESPAWNER to TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY
+               Rename TOCLIENT_DELETE_PARTICLESPAWNER to
+                       TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY
                Rename TOSERVER_PASSWORD to TOSERVER_PASSWORD_LEGACY
                Rename TOSERVER_INIT to TOSERVER_INIT_LEGACY
+               Rename TOCLIENT_INIT to TOCLIENT_INIT_LEGACY
                Add TOCLIENT_ACCESS_DENIED new opcode (0x0A), using error codes
                        for standard error, keeping customisation possible. This
                        permit translation
                Add TOCLIENT_DELETE_PARTICLESPAWNER (0x53), fixing the u16 read and
                        reading u32
+               Add TOSERVER_INIT new opcode (0x02) for client presentation to server
+               Add TOSERVER_AUTH new opcode (0x03) for client authentication
+               Add TOCLIENT_HELLO for presenting server to client after client
+                       presentation
+               Add TOCLIENT_AUTH_ACCEPT to accept connexion from client
 */
 
 #define LATEST_PROTOCOL_VERSION 24
@@ -143,6 +150,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 enum ToClientCommand
 {
+       TOCLIENT_HELLO = 0x02,
+       TOCLIENT_AUTH_ACCEPT = 0x03,
        TOCLIENT_ACCESS_DENIED = 0x0A,
        /*
                u16 command
@@ -150,7 +159,7 @@ enum ToClientCommand
                wstring reason
        */
 
-       TOCLIENT_INIT = 0x10,
+       TOCLIENT_INIT_LEGACY = 0x10,
        /*
                Server's reply to TOSERVER_INIT.
                Sent second after connected.
@@ -585,17 +594,22 @@ enum ToClientCommand
 
 enum ToServerCommand
 {
-       TOSERVER_INIT = 0x0F,
+       TOSERVER_INIT = 0x02,
        /*
                Sent first after connected.
 
                [0] u16 TOSERVER_INIT
                [2] u8 SER_FMT_VER_HIGHEST_READ
                [3] u8 compression_modes
-               [4] std::string player_name
-               [4+*] std::string password (new in some version)
-               [4+*+*] u16 minimum supported network protocol version (added sometime)
-               [4+*+*+2] u16 maximum supported network protocol version (added later than the previous one)
+       */
+
+       TOSERVER_AUTH = 0x03,
+       /*
+               Sent first after presentation (INIT).
+               [0] std::string player_name
+               [0+*] std::string password (new in some version)
+               [0+*+*] u16 minimum supported network protocol version (added sometime)
+               [0+*+*+2] u16 maximum supported network protocol version (added later than the previous one)
        */
 
        TOSERVER_INIT_LEGACY = 0x10,
@@ -856,8 +870,9 @@ enum AccessDeniedCode {
        SERVER_ACCESSDENIED_TOO_MANY_USERS = 6,
        SERVER_ACCESSDENIED_EMPTY_PASSWORD = 7,
        SERVER_ACCESSDENIED_ALREADY_CONNECTED = 8,
-       SERVER_ACCESSDENIED_CUSTOM_STRING = 9,
-       SERVER_ACCESSDENIED_MAX = 10,
+       SERVER_ACCESSDENIED_SERVER_FAIL = 9,
+       SERVER_ACCESSDENIED_CUSTOM_STRING = 10,
+       SERVER_ACCESSDENIED_MAX = 11,
 };
 
 enum NetProtoCompressionMode {
@@ -874,6 +889,7 @@ const static std::wstring accessDeniedStrings[SERVER_ACCESSDENIED_MAX] = {
        L"Too many users.",
        L"Empty passwords are disallowed. Set a password and try again.",
        L"Another client is connected with this name. If your client closed unexpectedly, try again in a minute.",
+       L"Server authenticator failed. Maybe the servers has some problems."
        L"",
 };
 
index ae24157e07d6f24c9dcb0a14ad6a8756c2ddefa4..838c85989febb29afa480911093a17422a8e2188 100644 (file)
@@ -38,7 +38,7 @@ void Client::handleCommand_Deprecated(NetworkPacket* pkt)
                        << pkt->getPeerId() << "!" << std::endl;
 }
 
-void Client::handleCommand_Init(NetworkPacket* pkt)
+void Client::handleCommand_Hello(NetworkPacket* pkt)
 {
        if (pkt->getSize() < 1)
                return;
@@ -46,11 +46,56 @@ void Client::handleCommand_Init(NetworkPacket* pkt)
        u8 deployed;
        *pkt >> deployed;
 
-       infostream << "Client: TOCLIENT_INIT received with "
+       infostream << "Client: TOCLIENT_HELLO received with "
                        "deployed=" << ((int)deployed & 0xff) << std::endl;
 
        if (!ser_ver_supported(deployed)) {
-               infostream << "Client: TOCLIENT_INIT: Server sent "
+               infostream << "Client: TOCLIENT_HELLO: Server sent "
+                               << "unsupported ser_fmt_ver"<< std::endl;
+               return;
+       }
+
+       m_server_ser_ver = deployed;
+
+       // @ TODO auth to server
+}
+
+void Client::handleCommand_AuthAccept(NetworkPacket* pkt)
+{
+       v3f playerpos;
+       *pkt >> playerpos >> m_map_seed >> m_recommended_send_interval;
+
+       playerpos -= v3f(0, BS / 2, 0);
+
+       // Set player position
+       Player *player = m_env.getLocalPlayer();
+       assert(player != NULL);
+       player->setPosition(playerpos);
+
+       infostream << "Client: received map seed: " << m_map_seed << std::endl;
+       infostream << "Client: received recommended send interval "
+                                       << m_recommended_send_interval<<std::endl;
+
+       // Reply to server
+       NetworkPacket* resp_pkt = new NetworkPacket(TOSERVER_INIT2, 0);
+       Send(resp_pkt);
+
+       m_state = LC_Init;
+}
+
+void Client::handleCommand_InitLegacy(NetworkPacket* pkt)
+{
+       if (pkt->getSize() < 1)
+               return;
+
+       u8 deployed;
+       *pkt >> deployed;
+
+       infostream << "Client: TOCLIENT_INIT_LEGACY received with "
+                       "deployed=" << ((int)deployed & 0xff) << std::endl;
+
+       if (!ser_ver_supported(deployed)) {
+               infostream << "Client: TOCLIENT_INIT_LEGACY: Server sent "
                                << "unsupported ser_fmt_ver"<< std::endl;
                return;
        }
@@ -98,10 +143,11 @@ void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
        m_access_denied_reason = L"Unknown";
 
        if (pkt->getCommand() == TOCLIENT_ACCESS_DENIED) {
+               if (pkt->getSize() < 1)
+                       return;
+
                u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA;
-               if(pkt->getSize() >= 1) {
-                       *pkt >> denyCode;
-               }
+               *pkt >> denyCode;
                if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) {
                        *pkt >> m_access_denied_reason;
                }
index 113ca6c8f8659bebf61e6e6ee610454ef63e9f1f..ee30dfd0686b06c97952f7fd3d2efc4e018d0159 100644 (file)
@@ -43,6 +43,283 @@ void Server::handleCommand_Deprecated(NetworkPacket* pkt)
                << " not supported anymore" << std::endl;
 }
 
+void Server::handleCommand_Init(NetworkPacket* pkt)
+{
+
+       if(pkt->getSize() < 1)
+               return;
+
+       RemoteClient* client = getClient(pkt->getPeerId(), CS_Created);
+
+       std::string addr_s;
+       try {
+               Address address = getPeerAddress(pkt->getPeerId());
+               addr_s = address.serializeString();
+       }
+       catch (con::PeerNotFoundException &e) {
+               /*
+                * no peer for this packet found
+                * most common reason is peer timeout, e.g. peer didn't
+                * respond for some time, your server was overloaded or
+                * things like that.
+                */
+               infostream << "Server::ProcessData(): Canceling: peer "
+                               << pkt->getPeerId() << " not found" << std::endl;
+               return;
+       }
+
+       // If net_proto_version is set, this client has already been handled
+       if (client->getState() > CS_Created) {
+               verbosestream << "Server: Ignoring multiple TOSERVER_INITs from "
+                               << addr_s << " (peer_id=" << pkt->getPeerId() << ")" << std::endl;
+               return;
+       }
+
+       verbosestream << "Server: Got TOSERVER_INIT from " << addr_s << " (peer_id="
+                       << pkt->getPeerId() << ")" << std::endl;
+
+       // Do not allow multiple players in simple singleplayer mode.
+       // This isn't a perfect way to do it, but will suffice for now
+       if (m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1) {
+               infostream << "Server: Not allowing another client (" << addr_s
+                               << ") to connect in simple singleplayer mode" << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_SINGLEPLAYER);
+               return;
+       }
+
+       // First byte after command is maximum supported
+       // serialization version
+       u8 client_max;
+       u8 compression_modes;
+       u16 min_net_proto_version = 0;
+       u16 max_net_proto_version;
+
+       *pkt >> client_max >> compression_modes >> min_net_proto_version
+                       >> max_net_proto_version;
+
+       u8 our_max = SER_FMT_VER_HIGHEST_READ;
+       // Use the highest version supported by both
+       int deployed = std::min(client_max, our_max);
+       // If it's lower than the lowest supported, give up.
+       if (deployed < SER_FMT_VER_LOWEST)
+               deployed = SER_FMT_VER_INVALID;
+
+       if (deployed == SER_FMT_VER_INVALID) {
+               actionstream << "Server: A mismatched client tried to connect from "
+                               << addr_s << std::endl;
+               infostream<<"Server: Cannot negotiate serialization version with "
+                               << addr_s << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_VERSION);
+               return;
+       }
+
+       client->setPendingSerializationVersion(deployed);
+
+       /*
+               Read and check network protocol version
+       */
+
+       u16 net_proto_version = 0;
+
+       // Figure out a working version if it is possible at all
+       if (max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
+                       min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX) {
+               // If maximum is larger than our maximum, go with our maximum
+               if (max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
+                       net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
+               // Else go with client's maximum
+               else
+                       net_proto_version = max_net_proto_version;
+       }
+
+       verbosestream << "Server: " << addr_s << ": Protocol version: min: "
+                       << min_net_proto_version << ", max: " << max_net_proto_version
+                       << ", chosen: " << net_proto_version << std::endl;
+
+       client->net_proto_version = net_proto_version;
+
+       // On this handler protocol version 25 is required
+       if (net_proto_version < 25 ||
+                       net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
+                       net_proto_version > SERVER_PROTOCOL_VERSION_MAX) {
+               actionstream << "Server: A mismatched client tried to connect from "
+                               << addr_s << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_VERSION);
+               return;
+       }
+
+       if (g_settings->getBool("strict_protocol_version_checking")) {
+               if (net_proto_version != LATEST_PROTOCOL_VERSION) {
+                       actionstream << "Server: A mismatched (strict) client tried to "
+                                       << "connect from " << addr_s << std::endl;
+                       DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_VERSION);
+                       return;
+               }
+       }
+
+       // @TODO: check if we support same modes, but not required now
+
+       client->setSupportedCompressionModes(compression_modes);
+
+       m_clients.event(pkt->getPeerId(), CSE_Init);
+}
+
+void Server::handleCommand_Auth(NetworkPacket* pkt)
+{
+       std::string addr_s;
+       try {
+               Address address = getPeerAddress(pkt->getPeerId());
+               addr_s = address.serializeString();
+       }
+       catch (con::PeerNotFoundException &e) {
+               /*
+                * no peer for this packet found
+                * most common reason is peer timeout, e.g. peer didn't
+                * respond for some time, your server was overloaded or
+                * things like that.
+                */
+               infostream << "Server::ProcessData(): Canceling: peer "
+                               << pkt->getPeerId() << " not found" << std::endl;
+               return;
+       }
+
+       std::string playerName, playerPassword;
+
+       *pkt >> playerName >> playerPassword;
+
+       const char* playername = playerName.c_str();
+
+       if (playerName.size() > PLAYERNAME_SIZE) {
+               actionstream << "Server: Player with an too long name "
+                               << "tried to connect from " << addr_s << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_NAME);
+               return;
+       }
+
+       if (string_allowed(playerName, PLAYERNAME_ALLOWED_CHARS) == false) {
+               actionstream << "Server: Player with an invalid name "
+                               << "tried to connect from " << addr_s << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_CHARS_IN_NAME);
+               return;
+       }
+
+       if (!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0) {
+               actionstream << "Server: Player with the name \"singleplayer\" "
+                               << "tried to connect from " << addr_s << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_NAME);
+               return;
+       }
+
+       {
+               std::string reason;
+               if(m_script->on_prejoinplayer(playername, addr_s, reason)) {
+                       actionstream << "Server: Player with the name \"" << playerName << "\" "
+                                       << "tried to connect from " << addr_s << " "
+                                       << "but it was disallowed for the following reason: "
+                                       << reason << std::endl;
+                       DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING,
+                                       narrow_to_wide(reason.c_str()));
+                       return;
+               }
+       }
+
+       if (playerPassword.size() > PASSWORD_SIZE) {
+               actionstream << "Server: Player with an too long password "
+                               << "tried to connect from " << addr_s << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_PASSWORD);
+               return;
+       }
+
+       infostream << "Server: New connection: \"" << playerName << "\" from "
+                       << addr_s << " (peer_id=" << pkt->getPeerId() << ")" << std::endl;
+
+       if(!base64_is_valid(playerPassword)){
+               actionstream << "Server: " << playerName
+                               << " supplied invalid password hash" << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_PASSWORD);
+               return;
+       }
+
+       // Enforce user limit.
+       // Don't enforce for users that have some admin right
+       if (m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
+                       !checkPriv(playername, "server") &&
+                       !checkPriv(playername, "ban") &&
+                       !checkPriv(playername, "privs") &&
+                       !checkPriv(playername, "password") &&
+                       playername != g_settings->get("name")) {
+               actionstream << "Server: " << playername << " tried to join, but there"
+                               << " are already max_users="
+                               << g_settings->getU16("max_users") << " players." << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_TOO_MANY_USERS);
+               return;
+       }
+
+       std::string checkpwd; // Password hash to check against
+       bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
+
+       // If no authentication info exists for user, create it
+       if (!has_auth) {
+               if (!isSingleplayer() &&
+                               g_settings->getBool("disallow_empty_password") &&
+                               playerPassword.empty()) {
+                       actionstream << "Server: " << playerName
+                                       << " supplied empty password" << std::endl;
+                       DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_EMPTY_PASSWORD);
+                       return;
+               }
+               std::wstring raw_default_password =
+                       narrow_to_wide(g_settings->get("default_password"));
+               std::string initial_password =
+                       translatePassword(playername, raw_default_password);
+
+               // If default_password is empty, allow any initial password
+               if (raw_default_password.length() == 0)
+                       initial_password = playerPassword.c_str();
+
+               m_script->createAuth(playername, initial_password);
+       }
+
+       has_auth = m_script->getAuth(playername, &checkpwd, NULL);
+
+       if(!has_auth) {
+               actionstream << "Server: " << playerName << " cannot be authenticated"
+                               << " (auth handler does not work?)" << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_SERVER_FAIL);
+               return;
+       }
+
+       if(playerPassword.c_str() != checkpwd) {
+               actionstream << "Server: " << playerName << " supplied wrong password"
+                               << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_WRONG_PASSWORD);
+               return;
+       }
+
+       RemotePlayer *player =
+                       static_cast<RemotePlayer*>(m_env->getPlayer(playername));
+
+       if (player && player->peer_id != 0) {
+               errorstream << "Server: " << playername << ": Failed to emerge player"
+                               << " (player allocated to an another client)" << std::endl;
+               DenyAccess(pkt->getPeerId(), SERVER_ACCESSDENIED_ALREADY_CONNECTED);
+       }
+
+       m_clients.setPlayerName(pkt->getPeerId(), playername);
+
+       /*
+               Answer with a TOCLIENT_INIT
+       */
+
+       NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, pkt->getPeerId());
+
+       resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
+                       << g_settings->getFloat("dedicated_server_step");
+
+       Send(&resp_pkt);
+       m_clients.event(pkt->getPeerId(), CSE_Init);
+}
+
 void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
 {
        // [0] u8 SER_FMT_VER_HIGHEST_READ
@@ -86,7 +363,7 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
        if (m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1) {
                infostream << "Server: Not allowing another client (" << addr_s
                                << ") to connect in simple singleplayer mode" << std::endl;
-               DenyAccess(pkt->getPeerId(), L"Running in simple singleplayer mode.");
+               DenyAccess_Legacy(pkt->getPeerId(), L"Running in simple singleplayer mode.");
                return;
        }
 
@@ -108,7 +385,7 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
                                << addr_s << std::endl;
                infostream<<"Server: Cannot negotiate serialization version with "
                                << addr_s << std::endl;
-               DenyAccess(pkt->getPeerId(), std::wstring(
+               DenyAccess_Legacy(pkt->getPeerId(), std::wstring(
                                L"Your client's version is not supported.\n"
                                L"Server version is ")
                                + narrow_to_wide(minetest_version_simple) + L"."
@@ -156,7 +433,7 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
                        net_proto_version > SERVER_PROTOCOL_VERSION_MAX) {
                actionstream << "Server: A mismatched client tried to connect from "
                                << addr_s << std::endl;
-               DenyAccess(pkt->getPeerId(), std::wstring(
+               DenyAccess_Legacy(pkt->getPeerId(), std::wstring(
                                L"Your client's version is not supported.\n"
                                L"Server version is ")
                                + narrow_to_wide(minetest_version_simple) + L",\n"
@@ -176,7 +453,7 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
                if (net_proto_version != LATEST_PROTOCOL_VERSION) {
                        actionstream << "Server: A mismatched (strict) client tried to "
                                        << "connect from " << addr_s << std::endl;
-                       DenyAccess(pkt->getPeerId(), std::wstring(
+                       DenyAccess_Legacy(pkt->getPeerId(), std::wstring(
                                        L"Your client's version is not supported.\n"
                                        L"Server version is ")
                                        + narrow_to_wide(minetest_version_simple) + L",\n"
@@ -205,7 +482,7 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
        if (playername_length == PLAYERNAME_SIZE) {
                actionstream << "Server: Player with name exceeding max length "
                                << "tried to connect from " << addr_s << std::endl;
-               DenyAccess(pkt->getPeerId(), L"Name too long");
+               DenyAccess_Legacy(pkt->getPeerId(), L"Name too long");
                return;
        }
 
@@ -213,21 +490,21 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
        if (playername[0]=='\0') {
                actionstream << "Server: Player with an empty name "
                                << "tried to connect from " << addr_s << std::endl;
-               DenyAccess(pkt->getPeerId(), L"Empty name");
+               DenyAccess_Legacy(pkt->getPeerId(), L"Empty name");
                return;
        }
 
        if (string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false) {
                actionstream << "Server: Player with an invalid name "
                                << "tried to connect from " << addr_s << std::endl;
-               DenyAccess(pkt->getPeerId(), L"Name contains unallowed characters");
+               DenyAccess_Legacy(pkt->getPeerId(), L"Name contains unallowed characters");
                return;
        }
 
        if (!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0) {
                actionstream << "Server: Player with the name \"singleplayer\" "
                                << "tried to connect from " << addr_s << std::endl;
-               DenyAccess(pkt->getPeerId(), L"Name is not allowed");
+               DenyAccess_Legacy(pkt->getPeerId(), L"Name is not allowed");
                return;
        }
 
@@ -238,7 +515,7 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
                                        << "tried to connect from " << addr_s << " "
                                        << "but it was disallowed for the following reason: "
                                        << reason << std::endl;
-                       DenyAccess(pkt->getPeerId(), narrow_to_wide(reason.c_str()));
+                       DenyAccess_Legacy(pkt->getPeerId(), narrow_to_wide(reason.c_str()));
                        return;
                }
        }
@@ -262,7 +539,7 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
        if (!base64_is_valid(given_password)) {
                actionstream << "Server: " << playername
                                << " supplied invalid password hash" << std::endl;
-               DenyAccess(pkt->getPeerId(), L"Invalid password hash");
+               DenyAccess_Legacy(pkt->getPeerId(), L"Invalid password hash");
                return;
        }
 
@@ -277,7 +554,7 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
                actionstream << "Server: " << playername << " tried to join, but there"
                                << " are already max_users="
                                << g_settings->getU16("max_users") << " players." << std::endl;
-               DenyAccess(pkt->getPeerId(), L"Too many users.");
+               DenyAccess_Legacy(pkt->getPeerId(), L"Too many users.");
                return;
        }
 
@@ -291,7 +568,7 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
                                std::string(given_password) == "") {
                        actionstream << "Server: " << playername
                                        << " supplied empty password" << std::endl;
-                       DenyAccess(pkt->getPeerId(), L"Empty passwords are "
+                       DenyAccess_Legacy(pkt->getPeerId(), L"Empty passwords are "
                                        L"disallowed. Set a password and try again.");
                        return;
                }
@@ -312,14 +589,14 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
        if (!has_auth) {
                actionstream << "Server: " << playername << " cannot be authenticated"
                                << " (auth handler does not work?)" << std::endl;
-               DenyAccess(pkt->getPeerId(), L"Not allowed to login");
+               DenyAccess_Legacy(pkt->getPeerId(), L"Not allowed to login");
                return;
        }
 
        if (given_password != checkpwd) {
                actionstream << "Server: " << playername << " supplied wrong password"
                                << std::endl;
-               DenyAccess(pkt->getPeerId(), L"Wrong password");
+               DenyAccess_Legacy(pkt->getPeerId(), L"Wrong password");
                return;
        }
 
@@ -329,7 +606,7 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
        if (player && player->peer_id != 0) {
                errorstream << "Server: " << playername << ": Failed to emerge player"
                                << " (player allocated to an another client)" << std::endl;
-               DenyAccess(pkt->getPeerId(), L"Another client is connected with this "
+               DenyAccess_Legacy(pkt->getPeerId(), L"Another client is connected with this "
                                L"name. If your client closed unexpectedly, try again in "
                                L"a minute.");
        }
@@ -340,7 +617,7 @@ void Server::handleCommand_Init_Legacy(NetworkPacket* pkt)
                Answer with a TOCLIENT_INIT
        */
 
-       NetworkPacket* resp_pkt = new NetworkPacket(TOCLIENT_INIT, 1 + 6 + 8 + 4,
+       NetworkPacket* resp_pkt = new NetworkPacket(TOCLIENT_INIT_LEGACY, 1 + 6 + 8 + 4,
                        pkt->getPeerId());
 
        *resp_pkt << (u8) deployed << (v3s16) floatToInt(v3f(0,0,0), BS)
@@ -942,33 +1219,36 @@ void Server::handleCommand_Breath(NetworkPacket* pkt)
        SendPlayerBreath(pkt->getPeerId());
 }
 
-void Server::handleCommand_Password_Legacy(NetworkPacket* pkt)
+void Server::handleCommand_Password(NetworkPacket* pkt)
 {
-       /*
-               [0] u16 TOSERVER_PASSWORD
-               [2] u8[28] old password
-               [30] u8[28] new password
-       */
-
        errorstream << "PAssword packet size: " << pkt->getSize() << " size required: " << PASSWORD_SIZE * 2 << std::endl;
-       if (pkt->getSize() != PASSWORD_SIZE * 2)
+       if ((pkt->getCommand() == TOSERVER_PASSWORD && pkt->getSize() < 4) ||
+                       pkt->getSize() != PASSWORD_SIZE * 2)
                return;
 
        std::string oldpwd;
        std::string newpwd;
 
-       for (u16 i = 0; i < PASSWORD_SIZE - 1; i++) {
-               char c = pkt->getChar(i);
-               if (c == 0)
-                       break;
-               oldpwd += c;
+       if (pkt->getCommand() == TOSERVER_PASSWORD) {
+               *pkt >> oldpwd >> newpwd;
        }
+       // 13/03/15
+       // Protocol v24 compat. Please remove in 1 year after
+       // client convergence to 0.4.13/0.5.x
+       else {
+               for (u16 i = 0; i < PASSWORD_SIZE - 1; i++) {
+                       char c = pkt->getChar(i);
+                       if (c == 0)
+                               break;
+                       oldpwd += c;
+               }
 
-       for (u16 i = 0; i < PASSWORD_SIZE - 1; i++) {
-               char c = pkt->getChar(PASSWORD_SIZE + i);
-               if (c == 0)
-                       break;
-               newpwd += c;
+               for (u16 i = 0; i < PASSWORD_SIZE - 1; i++) {
+                       char c = pkt->getChar(PASSWORD_SIZE + i);
+                       if (c == 0)
+                               break;
+                       newpwd += c;
+               }
        }
 
        Player *player = m_env->getPlayer(pkt->getPeerId());
index cecabf7a82782f4e870b5307f5e94b7f181ec9d7..9c1da9ad17a6b48ed6c464260d60ec60dd08625e 100644 (file)
@@ -26,8 +26,8 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] =
 {
        null_command_handler, // 0x00 (never use this)
        null_command_handler, // 0x01
-       null_command_handler, // 0x02
-       null_command_handler, // 0x03
+       { "TOSERVER_INIT",                    TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_Init }, // 0x02
+       { "TOSERVER_AUTH",                    TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_Auth }, // 0x03
        null_command_handler, // 0x04
        null_command_handler, // 0x05
        null_command_handler, // 0x06
@@ -78,14 +78,14 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] =
        { "TOSERVER_SIGNNODETEXT",             TOSERVER_STATE_INGAME, &Server::handleCommand_Deprecated }, // 0x33
        { "TOSERVER_CLICK_ACTIVEOBJECT",       TOSERVER_STATE_INGAME, &Server::handleCommand_Deprecated }, // 0x34
        { "TOSERVER_DAMAGE",                   TOSERVER_STATE_INGAME, &Server::handleCommand_Damage }, // 0x35
-       { "TOSERVER_PASSWORD_LEGACY",          TOSERVER_STATE_INGAME, &Server::handleCommand_Password_Legacy }, // 0x36
+       { "TOSERVER_PASSWORD_LEGACY",          TOSERVER_STATE_INGAME, &Server::handleCommand_Password }, // 0x36
        { "TOSERVER_PLAYERITEM",               TOSERVER_STATE_INGAME, &Server::handleCommand_PlayerItem }, // 0x37
        { "TOSERVER_RESPAWN",                  TOSERVER_STATE_INGAME, &Server::handleCommand_Respawn }, // 0x38
        { "TOSERVER_INTERACT",                 TOSERVER_STATE_INGAME, &Server::handleCommand_Interact }, // 0x39
        { "TOSERVER_REMOVED_SOUNDS",           TOSERVER_STATE_INGAME, &Server::handleCommand_RemovedSounds }, // 0x3a
        { "TOSERVER_NODEMETA_FIELDS",          TOSERVER_STATE_INGAME, &Server::handleCommand_NodeMetaFields }, // 0x3b
        { "TOSERVER_INVENTORY_FIELDS",         TOSERVER_STATE_INGAME, &Server::handleCommand_InventoryFields }, // 0x3c
-       null_command_handler, // 0x3d
+       { "TOSERVER_PASSWORD",                 TOSERVER_STATE_INGAME, &Server::handleCommand_Password }, // 0x3d
        null_command_handler, // 0x3e
        null_command_handler, // 0x3f
        { "TOSERVER_REQUEST_MEDIA",            TOSERVER_STATE_STARTUP, &Server::handleCommand_RequestMedia }, // 0x40
@@ -100,8 +100,8 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
 {
        null_command_factory, // 0x00
        null_command_factory, // 0x01
-       null_command_factory, // 0x02
-       null_command_factory, // 0x03
+       { "TOCLIENT_HELLO",             0, true }, // 0x02
+       { "TOCLIENT_AUTH_ACCEPT",       0, true }, // 0x03
        null_command_factory, // 0x04
        null_command_factory, // 0x05
        null_command_factory, // 0x06
index fcdd8c2ff4558d6fcea21d66aac1f6d922265a78..99e73b03e50b95f85aae434becbac6753f42853a 100644 (file)
@@ -306,7 +306,7 @@ int ModApiServer::l_kick_player(lua_State *L)
                lua_pushboolean(L, false); // No such player
                return 1;
        }
-       getServer(L)->DenyAccess(player->peer_id, narrow_to_wide(message));
+       getServer(L)->DenyAccess_Legacy(player->peer_id, narrow_to_wide(message));
        lua_pushboolean(L, true);
        return 1;
 }
index b230ffd18e09ebd86e790a007b4dc67d39b09da5..7e0ee7d0355231d7843ba11963d4bc0738cc1e64 100644 (file)
@@ -1040,7 +1040,7 @@ void Server::Receive()
        }
        catch(ClientStateError &e) {
                errorstream << "ProcessData: peer=" << peer_id  << e.what() << std::endl;
-               DenyAccess(peer_id, L"Your client sent something server didn't expect."
+               DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
                                L"Try reconnecting or updating your client");
        }
        catch(con::PeerNotFoundException &e) {
@@ -1073,13 +1073,13 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
                if(player && player->peer_id != 0) {
                        errorstream<<"Server: "<<playername<<": Failed to emerge player"
                                        <<" (player allocated to an another client)"<<std::endl;
-                       DenyAccess(peer_id, L"Another client is connected with this "
+                       DenyAccess_Legacy(peer_id, L"Another client is connected with this "
                                        L"name. If your client closed unexpectedly, try again in "
                                        L"a minute.");
                } else {
                        errorstream<<"Server: "<<playername<<": Failed to emerge player"
                                        <<std::endl;
-                       DenyAccess(peer_id, L"Could not allocate player.");
+                       DenyAccess_Legacy(peer_id, L"Could not allocate player.");
                }
                return NULL;
        }
@@ -1173,7 +1173,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        << addr_s << "; banned name was "
                                        << ban_name << std::endl;
                        // This actually doesn't seem to transfer to the client
-                       DenyAccess(peer_id, L"Your ip is banned. Banned name was "
+                       DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
                                        + narrow_to_wide(ban_name));
                        return;
                }
@@ -1502,7 +1502,20 @@ void Server::SendBreath(u16 peer_id, u16 breath)
        Send(pkt);
 }
 
-void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
+void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
+       pkt << (u8) reason;
+
+       if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
+               pkt << custom_reason;
+       }
+       Send(&pkt);
+}
+
+void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
 {
        DSTACK(__FUNCTION_NAME);
 
@@ -2525,11 +2538,22 @@ void Server::RespawnPlayer(u16 peer_id)
        }
 }
 
-void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
+void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       SendAccessDenied(peer_id, reason, custom_reason);
+       m_clients.event(peer_id, CSE_SetDenied);
+       m_con.DisconnectPeer(peer_id);
+}
+
+// 13/03/15: remove this function when protocol version 25 will become
+// the minimum version for MT users, maybe in 1 year
+void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
 {
        DSTACK(__FUNCTION_NAME);
 
-       SendAccessDenied(peer_id, reason);
+       SendAccessDenied_Legacy(peer_id, reason);
        m_clients.event(peer_id, CSE_SetDenied);
        m_con.DisconnectPeer(peer_id);
 }
index 897841406235b17d4142f60a9a4600d822ef5d77..546a44a20c1f379b9cb77a75a45be47f0b162c80 100644 (file)
@@ -197,6 +197,8 @@ public:
 
        void handleCommand_Null(NetworkPacket* pkt) {};
        void handleCommand_Deprecated(NetworkPacket* pkt);
+       void handleCommand_Init(NetworkPacket* pkt);
+       void handleCommand_Auth(NetworkPacket* pkt);
        void handleCommand_Init_Legacy(NetworkPacket* pkt);
        void handleCommand_Init2(NetworkPacket* pkt);
        void handleCommand_RequestMedia(NetworkPacket* pkt);
@@ -209,7 +211,7 @@ public:
        void handleCommand_ChatMessage(NetworkPacket* pkt);
        void handleCommand_Damage(NetworkPacket* pkt);
        void handleCommand_Breath(NetworkPacket* pkt);
-       void handleCommand_Password_Legacy(NetworkPacket* pkt);
+       void handleCommand_Password(NetworkPacket* pkt);
        void handleCommand_PlayerItem(NetworkPacket* pkt);
        void handleCommand_Respawn(NetworkPacket* pkt);
        void handleCommand_Interact(NetworkPacket* pkt);
@@ -366,7 +368,8 @@ public:
        void peerAdded(con::Peer *peer);
        void deletingPeer(con::Peer *peer, bool timeout);
 
-       void DenyAccess(u16 peer_id, const std::wstring &reason);
+       void DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason=NULL);
+       void DenyAccess_Legacy(u16 peer_id, const std::wstring &reason);
        bool getClientConInfo(u16 peer_id, con::rtt_stat_type type,float* retval);
        bool getClientInfo(u16 peer_id,ClientState* state, u32* uptime,
                        u8* ser_vers, u16* prot_vers, u8* major, u8* minor, u8* patch,
@@ -388,7 +391,8 @@ private:
        void SendMovement(u16 peer_id);
        void SendHP(u16 peer_id, u8 hp);
        void SendBreath(u16 peer_id, u16 breath);
-       void SendAccessDenied(u16 peer_id,const std::wstring &reason);
+       void SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::wstring &custom_reason);
+       void SendAccessDenied_Legacy(u16 peer_id, const std::wstring &reason);
        void SendDeathscreen(u16 peer_id,bool set_camera_point_target, v3f camera_point_target);
        void SendItemDef(u16 peer_id,IItemDefManager *itemdef, u16 protocol_version);
        void SendNodeDef(u16 peer_id,INodeDefManager *nodedef, u16 protocol_version);