aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCiaran Gultnieks <ciaran@ciarang.com>2011-05-16 10:41:19 +0100
committerCiaran Gultnieks <ciaran@ciarang.com>2011-05-16 10:41:19 +0100
commit248d7c8469f8cb37406ea0ce56d0945e38334cfb (patch)
treedf8c2ad03a674f8d7c08d6af01ddb3f2a7e7b689
parentdadac0e79f96b112947a50f37b39ad9677e870d0 (diff)
downloadminetest-248d7c8469f8cb37406ea0ce56d0945e38334cfb.tar.gz
minetest-248d7c8469f8cb37406ea0ce56d0945e38334cfb.tar.bz2
minetest-248d7c8469f8cb37406ea0ce56d0945e38334cfb.zip
Improved server commands and added player permissions.
--HG-- extra : rebase_source : 178fe08f10b7de3ebaba088bd24faad795114216
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/player.cpp9
-rw-r--r--src/player.h72
-rw-r--r--src/server.cpp91
-rw-r--r--src/server.h23
-rw-r--r--src/servercommand.cpp233
-rw-r--r--src/servercommand.h76
-rw-r--r--src/utility.h19
8 files changed, 454 insertions, 70 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8e6f54303..42260b3ae 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -69,6 +69,7 @@ set(common_SRCS
connection.cpp
environment.cpp
server.cpp
+ servercommand.cpp
socket.cpp
mapblock.cpp
mapsector.cpp
diff --git a/src/player.cpp b/src/player.cpp
index 64780de75..a6ddeee64 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -34,7 +34,8 @@ Player::Player():
m_pitch(0),
m_yaw(0),
m_speed(0,0,0),
- m_position(0,0,0)
+ m_position(0,0,0),
+ privs(PRIV_DEFAULT)
{
updateName("<not set>");
resetInventory();
@@ -100,6 +101,7 @@ void Player::serialize(std::ostream &os)
args.setV3F("position", m_position);
args.setBool("craftresult_is_preview", craftresult_is_preview);
args.setS32("hp", hp);
+ args.setU64("privs", privs);
args.writeLines(os);
@@ -141,6 +143,11 @@ void Player::deSerialize(std::istream &is)
}catch(SettingNotFoundException &e){
hp = 20;
}
+ try{
+ privs = args.getU64("privs");
+ }catch(SettingNotFoundException &e){
+ privs = PRIV_DEFAULT;
+ }
inventory.deSerialize(is);
}
diff --git a/src/player.h b/src/player.h
index f70b52fe7..778bb54b3 100644
--- a/src/player.h
+++ b/src/player.h
@@ -28,11 +28,29 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,"
+// Player privileges. These form a bitmask stored in the privs field
+// of the player, and define things they're allowed to do. See also
+// the static methods Player::privsToString and stringToPrivs that
+// convert these to human-readable form.
+const u64 PRIV_BUILD = 1; // Can build - i.e. modify the world
+ // (not enforced yet)
+const u64 PRIV_TELEPORT = 2; // Can teleport
+const u64 PRIV_SETTIME = 4; // Can set the time
+const u64 PRIV_PRIVS = 8; // Can grant and revoke privileges
+const u64 PRIV_SERVER = 16; // Can manage the server (e.g. shutodwn ,settings)
+
+const u64 PRIV_DEFAULT = PRIV_BUILD;
+const u64 PRIV_ALL = 0x7FFFFFFFFFFFFFFFULL;
+const u64 PRIV_INVALID = 0x8000000000000000ULL;
+
+
class Map;
class Player
{
public:
+
+
Player();
virtual ~Player();
@@ -123,6 +141,9 @@ public:
u16 hp;
+ // Player's privileges - a bitmaps of PRIV_xxxx.
+ u64 privs;
+
u16 peer_id;
protected:
@@ -131,6 +152,57 @@ protected:
f32 m_yaw;
v3f m_speed;
v3f m_position;
+
+public:
+
+ // Converst a prvileges value into a human-readable string,
+ // with each component separated by a comma.
+ static std::wstring privsToString(u64 privs)
+ {
+ std::wostringstream os(std::ios_base::binary);
+ if(privs & PRIV_BUILD)
+ os<<L"build,";
+ if(privs & PRIV_TELEPORT)
+ os<<L"teleport,";
+ if(privs & PRIV_SETTIME)
+ os<<L"settime,";
+ if(privs & PRIV_PRIVS)
+ os<<L"privs,";
+ if(os.tellp())
+ {
+ // Drop the trailing comma. (Why on earth can't
+ // you truncate a C++ stream anyway???)
+ std::wstring tmp = os.str();
+ return tmp.substr(0, tmp.length() -1);
+ }
+ return os.str();
+ }
+
+ // Converts a comma-seperated list of privilege values into a
+ // privileges value. The reverse of privsToString(). Returns
+ // PRIV_INVALID if there is anything wrong with the input.
+ static u64 stringToPrivs(std::wstring str)
+ {
+ u64 privs=0;
+ std::vector<std::wstring> pr;
+ pr=str_split(str, ',');
+ for(std::vector<std::wstring>::iterator i = pr.begin();
+ i != pr.end(); ++i)
+ {
+ if(*i == L"build")
+ privs |= PRIV_BUILD;
+ else if(*i == L"teleport")
+ privs |= PRIV_TELEPORT;
+ else if(*i == L"settime")
+ privs |= PRIV_SETTIME;
+ else if(*i == L"privs")
+ privs |= PRIV_PRIVS;
+ else
+ return PRIV_INVALID;
+ }
+ return privs;
+ }
+
};
/*
diff --git a/src/server.cpp b/src/server.cpp
index b5a38aa06..f77b4f3c6 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "materials.h"
#include "mineral.h"
#include "config.h"
+#include "servercommand.h"
#define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
@@ -1994,6 +1995,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(datasize < 13)
return;
+ if((player->privs & PRIV_BUILD) == 0)
+ return;
+
/*
[0] u16 command
[2] u8 button (0=left, 1=right)
@@ -2075,6 +2079,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(datasize < 7)
return;
+ if((player->privs & PRIV_BUILD) == 0)
+ return;
+
/*
length: 7
[0] u16 command
@@ -2167,6 +2174,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
if(datasize < 17)
return;
+ if((player->privs & PRIV_BUILD) == 0)
+ return;
/*
length: 17
[0] u16 command
@@ -2615,6 +2624,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
#endif
else if(command == TOSERVER_SIGNTEXT)
{
+ if((player->privs & PRIV_BUILD) == 0)
+ return;
/*
u16 command
v3s16 blockpos
@@ -2672,6 +2683,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
else if(command == TOSERVER_SIGNNODETEXT)
{
+ if((player->privs & PRIV_BUILD) == 0)
+ return;
/*
u16 command
v3s16 p
@@ -2853,71 +2866,19 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
line += L"Server: ";
message = message.substr(commandprefix.size());
- // Get player name as narrow string
- std::string name_s = player->getName();
- // Convert message to narrow string
- std::string message_s = wide_to_narrow(message);
- // Operator is the single name defined in config.
- std::string operator_name = g_settings.get("name");
- bool is_operator = (operator_name != "" &&
- wide_to_narrow(name) == operator_name);
- bool valid_command = false;
- if(message_s == "help")
- {
- line += L"-!- Available commands: ";
- line += L"status ";
- if(is_operator)
- {
- line += L"shutdown setting time ";
- }
- else
- {
- }
- send_to_sender = true;
- valid_command = true;
- }
- else if(message_s == "status")
- {
- line = getStatusString();
- send_to_sender = true;
- valid_command = true;
- }
- else if(is_operator)
- {
- if(message_s == "shutdown")
- {
- dstream<<DTIME<<" Server: Operator requested shutdown."
- <<std::endl;
- m_shutdown_requested.set(true);
-
- line += L"*** Server shutting down (operator request)";
- send_to_sender = true;
- valid_command = true;
- }
- else if(message_s.substr(0,8) == "setting ")
- {
- std::string confline = message_s.substr(8);
- g_settings.parseConfigLine(confline);
- line += L"-!- Setting changed.";
- send_to_sender = true;
- valid_command = true;
- }
- else if(message_s.substr(0,5) == "time ")
- {
- u32 time = stoi(message_s.substr(5));
- m_time_of_day.set(time);
- m_time_of_day_send_timer = 0;
- line += L"-!- time_of_day changed.";
- send_to_sender = true;
- valid_command = true;
- }
- }
-
- if(valid_command == false)
- {
- line += L"-!- Invalid command: " + message;
- send_to_sender = true;
- }
+
+ ServerCommandContext *ctx = new ServerCommandContext(
+ str_split(message, L' '),
+ this,
+ &m_env,
+ player
+ );
+
+ line += ServerCommand::processCommand(ctx);
+ send_to_sender = ctx->flags & 1;
+ send_to_others = ctx->flags & 2;
+ delete ctx;
+
}
else
{
diff --git a/src/server.h b/src/server.h
index 4603f98ed..d8b47aef9 100644
--- a/src/server.h
+++ b/src/server.h
@@ -387,6 +387,12 @@ public:
return time_to_daynight_ratio(m_time_of_day.get());
}
+ void setTimeOfDay(u32 time)
+ {
+ m_time_of_day.set(time);
+ m_time_of_day_send_timer = 0;
+ }
+
bool getShutdownRequested()
{
return m_shutdown_requested.get();
@@ -405,6 +411,19 @@ public:
Inventory* getInventory(InventoryContext *c, std::string id);
void inventoryModified(InventoryContext *c, std::string id);
+ // Connection must be locked when called
+ std::wstring getStatusString();
+
+ void requestShutdown(void)
+ {
+ m_shutdown_requested.set(true);
+ }
+
+
+ // Envlock and conlock should be locked when calling this
+ void SendMovePlayer(Player *player);
+
+
private:
// Virtual methods from con::PeerHandler.
@@ -429,7 +448,6 @@ private:
void SendChatMessage(u16 peer_id, const std::wstring &message);
void BroadcastChatMessage(const std::wstring &message);
void SendPlayerHP(Player *player);
- void SendMovePlayer(Player *player);
/*
Send a node removal/addition event to all clients except ignore_id.
Additionally, if far_players!=NULL, players further away than
@@ -455,9 +473,6 @@ private:
// When called, connection mutex should be locked
RemoteClient* getClient(u16 peer_id);
- // Connection must be locked when called
- std::wstring getStatusString();
-
/*
Get a player from memory or creates one.
If player is already connected, return NULL
diff --git a/src/servercommand.cpp b/src/servercommand.cpp
new file mode 100644
index 000000000..fa841a1bb
--- /dev/null
+++ b/src/servercommand.cpp
@@ -0,0 +1,233 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+
+#include "servercommand.h"
+#include "utility.h"
+
+// Process a command sent from a client. The environment and connection
+// should be locked when this is called.
+// Returns a response message, to be dealt with according to the flags set
+// in the context.
+std::wstring ServerCommand::processCommand(ServerCommandContext *ctx)
+{
+
+ std::wostringstream os(std::ios_base::binary);
+ ctx->flags = 1; // Default, unless we change it.
+
+ u64 privs = ctx->player->privs;
+
+ if(ctx->parms.size() == 0 || ctx->parms[0] == L"help")
+ {
+ os<<L"-!- Available commands: ";
+ os<<L"status privs ";
+ if(privs & PRIV_SERVER)
+ os<<L"shutdown setting ";
+ if(privs & PRIV_SETTIME)
+ os<<L" time";
+ if(privs & PRIV_TELEPORT)
+ os<<L" teleport";
+ if(privs & PRIV_PRIVS)
+ os<<L" grant revoke";
+ }
+ else if(ctx->parms[0] == L"status")
+ {
+ cmd_status(os, ctx);
+ }
+ else if(ctx->parms[0] == L"privs")
+ {
+ cmd_privs(os, ctx);
+ }
+ else if(ctx->parms[0] == L"grant" || ctx->parms[0] == L"revoke")
+ {
+ cmd_grantrevoke(os, ctx);
+ }
+ else if(ctx->parms[0] == L"time")
+ {
+ cmd_time(os, ctx);
+ }
+ else if(ctx->parms[0] == L"shutdown")
+ {
+ cmd_shutdown(os, ctx);
+ }
+ else if(ctx->parms[0] == L"setting")
+ {
+ cmd_setting(os, ctx);
+ }
+ else if(ctx->parms[0] == L"teleport")
+ {
+ cmd_teleport(os, ctx);
+ }
+ else
+ {
+ os<<L"-!- Invalid command: " + ctx->parms[0];
+ }
+ return os.str();
+}
+
+void ServerCommand::cmd_status(std::wostringstream &os,
+ ServerCommandContext *ctx)
+{
+ os<<ctx->server->getStatusString();
+}
+
+void ServerCommand::cmd_privs(std::wostringstream &os,
+ ServerCommandContext *ctx)
+{
+ if(ctx->parms.size() == 1)
+ {
+ os<<L"-!- " + Player::privsToString(ctx->player->privs);
+ return;
+ }
+
+ if((ctx->player->privs & PRIV_PRIVS) == 0)
+ {
+ os<<L"-!- You don't have permission to do that";
+ return;
+ }
+
+ Player *tp = ctx->env->getPlayer(wide_to_narrow(ctx->parms[1]).c_str());
+ if(tp == NULL)
+ {
+ os<<L"-!- No such player";
+ return;
+ }
+
+ os<<L"-!- " + Player::privsToString(tp->privs);
+}
+
+void ServerCommand::cmd_grantrevoke(std::wostringstream &os,
+ ServerCommandContext *ctx)
+{
+ if(ctx->parms.size() != 3)
+ {
+ os<<L"-!- Missing parameter";
+ return;
+ }
+
+ if((ctx->player->privs & PRIV_PRIVS) == 0)
+ {
+ os<<L"-!- You don't have permission to do that";
+ return;
+ }
+
+ u64 newprivs = Player::stringToPrivs(ctx->parms[2]);
+ if(newprivs == PRIV_INVALID)
+ {
+ os<<L"-!- Invalid privileges specified";
+ return;
+ }
+
+ Player *tp = ctx->env->getPlayer(wide_to_narrow(ctx->parms[1]).c_str());
+ if(tp == NULL)
+ {
+ os<<L"-!- No such player";
+ return;
+ }
+
+ if(ctx->parms[0] == L"grant")
+ tp->privs |= newprivs;
+ else
+ tp->privs &= ~newprivs;
+
+ os<<L"-!- Privileges change to ";
+ os<<Player::privsToString(tp->privs);
+}
+
+void ServerCommand::cmd_time(std::wostringstream &os,
+ ServerCommandContext *ctx)
+{
+ if(ctx->parms.size() != 2)
+ {
+ os<<L"-!- Missing parameter";
+ return;
+ }
+
+ if((ctx->player->privs & PRIV_SETTIME) ==0)
+ {
+ os<<L"-!- You don't have permission to do that";
+ return;
+ }
+
+ u32 time = stoi(wide_to_narrow(ctx->parms[1]));
+ ctx->server->setTimeOfDay(time);
+ os<<L"-!- time_of_day changed.";
+}
+
+void ServerCommand::cmd_shutdown(std::wostringstream &os,
+ ServerCommandContext *ctx)
+{
+ if((ctx->player->privs & PRIV_SERVER) ==0)
+ {
+ os<<L"-!- You don't have permission to do that";
+ return;
+ }
+
+ dstream<<DTIME<<" Server: Operator requested shutdown."
+ <<std::endl;
+ ctx->server->requestShutdown();
+
+ os<<L"*** Server shutting down (operator request)";
+ ctx->flags |= 2;
+}
+
+void ServerCommand::cmd_setting(std::wostringstream &os,
+ ServerCommandContext *ctx)
+{
+ if((ctx->player->privs & PRIV_SERVER) ==0)
+ {
+ os<<L"-!- You don't have permission to do that";
+ return;
+ }
+
+ std::string confline = wide_to_narrow(ctx->parms[1] + L" = " + ctx->parms[2]);
+ g_settings.parseConfigLine(confline);
+ os<< L"-!- Setting changed.";
+}
+
+void ServerCommand::cmd_teleport(std::wostringstream &os,
+ ServerCommandContext *ctx)
+{
+ if((ctx->player->privs & PRIV_TELEPORT) ==0)
+ {
+ os<<L"-!- You don't have permission to do that";
+ return;
+ }
+
+ if(ctx->parms.size() != 2)
+ {
+ os<<L"-!- Missing parameter";
+ return;
+ }
+
+ std::vector<std::wstring> coords = str_split(ctx->parms[1], L',');
+ if(coords.size() != 3)
+ {
+ os<<L"-!- You can only specify coordinates currently";
+ return;
+ }
+
+ v3f dest(stoi(coords[0])*10, stoi(coords[1])*10, stoi(coords[2])*10);
+ ctx->player->setPosition(dest);
+ ctx->server->SendMovePlayer(ctx->player);
+
+ os<< L"-!- Teleported.";
+}
+
diff --git a/src/servercommand.h b/src/servercommand.h
new file mode 100644
index 000000000..01efcae06
--- /dev/null
+++ b/src/servercommand.h
@@ -0,0 +1,76 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef SERVERCOMMAND_HEADER
+#define SERVERCOMMAND_HEADER
+
+#include <vector>
+#include <sstream>
+#include "common_irrlicht.h"
+#include "player.h"
+#include "server.h"
+
+struct ServerCommandContext
+{
+
+ std::vector<std::wstring> parms;
+ Server* server;
+ ServerEnvironment *env;
+ Player* player;
+ u32 flags;
+
+ ServerCommandContext(
+ std::vector<std::wstring> parms,
+ Server* server,
+ ServerEnvironment *env,
+ Player* player)
+ : parms(parms), server(server), env(env), player(player)
+ {
+ }
+
+};
+
+class ServerCommand
+{
+public:
+
+ static std::wstring processCommand(ServerCommandContext *ctx);
+
+private:
+
+ static void cmd_status(std::wostringstream &os,
+ ServerCommandContext *ctx);
+ static void cmd_privs(std::wostringstream &os,
+ ServerCommandContext *ctx);
+ static void cmd_grantrevoke(std::wostringstream &os,
+ ServerCommandContext *ctx);
+ static void cmd_time(std::wostringstream &os,
+ ServerCommandContext *ctx);
+ static void cmd_shutdown(std::wostringstream &os,
+ ServerCommandContext *ctx);
+ static void cmd_setting(std::wostringstream &os,
+ ServerCommandContext *ctx);
+ static void cmd_teleport(std::wostringstream &os,
+ ServerCommandContext *ctx);
+};
+
+#endif
+
+
diff --git a/src/utility.h b/src/utility.h
index 12d732bea..326ebf161 100644
--- a/src/utility.h
+++ b/src/utility.h
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <fstream>
#include <string>
#include <sstream>
+#include <vector>
#include <jthread.h>
#include <jmutex.h>
#include <jmutexautolock.h>
@@ -731,6 +732,19 @@ inline std::string wide_to_narrow(const std::wstring& wcs)
return *mbs;
}
+// Split a string using the given delimiter. Returns a vector containing
+// the component parts.
+inline std::vector<std::wstring> str_split(const std::wstring &str, wchar_t delimiter)
+{
+ std::vector<std::wstring> parts;
+ std::wstringstream sstr(str);
+ std::wstring part;
+ while(std::getline(sstr, part, delimiter))
+ parts.push_back(part);
+ return parts;
+}
+
+
/*
See test.cpp for example cases.
wraps degrees to the range of -360...360
@@ -791,6 +805,11 @@ inline s32 stoi(std::string s)
return atoi(s.c_str());
}
+inline s32 stoi(std::wstring s)
+{
+ return atoi(wide_to_narrow(s).c_str());
+}
+
inline float stof(std::string s)
{
float f;