Reimplement authentication handler in Lua; now we have 1) infinite privilege names...
authorPerttu Ahola <celeron55@gmail.com>
Fri, 30 Mar 2012 15:42:18 +0000 (18:42 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Fri, 30 Mar 2012 15:42:18 +0000 (18:42 +0300)
builtin/builtin.lua
doc/lua_api.txt
src/CMakeLists.txt
src/auth.cpp [deleted file]
src/auth.h [deleted file]
src/scriptapi.cpp
src/scriptapi.h
src/server.cpp
src/server.h
src/servercommand.cpp
src/servercommand.h

index 55220a607012970bfca1708cd99267fd9b3b0b26..45119be4855ad9ce5a8fb6b4424ecc49175898db 100644 (file)
@@ -12,7 +12,7 @@
 print = minetest.debug
 
 --
---
+-- Define some random basic things
 --
 
 function basic_dump2(o)
@@ -89,6 +89,19 @@ function dump(o, dumped)
        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
 --
@@ -818,7 +831,7 @@ minetest.register_globalstep(function(dtime)
 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)
@@ -848,6 +861,21 @@ function minetest.get_connected_players()
        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
 --
@@ -873,7 +901,7 @@ minetest.register_chatcommand("help", {
                        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
@@ -905,18 +933,89 @@ minetest.register_chatcommand("help", {
 -- 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
@@ -924,6 +1023,9 @@ minetest.register_chatcommand("clearpassword", {params = "<name>", description =
 
 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
@@ -942,6 +1044,149 @@ minetest.register_on_chat_message(function(name, message)
        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
 --
index 1199f8108ece4df96dd7b0c0739f0e93da6127dc..a355f89320947f0e99043360ba8eb5f6a7c8a9b1 100644 (file)
@@ -464,6 +464,8 @@ dump2(obj, name="_", dumped={})
 ^ 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
 -----------------------------
@@ -480,6 +482,7 @@ minetest.log(line)
 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)
@@ -487,7 +490,6 @@ minetest.register_tool(name, item 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))
@@ -500,24 +502,40 @@ minetest.register_on_respawnplayer(func(ObjectRef))
 ^ 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.
index fce887047d660c100a8289745be86199572c398e..0c7fc988c9263fee1c0931fbf3cf3690d97dedcc 100644 (file)
@@ -173,7 +173,6 @@ set(common_SRCS
        mapgen.cpp
        content_nodemeta.cpp
        content_mapnode.cpp
-       auth.cpp
        collision.cpp
        nodemetadata.cpp
        serverobject.cpp
diff --git a/src/auth.cpp b/src/auth.cpp
deleted file mode 100644 (file)
index cafeb38..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
-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;
-}
-
-
diff --git a/src/auth.h b/src/auth.h
deleted file mode 100644 (file)
index 6f17693..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-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
-
index 65894e28444b9193e07eeadcfd0ecca4c13c1838..4ca114a0cd37d57da4eaf64129ab2016a24b8b52 100644 (file)
@@ -141,14 +141,14 @@ static Server* get_server(lua_State *L)
        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)
 {
@@ -647,6 +647,27 @@ static void read_groups(lua_State *L, int index,
        }
 }
 
+/*
+       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
 */
@@ -3837,8 +3858,7 @@ static int l_get_player_privs(lua_State *L)
        // 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);
@@ -3954,6 +3974,17 @@ static int l_is_singleplayer(lua_State *L)
        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},
@@ -3974,6 +4005,7 @@ static const struct luaL_Reg minetest_f [] = {
        {"sound_play", l_sound_play},
        {"sound_stop", l_sound_stop},
        {"is_singleplayer", l_is_singleplayer},
+       {"get_password_hash", l_get_password_hash},
        {NULL, NULL}
 };
 
@@ -4421,6 +4453,10 @@ void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player)
 
 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);
 
@@ -4430,6 +4466,91 @@ void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player)
        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
 */
index b80039f9e8410ed8580589d07d9ffb56cc6ee872..fe8b26e04c1823d926aaefb89b108102f598dcf7 100644 (file)
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "irrlichttypes.h"
 #include <string>
 #include "mapnode.h"
+#include <set>
 
 class Server;
 class ServerEnvironment;
@@ -60,6 +61,12 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player);
 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,
index 4a6165f307a61e4488b99aa971f876a7b9d8ed19..e9b236cc428e21d3723497be627e5f4f9b51ccfd 100644 (file)
@@ -142,6 +142,10 @@ void * ServerThread::Thread()
                {
                        m_server->setAsyncFatalError(e.what());
                }
+               catch(LuaError &e)
+               {
+                       m_server->setAsyncFatalError(e.what());
+               }
        }
        
        END_DEBUG_EXCEPTION_HANDLER(errorstream)
@@ -905,7 +909,6 @@ Server::Server(
        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()),
@@ -1844,10 +1847,6 @@ void Server::AsyncRunStep()
 
                        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();
@@ -2083,34 +2082,30 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        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;
@@ -2131,8 +2126,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                // 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"
@@ -2407,7 +2404,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
        }
        else if(command == TOSERVER_SIGNNODETEXT)
        {
-               if((getPlayerPrivs(player) & PRIV_INTERACT) == 0)
+               if(!checkPriv(player->getName(), "interact"))
                        return;
                /*
                        u16 command
@@ -2519,9 +2516,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                        // 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;
@@ -2530,7 +2527,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        }
 
                        // 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())
@@ -2565,13 +2562,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        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())
@@ -2600,7 +2597,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        //      (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;
@@ -2609,7 +2606,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        }
 
                        // 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())
@@ -2667,10 +2664,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                // 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'/')
                {
@@ -2688,8 +2681,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                paramstring,
                                this,
                                m_env,
-                               player,
-                               privs);
+                               player);
 
                        std::wstring reply(processServerCommand(ctx));
                        send_to_sender = ctx->flags & SEND_TO_SENDER;
@@ -2705,16 +2697,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                }
                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;
                        }
@@ -2803,15 +2792,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                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)
                {
@@ -2821,13 +2803,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        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)
        {
@@ -2970,11 +2954,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                /*
                        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;
                }
 
@@ -4277,54 +4260,17 @@ std::wstring Server::getStatusString()
        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
@@ -4698,14 +4644,6 @@ void Server::handlePeerChanges()
        }
 }
 
-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);
index d40c7c73e87f19ac9ec5eb1843d261e27b815486..4b04044e1284b823749e61de70f737fdb1fbb742 100644 (file)
@@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #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
@@ -500,15 +499,10 @@ public:
        s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams &params);
        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();
 
@@ -670,8 +664,6 @@ private:
        void handlePeerChange(PeerChange &c);
        void handlePeerChanges();
 
-       u64 getPlayerPrivs(Player *player);
-
        /*
                Variables
        */
@@ -710,9 +702,6 @@ private:
        // Connected clients (behind the con mutex)
        core::map<u16, RemoteClient*> m_clients;
 
-       // User authentication
-       AuthManager m_authmanager;
-
        // Bann checking
        BanManager m_banmanager;
 
index 48ada56fe1c11d23b5b2e90fdb2e8ffe0fdf271e..64c43d4f5cb8e373bc5dd0fe54dc561142d96e0d 100644 (file)
@@ -38,98 +38,6 @@ void cmd_me(std::wostringstream &os,
        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)
 {
@@ -138,8 +46,8 @@ void cmd_time(std::wostringstream &os,
                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;
@@ -156,7 +64,7 @@ void cmd_time(std::wostringstream &os,
 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;
@@ -174,7 +82,7 @@ void cmd_shutdown(std::wostringstream &os,
 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;
@@ -198,7 +106,7 @@ void cmd_setting(std::wostringstream &os,
 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;
@@ -241,7 +149,7 @@ void cmd_teleport(std::wostringstream &os,
 
 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;
@@ -288,62 +196,10 @@ void cmd_banunban(std::wostringstream &os, ServerCommandContext *ctx)
        }
 }
 
-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;
@@ -378,10 +234,6 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
 
        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")
@@ -392,8 +244,6 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
                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")
index 648a57332716ebbbf5f05e42eb830ad2a271aa9d..a3cf750daeb26a96b981e9013e13796f2d5c4931 100644 (file)
@@ -36,9 +36,6 @@ struct ServerCommandContext
        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(
@@ -46,10 +43,9 @@ struct 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)
        {
        }