diff options
-rw-r--r-- | src/client.h | 4 | ||||
-rw-r--r-- | src/clientiface.h | 6 | ||||
-rw-r--r-- | src/network/clientopcodes.cpp | 6 | ||||
-rw-r--r-- | src/network/networkprotocol.h | 34 | ||||
-rw-r--r-- | src/network/packethandlers/client.cpp | 58 | ||||
-rw-r--r-- | src/network/packethandlers/server.cpp | 348 | ||||
-rw-r--r-- | src/network/serveropcodes.cpp | 12 | ||||
-rw-r--r-- | src/script/lua_api/l_server.cpp | 2 | ||||
-rw-r--r-- | src/server.cpp | 38 | ||||
-rw-r--r-- | src/server.h | 10 |
10 files changed, 448 insertions, 70 deletions
diff --git a/src/client.h b/src/client.h index a0add689a..9baa034de 100644 --- a/src/client.h +++ b/src/client.h @@ -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); diff --git a/src/clientiface.h b/src/clientiface.h index cc303734a..2fd293de2 100644 --- a/src/clientiface.h +++ b/src/clientiface.h @@ -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 */ diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp index f236b6353..556e8d0c0 100644 --- a/src/network/clientopcodes.cpp +++ b/src/network/clientopcodes.cpp @@ -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, diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 1e0896ebf..599b70006 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -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"", }; diff --git a/src/network/packethandlers/client.cpp b/src/network/packethandlers/client.cpp index ae24157e0..838c85989 100644 --- a/src/network/packethandlers/client.cpp +++ b/src/network/packethandlers/client.cpp @@ -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; } diff --git a/src/network/packethandlers/server.cpp b/src/network/packethandlers/server.cpp index 113ca6c8f..ee30dfd06 100644 --- a/src/network/packethandlers/server.cpp +++ b/src/network/packethandlers/server.cpp @@ -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()); diff --git a/src/network/serveropcodes.cpp b/src/network/serveropcodes.cpp index cecabf7a8..9c1da9ad1 100644 --- a/src/network/serveropcodes.cpp +++ b/src/network/serveropcodes.cpp @@ -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 diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index fcdd8c2ff..99e73b03e 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -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; } diff --git a/src/server.cpp b/src/server.cpp index b230ffd18..7e0ee7d03 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -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); } diff --git a/src/server.h b/src/server.h index 897841406..546a44a20 100644 --- a/src/server.h +++ b/src/server.h @@ -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); |