]> git.lizzy.rs Git - minetest.git/blob - src/network/serverpackethandler.cpp
Add server side translations capability (#9733)
[minetest.git] / src / network / serverpackethandler.cpp
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 "chatmessage.h"
21 #include "server.h"
22 #include "log.h"
23 #include "emerge.h"
24 #include "mapblock.h"
25 #include "modchannels.h"
26 #include "nodedef.h"
27 #include "remoteplayer.h"
28 #include "rollback_interface.h"
29 #include "scripting_server.h"
30 #include "settings.h"
31 #include "tool.h"
32 #include "version.h"
33 #include "network/connection.h"
34 #include "network/networkprotocol.h"
35 #include "network/serveropcodes.h"
36 #include "server/player_sao.h"
37 #include "util/auth.h"
38 #include "util/base64.h"
39 #include "util/pointedthing.h"
40 #include "util/serialize.h"
41 #include "util/srp.h"
42
43 void Server::handleCommand_Deprecated(NetworkPacket* pkt)
44 {
45         infostream << "Server: " << toServerCommandTable[pkt->getCommand()].name
46                 << " not supported anymore" << std::endl;
47 }
48
49 void Server::handleCommand_Init(NetworkPacket* pkt)
50 {
51
52         if(pkt->getSize() < 1)
53                 return;
54
55         session_t peer_id = pkt->getPeerId();
56         RemoteClient *client = getClient(peer_id, CS_Created);
57
58         std::string addr_s;
59         try {
60                 Address address = getPeerAddress(peer_id);
61                 addr_s = address.serializeString();
62         }
63         catch (con::PeerNotFoundException &e) {
64                 /*
65                  * no peer for this packet found
66                  * most common reason is peer timeout, e.g. peer didn't
67                  * respond for some time, your server was overloaded or
68                  * things like that.
69                  */
70                 infostream << "Server::ProcessData(): Canceling: peer " << peer_id <<
71                         " not found" << std::endl;
72                 return;
73         }
74
75         // If net_proto_version is set, this client has already been handled
76         if (client->getState() > CS_Created) {
77                 verbosestream << "Server: Ignoring multiple TOSERVER_INITs from " <<
78                         addr_s << " (peer_id=" << peer_id << ")" << std::endl;
79                 return;
80         }
81
82         verbosestream << "Server: Got TOSERVER_INIT from " << addr_s <<
83                 " (peer_id=" << peer_id << ")" << std::endl;
84
85         // Do not allow multiple players in simple singleplayer mode.
86         // This isn't a perfect way to do it, but will suffice for now
87         if (m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1) {
88                 infostream << "Server: Not allowing another client (" << addr_s <<
89                         ") to connect in simple singleplayer mode" << std::endl;
90                 DenyAccess(peer_id, SERVER_ACCESSDENIED_SINGLEPLAYER);
91                 return;
92         }
93
94         // First byte after command is maximum supported
95         // serialization version
96         u8 client_max;
97         u16 supp_compr_modes;
98         u16 min_net_proto_version = 0;
99         u16 max_net_proto_version;
100         std::string playerName;
101
102         *pkt >> client_max >> supp_compr_modes >> min_net_proto_version
103                         >> max_net_proto_version >> playerName;
104
105         u8 our_max = SER_FMT_VER_HIGHEST_READ;
106         // Use the highest version supported by both
107         u8 depl_serial_v = std::min(client_max, our_max);
108         // If it's lower than the lowest supported, give up.
109         if (depl_serial_v < SER_FMT_VER_LOWEST_READ)
110                 depl_serial_v = SER_FMT_VER_INVALID;
111
112         if (depl_serial_v == SER_FMT_VER_INVALID) {
113                 actionstream << "Server: A mismatched client tried to connect from " <<
114                         addr_s << std::endl;
115                 infostream << "Server: Cannot negotiate serialization version with " <<
116                         addr_s << " client_max=" << (int)client_max << std::endl;
117                 DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_VERSION);
118                 return;
119         }
120
121         client->setPendingSerializationVersion(depl_serial_v);
122
123         /*
124                 Read and check network protocol version
125         */
126
127         u16 net_proto_version = 0;
128
129         // Figure out a working version if it is possible at all
130         if (max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
131                         min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX) {
132                 // If maximum is larger than our maximum, go with our maximum
133                 if (max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
134                         net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
135                 // Else go with client's maximum
136                 else
137                         net_proto_version = max_net_proto_version;
138         }
139
140         verbosestream << "Server: " << addr_s << ": Protocol version: min: "
141                         << min_net_proto_version << ", max: " << max_net_proto_version
142                         << ", chosen: " << net_proto_version << std::endl;
143
144         client->net_proto_version = net_proto_version;
145
146         if ((g_settings->getBool("strict_protocol_version_checking") &&
147                         net_proto_version != LATEST_PROTOCOL_VERSION) ||
148                         net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
149                         net_proto_version > SERVER_PROTOCOL_VERSION_MAX) {
150                 actionstream << "Server: A mismatched client tried to connect from " <<
151                         addr_s << std::endl;
152                 DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_VERSION);
153                 return;
154         }
155
156         /*
157                 Validate player name
158         */
159         const char* playername = playerName.c_str();
160
161         size_t pns = playerName.size();
162         if (pns == 0 || pns > PLAYERNAME_SIZE) {
163                 actionstream << "Server: Player with " <<
164                         ((pns > PLAYERNAME_SIZE) ? "a too long" : "an empty") <<
165                         " name tried to connect from " << addr_s << std::endl;
166                 DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_NAME);
167                 return;
168         }
169
170         if (!string_allowed(playerName, PLAYERNAME_ALLOWED_CHARS)) {
171                 actionstream << "Server: Player with an invalid name tried to connect "
172                         "from " << addr_s << std::endl;
173                 DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_CHARS_IN_NAME);
174                 return;
175         }
176
177         m_clients.setPlayerName(peer_id, playername);
178         //TODO (later) case insensitivity
179
180         std::string legacyPlayerNameCasing = playerName;
181
182         if (!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0) {
183                 actionstream << "Server: Player with the name \"singleplayer\" tried "
184                         "to connect from " << addr_s << std::endl;
185                 DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_NAME);
186                 return;
187         }
188
189         {
190                 std::string reason;
191                 if (m_script->on_prejoinplayer(playername, addr_s, &reason)) {
192                         actionstream << "Server: Player with the name \"" << playerName <<
193                                 "\" tried to connect from " << addr_s <<
194                                 " but it was disallowed for the following reason: " << reason <<
195                                 std::endl;
196                         DenyAccess(peer_id, SERVER_ACCESSDENIED_CUSTOM_STRING, reason);
197                         return;
198                 }
199         }
200
201         infostream << "Server: New connection: \"" << playerName << "\" from " <<
202                 addr_s << " (peer_id=" << peer_id << ")" << std::endl;
203
204         // Enforce user limit.
205         // Don't enforce for users that have some admin right or mod permits it.
206         if (m_clients.isUserLimitReached() &&
207                         playername != g_settings->get("name") &&
208                         !m_script->can_bypass_userlimit(playername, addr_s)) {
209                 actionstream << "Server: " << playername << " tried to join from " <<
210                         addr_s << ", but there are already max_users=" <<
211                         g_settings->getU16("max_users") << " players." << std::endl;
212                 DenyAccess(peer_id, SERVER_ACCESSDENIED_TOO_MANY_USERS);
213                 return;
214         }
215
216         /*
217                 Compose auth methods for answer
218         */
219         std::string encpwd; // encrypted Password field for the user
220         bool has_auth = m_script->getAuth(playername, &encpwd, NULL);
221         u32 auth_mechs = 0;
222
223         client->chosen_mech = AUTH_MECHANISM_NONE;
224
225         if (has_auth) {
226                 std::vector<std::string> pwd_components = str_split(encpwd, '#');
227                 if (pwd_components.size() == 4) {
228                         if (pwd_components[1] == "1") { // 1 means srp
229                                 auth_mechs |= AUTH_MECHANISM_SRP;
230                                 client->enc_pwd = encpwd;
231                         } else {
232                                 actionstream << "User " << playername << " tried to log in, "
233                                         "but password field was invalid (unknown mechcode)." <<
234                                         std::endl;
235                                 DenyAccess(peer_id, SERVER_ACCESSDENIED_SERVER_FAIL);
236                                 return;
237                         }
238                 } else if (base64_is_valid(encpwd)) {
239                         auth_mechs |= AUTH_MECHANISM_LEGACY_PASSWORD;
240                         client->enc_pwd = encpwd;
241                 } else {
242                         actionstream << "User " << playername << " tried to log in, but "
243                                 "password field was invalid (invalid base64)." << std::endl;
244                         DenyAccess(peer_id, SERVER_ACCESSDENIED_SERVER_FAIL);
245                         return;
246                 }
247         } else {
248                 std::string default_password = g_settings->get("default_password");
249                 if (default_password.length() == 0) {
250                         auth_mechs |= AUTH_MECHANISM_FIRST_SRP;
251                 } else {
252                         // Take care of default passwords.
253                         client->enc_pwd = get_encoded_srp_verifier(playerName, default_password);
254                         auth_mechs |= AUTH_MECHANISM_SRP;
255                         // Allocate player in db, but only on successful login.
256                         client->create_player_on_auth_success = true;
257                 }
258         }
259
260         /*
261                 Answer with a TOCLIENT_HELLO
262         */
263
264         verbosestream << "Sending TOCLIENT_HELLO with auth method field: "
265                 << auth_mechs << std::endl;
266
267         NetworkPacket resp_pkt(TOCLIENT_HELLO,
268                 1 + 4 + legacyPlayerNameCasing.size(), peer_id);
269
270         u16 depl_compress_mode = NETPROTO_COMPRESSION_NONE;
271         resp_pkt << depl_serial_v << depl_compress_mode << net_proto_version
272                 << auth_mechs << legacyPlayerNameCasing;
273
274         Send(&resp_pkt);
275
276         client->allowed_auth_mechs = auth_mechs;
277         client->setDeployedCompressionMode(depl_compress_mode);
278
279         m_clients.event(peer_id, CSE_Hello);
280 }
281
282 void Server::handleCommand_Init2(NetworkPacket* pkt)
283 {
284         session_t peer_id = pkt->getPeerId();
285         verbosestream << "Server: Got TOSERVER_INIT2 from " << peer_id << std::endl;
286
287         m_clients.event(peer_id, CSE_GotInit2);
288         u16 protocol_version = m_clients.getProtocolVersion(peer_id);
289
290         std::string lang;
291         if (pkt->getSize() > 0)
292                 *pkt >> lang;
293
294         /*
295                 Send some initialization data
296         */
297
298         infostream << "Server: Sending content to " << getPlayerName(peer_id) <<
299                 std::endl;
300
301         // Send item definitions
302         SendItemDef(peer_id, m_itemdef, protocol_version);
303
304         // Send node definitions
305         SendNodeDef(peer_id, m_nodedef, protocol_version);
306
307         m_clients.event(peer_id, CSE_SetDefinitionsSent);
308
309         // Send media announcement
310         sendMediaAnnouncement(peer_id, lang);
311
312         RemoteClient *client = getClient(peer_id, CS_InitDone);
313
314         // Keep client language for server translations
315         client->setLangCode(lang);
316
317         // Send active objects
318         {
319                 PlayerSAO *sao = getPlayerSAO(peer_id);
320                 if (client && sao)
321                         SendActiveObjectRemoveAdd(client, sao);
322         }
323
324         // Send detached inventories
325         sendDetachedInventories(peer_id, false);
326
327         // Send player movement settings
328         SendMovement(peer_id);
329
330         // Send time of day
331         u16 time = m_env->getTimeOfDay();
332         float time_speed = g_settings->getFloat("time_speed");
333         SendTimeOfDay(peer_id, time, time_speed);
334
335         SendCSMRestrictionFlags(peer_id);
336
337         // Warnings about protocol version can be issued here
338         if (client->net_proto_version < LATEST_PROTOCOL_VERSION) {
339                 SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
340                         L"# Server: WARNING: YOUR CLIENT'S VERSION MAY NOT BE FULLY COMPATIBLE "
341                         L"WITH THIS SERVER!"));
342         }
343 }
344
345 void Server::handleCommand_RequestMedia(NetworkPacket* pkt)
346 {
347         std::vector<std::string> tosend;
348         u16 numfiles;
349
350         *pkt >> numfiles;
351
352         session_t peer_id = pkt->getPeerId();
353         infostream << "Sending " << numfiles << " files to " <<
354                 getPlayerName(peer_id) << std::endl;
355         verbosestream << "TOSERVER_REQUEST_MEDIA: " << std::endl;
356
357         for (u16 i = 0; i < numfiles; i++) {
358                 std::string name;
359
360                 *pkt >> name;
361
362                 tosend.push_back(name);
363                 verbosestream << "TOSERVER_REQUEST_MEDIA: requested file "
364                                 << name << std::endl;
365         }
366
367         sendRequestedMedia(peer_id, tosend);
368 }
369
370 void Server::handleCommand_ClientReady(NetworkPacket* pkt)
371 {
372         session_t peer_id = pkt->getPeerId();
373
374         PlayerSAO* playersao = StageTwoClientInit(peer_id);
375
376         if (playersao == NULL) {
377                 errorstream << "TOSERVER_CLIENT_READY stage 2 client init failed "
378                         "peer_id=" << peer_id << std::endl;
379                 DisconnectPeer(peer_id);
380                 return;
381         }
382
383
384         if (pkt->getSize() < 8) {
385                 errorstream << "TOSERVER_CLIENT_READY client sent inconsistent data, "
386                         "disconnecting peer_id: " << peer_id << std::endl;
387                 DisconnectPeer(peer_id);
388                 return;
389         }
390
391         u8 major_ver, minor_ver, patch_ver, reserved;
392         std::string full_ver;
393         *pkt >> major_ver >> minor_ver >> patch_ver >> reserved >> full_ver;
394
395         m_clients.setClientVersion(peer_id, major_ver, minor_ver, patch_ver,
396                 full_ver);
397
398         if (pkt->getRemainingBytes() >= 2)
399                 *pkt >> playersao->getPlayer()->formspec_version;
400
401         const std::vector<std::string> &players = m_clients.getPlayerNames();
402         NetworkPacket list_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, peer_id);
403         list_pkt << (u8) PLAYER_LIST_INIT << (u16) players.size();
404         for (const std::string &player: players) {
405                 list_pkt <<  player;
406         }
407         m_clients.send(peer_id, 0, &list_pkt, true);
408
409         NetworkPacket notice_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
410         // (u16) 1 + std::string represents a pseudo vector serialization representation
411         notice_pkt << (u8) PLAYER_LIST_ADD << (u16) 1 << std::string(playersao->getPlayer()->getName());
412         m_clients.sendToAll(&notice_pkt);
413
414         m_clients.event(peer_id, CSE_SetClientReady);
415         m_script->on_joinplayer(playersao);
416         // Send shutdown timer if shutdown has been scheduled
417         if (m_shutdown_state.isTimerRunning()) {
418                 SendChatMessage(peer_id, m_shutdown_state.getShutdownTimerMessage());
419         }
420 }
421
422 void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
423 {
424         if (pkt->getSize() < 1)
425                 return;
426
427         /*
428                 [0] u16 command
429                 [2] u8 count
430                 [3] v3s16 pos_0
431                 [3+6] v3s16 pos_1
432                 ...
433         */
434
435         u8 count;
436         *pkt >> count;
437
438         RemoteClient *client = getClient(pkt->getPeerId());
439
440         if ((s16)pkt->getSize() < 1 + (int)count * 6) {
441                 throw con::InvalidIncomingDataException
442                                 ("GOTBLOCKS length is too short");
443         }
444
445         for (u16 i = 0; i < count; i++) {
446                 v3s16 p;
447                 *pkt >> p;
448                 client->GotBlock(p);
449         }
450 }
451
452 void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
453         NetworkPacket *pkt)
454 {
455         if (pkt->getRemainingBytes() < 12 + 12 + 4 + 4 + 4 + 1 + 1)
456                 return;
457
458         v3s32 ps, ss;
459         s32 f32pitch, f32yaw;
460         u8 f32fov;
461
462         *pkt >> ps;
463         *pkt >> ss;
464         *pkt >> f32pitch;
465         *pkt >> f32yaw;
466
467         f32 pitch = (f32)f32pitch / 100.0f;
468         f32 yaw = (f32)f32yaw / 100.0f;
469         u32 keyPressed = 0;
470
471         // default behavior (in case an old client doesn't send these)
472         f32 fov = 0;
473         u8 wanted_range = 0;
474
475         *pkt >> keyPressed;
476         *pkt >> f32fov;
477         fov = (f32)f32fov / 80.0f;
478         *pkt >> wanted_range;
479
480         v3f position((f32)ps.X / 100.0f, (f32)ps.Y / 100.0f, (f32)ps.Z / 100.0f);
481         v3f speed((f32)ss.X / 100.0f, (f32)ss.Y / 100.0f, (f32)ss.Z / 100.0f);
482
483         pitch = modulo360f(pitch);
484         yaw = wrapDegrees_0_360(yaw);
485
486         playersao->setBasePosition(position);
487         player->setSpeed(speed);
488         playersao->setLookPitch(pitch);
489         playersao->setPlayerYaw(yaw);
490         playersao->setFov(fov);
491         playersao->setWantedRange(wanted_range);
492         player->keyPressed = keyPressed;
493         player->control.up = (keyPressed & 1);
494         player->control.down = (keyPressed & 2);
495         player->control.left = (keyPressed & 4);
496         player->control.right = (keyPressed & 8);
497         player->control.jump = (keyPressed & 16);
498         player->control.aux1 = (keyPressed & 32);
499         player->control.sneak = (keyPressed & 64);
500         player->control.LMB = (keyPressed & 128);
501         player->control.RMB = (keyPressed & 256);
502
503         if (playersao->checkMovementCheat()) {
504                 // Call callbacks
505                 m_script->on_cheat(playersao, "moved_too_fast");
506                 SendMovePlayer(pkt->getPeerId());
507         }
508 }
509
510 void Server::handleCommand_PlayerPos(NetworkPacket* pkt)
511 {
512         session_t peer_id = pkt->getPeerId();
513         RemotePlayer *player = m_env->getPlayer(peer_id);
514         if (player == NULL) {
515                 errorstream <<
516                         "Server::ProcessData(): Canceling: No player for peer_id=" <<
517                         peer_id << " disconnecting peer!" << std::endl;
518                 DisconnectPeer(peer_id);
519                 return;
520         }
521
522         PlayerSAO *playersao = player->getPlayerSAO();
523         if (playersao == NULL) {
524                 errorstream <<
525                         "Server::ProcessData(): Canceling: No player object for peer_id=" <<
526                         peer_id << " disconnecting peer!" << std::endl;
527                 DisconnectPeer(peer_id);
528                 return;
529         }
530
531         // If player is dead we don't care of this packet
532         if (playersao->isDead()) {
533                 verbosestream << "TOSERVER_PLAYERPOS: " << player->getName()
534                                 << " is dead. Ignoring packet";
535                 return;
536         }
537
538         process_PlayerPos(player, playersao, pkt);
539 }
540
541 void Server::handleCommand_DeletedBlocks(NetworkPacket* pkt)
542 {
543         if (pkt->getSize() < 1)
544                 return;
545
546         /*
547                 [0] u16 command
548                 [2] u8 count
549                 [3] v3s16 pos_0
550                 [3+6] v3s16 pos_1
551                 ...
552         */
553
554         u8 count;
555         *pkt >> count;
556
557         RemoteClient *client = getClient(pkt->getPeerId());
558
559         if ((s16)pkt->getSize() < 1 + (int)count * 6) {
560                 throw con::InvalidIncomingDataException
561                                 ("DELETEDBLOCKS length is too short");
562         }
563
564         for (u16 i = 0; i < count; i++) {
565                 v3s16 p;
566                 *pkt >> p;
567                 client->SetBlockNotSent(p);
568         }
569 }
570
571 void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
572 {
573         session_t peer_id = pkt->getPeerId();
574         RemotePlayer *player = m_env->getPlayer(peer_id);
575
576         if (player == NULL) {
577                 errorstream <<
578                         "Server::ProcessData(): Canceling: No player for peer_id=" <<
579                         peer_id << " disconnecting peer!" << std::endl;
580                 DisconnectPeer(peer_id);
581                 return;
582         }
583
584         PlayerSAO *playersao = player->getPlayerSAO();
585         if (playersao == NULL) {
586                 errorstream <<
587                         "Server::ProcessData(): Canceling: No player object for peer_id=" <<
588                         peer_id << " disconnecting peer!" << std::endl;
589                 DisconnectPeer(peer_id);
590                 return;
591         }
592
593         // Strip command and create a stream
594         std::string datastring(pkt->getString(0), pkt->getSize());
595         verbosestream << "TOSERVER_INVENTORY_ACTION: data=" << datastring
596                 << std::endl;
597         std::istringstream is(datastring, std::ios_base::binary);
598         // Create an action
599         InventoryAction *a = InventoryAction::deSerialize(is);
600         if (!a) {
601                 infostream << "TOSERVER_INVENTORY_ACTION: "
602                                 << "InventoryAction::deSerialize() returned NULL"
603                                 << std::endl;
604                 return;
605         }
606
607         // If something goes wrong, this player is to blame
608         RollbackScopeActor rollback_scope(m_rollback,
609                         std::string("player:")+player->getName());
610
611         /*
612                 Note: Always set inventory not sent, to repair cases
613                 where the client made a bad prediction.
614         */
615
616         /*
617                 Handle restrictions and special cases of the move action
618         */
619         if (a->getType() == IAction::Move) {
620                 IMoveAction *ma = (IMoveAction*)a;
621
622                 ma->from_inv.applyCurrentPlayer(player->getName());
623                 ma->to_inv.applyCurrentPlayer(player->getName());
624
625                 setInventoryModified(ma->from_inv);
626                 if (ma->from_inv != ma->to_inv)
627                         setInventoryModified(ma->to_inv);
628
629                 bool from_inv_is_current_player =
630                         (ma->from_inv.type == InventoryLocation::PLAYER) &&
631                         (ma->from_inv.name == player->getName());
632
633                 bool to_inv_is_current_player =
634                         (ma->to_inv.type == InventoryLocation::PLAYER) &&
635                         (ma->to_inv.name == player->getName());
636
637                 InventoryLocation *remote = from_inv_is_current_player ?
638                         &ma->to_inv : &ma->from_inv;
639
640                 // Check for out-of-range interaction
641                 if (remote->type == InventoryLocation::NODEMETA) {
642                         v3f node_pos   = intToFloat(remote->p, BS);
643                         v3f player_pos = player->getPlayerSAO()->getEyePosition();
644                         f32 d = player_pos.getDistanceFrom(node_pos);
645                         if (!checkInteractDistance(player, d, "inventory"))
646                                 return;
647                 }
648
649                 /*
650                         Disable moving items out of craftpreview
651                 */
652                 if (ma->from_list == "craftpreview") {
653                         infostream << "Ignoring IMoveAction from "
654                                         << (ma->from_inv.dump()) << ":" << ma->from_list
655                                         << " to " << (ma->to_inv.dump()) << ":" << ma->to_list
656                                         << " because src is " << ma->from_list << std::endl;
657                         delete a;
658                         return;
659                 }
660
661                 /*
662                         Disable moving items into craftresult and craftpreview
663                 */
664                 if (ma->to_list == "craftpreview" || ma->to_list == "craftresult") {
665                         infostream << "Ignoring IMoveAction from "
666                                         << (ma->from_inv.dump()) << ":" << ma->from_list
667                                         << " to " << (ma->to_inv.dump()) << ":" << ma->to_list
668                                         << " because dst is " << ma->to_list << std::endl;
669                         delete a;
670                         return;
671                 }
672
673                 // Disallow moving items in elsewhere than player's inventory
674                 // if not allowed to interact
675                 if (!checkPriv(player->getName(), "interact") &&
676                                 (!from_inv_is_current_player ||
677                                 !to_inv_is_current_player)) {
678                         infostream << "Cannot move outside of player's inventory: "
679                                         << "No interact privilege" << std::endl;
680                         delete a;
681                         return;
682                 }
683         }
684         /*
685                 Handle restrictions and special cases of the drop action
686         */
687         else if (a->getType() == IAction::Drop) {
688                 IDropAction *da = (IDropAction*)a;
689
690                 da->from_inv.applyCurrentPlayer(player->getName());
691
692                 setInventoryModified(da->from_inv);
693
694                 /*
695                         Disable dropping items out of craftpreview
696                 */
697                 if (da->from_list == "craftpreview") {
698                         infostream << "Ignoring IDropAction from "
699                                         << (da->from_inv.dump()) << ":" << da->from_list
700                                         << " because src is " << da->from_list << std::endl;
701                         delete a;
702                         return;
703                 }
704
705                 // Disallow dropping items if not allowed to interact
706                 if (!checkPriv(player->getName(), "interact")) {
707                         delete a;
708                         return;
709                 }
710
711                 // Disallow dropping items if dead
712                 if (playersao->isDead()) {
713                         infostream << "Ignoring IDropAction from "
714                                         << (da->from_inv.dump()) << ":" << da->from_list
715                                         << " because player is dead." << std::endl;
716                         delete a;
717                         return;
718                 }
719         }
720         /*
721                 Handle restrictions and special cases of the craft action
722         */
723         else if (a->getType() == IAction::Craft) {
724                 ICraftAction *ca = (ICraftAction*)a;
725
726                 ca->craft_inv.applyCurrentPlayer(player->getName());
727
728                 setInventoryModified(ca->craft_inv);
729
730                 //bool craft_inv_is_current_player =
731                 //      (ca->craft_inv.type == InventoryLocation::PLAYER) &&
732                 //      (ca->craft_inv.name == player->getName());
733
734                 // Disallow crafting if not allowed to interact
735                 if (!checkPriv(player->getName(), "interact")) {
736                         infostream << "Cannot craft: "
737                                         << "No interact privilege" << std::endl;
738                         delete a;
739                         return;
740                 }
741         }
742
743         // Do the action
744         a->apply(this, playersao, this);
745         // Eat the action
746         delete a;
747 }
748
749 void Server::handleCommand_ChatMessage(NetworkPacket* pkt)
750 {
751         /*
752                 u16 command
753                 u16 length
754                 wstring message
755         */
756         u16 len;
757         *pkt >> len;
758
759         std::wstring message;
760         for (u16 i = 0; i < len; i++) {
761                 u16 tmp_wchar;
762                 *pkt >> tmp_wchar;
763
764                 message += (wchar_t)tmp_wchar;
765         }
766
767         session_t peer_id = pkt->getPeerId();
768         RemotePlayer *player = m_env->getPlayer(peer_id);
769         if (player == NULL) {
770                 errorstream <<
771                         "Server::ProcessData(): Canceling: No player for peer_id=" <<
772                         peer_id << " disconnecting peer!" << std::endl;
773                 DisconnectPeer(peer_id);
774                 return;
775         }
776
777         // Get player name of this client
778         std::string name = player->getName();
779         std::wstring wname = narrow_to_wide(name);
780
781         std::wstring answer_to_sender = handleChat(name, wname, message, true, player);
782         if (!answer_to_sender.empty()) {
783                 // Send the answer to sender
784                 SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_NORMAL,
785                         answer_to_sender, wname));
786         }
787 }
788
789 void Server::handleCommand_Damage(NetworkPacket* pkt)
790 {
791         u16 damage;
792
793         *pkt >> damage;
794
795         session_t peer_id = pkt->getPeerId();
796         RemotePlayer *player = m_env->getPlayer(peer_id);
797
798         if (player == NULL) {
799                 errorstream <<
800                         "Server::ProcessData(): Canceling: No player for peer_id=" <<
801                         peer_id << " disconnecting peer!" << std::endl;
802                 DisconnectPeer(peer_id);
803                 return;
804         }
805
806         PlayerSAO *playersao = player->getPlayerSAO();
807         if (playersao == NULL) {
808                 errorstream <<
809                         "Server::ProcessData(): Canceling: No player object for peer_id=" <<
810                         peer_id << " disconnecting peer!" << std::endl;
811                 DisconnectPeer(peer_id);
812                 return;
813         }
814
815         if (!playersao->isImmortal()) {
816                 if (playersao->isDead()) {
817                         verbosestream << "Server::ProcessData(): Info: "
818                                 "Ignoring damage as player " << player->getName()
819                                 << " is already dead." << std::endl;
820                         return;
821                 }
822
823                 actionstream << player->getName() << " damaged by "
824                                 << (int)damage << " hp at " << PP(playersao->getBasePosition() / BS)
825                                 << std::endl;
826
827                 PlayerHPChangeReason reason(PlayerHPChangeReason::FALL);
828                 playersao->setHP((s32)playersao->getHP() - (s32)damage, reason);
829                 SendPlayerHPOrDie(playersao, reason);
830         }
831 }
832
833 void Server::handleCommand_PlayerItem(NetworkPacket* pkt)
834 {
835         if (pkt->getSize() < 2)
836                 return;
837
838         session_t peer_id = pkt->getPeerId();
839         RemotePlayer *player = m_env->getPlayer(peer_id);
840
841         if (player == NULL) {
842                 errorstream <<
843                         "Server::ProcessData(): Canceling: No player for peer_id=" <<
844                         peer_id << " disconnecting peer!" << std::endl;
845                 DisconnectPeer(peer_id);
846                 return;
847         }
848
849         PlayerSAO *playersao = player->getPlayerSAO();
850         if (playersao == NULL) {
851                 errorstream <<
852                         "Server::ProcessData(): Canceling: No player object for peer_id=" <<
853                         peer_id << " disconnecting peer!" << std::endl;
854                 DisconnectPeer(peer_id);
855                 return;
856         }
857
858         u16 item;
859
860         *pkt >> item;
861
862         playersao->getPlayer()->setWieldIndex(item);
863 }
864
865 void Server::handleCommand_Respawn(NetworkPacket* pkt)
866 {
867         session_t peer_id = pkt->getPeerId();
868         RemotePlayer *player = m_env->getPlayer(peer_id);
869         if (player == NULL) {
870                 errorstream <<
871                         "Server::ProcessData(): Canceling: No player for peer_id=" <<
872                         peer_id << " disconnecting peer!" << std::endl;
873                 DisconnectPeer(peer_id);
874                 return;
875         }
876
877         PlayerSAO *playersao = player->getPlayerSAO();
878         assert(playersao);
879
880         if (!playersao->isDead())
881                 return;
882
883         RespawnPlayer(peer_id);
884
885         actionstream << player->getName() << " respawns at "
886                         << PP(playersao->getBasePosition() / BS) << std::endl;
887
888         // ActiveObject is added to environment in AsyncRunStep after
889         // the previous addition has been successfully removed
890 }
891
892 bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std::string &what)
893 {
894         ItemStack selected_item, hand_item;
895         player->getWieldedItem(&selected_item, &hand_item);
896         f32 max_d = BS * getToolRange(selected_item.getDefinition(m_itemdef),
897                         hand_item.getDefinition(m_itemdef));
898
899         // Cube diagonal * 1.5 for maximal supported node extents:
900         // sqrt(3) * 1.5 â‰… 2.6
901         if (d > max_d + 2.6f * BS) {
902                 actionstream << "Player " << player->getName()
903                                 << " tried to access " << what
904                                 << " from too far: "
905                                 << "d=" << d <<", max_d=" << max_d
906                                 << ". ignoring." << std::endl;
907                 // Call callbacks
908                 m_script->on_cheat(player->getPlayerSAO(), "interacted_too_far");
909                 return false;
910         }
911         return true;
912 }
913
914 void Server::handleCommand_Interact(NetworkPacket *pkt)
915 {
916         /*
917                 [0] u16 command
918                 [2] u8 action
919                 [3] u16 item
920                 [5] u32 length of the next item (plen)
921                 [9] serialized PointedThing
922                 [9 + plen] player position information
923         */
924
925         InteractAction action;
926         u16 item_i;
927
928         *pkt >> (u8 &)action;
929         *pkt >> item_i;
930
931         std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
932         PointedThing pointed;
933         pointed.deSerialize(tmp_is);
934
935         verbosestream << "TOSERVER_INTERACT: action=" << (int)action << ", item="
936                         << item_i << ", pointed=" << pointed.dump() << std::endl;
937
938         session_t peer_id = pkt->getPeerId();
939         RemotePlayer *player = m_env->getPlayer(peer_id);
940
941         if (player == NULL) {
942                 errorstream <<
943                         "Server::ProcessData(): Canceling: No player for peer_id=" <<
944                         peer_id << " disconnecting peer!" << std::endl;
945                 DisconnectPeer(peer_id);
946                 return;
947         }
948
949         PlayerSAO *playersao = player->getPlayerSAO();
950         if (playersao == NULL) {
951                 errorstream <<
952                         "Server::ProcessData(): Canceling: No player object for peer_id=" <<
953                         peer_id << " disconnecting peer!" << std::endl;
954                 DisconnectPeer(peer_id);
955                 return;
956         }
957
958         if (playersao->isDead()) {
959                 actionstream << "Server: NoCheat: " << player->getName()
960                                 << " tried to interact while dead; ignoring." << std::endl;
961                 if (pointed.type == POINTEDTHING_NODE) {
962                         // Re-send block to revert change on client-side
963                         RemoteClient *client = getClient(peer_id);
964                         v3s16 blockpos = getNodeBlockPos(pointed.node_undersurface);
965                         client->SetBlockNotSent(blockpos);
966                 }
967                 // Call callbacks
968                 m_script->on_cheat(playersao, "interacted_while_dead");
969                 return;
970         }
971
972         process_PlayerPos(player, playersao, pkt);
973
974         v3f player_pos = playersao->getLastGoodPosition();
975
976         // Update wielded item
977         playersao->getPlayer()->setWieldIndex(item_i);
978
979         // Get pointed to node (undefined if not POINTEDTYPE_NODE)
980         v3s16 p_under = pointed.node_undersurface;
981         v3s16 p_above = pointed.node_abovesurface;
982
983         // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
984         ServerActiveObject *pointed_object = NULL;
985         if (pointed.type == POINTEDTHING_OBJECT) {
986                 pointed_object = m_env->getActiveObject(pointed.object_id);
987                 if (pointed_object == NULL) {
988                         verbosestream << "TOSERVER_INTERACT: "
989                                 "pointed object is NULL" << std::endl;
990                         return;
991                 }
992
993         }
994
995         v3f pointed_pos_under = player_pos;
996         v3f pointed_pos_above = player_pos;
997         if (pointed.type == POINTEDTHING_NODE) {
998                 pointed_pos_under = intToFloat(p_under, BS);
999                 pointed_pos_above = intToFloat(p_above, BS);
1000         }
1001         else if (pointed.type == POINTEDTHING_OBJECT) {
1002                 pointed_pos_under = pointed_object->getBasePosition();
1003                 pointed_pos_above = pointed_pos_under;
1004         }
1005
1006         /*
1007                 Make sure the player is allowed to do it
1008         */
1009         if (!checkPriv(player->getName(), "interact")) {
1010                 actionstream << player->getName() << " attempted to interact with " <<
1011                                 pointed.dump() << " without 'interact' privilege" << std::endl;
1012
1013                 // Re-send block to revert change on client-side
1014                 RemoteClient *client = getClient(peer_id);
1015                 // Digging completed -> under
1016                 if (action == INTERACT_DIGGING_COMPLETED) {
1017                         v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
1018                         client->SetBlockNotSent(blockpos);
1019                 }
1020                 // Placement -> above
1021                 else if (action == INTERACT_PLACE) {
1022                         v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
1023                         client->SetBlockNotSent(blockpos);
1024                 }
1025                 return;
1026         }
1027
1028         /*
1029                 Check that target is reasonably close
1030                 (only when digging or placing things)
1031         */
1032         static thread_local const bool enable_anticheat =
1033                         !g_settings->getBool("disable_anticheat");
1034
1035         if ((action == INTERACT_START_DIGGING || action == INTERACT_DIGGING_COMPLETED ||
1036                         action == INTERACT_PLACE || action == INTERACT_USE) &&
1037                         enable_anticheat && !isSingleplayer()) {
1038                 float d = playersao->getEyePosition().getDistanceFrom(pointed_pos_under);
1039
1040                 if (!checkInteractDistance(player, d, pointed.dump())) {
1041                         // Re-send block to revert change on client-side
1042                         RemoteClient *client = getClient(peer_id);
1043                         v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
1044                         client->SetBlockNotSent(blockpos);
1045                         return;
1046                 }
1047         }
1048
1049         /*
1050                 If something goes wrong, this player is to blame
1051         */
1052         RollbackScopeActor rollback_scope(m_rollback,
1053                         std::string("player:")+player->getName());
1054
1055         /*
1056                 0: start digging or punch object
1057         */
1058         if (action == INTERACT_START_DIGGING) {
1059                 if (pointed.type == POINTEDTHING_NODE) {
1060                         MapNode n(CONTENT_IGNORE);
1061                         bool pos_ok;
1062
1063                         n = m_env->getMap().getNode(p_under, &pos_ok);
1064                         if (!pos_ok) {
1065                                 infostream << "Server: Not punching: Node not found. "
1066                                         "Adding block to emerge queue." << std::endl;
1067                                 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above),
1068                                         false);
1069                         }
1070
1071                         if (n.getContent() != CONTENT_IGNORE)
1072                                 m_script->node_on_punch(p_under, n, playersao, pointed);
1073
1074                         // Cheat prevention
1075                         playersao->noCheatDigStart(p_under);
1076                 }
1077                 else if (pointed.type == POINTEDTHING_OBJECT) {
1078                         // Skip if object can't be interacted with anymore
1079                         if (pointed_object->isGone())
1080                                 return;
1081
1082                         ItemStack selected_item, hand_item;
1083                         ItemStack tool_item = playersao->getWieldedItem(&selected_item, &hand_item);
1084                         ToolCapabilities toolcap =
1085                                         tool_item.getToolCapabilities(m_itemdef);
1086                         v3f dir = (pointed_object->getBasePosition() -
1087                                         (playersao->getBasePosition() + playersao->getEyeOffset())
1088                                                 ).normalize();
1089                         float time_from_last_punch =
1090                                 playersao->resetTimeFromLastPunch();
1091
1092                         u16 src_original_hp = pointed_object->getHP();
1093                         u16 dst_origin_hp = playersao->getHP();
1094
1095                         u16 wear = pointed_object->punch(dir, &toolcap, playersao,
1096                                         time_from_last_punch);
1097
1098                         // Callback may have changed item, so get it again
1099                         playersao->getWieldedItem(&selected_item);
1100                         bool changed = selected_item.addWear(wear, m_itemdef);
1101                         if (changed)
1102                                 playersao->setWieldedItem(selected_item);
1103
1104                         // If the object is a player and its HP changed
1105                         if (src_original_hp != pointed_object->getHP() &&
1106                                         pointed_object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
1107                                 SendPlayerHPOrDie((PlayerSAO *)pointed_object,
1108                                                 PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, playersao));
1109                         }
1110
1111                         // If the puncher is a player and its HP changed
1112                         if (dst_origin_hp != playersao->getHP())
1113                                 SendPlayerHPOrDie(playersao,
1114                                                 PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, pointed_object));
1115                 }
1116
1117         } // action == INTERACT_START_DIGGING
1118
1119         /*
1120                 1: stop digging
1121         */
1122         else if (action == INTERACT_STOP_DIGGING) {
1123         } // action == INTERACT_STOP_DIGGING
1124
1125         /*
1126                 2: Digging completed
1127         */
1128         else if (action == INTERACT_DIGGING_COMPLETED) {
1129                 // Only digging of nodes
1130                 if (pointed.type == POINTEDTHING_NODE) {
1131                         bool pos_ok;
1132                         MapNode n = m_env->getMap().getNode(p_under, &pos_ok);
1133                         if (!pos_ok) {
1134                                 infostream << "Server: Not finishing digging: Node not found. "
1135                                         "Adding block to emerge queue." << std::endl;
1136                                 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above),
1137                                         false);
1138                         }
1139
1140                         /* Cheat prevention */
1141                         bool is_valid_dig = true;
1142                         if (enable_anticheat && !isSingleplayer()) {
1143                                 v3s16 nocheat_p = playersao->getNoCheatDigPos();
1144                                 float nocheat_t = playersao->getNoCheatDigTime();
1145                                 playersao->noCheatDigEnd();
1146                                 // If player didn't start digging this, ignore dig
1147                                 if (nocheat_p != p_under) {
1148                                         infostream << "Server: NoCheat: " << player->getName()
1149                                                         << " started digging "
1150                                                         << PP(nocheat_p) << " and completed digging "
1151                                                         << PP(p_under) << "; not digging." << std::endl;
1152                                         is_valid_dig = false;
1153                                         // Call callbacks
1154                                         m_script->on_cheat(playersao, "finished_unknown_dig");
1155                                 }
1156
1157                                 // Get player's wielded item
1158                                 // See also: Game::handleDigging
1159                                 ItemStack selected_item, hand_item;
1160                                 playersao->getPlayer()->getWieldedItem(&selected_item, &hand_item);
1161
1162                                 // Get diggability and expected digging time
1163                                 DigParams params = getDigParams(m_nodedef->get(n).groups,
1164                                                 &selected_item.getToolCapabilities(m_itemdef));
1165                                 // If can't dig, try hand
1166                                 if (!params.diggable) {
1167                                         params = getDigParams(m_nodedef->get(n).groups,
1168                                                 &hand_item.getToolCapabilities(m_itemdef));
1169                                 }
1170                                 // If can't dig, ignore dig
1171                                 if (!params.diggable) {
1172                                         infostream << "Server: NoCheat: " << player->getName()
1173                                                         << " completed digging " << PP(p_under)
1174                                                         << ", which is not diggable with tool. not digging."
1175                                                         << std::endl;
1176                                         is_valid_dig = false;
1177                                         // Call callbacks
1178                                         m_script->on_cheat(playersao, "dug_unbreakable");
1179                                 }
1180                                 // Check digging time
1181                                 // If already invalidated, we don't have to
1182                                 if (!is_valid_dig) {
1183                                         // Well not our problem then
1184                                 }
1185                                 // Clean and long dig
1186                                 else if (params.time > 2.0 && nocheat_t * 1.2 > params.time) {
1187                                         // All is good, but grab time from pool; don't care if
1188                                         // it's actually available
1189                                         playersao->getDigPool().grab(params.time);
1190                                 }
1191                                 // Short or laggy dig
1192                                 // Try getting the time from pool
1193                                 else if (playersao->getDigPool().grab(params.time)) {
1194                                         // All is good
1195                                 }
1196                                 // Dig not possible
1197                                 else {
1198                                         infostream << "Server: NoCheat: " << player->getName()
1199                                                         << " completed digging " << PP(p_under)
1200                                                         << "too fast; not digging." << std::endl;
1201                                         is_valid_dig = false;
1202                                         // Call callbacks
1203                                         m_script->on_cheat(playersao, "dug_too_fast");
1204                                 }
1205                         }
1206
1207                         /* Actually dig node */
1208
1209                         if (is_valid_dig && n.getContent() != CONTENT_IGNORE)
1210                                 m_script->node_on_dig(p_under, n, playersao);
1211
1212                         v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
1213                         RemoteClient *client = getClient(peer_id);
1214                         // Send unusual result (that is, node not being removed)
1215                         if (m_env->getMap().getNode(p_under).getContent() != CONTENT_AIR) {
1216                                 // Re-send block to revert change on client-side
1217                                 client->SetBlockNotSent(blockpos);
1218                         }
1219                         else {
1220                                 client->ResendBlockIfOnWire(blockpos);
1221                         }
1222                 }
1223         } // action == INTERACT_DIGGING_COMPLETED
1224
1225         /*
1226                 3: place block or right-click object
1227         */
1228         else if (action == INTERACT_PLACE) {
1229                 ItemStack selected_item;
1230                 playersao->getWieldedItem(&selected_item, nullptr);
1231
1232                 // Reset build time counter
1233                 if (pointed.type == POINTEDTHING_NODE &&
1234                                 selected_item.getDefinition(m_itemdef).type == ITEM_NODE)
1235                         getClient(peer_id)->m_time_from_building = 0.0;
1236
1237                 if (pointed.type == POINTEDTHING_OBJECT) {
1238                         // Right click object
1239
1240                         // Skip if object can't be interacted with anymore
1241                         if (pointed_object->isGone())
1242                                 return;
1243
1244                         actionstream << player->getName() << " right-clicks object "
1245                                         << pointed.object_id << ": "
1246                                         << pointed_object->getDescription() << std::endl;
1247
1248                         // Do stuff
1249                         if (m_script->item_OnSecondaryUse(
1250                                         selected_item, playersao, pointed)) {
1251                                 if (playersao->setWieldedItem(selected_item)) {
1252                                         SendInventory(playersao, true);
1253                                 }
1254                         }
1255
1256                         pointed_object->rightClick(playersao);
1257                 } else if (m_script->item_OnPlace(
1258                                 selected_item, playersao, pointed)) {
1259                         // Placement was handled in lua
1260
1261                         // Apply returned ItemStack
1262                         if (playersao->setWieldedItem(selected_item)) {
1263                                 SendInventory(playersao, true);
1264                         }
1265                 }
1266
1267                 // If item has node placement prediction, always send the
1268                 // blocks to make sure the client knows what exactly happened
1269                 RemoteClient *client = getClient(peer_id);
1270                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
1271                 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
1272                 if (!selected_item.getDefinition(m_itemdef).node_placement_prediction.empty()) {
1273                         client->SetBlockNotSent(blockpos);
1274                         if (blockpos2 != blockpos) {
1275                                 client->SetBlockNotSent(blockpos2);
1276                         }
1277                 }
1278                 else {
1279                         client->ResendBlockIfOnWire(blockpos);
1280                         if (blockpos2 != blockpos) {
1281                                 client->ResendBlockIfOnWire(blockpos2);
1282                         }
1283                 }
1284         } // action == INTERACT_PLACE
1285
1286         /*
1287                 4: use
1288         */
1289         else if (action == INTERACT_USE) {
1290                 ItemStack selected_item;
1291                 playersao->getWieldedItem(&selected_item, nullptr);
1292
1293                 actionstream << player->getName() << " uses " << selected_item.name
1294                                 << ", pointing at " << pointed.dump() << std::endl;
1295
1296                 if (m_script->item_OnUse(
1297                                 selected_item, playersao, pointed)) {
1298                         // Apply returned ItemStack
1299                         if (playersao->setWieldedItem(selected_item)) {
1300                                 SendInventory(playersao, true);
1301                         }
1302                 }
1303
1304         } // action == INTERACT_USE
1305
1306         /*
1307                 5: rightclick air
1308         */
1309         else if (action == INTERACT_ACTIVATE) {
1310                 ItemStack selected_item;
1311                 playersao->getWieldedItem(&selected_item, nullptr);
1312
1313                 actionstream << player->getName() << " activates "
1314                                 << selected_item.name << std::endl;
1315
1316                 pointed.type = POINTEDTHING_NOTHING; // can only ever be NOTHING
1317
1318                 if (m_script->item_OnSecondaryUse(
1319                                 selected_item, playersao, pointed)) {
1320                         if (playersao->setWieldedItem(selected_item)) {
1321                                 SendInventory(playersao, true);
1322                         }
1323                 }
1324         } // action == INTERACT_ACTIVATE
1325
1326
1327         /*
1328                 Catch invalid actions
1329         */
1330         else {
1331                 warningstream << "Server: Invalid action "
1332                                 << action << std::endl;
1333         }
1334 }
1335
1336 void Server::handleCommand_RemovedSounds(NetworkPacket* pkt)
1337 {
1338         u16 num;
1339         *pkt >> num;
1340         for (u16 k = 0; k < num; k++) {
1341                 s32 id;
1342
1343                 *pkt >> id;
1344
1345                 std::unordered_map<s32, ServerPlayingSound>::iterator i =
1346                         m_playing_sounds.find(id);
1347                 if (i == m_playing_sounds.end())
1348                         continue;
1349
1350                 ServerPlayingSound &psound = i->second;
1351                 psound.clients.erase(pkt->getPeerId());
1352                 if (psound.clients.empty())
1353                         m_playing_sounds.erase(i++);
1354         }
1355 }
1356
1357 void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt)
1358 {
1359         v3s16 p;
1360         std::string formname;
1361         u16 num;
1362
1363         *pkt >> p >> formname >> num;
1364
1365         StringMap fields;
1366         for (u16 k = 0; k < num; k++) {
1367                 std::string fieldname;
1368                 *pkt >> fieldname;
1369                 fields[fieldname] = pkt->readLongString();
1370         }
1371
1372         session_t peer_id = pkt->getPeerId();
1373         RemotePlayer *player = m_env->getPlayer(peer_id);
1374
1375         if (player == NULL) {
1376                 errorstream <<
1377                         "Server::ProcessData(): Canceling: No player for peer_id=" <<
1378                         peer_id << " disconnecting peer!" << std::endl;
1379                 DisconnectPeer(peer_id);
1380                 return;
1381         }
1382
1383         PlayerSAO *playersao = player->getPlayerSAO();
1384         if (playersao == NULL) {
1385                 errorstream <<
1386                         "Server::ProcessData(): Canceling: No player object for peer_id=" <<
1387                         peer_id << " disconnecting peer!" << std::endl;
1388                 DisconnectPeer(peer_id);
1389                 return;
1390         }
1391
1392         // If something goes wrong, this player is to blame
1393         RollbackScopeActor rollback_scope(m_rollback,
1394                         std::string("player:")+player->getName());
1395
1396         // Check the target node for rollback data; leave others unnoticed
1397         RollbackNode rn_old(&m_env->getMap(), p, this);
1398
1399         m_script->node_on_receive_fields(p, formname, fields, playersao);
1400
1401         // Report rollback data
1402         RollbackNode rn_new(&m_env->getMap(), p, this);
1403         if (rollback() && rn_new != rn_old) {
1404                 RollbackAction action;
1405                 action.setSetNode(p, rn_old, rn_new);
1406                 rollback()->reportAction(action);
1407         }
1408 }
1409
1410 void Server::handleCommand_InventoryFields(NetworkPacket* pkt)
1411 {
1412         std::string client_formspec_name;
1413         u16 num;
1414
1415         *pkt >> client_formspec_name >> num;
1416
1417         StringMap fields;
1418         for (u16 k = 0; k < num; k++) {
1419                 std::string fieldname;
1420                 *pkt >> fieldname;
1421                 fields[fieldname] = pkt->readLongString();
1422         }
1423
1424         session_t peer_id = pkt->getPeerId();
1425         RemotePlayer *player = m_env->getPlayer(peer_id);
1426
1427         if (player == NULL) {
1428                 errorstream <<
1429                         "Server::ProcessData(): Canceling: No player for peer_id=" <<
1430                         peer_id << " disconnecting peer!" << std::endl;
1431                 DisconnectPeer(peer_id);
1432                 return;
1433         }
1434
1435         PlayerSAO *playersao = player->getPlayerSAO();
1436         if (playersao == NULL) {
1437                 errorstream <<
1438                         "Server::ProcessData(): Canceling: No player object for peer_id=" <<
1439                         peer_id << " disconnecting peer!" << std::endl;
1440                 DisconnectPeer(peer_id);
1441                 return;
1442         }
1443
1444         if (client_formspec_name.empty()) { // pass through inventory submits
1445                 m_script->on_playerReceiveFields(playersao, client_formspec_name, fields);
1446                 return;
1447         }
1448
1449         // verify that we displayed the formspec to the user
1450         const auto peer_state_iterator = m_formspec_state_data.find(peer_id);
1451         if (peer_state_iterator != m_formspec_state_data.end()) {
1452                 const std::string &server_formspec_name = peer_state_iterator->second;
1453                 if (client_formspec_name == server_formspec_name) {
1454                         auto it = fields.find("quit");
1455                         if (it != fields.end() && it->second == "true")
1456                                 m_formspec_state_data.erase(peer_state_iterator);
1457
1458                         m_script->on_playerReceiveFields(playersao, client_formspec_name, fields);
1459                         return;
1460                 }
1461                 actionstream << "'" << player->getName()
1462                         << "' submitted formspec ('" << client_formspec_name
1463                         << "') but the name of the formspec doesn't match the"
1464                         " expected name ('" << server_formspec_name << "')";
1465
1466         } else {
1467                 actionstream << "'" << player->getName()
1468                         << "' submitted formspec ('" << client_formspec_name
1469                         << "') but server hasn't sent formspec to client";
1470         }
1471         actionstream << ", possible exploitation attempt" << std::endl;
1472 }
1473
1474 void Server::handleCommand_FirstSrp(NetworkPacket* pkt)
1475 {
1476         session_t peer_id = pkt->getPeerId();
1477         RemoteClient *client = getClient(peer_id, CS_Invalid);
1478         ClientState cstate = client->getState();
1479
1480         std::string playername = client->getName();
1481
1482         std::string salt;
1483         std::string verification_key;
1484
1485         std::string addr_s = getPeerAddress(peer_id).serializeString();
1486         u8 is_empty;
1487
1488         *pkt >> salt >> verification_key >> is_empty;
1489
1490         verbosestream << "Server: Got TOSERVER_FIRST_SRP from " << addr_s
1491                 << ", with is_empty=" << (is_empty == 1) << std::endl;
1492
1493         // Either this packet is sent because the user is new or to change the password
1494         if (cstate == CS_HelloSent) {
1495                 if (!client->isMechAllowed(AUTH_MECHANISM_FIRST_SRP)) {
1496                         actionstream << "Server: Client from " << addr_s
1497                                         << " tried to set password without being "
1498                                         << "authenticated, or the username being new." << std::endl;
1499                         DenyAccess(peer_id, SERVER_ACCESSDENIED_UNEXPECTED_DATA);
1500                         return;
1501                 }
1502
1503                 if (!isSingleplayer() &&
1504                                 g_settings->getBool("disallow_empty_password") &&
1505                                 is_empty == 1) {
1506                         actionstream << "Server: " << playername
1507                                         << " supplied empty password from " << addr_s << std::endl;
1508                         DenyAccess(peer_id, SERVER_ACCESSDENIED_EMPTY_PASSWORD);
1509                         return;
1510                 }
1511
1512                 std::string initial_ver_key;
1513
1514                 initial_ver_key = encode_srp_verifier(verification_key, salt);
1515                 m_script->createAuth(playername, initial_ver_key);
1516
1517                 acceptAuth(peer_id, false);
1518         } else {
1519                 if (cstate < CS_SudoMode) {
1520                         infostream << "Server::ProcessData(): Ignoring TOSERVER_FIRST_SRP from "
1521                                         << addr_s << ": " << "Client has wrong state " << cstate << "."
1522                                         << std::endl;
1523                         return;
1524                 }
1525                 m_clients.event(peer_id, CSE_SudoLeave);
1526                 std::string pw_db_field = encode_srp_verifier(verification_key, salt);
1527                 bool success = m_script->setPassword(playername, pw_db_field);
1528                 if (success) {
1529                         actionstream << playername << " changes password" << std::endl;
1530                         SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
1531                                 L"Password change successful."));
1532                 } else {
1533                         actionstream << playername <<
1534                                 " tries to change password but it fails" << std::endl;
1535                         SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
1536                                 L"Password change failed or unavailable."));
1537                 }
1538         }
1539 }
1540
1541 void Server::handleCommand_SrpBytesA(NetworkPacket* pkt)
1542 {
1543         session_t peer_id = pkt->getPeerId();
1544         RemoteClient *client = getClient(peer_id, CS_Invalid);
1545         ClientState cstate = client->getState();
1546
1547         bool wantSudo = (cstate == CS_Active);
1548
1549         if (!((cstate == CS_HelloSent) || (cstate == CS_Active))) {
1550                 actionstream << "Server: got SRP _A packet in wrong state " << cstate <<
1551                         " from " << getPeerAddress(peer_id).serializeString() <<
1552                         ". Ignoring." << std::endl;
1553                 return;
1554         }
1555
1556         if (client->chosen_mech != AUTH_MECHANISM_NONE) {
1557                 actionstream << "Server: got SRP _A packet, while auth is already "
1558                         "going on with mech " << client->chosen_mech << " from " <<
1559                         getPeerAddress(peer_id).serializeString() <<
1560                         " (wantSudo=" << wantSudo << "). Ignoring." << std::endl;
1561                 if (wantSudo) {
1562                         DenySudoAccess(peer_id);
1563                         return;
1564                 }
1565
1566                 DenyAccess(peer_id, SERVER_ACCESSDENIED_UNEXPECTED_DATA);
1567                 return;
1568         }
1569
1570         std::string bytes_A;
1571         u8 based_on;
1572         *pkt >> bytes_A >> based_on;
1573
1574         infostream << "Server: TOSERVER_SRP_BYTES_A received with "
1575                 << "based_on=" << int(based_on) << " and len_A="
1576                 << bytes_A.length() << "." << std::endl;
1577
1578         AuthMechanism chosen = (based_on == 0) ?
1579                 AUTH_MECHANISM_LEGACY_PASSWORD : AUTH_MECHANISM_SRP;
1580
1581         if (wantSudo) {
1582                 if (!client->isSudoMechAllowed(chosen)) {
1583                         actionstream << "Server: Player \"" << client->getName() <<
1584                                 "\" at " << getPeerAddress(peer_id).serializeString() <<
1585                                 " tried to change password using unallowed mech " << chosen <<
1586                                 "." << std::endl;
1587                         DenySudoAccess(peer_id);
1588                         return;
1589                 }
1590         } else {
1591                 if (!client->isMechAllowed(chosen)) {
1592                         actionstream << "Server: Client tried to authenticate from " <<
1593                                 getPeerAddress(peer_id).serializeString() <<
1594                                 " using unallowed mech " << chosen << "." << std::endl;
1595                         DenyAccess(peer_id, SERVER_ACCESSDENIED_UNEXPECTED_DATA);
1596                         return;
1597                 }
1598         }
1599
1600         client->chosen_mech = chosen;
1601
1602         std::string salt;
1603         std::string verifier;
1604
1605         if (based_on == 0) {
1606
1607                 generate_srp_verifier_and_salt(client->getName(), client->enc_pwd,
1608                         &verifier, &salt);
1609         } else if (!decode_srp_verifier_and_salt(client->enc_pwd, &verifier, &salt)) {
1610                 // Non-base64 errors should have been catched in the init handler
1611                 actionstream << "Server: User " << client->getName() <<
1612                         " tried to log in, but srp verifier field was invalid (most likely "
1613                         "invalid base64)." << std::endl;
1614                 DenyAccess(peer_id, SERVER_ACCESSDENIED_SERVER_FAIL);
1615                 return;
1616         }
1617
1618         char *bytes_B = 0;
1619         size_t len_B = 0;
1620
1621         client->auth_data = srp_verifier_new(SRP_SHA256, SRP_NG_2048,
1622                 client->getName().c_str(),
1623                 (const unsigned char *) salt.c_str(), salt.size(),
1624                 (const unsigned char *) verifier.c_str(), verifier.size(),
1625                 (const unsigned char *) bytes_A.c_str(), bytes_A.size(),
1626                 NULL, 0,
1627                 (unsigned char **) &bytes_B, &len_B, NULL, NULL);
1628
1629         if (!bytes_B) {
1630                 actionstream << "Server: User " << client->getName()
1631                         << " tried to log in, SRP-6a safety check violated in _A handler."
1632                         << std::endl;
1633                 if (wantSudo) {
1634                         DenySudoAccess(peer_id);
1635                         return;
1636                 }
1637
1638                 DenyAccess(peer_id, SERVER_ACCESSDENIED_UNEXPECTED_DATA);
1639                 return;
1640         }
1641
1642         NetworkPacket resp_pkt(TOCLIENT_SRP_BYTES_S_B, 0, peer_id);
1643         resp_pkt << salt << std::string(bytes_B, len_B);
1644         Send(&resp_pkt);
1645 }
1646
1647 void Server::handleCommand_SrpBytesM(NetworkPacket* pkt)
1648 {
1649         session_t peer_id = pkt->getPeerId();
1650         RemoteClient *client = getClient(peer_id, CS_Invalid);
1651         ClientState cstate = client->getState();
1652
1653         bool wantSudo = (cstate == CS_Active);
1654
1655         verbosestream << "Server: Received TOCLIENT_SRP_BYTES_M." << std::endl;
1656
1657         if (!((cstate == CS_HelloSent) || (cstate == CS_Active))) {
1658                 actionstream << "Server: got SRP _M packet in wrong state " << cstate <<
1659                         " from " << getPeerAddress(peer_id).serializeString() <<
1660                         ". Ignoring." << std::endl;
1661                 return;
1662         }
1663
1664         if (client->chosen_mech != AUTH_MECHANISM_SRP &&
1665                         client->chosen_mech != AUTH_MECHANISM_LEGACY_PASSWORD) {
1666                 actionstream << "Server: got SRP _M packet, while auth is going on "
1667                         "with mech " << client->chosen_mech << " from " <<
1668                         getPeerAddress(peer_id).serializeString() <<
1669                         " (wantSudo=" << wantSudo << "). Denying." << std::endl;
1670                 if (wantSudo) {
1671                         DenySudoAccess(peer_id);
1672                         return;
1673                 }
1674
1675                 DenyAccess(peer_id, SERVER_ACCESSDENIED_UNEXPECTED_DATA);
1676                 return;
1677         }
1678
1679         std::string bytes_M;
1680         *pkt >> bytes_M;
1681
1682         if (srp_verifier_get_session_key_length((SRPVerifier *) client->auth_data)
1683                         != bytes_M.size()) {
1684                 actionstream << "Server: User " << client->getName() << " at " <<
1685                         getPeerAddress(peer_id).serializeString() <<
1686                         " sent bytes_M with invalid length " << bytes_M.size() << std::endl;
1687                 DenyAccess(peer_id, SERVER_ACCESSDENIED_UNEXPECTED_DATA);
1688                 return;
1689         }
1690
1691         unsigned char *bytes_HAMK = 0;
1692
1693         srp_verifier_verify_session((SRPVerifier *) client->auth_data,
1694                 (unsigned char *)bytes_M.c_str(), &bytes_HAMK);
1695
1696         if (!bytes_HAMK) {
1697                 if (wantSudo) {
1698                         actionstream << "Server: User " << client->getName() << " at " <<
1699                                 getPeerAddress(peer_id).serializeString() <<
1700                                 " tried to change their password, but supplied wrong (SRP) "
1701                                 "password for authentication." << std::endl;
1702                         DenySudoAccess(peer_id);
1703                         return;
1704                 }
1705
1706                 std::string ip = getPeerAddress(peer_id).serializeString();
1707                 actionstream << "Server: User " << client->getName() << " at " << ip <<
1708                         " supplied wrong password (auth mechanism: SRP)." << std::endl;
1709                 m_script->on_auth_failure(client->getName(), ip);
1710                 DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_PASSWORD);
1711                 return;
1712         }
1713
1714         if (client->create_player_on_auth_success) {
1715                 std::string playername = client->getName();
1716                 m_script->createAuth(playername, client->enc_pwd);
1717
1718                 std::string checkpwd; // not used, but needed for passing something
1719                 if (!m_script->getAuth(playername, &checkpwd, NULL)) {
1720                         actionstream << "Server: " << playername <<
1721                                 " cannot be authenticated (auth handler does not work?)" <<
1722                                 std::endl;
1723                         DenyAccess(peer_id, SERVER_ACCESSDENIED_SERVER_FAIL);
1724                         return;
1725                 }
1726                 client->create_player_on_auth_success = false;
1727         }
1728
1729         acceptAuth(peer_id, wantSudo);
1730 }
1731
1732 /*
1733  * Mod channels
1734  */
1735
1736 void Server::handleCommand_ModChannelJoin(NetworkPacket *pkt)
1737 {
1738         std::string channel_name;
1739         *pkt >> channel_name;
1740
1741         session_t peer_id = pkt->getPeerId();
1742         NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_SIGNAL,
1743                 1 + 2 + channel_name.size(), peer_id);
1744
1745         // Send signal to client to notify join succeed or not
1746         if (g_settings->getBool("enable_mod_channels") &&
1747                         m_modchannel_mgr->joinChannel(channel_name, peer_id)) {
1748                 resp_pkt << (u8) MODCHANNEL_SIGNAL_JOIN_OK;
1749                 infostream << "Peer " << peer_id << " joined channel " <<
1750                         channel_name << std::endl;
1751         }
1752         else {
1753                 resp_pkt << (u8)MODCHANNEL_SIGNAL_JOIN_FAILURE;
1754                 infostream << "Peer " << peer_id << " tried to join channel " <<
1755                         channel_name << ", but was already registered." << std::endl;
1756         }
1757         resp_pkt << channel_name;
1758         Send(&resp_pkt);
1759 }
1760
1761 void Server::handleCommand_ModChannelLeave(NetworkPacket *pkt)
1762 {
1763         std::string channel_name;
1764         *pkt >> channel_name;
1765
1766         session_t peer_id = pkt->getPeerId();
1767         NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_SIGNAL,
1768                 1 + 2 + channel_name.size(), peer_id);
1769
1770         // Send signal to client to notify join succeed or not
1771         if (g_settings->getBool("enable_mod_channels") &&
1772                         m_modchannel_mgr->leaveChannel(channel_name, peer_id)) {
1773                 resp_pkt << (u8)MODCHANNEL_SIGNAL_LEAVE_OK;
1774                 infostream << "Peer " << peer_id << " left channel " << channel_name <<
1775                         std::endl;
1776         } else {
1777                 resp_pkt << (u8) MODCHANNEL_SIGNAL_LEAVE_FAILURE;
1778                 infostream << "Peer " << peer_id << " left channel " << channel_name <<
1779                         ", but was not registered." << std::endl;
1780         }
1781         resp_pkt << channel_name;
1782         Send(&resp_pkt);
1783 }
1784
1785 void Server::handleCommand_ModChannelMsg(NetworkPacket *pkt)
1786 {
1787         std::string channel_name, channel_msg;
1788         *pkt >> channel_name >> channel_msg;
1789
1790         session_t peer_id = pkt->getPeerId();
1791         verbosestream << "Mod channel message received from peer " << peer_id <<
1792                 " on channel " << channel_name << " message: " << channel_msg <<
1793                 std::endl;
1794
1795         // If mod channels are not enabled, discard message
1796         if (!g_settings->getBool("enable_mod_channels")) {
1797                 return;
1798         }
1799
1800         // If channel not registered, signal it and ignore message
1801         if (!m_modchannel_mgr->channelRegistered(channel_name)) {
1802                 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_SIGNAL,
1803                         1 + 2 + channel_name.size(), peer_id);
1804                 resp_pkt << (u8)MODCHANNEL_SIGNAL_CHANNEL_NOT_REGISTERED << channel_name;
1805                 Send(&resp_pkt);
1806                 return;
1807         }
1808
1809         // @TODO: filter, rate limit
1810
1811         broadcastModChannelMessage(channel_name, channel_msg, peer_id);
1812 }