From 6c06330daf04ed1c390131755b64338ca7d79a7e Mon Sep 17 00:00:00 2001
From: ShadowNinja <shadowninja@minetest.net>
Date: Tue, 9 Sep 2014 21:52:07 -0400
Subject: [PATCH] Add core.request_insecure_environment()

---
 doc/lua_api.txt               | 13 ++++++++++---
 minetest.conf.example         |  3 +++
 src/defaultsettings.cpp       |  1 +
 src/script/lua_api/l_util.cpp | 29 ++++++++++++++++++++++++++++-
 src/script/lua_api/l_util.h   |  4 ++++
 5 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index c82208286..0e1dc487f 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -2290,13 +2290,20 @@ These functions return the leftover itemstack.
 * `minetest.forceload_block(pos)`
     * forceloads the position `pos`.
     * returns `true` if area could be forceloaded
+    * Please note that forceloaded areas are saved when the server restarts.
 
 * `minetest.forceload_free_block(pos)`
     * stops forceloading the position `pos`
-Please note that forceloaded areas are saved when the server restarts.
 
-minetest.global_exists(name)
-^ Checks if a global variable has been set, without triggering a warning.
+* `minetest.request_insecure_environment()`: returns an environment containing
+  insecure functions if the calling mod has been listed as trusted in the
+  `secure.trusted_mods` setting or security is disabled, otherwise returns `nil`.
+    * Only works at init time.
+    * **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED ENVIRONMENT, STORE IT IN
+      A LOCAL VARIABLE!**
+
+* `minetest.global_exists(name)`
+    * Checks if a global variable has been set, without triggering a warning.
 
 ### Global objects
 * `minetest.env`: `EnvRef` of the server environment and world.
diff --git a/minetest.conf.example b/minetest.conf.example
index 6474289bd..392bd55bb 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -571,4 +571,7 @@
 
 #    Prevent mods from doing insecure things like running shell commands.
 #secure.enable_security = false
+#    Comma-separated list of trusted mods that are allowed to access insecure
+#    functions even when mod security is on (via request_insecure_environment()).
+#secure.trusted_mods =
 
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index f26b4c8ad..af1aa4140 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -273,6 +273,7 @@ void set_default_settings(Settings *settings)
 	settings->setDefault("emergequeue_limit_generate", "32");
 	settings->setDefault("num_emerge_threads", "1");
 	settings->setDefault("secure.enable_security", "false");
+	settings->setDefault("secure.trusted_mods", "");
 
 	// physics stuff
 	settings->setDefault("movement_acceleration_default", "3");
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index e16b6feab..2bcc114e2 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "filesys.h"
 #include "settings.h"
 #include "util/auth.h"
+#include <algorithm>
 
 // debug(...)
 // Writes a line to dstream
@@ -316,7 +317,7 @@ int ModApiUtil::l_compress(lua_State *L)
 int ModApiUtil::l_decompress(lua_State *L)
 {
 	size_t size;
-	const char * data = luaL_checklstring(L, 1, &size);
+	const char *data = luaL_checklstring(L, 1, &size);
 
 	std::istringstream is(std::string(data, size));
 	std::ostringstream os;
@@ -339,6 +340,30 @@ int ModApiUtil::l_mkdir(lua_State *L)
 }
 
 
+int ModApiUtil::l_request_insecure_environment(lua_State *L)
+{
+	NO_MAP_LOCK_REQUIRED;
+	if (!ScriptApiSecurity::isSecure(L)) {
+		lua_getglobal(L, "_G");
+		return 1;
+	}
+	lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+	if (!lua_isstring(L, -1)) {
+		lua_pushnil(L);
+		return 1;
+	}
+	const char *mod_name = lua_tostring(L, -1);
+	std::string trusted_mods = g_settings->get("secure.trusted_mods");
+	std::vector<std::string> mod_list = str_split(trusted_mods, ',');
+	if (std::find(mod_list.begin(), mod_list.end(), mod_name) == mod_list.end()) {
+		lua_pushnil(L);
+		return 1;
+	}
+	lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
+	return 1;
+}
+
+
 void ModApiUtil::Initialize(lua_State *L, int top)
 {
 	API_FCT(debug);
@@ -366,6 +391,8 @@ void ModApiUtil::Initialize(lua_State *L, int top)
 	API_FCT(decompress);
 
 	API_FCT(mkdir);
+
+	API_FCT(request_insecure_environment);
 }
 
 void ModApiUtil::InitializeAsync(AsyncEngine& engine)
diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h
index bf7cd71d3..336173664 100644
--- a/src/script/lua_api/l_util.h
+++ b/src/script/lua_api/l_util.h
@@ -90,6 +90,9 @@ class ModApiUtil : public ModApiBase {
 	// mkdir(path)
 	static int l_mkdir(lua_State *L);
 
+	// request_insecure_environment()
+	static int l_request_insecure_environment(lua_State *L);
+
 public:
 	static void Initialize(lua_State *L, int top);
 
@@ -98,3 +101,4 @@ class ModApiUtil : public ModApiBase {
 };
 
 #endif /* L_UTIL_H_ */
+
-- 
GitLab