print = minetest.debug
--
---
+-- Define some random basic things
--
function basic_dump2(o)
end
end
+function string:split(sep)
+ local sep, fields = sep or ",", {}
+ local pattern = string.format("([^%s]+)", sep)
+ self:gsub(pattern, function(c) fields[#fields+1] = c end)
+ return fields
+end
+
+function string:trim()
+ return (self:gsub("^%s*(.-)%s*$", "%1"))
+end
+
+assert(string.trim("\n \t\tfoo\t ") == "foo")
+
--
-- Item definition helpers
--
end)
function minetest.after(time, func, param)
- table.insert(minetest.timers_to_add, {time=time, func=func, param=param})
+ table.insert(minetest.timers_to_add, {time=time, func=func, param=param})
end
function minetest.check_player_privs(name, privs)
return list
end
+minetest.registered_privileges = {}
+function minetest.register_privilege(name, description)
+ minetest.registered_privileges[name] = description
+end
+
+minetest.register_privilege("interact", "Can interact with things and modify the world")
+minetest.register_privilege("teleport", "Can use /teleport command")
+minetest.register_privilege("settime", "Can use /time")
+minetest.register_privilege("privs", "Can modify privileges")
+minetest.register_privilege("server", "Can do server maintenance stuff")
+minetest.register_privilege("shout", "Can speak in chat")
+minetest.register_privilege("ban", "Can ban and unban players")
+minetest.register_privilege("give", "Can use /give and /giveme")
+minetest.register_privilege("password", "Can use /setpassword and /clearpassword")
+
--
-- Chat commands
--
if def.description and def.description ~= "" then msg = msg .. ": " .. def.description end
return msg
end
- if not param or param == "" then
+ if param == "" then
local msg = ""
cmds = {}
for cmd, def in pairs(minetest.chatcommands) do
-- Register C++ commands without functions
minetest.register_chatcommand("me", {params = nil, description = "chat action (eg. /me orders a pizza)"})
minetest.register_chatcommand("status", {description = "print server status line"})
-minetest.register_chatcommand("privs", {params = "<name>", description = "print out privileges of player"})
minetest.register_chatcommand("shutdown", {params = "", description = "shutdown server", privs = {server=true}})
minetest.register_chatcommand("setting", {params = "<name> = <value>", description = "set line in configuration file", privs = {server=true}})
minetest.register_chatcommand("clearobjects", {params = "", description = "clear all objects in world", privs = {server=true}})
minetest.register_chatcommand("time", {params = "<0...24000>", description = "set time of day", privs = {settime=true}})
minetest.register_chatcommand("teleport", {params = "<X>,<Y>,<Z>", description = "teleport to given position", privs = {teleport=true}})
-minetest.register_chatcommand("grant", {params = "<name> <privilege>", description = "Give privilege to player", privs = {privs=true}})
-minetest.register_chatcommand("revoke", {params = "<name> <privilege>", description = "Remove privilege from player", privs = {privs=true}})
minetest.register_chatcommand("ban", {params = "<name>", description = "ban IP of player", privs = {ban=true}})
minetest.register_chatcommand("unban", {params = "<name/ip>", description = "remove IP ban", privs = {ban=true}})
-minetest.register_chatcommand("setpassword", {params = "<name> <password>", description = "set given password", privs = {password=true}})
-minetest.register_chatcommand("clearpassword", {params = "<name>", description = "set empty password", privs = {password=true}})
+
+-- Register some other commands
+minetest.register_chatcommand("privs", {
+ params = "<name>",
+ description = "print out privileges of player",
+ func = function(name, param)
+ if param == "" then
+ param = name
+ else
+ if not minetest.check_player_privs(name, {privs=true}) then
+ minetest.chat_send_player(name, "Privileges of "..param.." are hidden from you.")
+ end
+ end
+ privs = {}
+ for priv, _ in pairs(minetest.get_player_privs(param)) do
+ table.insert(privs, priv)
+ end
+ minetest.chat_send_player(name, "Privileges of "..param..": "..table.concat(privs, " "))
+ end,
+})
+minetest.register_chatcommand("grant", {
+ params = "<name> <privilege>",
+ description = "Give privilege to player",
+ privs = {privs=true},
+ func = function(name, param)
+ local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
+ if not grantname or not grantprivstr then
+ minetest.chat_send_player(name, "Invalid parameters (see /help grant)")
+ return
+ end
+ local grantprivs = minetest.string_to_privs(grantprivstr)
+ local privs = minetest.get_player_privs(grantname)
+ for priv, _ in pairs(grantprivs) do
+ privs[priv] = true
+ end
+ minetest.set_player_privs(grantname, privs)
+ end,
+})
+minetest.register_chatcommand("revoke", {
+ params = "<name> <privilege>",
+ description = "Remove privilege from player",
+ privs = {privs=true},
+ func = function(name, param)
+ local revokename, revokeprivstr = string.match(param, "([^ ]+) (.+)")
+ if not revokename or not revokeprivstr then
+ minetest.chat_send_player(name, "Invalid parameters (see /help revoke)")
+ return
+ end
+ local revokeprivs = minetest.string_to_privs(revokeprivstr)
+ local privs = minetest.get_player_privs(revokename)
+ for priv, _ in pairs(revokeprivs) do
+ table.remove(privs, priv)
+ end
+ minetest.set_player_privs(revokename, privs)
+ end,
+})
+minetest.register_chatcommand("setpassword", {
+ params = "<name> <password>",
+ description = "set given password",
+ privs = {password=true},
+ func = function(name, param)
+ if param == "" then
+ minetest.chat_send_player(name, "Password field required")
+ return
+ end
+ minetest.set_player_password(name, param)
+ end,
+})
+minetest.register_chatcommand("clearpassword", {
+ params = "<name>",
+ description = "set empty password",
+ privs = {password=true},
+ func = function(name, param)
+ minetest.set_player_password(name, '')
+ end,
+})
--
-- Builtin chat handler
minetest.register_on_chat_message(function(name, message)
local cmd, param = string.match(message, "/([^ ]+) *(.*)")
+ if not param then
+ param = ""
+ end
local cmd_def = minetest.chatcommands[cmd]
if cmd_def then
if not cmd_def.func then
return false
end)
+--
+-- Authentication handler
+--
+
+function minetest.string_to_privs(str)
+ assert(type(str) == "string")
+ privs = {}
+ for _, priv in pairs(string.split(str, ',')) do
+ privs[priv:trim()] = true
+ end
+ return privs
+end
+
+function minetest.privs_to_string(privs)
+ assert(type(privs) == "table")
+ list = {}
+ for priv, bool in pairs(privs) do
+ if bool then
+ table.insert(list, priv)
+ end
+ end
+ return table.concat(list, ',')
+end
+
+assert(minetest.string_to_privs("a,b").b == true)
+assert(minetest.privs_to_string({a=true,b=true}) == "a,b")
+
+minetest.auth_file_path = minetest.get_worldpath().."/auth.txt"
+minetest.auth_table = {}
+
+local function read_auth_file()
+ local newtable = {}
+ local file, errmsg = io.open(minetest.auth_file_path, 'rb')
+ if not file then
+ error(minetest.auth_file_path.." could not be opened for reading: "..errmsg)
+ end
+ for line in file:lines() do
+ if line ~= "" then
+ local name, password, privilegestring = string.match(line, "([^:]*):([^:]*):([^:]*)")
+ if not name or not password or not privilegestring then
+ error("Invalid line in auth.txt: "..dump(line))
+ end
+ local privileges = minetest.string_to_privs(privilegestring)
+ newtable[name] = {password=password, privileges=privileges}
+ end
+ end
+ io.close(file)
+ minetest.auth_table = newtable
+end
+
+local function save_auth_file()
+ local newtable = {}
+ -- Check table for validness before attempting to save
+ for name, stuff in pairs(minetest.auth_table) do
+ assert(type(name) == "string")
+ assert(name ~= "")
+ assert(type(stuff) == "table")
+ assert(type(stuff.password) == "string")
+ assert(type(stuff.privileges) == "table")
+ end
+ local file, errmsg = io.open(minetest.auth_file_path, 'w+b')
+ if not file then
+ error(minetest.auth_file_path.." could not be opened for writing: "..errmsg)
+ end
+ for name, stuff in pairs(minetest.auth_table) do
+ local privstring = minetest.privs_to_string(stuff.privileges)
+ file:write(name..":"..stuff.password..":"..privstring..'\n')
+ end
+ io.close(file)
+end
+
+read_auth_file()
+
+minetest.builtin_auth_handler = {
+ get_auth = function(name)
+ assert(type(name) == "string")
+ if not minetest.auth_table[name] then
+ minetest.builtin_auth_handler.create_auth(name, minetest.get_password_hash(name, minetest.setting_get("default_password")))
+ end
+ if minetest.is_singleplayer() or name == minetest.setting_get("name") then
+ return {
+ password = "",
+ privileges = minetest.registered_privileges
+ }
+ else
+ return minetest.auth_table[name]
+ end
+ end,
+ create_auth = function(name, password)
+ assert(type(name) == "string")
+ assert(type(password) == "string")
+ minetest.log('info', "Built-in authentication handler adding player '"..name.."'")
+ minetest.auth_table[name] = {
+ password = password,
+ privileges = minetest.string_to_privs(minetest.setting_get("default_privs")),
+ }
+ save_auth_file()
+ end,
+ set_password = function(name, password)
+ assert(type(name) == "string")
+ assert(type(password) == "string")
+ if not minetest.auth_table[name] then
+ minetest.builtin_auth_handler.create_auth(name, password)
+ else
+ minetest.log('info', "Built-in authentication handler setting password of player '"..name.."'")
+ minetest.auth_table[name].password = password
+ save_auth_file()
+ end
+ end,
+ set_privileges = function(name, privileges)
+ assert(type(name) == "string")
+ assert(type(privileges) == "table")
+ if not minetest.auth_table[name] then
+ minetest.builtin_auth_handler.create_auth(name, minetest.get_password_hash(name, minetest.setting_get("default_password")))
+ end
+ minetest.auth_table[name].privileges = privileges
+ save_auth_file()
+ end
+}
+
+function minetest.register_authentication_handler(handler)
+ if minetest.registered_auth_handler then
+ error("Add-on authentication handler already registered by "..minetest.registered_auth_handler_modname)
+ end
+ minetest.registered_auth_handler = handler
+ minetest.registered_auth_handler_modname = minetest.get_current_modname()
+end
+
+function minetest.get_auth_handler()
+ if minetest.registered_auth_handler then
+ return minetest.registered_auth_handler
+ end
+ return minetest.builtin_auth_handler
+end
+
+function minetest.set_player_password(name, password)
+ minetest.get_auth_handler().set_password(name, password)
+end
+
+function minetest.set_player_privs(name, privs)
+ minetest.get_auth_handler().set_privileges(name, privs)
+end
+
--
-- Set random seed
--
^ Return object serialized as a string, handles reference loops
dump(obj, dumped={})
^ Return object serialized as a string
+string:split(separator)
+string:trim()
minetest namespace reference
-----------------------------
minetest.log(loglevel, line)
^ loglevel one of "error", "action", "info", "verbose"
+Registration functions: (Call these only at load time)
minetest.register_entity(name, prototype table)
minetest.register_abm(abm definition)
minetest.register_node(name, node definition)
minetest.register_craftitem(name, item definition)
minetest.register_alias(name, convert_to)
minetest.register_craft(recipe)
-
minetest.register_globalstep(func(dtime))
minetest.register_on_placenode(func(pos, newnode, placer))
minetest.register_on_dignode(func(pos, oldnode, digger))
^ currently called _before_ repositioning of player occurs
minetest.register_on_chat_message(func(name, message))
minetest.register_chatcommand(cmd, chatcommand definition)
+minetest.register_privilege(name, description)
+minetest.register_authentication_handler(handler)
+^ See minetest.builtin_auth_handler in builtin.lua for reference
-minetest.add_to_creative_inventory(itemstring)
+Setting-related:
minetest.setting_get(name) -> string or nil
minetest.setting_getbool(name) -> boolean value or nil
+minetest.add_to_creative_inventory(itemstring)
+Authentication:
+minetest.get_password_hash(name, raw_password)
+minetest.set_player_password(name, password_hash)
+minetest.string_to_privs(str) -> {priv1=true,...}
+minetest.privs_to_string(privs) -> "priv1,priv2,..."
+minetest.set_player_privs(name, {priv1=true,...})
+minetest.get_player_privs(name) -> {priv1=true,...}
+minetest.check_player_privs(name, {priv1=true,...}) -> bool, missing_privs
+
+Chat:
minetest.chat_send_all(text)
minetest.chat_send_player(name, text)
-minetest.get_player_privs(name) -> set of privs
-minetest.check_player_privs(name, {priv1=true,...}) -> bool, missing_privs
+
+Inventory:
minetest.get_inventory(location) -> InvRef
^ location = eg. {type="player", name="celeron55"}
{type="node", pos={x=, y=, z=}}
+Sounds:
minetest.sound_play(spec, parameters) -> handle
^ spec = SimpleSoundSpec
^ parameters = sound parameter table
minetest.sound_stop(handle)
+Timing:
minetest.after(time, func, param)
^ Call function after time seconds
^ param is optional; to pass multiple parameters, pass a table.
mapgen.cpp
content_nodemeta.cpp
content_mapnode.cpp
- auth.cpp
collision.cpp
nodemetadata.cpp
serverobject.cpp
+++ /dev/null
-/*
-Minetest-c55
-Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.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 "auth.h"
-#include <fstream>
-#include <jmutexautolock.h>
-//#include "main.h" // for g_settings
-#include <sstream>
-#include "strfnd.h"
-#include "log.h"
-
-std::set<std::string> privsToSet(u64 privs)
-{
- std::set<std::string> s;
- if(privs & PRIV_INTERACT)
- s.insert("interact");
- if(privs & PRIV_TELEPORT)
- s.insert("teleport");
- if(privs & PRIV_SETTIME)
- s.insert("settime");
- if(privs & PRIV_PRIVS)
- s.insert("privs");
- if(privs & PRIV_SERVER)
- s.insert("server");
- if(privs & PRIV_SHOUT)
- s.insert("shout");
- if(privs & PRIV_BAN)
- s.insert("ban");
- if(privs & PRIV_GIVE)
- s.insert("give");
- if(privs & PRIV_PASSWORD)
- s.insert("password");
- return s;
-}
-
-// Convert a privileges value into a human-readable string,
-// with each component separated by a comma.
-std::string privsToString(u64 privs)
-{
- std::ostringstream os(std::ios_base::binary);
- if(privs & PRIV_INTERACT)
- os<<"interact,";
- if(privs & PRIV_TELEPORT)
- os<<"teleport,";
- if(privs & PRIV_SETTIME)
- os<<"settime,";
- if(privs & PRIV_PRIVS)
- os<<"privs,";
- if(privs & PRIV_SERVER)
- os<<"server,";
- if(privs & PRIV_SHOUT)
- os<<"shout,";
- if(privs & PRIV_BAN)
- os<<"ban,";
- if(privs & PRIV_GIVE)
- os<<"give,";
- if(privs & PRIV_PASSWORD)
- os<<"password,";
- if(os.tellp())
- {
- // Drop the trailing comma. (Why on earth can't
- // you truncate a C++ stream anyway???)
- std::string 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.
-u64 stringToPrivs(std::string str)
-{
- u64 privs=0;
- Strfnd f(str);
- while(f.atend() == false)
- {
- std::string s = trim(f.next(","));
- if(s == "build")
- privs |= PRIV_INTERACT;
- else if(s == "interact")
- privs |= PRIV_INTERACT;
- else if(s == "teleport")
- privs |= PRIV_TELEPORT;
- else if(s == "settime")
- privs |= PRIV_SETTIME;
- else if(s == "privs")
- privs |= PRIV_PRIVS;
- else if(s == "server")
- privs |= PRIV_SERVER;
- else if(s == "shout")
- privs |= PRIV_SHOUT;
- else if(s == "ban")
- privs |= PRIV_BAN;
- else if(s == "give")
- privs |= PRIV_GIVE;
- else if(s == "password")
- privs |= PRIV_PASSWORD;
- else
- return PRIV_INVALID;
- }
- return privs;
-}
-
-AuthManager::AuthManager(const std::string &authfilepath):
- m_authfilepath(authfilepath),
- m_modified(false)
-{
- m_mutex.Init();
-
- try{
- load();
- }
- catch(SerializationError &e)
- {
- infostream<<"WARNING: AuthManager: creating "
- <<m_authfilepath<<std::endl;
- }
-}
-
-AuthManager::~AuthManager()
-{
- save();
-}
-
-void AuthManager::load()
-{
- JMutexAutoLock lock(m_mutex);
-
- infostream<<"AuthManager: loading from "<<m_authfilepath<<std::endl;
- std::ifstream is(m_authfilepath.c_str(), std::ios::binary);
- if(is.good() == false)
- {
- infostream<<"AuthManager: failed loading from "<<m_authfilepath<<std::endl;
- throw SerializationError("AuthManager::load(): Couldn't open file");
- }
-
- for(;;)
- {
- if(is.eof() || is.good() == false)
- break;
-
- // Read a line
- std::string line;
- std::getline(is, line, '\n');
-
- std::istringstream iss(line);
-
- // Read name
- std::string name;
- std::getline(iss, name, ':');
-
- // Read password
- std::string pwd;
- std::getline(iss, pwd, ':');
-
- // Read privileges
- std::string stringprivs;
- std::getline(iss, stringprivs, ':');
- u64 privs = stringToPrivs(stringprivs);
-
- // Store it
- AuthData ad;
- ad.pwd = pwd;
- ad.privs = privs;
- m_authdata[name] = ad;
- }
-
- m_modified = false;
-}
-
-void AuthManager::save()
-{
- JMutexAutoLock lock(m_mutex);
-
- infostream<<"AuthManager: saving to "<<m_authfilepath<<std::endl;
- std::ofstream os(m_authfilepath.c_str(), std::ios::binary);
- if(os.good() == false)
- {
- infostream<<"AuthManager: failed saving to "<<m_authfilepath<<std::endl;
- throw SerializationError("AuthManager::save(): Couldn't open file");
- }
-
- for(core::map<std::string, AuthData>::Iterator
- i = m_authdata.getIterator();
- i.atEnd()==false; i++)
- {
- std::string name = i.getNode()->getKey();
- if(name == "")
- continue;
- AuthData ad = i.getNode()->getValue();
- os<<name<<":"<<ad.pwd<<":"<<privsToString(ad.privs)<<"\n";
- }
-
- m_modified = false;
-}
-
-bool AuthManager::exists(const std::string &username)
-{
- JMutexAutoLock lock(m_mutex);
-
- core::map<std::string, AuthData>::Node *n;
- n = m_authdata.find(username);
- if(n == NULL)
- return false;
- return true;
-}
-
-void AuthManager::set(const std::string &username, AuthData ad)
-{
- JMutexAutoLock lock(m_mutex);
-
- m_authdata[username] = ad;
-
- m_modified = true;
-}
-
-void AuthManager::add(const std::string &username)
-{
- JMutexAutoLock lock(m_mutex);
-
- m_authdata[username] = AuthData();
-
- m_modified = true;
-}
-
-std::string AuthManager::getPassword(const std::string &username)
-{
- JMutexAutoLock lock(m_mutex);
-
- core::map<std::string, AuthData>::Node *n;
- n = m_authdata.find(username);
- if(n == NULL)
- throw AuthNotFoundException("");
-
- return n->getValue().pwd;
-}
-
-void AuthManager::setPassword(const std::string &username,
- const std::string &password)
-{
- JMutexAutoLock lock(m_mutex);
-
- core::map<std::string, AuthData>::Node *n;
- n = m_authdata.find(username);
- if(n == NULL)
- throw AuthNotFoundException("");
-
- AuthData ad = n->getValue();
- ad.pwd = password;
- n->setValue(ad);
-
- m_modified = true;
-}
-
-u64 AuthManager::getPrivs(const std::string &username)
-{
- JMutexAutoLock lock(m_mutex);
-
- core::map<std::string, AuthData>::Node *n;
- n = m_authdata.find(username);
- if(n == NULL)
- throw AuthNotFoundException("");
-
- return n->getValue().privs;
-}
-
-void AuthManager::setPrivs(const std::string &username, u64 privs)
-{
- JMutexAutoLock lock(m_mutex);
-
- core::map<std::string, AuthData>::Node *n;
- n = m_authdata.find(username);
- if(n == NULL)
- throw AuthNotFoundException("");
-
- AuthData ad = n->getValue();
- ad.privs = privs;
- n->setValue(ad);
-
- m_modified = true;
-}
-
-bool AuthManager::isModified()
-{
- JMutexAutoLock lock(m_mutex);
- return m_modified;
-}
-
-
+++ /dev/null
-/*
-Minetest-c55
-Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.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 AUTH_HEADER
-#define AUTH_HEADER
-
-#include <set>
-#include <string>
-#include <jthread.h>
-#include <jmutex.h>
-#include "irrlichttypes.h"
-#include "exceptions.h"
-
-// 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_INTERACT = 1; // Can interact
-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_SHOUT = 32; // Can broadcast chat messages to all
- // players
-const u64 PRIV_BAN = 64; // Can ban players
-const u64 PRIV_GIVE = 128; // Can give stuff
-const u64 PRIV_PASSWORD = 256; // Can set other players' passwords
-
-// Default privileges - these can be overriden for new players using the
-// config option "default_privs" - however, this value still applies for
-// players that existed before the privileges system was added.
-const u64 PRIV_DEFAULT = PRIV_INTERACT|PRIV_SHOUT;
-const u64 PRIV_ALL = 0x7FFFFFFFFFFFFFFFULL;
-const u64 PRIV_INVALID = 0x8000000000000000ULL;
-
-std::set<std::string> privsToSet(u64 privs);
-
-// Convert a privileges value into a human-readable string,
-// with each component separated by a comma.
-std::string privsToString(u64 privs);
-
-// 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.
-u64 stringToPrivs(std::string str);
-
-struct AuthData
-{
- std::string pwd;
- u64 privs;
-
- AuthData():
- privs(PRIV_DEFAULT)
- {
- }
-};
-
-class AuthNotFoundException : public BaseException
-{
-public:
- AuthNotFoundException(const char *s):
- BaseException(s)
- {}
-};
-
-class AuthManager
-{
-public:
- AuthManager(const std::string &authfilepath);
- ~AuthManager();
- void load();
- void save();
- bool exists(const std::string &username);
- void set(const std::string &username, AuthData ad);
- void add(const std::string &username);
- std::string getPassword(const std::string &username);
- void setPassword(const std::string &username,
- const std::string &password);
- u64 getPrivs(const std::string &username);
- void setPrivs(const std::string &username, u64 privs);
- bool isModified();
-private:
- JMutex m_mutex;
- std::string m_authfilepath;
- core::map<std::string, AuthData> m_authdata;
- bool m_modified;
-};
-
-#endif
-
return server;
}
-static ServerEnvironment* get_env(lua_State *L)
+/*static ServerEnvironment* get_env(lua_State *L)
{
// Get environment from registry
lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
ServerEnvironment *env = (ServerEnvironment*)lua_touserdata(L, -1);
lua_pop(L, 1);
return env;
-}
+}*/
static void objectref_get(lua_State *L, u16 id)
{
}
}
+/*
+ Privileges
+*/
+static void read_privileges(lua_State *L, int index,
+ std::set<std::string> &result)
+{
+ result.clear();
+ lua_pushnil(L);
+ if(index < 0)
+ index -= 1;
+ while(lua_next(L, index) != 0){
+ // key at index -2 and value at index -1
+ std::string key = luaL_checkstring(L, -2);
+ bool value = lua_toboolean(L, -1);
+ if(value)
+ result.insert(key);
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+}
+
/*
ToolCapabilities
*/
// Do it
lua_newtable(L);
int table = lua_gettop(L);
- u64 privs_i = server->getPlayerEffectivePrivs(name);
- std::set<std::string> privs_s = privsToSet(privs_i);
+ std::set<std::string> privs_s = server->getPlayerEffectivePrivs(name);
for(std::set<std::string>::const_iterator
i = privs_s.begin(); i != privs_s.end(); i++){
lua_pushboolean(L, true);
return 1;
}
+// get_password_hash(name, raw_password)
+static int l_get_password_hash(lua_State *L)
+{
+ std::string name = luaL_checkstring(L, 1);
+ std::string raw_password = luaL_checkstring(L, 2);
+ std::string hash = translatePassword(name,
+ narrow_to_wide(raw_password));
+ lua_pushstring(L, hash.c_str());
+ return 1;
+}
+
static const struct luaL_Reg minetest_f [] = {
{"debug", l_debug},
{"log", l_log},
{"sound_play", l_sound_play},
{"sound_stop", l_sound_stop},
{"is_singleplayer", l_is_singleplayer},
+ {"get_password_hash", l_get_password_hash},
{NULL, NULL}
};
void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player)
{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
Inventory *inv = player->getInventory();
assert(inv);
inventory_set_list_from_lua(inv, "main", L, -1, PLAYER_INVENTORY_SIZE);
}
+static void get_auth_handler(lua_State *L)
+{
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "registered_auth_handler");
+ if(lua_isnil(L, -1)){
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "builtin_auth_handler");
+ }
+ if(lua_type(L, -1) != LUA_TTABLE)
+ throw LuaError(L, "Authentication handler table not valid");
+}
+
+bool scriptapi_get_auth(lua_State *L, const std::string &playername,
+ std::string *dst_password, std::set<std::string> *dst_privs)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ get_auth_handler(L);
+ lua_getfield(L, -1, "get_auth");
+ if(lua_type(L, -1) != LUA_TFUNCTION)
+ throw LuaError(L, "Authentication handler missing get_auth");
+ lua_pushstring(L, playername.c_str());
+ if(lua_pcall(L, 1, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+
+ // nil = login not allowed
+ if(lua_isnil(L, -1))
+ return false;
+ luaL_checktype(L, -1, LUA_TTABLE);
+
+ std::string password;
+ bool found = getstringfield(L, -1, "password", password);
+ if(!found)
+ throw LuaError(L, "Authentication handler didn't return password");
+ if(dst_password)
+ *dst_password = password;
+
+ lua_getfield(L, -1, "privileges");
+ if(!lua_istable(L, -1))
+ throw LuaError(L,
+ "Authentication handler didn't return privilege table");
+ if(dst_privs)
+ read_privileges(L, -1, *dst_privs);
+ lua_pop(L, 1);
+
+ return true;
+}
+
+void scriptapi_create_auth(lua_State *L, const std::string &playername,
+ const std::string &password)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ get_auth_handler(L);
+ lua_getfield(L, -1, "create_auth");
+ if(lua_type(L, -1) != LUA_TFUNCTION)
+ throw LuaError(L, "Authentication handler missing create_auth");
+ lua_pushstring(L, playername.c_str());
+ lua_pushstring(L, password.c_str());
+ if(lua_pcall(L, 2, 0, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+}
+
+bool scriptapi_set_password(lua_State *L, const std::string &playername,
+ const std::string &password)
+{
+ realitycheck(L);
+ assert(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ get_auth_handler(L);
+ lua_getfield(L, -1, "set_password");
+ if(lua_type(L, -1) != LUA_TFUNCTION)
+ throw LuaError(L, "Authentication handler missing set_password");
+ lua_pushstring(L, playername.c_str());
+ lua_pushstring(L, password.c_str());
+ if(lua_pcall(L, 2, 1, 0))
+ script_error(L, "error: %s", lua_tostring(L, -1));
+ return lua_toboolean(L, -1);
+}
+
/*
item callbacks and node callbacks
*/
#include "irrlichttypes.h"
#include <string>
#include "mapnode.h"
+#include <set>
class Server;
class ServerEnvironment;
void scriptapi_on_joinplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player);
+bool scriptapi_get_auth(lua_State *L, const std::string &playername,
+ std::string *dst_password, std::set<std::string> *dst_privs);
+void scriptapi_create_auth(lua_State *L, const std::string &playername,
+ const std::string &password);
+bool scriptapi_set_password(lua_State *L, const std::string &playername,
+ const std::string &password);
/* item callbacks */
bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,
{
m_server->setAsyncFatalError(e.what());
}
+ catch(LuaError &e)
+ {
+ m_server->setAsyncFatalError(e.what());
+ }
}
END_DEBUG_EXCEPTION_HANDLER(errorstream)
m_async_fatal_error(""),
m_env(NULL),
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
- m_authmanager(path_world+DIR_DELIM+"auth.txt"),
m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
m_lua(NULL),
m_itemdef(createItemDefManager()),
ScopeProfiler sp(g_profiler, "Server: saving stuff");
- // Auth stuff
- if(m_authmanager.isModified())
- m_authmanager.save();
-
//Ban stuff
if(m_banmanager.isModified())
m_banmanager.save();
password[PASSWORD_SIZE-1] = 0;
}
- // Add player to auth manager
- if(m_authmanager.exists(playername) == false)
- {
- std::wstring default_password =
+ std::string checkpwd;
+ bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
+
+ if(!has_auth){
+ std::wstring raw_default_password =
narrow_to_wide(g_settings->get("default_password"));
- std::string translated_default_password =
- translatePassword(playername, default_password);
+ std::string use_password =
+ translatePassword(playername, raw_default_password);
// If default_password is empty, allow any initial password
- if (default_password.length() == 0)
- translated_default_password = password;
-
- infostream<<"Server: adding player "<<playername
- <<" to auth manager"<<std::endl;
- m_authmanager.add(playername);
- m_authmanager.setPassword(playername, translated_default_password);
- m_authmanager.setPrivs(playername,
- stringToPrivs(g_settings->get("default_privs")));
- m_authmanager.save();
- }
+ if (raw_default_password.length() == 0)
+ use_password = password;
- std::string checkpwd = m_authmanager.getPassword(playername);
+ scriptapi_create_auth(m_lua, playername, use_password);
+ }
+
+ has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
- /*infostream<<"Server: Client gave password '"<<password
- <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
+ if(!has_auth){
+ SendAccessDenied(m_con, peer_id, L"Not allowed to login");
+ return;
+ }
- if(password != checkpwd)
- {
+ if(password != checkpwd){
infostream<<"Server: peer_id="<<peer_id
<<": supplied invalid password for "
<<playername<<std::endl;
// Enforce user limit.
// Don't enforce for users that have some admin right
if(m_clients.size() >= g_settings->getU16("max_users") &&
- (m_authmanager.getPrivs(playername)
- & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS|PRIV_PASSWORD)) == 0 &&
+ !checkPriv(playername, "server") &&
+ !checkPriv(playername, "ban") &&
+ !checkPriv(playername, "privs") &&
+ !checkPriv(playername, "password") &&
playername != g_settings->get("name"))
{
actionstream<<"Server: "<<playername<<" tried to join, but there"
}
else if(command == TOSERVER_SIGNNODETEXT)
{
- if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
+ if(!checkPriv(player->getName(), "interact"))
return;
/*
u16 command
// Disallow moving items in elsewhere than player's inventory
// if not allowed to interact
- if((getPlayerPrivs(player) & PRIV_INTERACT) == 0
- && (!from_inv_is_current_player
- || !to_inv_is_current_player))
+ if(!checkPriv(player->getName(), "interact") &&
+ (!from_inv_is_current_player ||
+ !to_inv_is_current_player))
{
infostream<<"Cannot move outside of player's inventory: "
<<"No interact privilege"<<std::endl;
}
// If player is not an admin, check for ownership of src and dst
- if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
+ if(!checkPriv(player->getName(), "server"))
{
std::string owner_from = getInventoryOwner(ma->from_inv);
if(owner_from != "" && owner_from != player->getName())
setInventoryModified(da->from_inv);
// Disallow dropping items if not allowed to interact
- if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
+ if(!checkPriv(player->getName(), "interact"))
{
delete a;
return;
}
// If player is not an admin, check for ownership
- else if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
+ else if(!checkPriv(player->getName(), "server"))
{
std::string owner_from = getInventoryOwner(da->from_inv);
if(owner_from != "" && owner_from != player->getName())
// (ca->craft_inv.name == player->getName());
// Disallow crafting if not allowed to interact
- if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
+ if(!checkPriv(player->getName(), "interact"))
{
infostream<<"Cannot craft: "
<<"No interact privilege"<<std::endl;
}
// If player is not an admin, check for ownership of inventory
- if((getPlayerPrivs(player) & PRIV_SERVER) == 0)
+ if(!checkPriv(player->getName(), "server"))
{
std::string owner_craft = getInventoryOwner(ca->craft_inv);
if(owner_craft != "" && owner_craft != player->getName())
// Whether to send to other players
bool send_to_others = false;
- // Local player gets all privileges regardless of
- // what's set on their account.
- u64 privs = getPlayerPrivs(player);
-
// Parse commands
if(message[0] == L'/')
{
paramstring,
this,
m_env,
- player,
- privs);
+ player);
std::wstring reply(processServerCommand(ctx));
send_to_sender = ctx->flags & SEND_TO_SENDER;
}
else
{
- if(privs & PRIV_SHOUT)
- {
+ if(checkPriv(player->getName(), "shout")){
line += L"<";
line += name;
line += L"> ";
line += message;
send_to_others = true;
- }
- else
- {
+ } else {
line += L"Server: You are not allowed to shout";
send_to_sender = true;
}
std::string playername = player->getName();
- if(m_authmanager.exists(playername) == false)
- {
- infostream<<"Server: playername not found in authmanager"<<std::endl;
- // Wrong old password supplied!!
- SendChatMessage(peer_id, L"playername not found in authmanager");
- return;
- }
-
- std::string checkpwd = m_authmanager.getPassword(playername);
+ std::string checkpwd;
+ scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
if(oldpwd != checkpwd)
{
return;
}
- actionstream<<player->getName()<<" changes password"<<std::endl;
-
- m_authmanager.setPassword(playername, newpwd);
-
- infostream<<"Server: password change successful for "<<playername
- <<std::endl;
- SendChatMessage(peer_id, L"Password change successful");
+ bool success = scriptapi_set_password(m_lua, playername, newpwd);
+ if(success){
+ actionstream<<player->getName()<<" changes password"<<std::endl;
+ SendChatMessage(peer_id, L"Password change successful");
+ } else {
+ actionstream<<player->getName()<<" tries to change password but "
+ <<"it fails"<<std::endl;
+ SendChatMessage(peer_id, L"Password change failed or inavailable");
+ }
}
else if(command == TOSERVER_PLAYERITEM)
{
/*
Make sure the player is allowed to do it
*/
- if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
+ if(!checkPriv(player->getName(), "interact"))
{
infostream<<"Ignoring interaction from player "<<player->getName()
- <<" because privileges are "<<getPlayerPrivs(player)
- <<std::endl;
+ <<" (no interact privilege)"<<std::endl;
return;
}
return os.str();
}
-u64 Server::getPlayerAuthPrivs(const std::string &name)
-{
- try{
- return m_authmanager.getPrivs(name);
- }
- catch(AuthNotFoundException &e)
- {
- dstream<<"WARNING: Auth not found for "<<name<<std::endl;
- return 0;
- }
-}
-
-void Server::setPlayerAuthPrivs(const std::string &name, u64 privs)
-{
- try{
- return m_authmanager.setPrivs(name, privs);
- }
- catch(AuthNotFoundException &e)
- {
- dstream<<"WARNING: Auth not found for "<<name<<std::endl;
- }
-}
-
-u64 Server::getPlayerEffectivePrivs(const std::string &name)
+std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
{
- // Local player gets all privileges regardless of
- // what's set on their account.
- if(m_simple_singleplayer_mode)
- return PRIV_ALL;
- if(name == g_settings->get("name"))
- return PRIV_ALL;
- return getPlayerAuthPrivs(name);
+ std::set<std::string> privs;
+ scriptapi_get_auth(m_lua, name, NULL, &privs);
+ return privs;
}
-void Server::setPlayerPassword(const std::string &name, const std::wstring &password)
+bool Server::checkPriv(const std::string &name, const std::string &priv)
{
- // Add player to auth manager
- if(m_authmanager.exists(name) == false)
- {
- infostream<<"Server: adding player "<<name
- <<" to auth manager"<<std::endl;
- m_authmanager.add(name);
- m_authmanager.setPrivs(name,
- stringToPrivs(g_settings->get("default_privs")));
- }
- // Change password and save
- m_authmanager.setPassword(name, translatePassword(name, password));
- m_authmanager.save();
+ std::set<std::string> privs = getPlayerEffectivePrivs(name);
+ return (privs.count(priv) != 0);
}
// Saves g_settings to configpath given at initialization
}
}
-u64 Server::getPlayerPrivs(Player *player)
-{
- if(player==NULL)
- return 0;
- std::string playername = player->getName();
- return getPlayerEffectivePrivs(playername);
-}
-
void dedicated_server_loop(Server &server, bool &kill)
{
DSTACK(__FUNCTION_NAME);
#include "porting.h"
#include "map.h"
#include "inventory.h"
-#include "auth.h"
#include "ban.h"
#include "gamedef.h"
#include "serialization.h" // For SER_FMT_VER_INVALID
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms);
void stopSound(s32 handle);
- // Thread-safe
- u64 getPlayerAuthPrivs(const std::string &name);
- void setPlayerAuthPrivs(const std::string &name, u64 privs);
- u64 getPlayerEffectivePrivs(const std::string &name);
+ // Envlock + conlock
+ std::set<std::string> getPlayerEffectivePrivs(const std::string &name);
+ bool checkPriv(const std::string &name, const std::string &priv);
- // Changes a player's password, password must be given as plaintext
- // If the player doesn't exist, a new entry is added to the auth manager
- void setPlayerPassword(const std::string &name, const std::wstring &password);
-
// Saves g_settings to configpath given at initialization
void saveConfig();
void handlePeerChange(PeerChange &c);
void handlePeerChanges();
- u64 getPlayerPrivs(Player *player);
-
/*
Variables
*/
// Connected clients (behind the con mutex)
core::map<u16, RemoteClient*> m_clients;
- // User authentication
- AuthManager m_authmanager;
-
// Bann checking
BanManager m_banmanager;
ctx->flags |= SEND_TO_OTHERS | SEND_NO_PREFIX;
}
-void cmd_privs(std::wostringstream &os,
- ServerCommandContext *ctx)
-{
- if(ctx->parms.size() == 1)
- {
- // Show our own real privs, without any adjustments
- // made for admin status
- os<<L"-!- " + narrow_to_wide(privsToString(
- ctx->server->getPlayerAuthPrivs(ctx->player->getName())));
- return;
- }
-
- if((ctx->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"-!- " + narrow_to_wide(privsToString(ctx->server->getPlayerAuthPrivs(tp->getName())));
-}
-
-void cmd_grantrevoke(std::wostringstream &os,
- ServerCommandContext *ctx)
-{
- if(ctx->parms.size() != 3)
- {
- os<<L"-!- Missing parameter";
- return;
- }
-
- if((ctx->privs & PRIV_PRIVS) == 0)
- {
- os<<L"-!- You don't have permission to do that";
- return;
- }
-
- u64 newprivs = stringToPrivs(wide_to_narrow(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;
- }
-
- std::string playername = wide_to_narrow(ctx->parms[1]);
- u64 privs = ctx->server->getPlayerAuthPrivs(playername);
-
- if(ctx->parms[0] == L"grant"){
- privs |= newprivs;
- actionstream<<ctx->player->getName()<<" grants "
- <<wide_to_narrow(ctx->parms[2])<<" to "
- <<playername<<std::endl;
-
- std::wstring msg;
- msg += narrow_to_wide(ctx->player->getName());
- msg += L" granted you the privilege \"";
- msg += ctx->parms[2];
- msg += L"\"";
- ctx->server->notifyPlayer(playername.c_str(), msg);
- } else {
- privs &= ~newprivs;
- actionstream<<ctx->player->getName()<<" revokes "
- <<wide_to_narrow(ctx->parms[2])<<" from "
- <<playername<<std::endl;
-
- std::wstring msg;
- msg += narrow_to_wide(ctx->player->getName());
- msg += L" revoked from you the privilege \"";
- msg += ctx->parms[2];
- msg += L"\"";
- ctx->server->notifyPlayer(playername.c_str(), msg);
- }
-
- ctx->server->setPlayerAuthPrivs(playername, privs);
-
- os<<L"-!- Privileges change to ";
- os<<narrow_to_wide(privsToString(privs));
-}
-
void cmd_time(std::wostringstream &os,
ServerCommandContext *ctx)
{
os<<L"-!- Missing parameter";
return;
}
-
- if((ctx->privs & PRIV_SETTIME) ==0)
+
+ if(!ctx->server->checkPriv(ctx->player->getName(), "settime"))
{
os<<L"-!- You don't have permission to do that";
return;
void cmd_shutdown(std::wostringstream &os,
ServerCommandContext *ctx)
{
- if((ctx->privs & PRIV_SERVER) ==0)
+ if(!ctx->server->checkPriv(ctx->player->getName(), "server"))
{
os<<L"-!- You don't have permission to do that";
return;
void cmd_setting(std::wostringstream &os,
ServerCommandContext *ctx)
{
- if((ctx->privs & PRIV_SERVER) ==0)
+ if(!ctx->server->checkPriv(ctx->player->getName(), "server"))
{
os<<L"-!- You don't have permission to do that";
return;
void cmd_teleport(std::wostringstream &os,
ServerCommandContext *ctx)
{
- if((ctx->privs & PRIV_TELEPORT) ==0)
+ if(!ctx->server->checkPriv(ctx->player->getName(), "teleport"))
{
os<<L"-!- You don't have permission to do that";
return;
void cmd_banunban(std::wostringstream &os, ServerCommandContext *ctx)
{
- if((ctx->privs & PRIV_BAN) == 0)
+ if(!ctx->server->checkPriv(ctx->player->getName(), "ban"))
{
os<<L"-!- You don't have permission to do that";
return;
}
}
-void cmd_setclearpassword(std::wostringstream &os,
- ServerCommandContext *ctx)
-{
- if((ctx->privs & PRIV_PASSWORD) == 0)
- {
- os<<L"-!- You don't have permission to do that";
- return;
- }
-
- std::string playername;
- std::wstring password;
-
- if(ctx->parms[0] == L"setpassword")
- {
- if(ctx->parms.size() != 3)
- {
- os<<L"-!- Missing parameter";
- return;
- }
-
- playername = wide_to_narrow(ctx->parms[1]);
- password = ctx->parms[2];
-
- actionstream<<ctx->player->getName()<<" sets password of "
- <<playername<<std::endl;
- }
- else
- {
- // clearpassword
-
- if(ctx->parms.size() != 2)
- {
- os<<L"-!- Missing parameter";
- return;
- }
-
- playername = wide_to_narrow(ctx->parms[1]);
- password = L"";
-
- actionstream<<ctx->player->getName()<<" clears password of"
- <<playername<<std::endl;
- }
-
- ctx->server->setPlayerPassword(playername, password);
-
- std::wostringstream msg;
- msg<<ctx->player->getName()<<L" changed your password";
- ctx->server->notifyPlayer(playername.c_str(), msg.str());
-
- os<<L"-!- Password change for "<<narrow_to_wide(playername)<<" successful";
-}
-
void cmd_clearobjects(std::wostringstream &os,
ServerCommandContext *ctx)
{
- if((ctx->privs & PRIV_SERVER) ==0)
+ if(!ctx->server->checkPriv(ctx->player->getName(), "server"))
{
os<<L"-!- You don't have permission to do that";
return;
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_teleport(os, ctx);
else if(ctx->parms[0] == L"ban" || ctx->parms[0] == L"unban")
cmd_banunban(os, ctx);
- else if(ctx->parms[0] == L"setpassword" || ctx->parms[0] == L"clearpassword")
- cmd_setclearpassword(os, ctx);
else if(ctx->parms[0] == L"me")
cmd_me(os, ctx);
else if(ctx->parms[0] == L"clearobjects")
Server* server;
ServerEnvironment *env;
Player* player;
- // Effective privs for the player, which may be different to their
- // stored ones - e.g. if they are named in the config as an admin.
- u64 privs;
u32 flags;
ServerCommandContext(
std::wstring paramstring,
Server* server,
ServerEnvironment *env,
- Player* player,
- u64 privs)
+ Player* player)
: parms(parms), paramstring(paramstring),
- server(server), env(env), player(player), privs(privs)
+ server(server), env(env), player(player)
{
}